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'
|
import type { Scene } from '@/types/scene'
|
||||||
|
|
||||||
const RUNTIME_VERSION = '2'
|
const RUNTIME_VERSION = '3'
|
||||||
|
|
||||||
const ENGINE_SOURCE = `(function(){
|
const ENGINE_SOURCE = `(function(){
|
||||||
if (window.AnimatrPlayer && window.AnimatrPlayer.__v === '${RUNTIME_VERSION}') return;
|
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 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){
|
function frame(now){
|
||||||
if(!start)start=now;
|
if(rangeLen<=0){
|
||||||
var elapsed=(now-start)/1000;
|
draw(currentT);
|
||||||
var t=rangeIn;
|
syncBgVideo(currentT);
|
||||||
if(rangeLen<=0){ draw(t); syncBgVideo(t); requestAnimationFrame(frame); return; }
|
requestAnimationFrame(frame);
|
||||||
if(loop) t=rangeIn+(elapsed%rangeLen);
|
return;
|
||||||
else if(elapsed>=rangeLen) t=rangeOut;
|
}
|
||||||
else t=rangeIn+elapsed;
|
if(!lastNow) lastNow=now;
|
||||||
draw(t);
|
var dt=(now-lastNow)/1000;
|
||||||
syncBgVideo(t);
|
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);
|
requestAnimationFrame(frame);
|
||||||
}
|
}
|
||||||
function tracePolyPath(tctx,sp,ap,offX,offY,closed){
|
function tracePolyPath(tctx,sp,ap,offX,offY,closed){
|
||||||
|
|||||||
Reference in new issue
Block a user