copy first keyframe button
This commit is contained in:
@@ -48,6 +48,8 @@ function harness() {
|
||||
const context = {
|
||||
Project: project, Group, Cube, Plugin: { register(id, definition) { context.registration = definition; } },
|
||||
Action: class { constructor(id, options) { Object.assign(this, options, { id }); } },
|
||||
Toggle: class { constructor(id, options) { Object.assign(this, options, { id, value: false }); } },
|
||||
Timeline: { loop() {} },
|
||||
Panel: class {
|
||||
constructor(id, options) {
|
||||
this.options = options;
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const vm = require('node:vm');
|
||||
|
||||
function harness() {
|
||||
const h = { Plugin: { register() {} }, Animation: { selected: null, all: [] }, Format: { id: 'geckolib_model' },
|
||||
Animator: { preview() { h.rendered = h.Animation.selected; } },
|
||||
Timeline: { playing: true, custom_range: [0, 0], loop() { this.playing = false; }, setTime(time) { this.time = time; }, start() { this.playing = true; this.loop(); } } };
|
||||
const source = fs.readFileSync(path.join(__dirname, '..', 'AnimationDirector.js'), 'utf8').replace(' Plugin.register(PLUGIN_ID, {',
|
||||
' globalThis.api = { installStageAutoplay, removeStageAutoplay, nextAutoplayStage, setEnabled(value) { autoplayStagesAction = { value }; } };\n Plugin.register(PLUGIN_ID, {');
|
||||
vm.runInNewContext(source, h);
|
||||
h.clip = (name, loop = 'once') => ({ name, length: 2, loop, select() { h.Animation.selected = this; } });
|
||||
h.api.setEnabled(true); h.api.installStageAutoplay();
|
||||
return h;
|
||||
}
|
||||
|
||||
test('autoplay advances completed non-looping stages by number within the same ID', () => {
|
||||
const h = harness(), first = h.clip('example.p1'), next = h.clip('example.p2');
|
||||
h.Animation.selected = first; h.Animation.all = [h.clip('other.p2'), h.clip('example.p10'), next, first];
|
||||
h.Timeline.loop();
|
||||
assert.equal(h.Animation.selected, next);
|
||||
assert.equal(h.Timeline.time, 0);
|
||||
assert.equal(h.Timeline.playing, true);
|
||||
assert.equal(h.rendered, next);
|
||||
});
|
||||
|
||||
test('autoplay leaves looping stages, custom ranges, disabled toggle and final stage alone', () => {
|
||||
for (const mode of ['loop', 'range', 'disabled', 'final']) {
|
||||
const h = harness(), first = h.clip('example.p1', mode === 'loop' ? 'loop' : 'hold');
|
||||
h.Animation.selected = first; h.Animation.all = mode === 'final' ? [first] : [first, h.clip('example.p2')];
|
||||
if (mode === 'range') h.Timeline.custom_range = [0, 1];
|
||||
if (mode === 'disabled') h.api.setEnabled(false);
|
||||
h.Timeline.loop();
|
||||
assert.equal(h.pending, undefined);
|
||||
assert.equal(h.Animation.selected, first);
|
||||
}
|
||||
});
|
||||
|
||||
test('manual playback stops do not advance and unload restores playback', () => {
|
||||
const h = harness(), first = h.clip('example.p1'), next = h.clip('example.p2');
|
||||
h.Animation.selected = first; h.Animation.all = [first, next];
|
||||
h.Timeline.playing = false; h.Timeline.loop();
|
||||
assert.equal(h.pending, undefined);
|
||||
assert.equal(h.Animation.selected, first);
|
||||
assert.equal(h.Timeline.playing, false);
|
||||
const wrapper = h.Timeline.loop; h.api.removeStageAutoplay();
|
||||
assert.notEqual(h.Timeline.loop, wrapper);
|
||||
});
|
||||
Reference in New Issue
Block a user