macro-clips slice 6: export runtime fires script frames
- exportPlayer engine refactored from elapsed-since-start to an explicit currentT / lastNow / paused model so actions can jump, pause, and resume cleanly - every frame: advance currentT by dt, fire script frames whose time sits in (prev, next], sorted; on loop wrap, fire frames up to rangeOut then snap to rangeIn without firing across the wrap - evalAction mirrors src/lib/actions.ts (play/pause/rewindToLoop/ jumpTo/jumpToFrame/jumpToMarker/setButtonState/setButtonDisabled/ script); marker map built from scene.markers; unknown markers warn via window.console - RUNTIME_VERSION bumped to '3' so old cached engines don't kick in Server render.html (PNG-sequence path) stays untouched — scripted interactivity is a runtime-only concern, the non-interactive server export should not bake it in. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8817a73c3d
commit
ec8d25a351
1 file changed
+74
-10
+74
-10
@@ -1,6 +1,6 @@
|
||||
import type { Scene } from '@/types/scene'
|
||||
|
||||
const RUNTIME_VERSION = '2'
|
||||
const RUNTIME_VERSION = '3'
|
||||
|
||||
const ENGINE_SOURCE = `(function(){
|
||||
if (window.AnimatrPlayer && window.AnimatrPlayer.__v === '${RUNTIME_VERSION}') return;
|
||||
@@ -189,16 +189,80 @@ const ENGINE_SOURCE = `(function(){
|
||||
}
|
||||
}
|
||||
var rangeLen=Math.max(0, rangeOut-rangeIn);
|
||||
var runtime={
|
||||
fps: scene.fps||60,
|
||||
rangeIn: rangeIn,
|
||||
duration: scene.duration,
|
||||
markers: {},
|
||||
jumpTo: null,
|
||||
forcePause: false,
|
||||
forcePlay: false,
|
||||
buttonStates: {},
|
||||
buttonDisabled: {},
|
||||
warn: function(m){ if(window.console)window.console.warn('[animatr]',m); }
|
||||
};
|
||||
(scene.markers||[]).forEach(function(mk){ runtime.markers[mk.name]=mk.time; });
|
||||
function evalAction(act){
|
||||
switch(act.type){
|
||||
case 'play': runtime.forcePlay=true; runtime.forcePause=false; return;
|
||||
case 'pause': runtime.forcePause=true; runtime.forcePlay=false; return;
|
||||
case 'rewindToLoop': runtime.jumpTo=runtime.rangeIn; return;
|
||||
case 'jumpTo': runtime.jumpTo=Math.max(0,Math.min(runtime.duration,act.time)); return;
|
||||
case 'jumpToFrame': runtime.jumpTo=Math.max(0,Math.min(runtime.duration,act.frame/runtime.fps)); return;
|
||||
case 'jumpToMarker': {
|
||||
var mt=runtime.markers[act.name];
|
||||
if(mt==null){ runtime.warn('Unknown marker: '+act.name); return; }
|
||||
runtime.jumpTo=Math.max(0,Math.min(runtime.duration,mt));
|
||||
return;
|
||||
}
|
||||
case 'setButtonState': runtime.buttonStates[act.instanceId]=act.state; return;
|
||||
case 'setButtonDisabled': runtime.buttonDisabled[act.instanceId]=act.disabled; return;
|
||||
case 'script': runtime.warn('Script DSL not implemented'); return;
|
||||
}
|
||||
}
|
||||
function fireFrames(prev, next){
|
||||
if(next<=prev) return;
|
||||
var frames=scene.scriptFrames||[];
|
||||
var toFire=[];
|
||||
for(var ffi=0; ffi<frames.length; ffi++){
|
||||
var fr=frames[ffi];
|
||||
if(fr.time>prev && fr.time<=next) toFire.push(fr);
|
||||
}
|
||||
toFire.sort(function(a,b){return a.time-b.time;});
|
||||
for(var ffj=0; ffj<toFire.length; ffj++){
|
||||
var acts=toFire[ffj].actions||[];
|
||||
for(var fai=0; fai<acts.length; fai++) evalAction(acts[fai]);
|
||||
}
|
||||
}
|
||||
var currentT=rangeIn;
|
||||
var paused=false;
|
||||
var lastNow=0;
|
||||
function frame(now){
|
||||
if(!start)start=now;
|
||||
var elapsed=(now-start)/1000;
|
||||
var t=rangeIn;
|
||||
if(rangeLen<=0){ draw(t); syncBgVideo(t); requestAnimationFrame(frame); return; }
|
||||
if(loop) t=rangeIn+(elapsed%rangeLen);
|
||||
else if(elapsed>=rangeLen) t=rangeOut;
|
||||
else t=rangeIn+elapsed;
|
||||
draw(t);
|
||||
syncBgVideo(t);
|
||||
if(rangeLen<=0){
|
||||
draw(currentT);
|
||||
syncBgVideo(currentT);
|
||||
requestAnimationFrame(frame);
|
||||
return;
|
||||
}
|
||||
if(!lastNow) lastNow=now;
|
||||
var dt=(now-lastNow)/1000;
|
||||
lastNow=now;
|
||||
if(!paused){
|
||||
var prev=currentT;
|
||||
var nextT=currentT+dt;
|
||||
if(nextT>=rangeOut){
|
||||
fireFrames(prev, rangeOut);
|
||||
currentT = loop ? rangeIn : rangeOut;
|
||||
} else {
|
||||
currentT=nextT;
|
||||
fireFrames(prev, currentT);
|
||||
}
|
||||
if(runtime.jumpTo!=null){ currentT=runtime.jumpTo; runtime.jumpTo=null; }
|
||||
if(runtime.forcePause){ paused=true; runtime.forcePause=false; }
|
||||
if(runtime.forcePlay){ paused=false; runtime.forcePlay=false; }
|
||||
}
|
||||
draw(currentT);
|
||||
syncBgVideo(currentT);
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
function tracePolyPath(tctx,sp,ap,offX,offY,closed){
|
||||
|
||||
Reference in new issue
Block a user