Phase 6 WIP working
This commit is contained in:
parent
968101c532
commit
d0f93e5c55
@ -8,7 +8,7 @@
|
|||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint:scenes": "node tools/lint-scenes.js",
|
"lint:scenes": "node tools/lint-scenes.js",
|
||||||
"test": "node --test test/"
|
"test": "node --test test/*.test.js"
|
||||||
},
|
},
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@ -95,18 +95,26 @@ document.addEventListener('drop', (e) => {
|
|||||||
|
|
||||||
// ---------------------------------------------------------------- transport
|
// ---------------------------------------------------------------- transport
|
||||||
|
|
||||||
function seekTo(frame) {
|
function seekTo(frame, options = {}) {
|
||||||
if (!state.show.ready) return;
|
if (!state.show.ready) return;
|
||||||
const clamped = Math.max(0, Math.min(state.show.frameCount - 1, Math.round(frame)));
|
const clamped = Math.max(0, Math.min(state.show.frameCount - 1, Math.round(frame)));
|
||||||
dom.audio.currentTime = clamped / state.show.fps;
|
dom.audio.currentTime = clamped / state.show.fps;
|
||||||
state.show.seek(clamped);
|
state.show.seek(clamped, options);
|
||||||
strip.setFrame(clamped);
|
strip.setFrame(clamped);
|
||||||
}
|
}
|
||||||
|
|
||||||
function togglePlay() {
|
function togglePlay() {
|
||||||
if (!state.show.ready) return;
|
if (!state.show.ready) return;
|
||||||
state.playing = !state.playing;
|
state.playing = !state.playing;
|
||||||
if (state.playing) dom.audio.play(); else dom.audio.pause();
|
if (state.playing) {
|
||||||
|
dom.audio.play().catch((err) => {
|
||||||
|
console.warn('[flow-state] playback failed:', err);
|
||||||
|
state.playing = false;
|
||||||
|
dom.play.textContent = '▶';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dom.audio.pause();
|
||||||
|
}
|
||||||
dom.play.textContent = state.playing ? '❚❚' : '▶';
|
dom.play.textContent = state.playing ? '❚❚' : '▶';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,6 +384,7 @@ function resize() {
|
|||||||
window.addEventListener('resize', resize);
|
window.addEventListener('resize', resize);
|
||||||
|
|
||||||
let lastPanelSection = -1;
|
let lastPanelSection = -1;
|
||||||
|
let lastRenderedFrame = -1;
|
||||||
|
|
||||||
function frame(now) {
|
function frame(now) {
|
||||||
requestAnimationFrame(frame);
|
requestAnimationFrame(frame);
|
||||||
@ -393,7 +402,10 @@ function frame(now) {
|
|||||||
if (dom.audio.ended) { state.playing = false; dom.play.textContent = '▶'; }
|
if (dom.audio.ended) { state.playing = false; dom.play.textContent = '▶'; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state.playing || show.timeline.frame !== lastRenderedFrame) {
|
||||||
show.present(show.renderFrame(show.timeline.frame));
|
show.present(show.renderFrame(show.timeline.frame));
|
||||||
|
lastRenderedFrame = show.timeline.frame;
|
||||||
|
}
|
||||||
|
|
||||||
strip.setFrame(show.timeline.frame);
|
strip.setFrame(show.timeline.frame);
|
||||||
strip.draw();
|
strip.draw();
|
||||||
|
|||||||
@ -23,14 +23,30 @@ export class TimelineStrip {
|
|||||||
this.frame = 0;
|
this.frame = 0;
|
||||||
this.hoverFrame = -1;
|
this.hoverFrame = -1;
|
||||||
this.loopSection = -1;
|
this.loopSection = -1;
|
||||||
|
this.isDragging = false;
|
||||||
|
|
||||||
canvas.addEventListener('pointerdown', (e) => this._seekFromEvent(e));
|
canvas.addEventListener('pointerdown', (e) => {
|
||||||
|
this.isDragging = true;
|
||||||
|
this._seekFromEvent(e, { warmup: false });
|
||||||
|
});
|
||||||
canvas.addEventListener('pointermove', (e) => {
|
canvas.addEventListener('pointermove', (e) => {
|
||||||
const rect = canvas.getBoundingClientRect();
|
const rect = canvas.getBoundingClientRect();
|
||||||
this.hoverFrame = this._frameAt(e.clientX - rect.left, rect.width);
|
this.hoverFrame = this._frameAt(e.clientX - rect.left, rect.width);
|
||||||
if (e.buttons & 1) this._seekFromEvent(e);
|
if (this.isDragging || (e.buttons & 1)) {
|
||||||
|
this.isDragging = true;
|
||||||
|
this._seekFromEvent(e, { warmup: false });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
canvas.addEventListener('pointerleave', () => { this.hoverFrame = -1; });
|
canvas.addEventListener('pointerleave', () => { this.hoverFrame = -1; });
|
||||||
|
|
||||||
|
window.addEventListener('pointerup', () => {
|
||||||
|
if (this.isDragging) {
|
||||||
|
this.isDragging = false;
|
||||||
|
if (this.onSeek && this.show && this.show.ready) {
|
||||||
|
this.onSeek(this.frame, { warmup: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setShow(show) { this.show = show; }
|
setShow(show) { this.show = show; }
|
||||||
@ -42,10 +58,10 @@ export class TimelineStrip {
|
|||||||
return Math.round((x / Math.max(1, width)) * (this.show.frameCount - 1));
|
return Math.round((x / Math.max(1, width)) * (this.show.frameCount - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
_seekFromEvent(event) {
|
_seekFromEvent(event, options = {}) {
|
||||||
if (!this.onSeek || !this.show || !this.show.ready) return;
|
if (!this.onSeek || !this.show || !this.show.ready) return;
|
||||||
const rect = this.canvas.getBoundingClientRect();
|
const rect = this.canvas.getBoundingClientRect();
|
||||||
this.onSeek(this._frameAt(event.clientX - rect.left, rect.width));
|
this.onSeek(this._frameAt(event.clientX - rect.left, rect.width), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
resize() {
|
resize() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user