Add output camera framing

This commit is contained in:
th committed 2026-06-07 23:12:46 +02:00
1 parent 616ced17ce
commit 23a66c6fdf
19 files changed
+1955 -43

No files matched your search

+59
View File
@@ -102,6 +102,56 @@
}
return merge(layer.base);
}
function defaultCameraProps(scene){
return {
x:0,
y:0,
width:Math.max(1, Number(scene.canvas && scene.canvas.width) || 1280),
height:Math.max(1, Number(scene.canvas && scene.canvas.height) || 720)
};
}
function mergeCameraProps(base, props){
props=props||{};
function finite(v, fallback){ return typeof v==='number' && isFinite(v) ? v : fallback; }
return {
x:finite(props.x, base.x),
y:finite(props.y, base.y),
width:Math.max(1, finite(props.width, base.width)),
height:Math.max(1, finite(props.height, base.height))
};
}
function lerpCameraProps(a,b,t){
return {
x:lerp(a.x,b.x,t),
y:lerp(a.y,b.y,t),
width:Math.max(1, lerp(a.width,b.width,t)),
height:Math.max(1, lerp(a.height,b.height,t))
};
}
function sampleCamera(scene,time){
var camera=scene.camera;
var base=defaultCameraProps(scene);
if(!camera) return base;
base=mergeCameraProps(base, camera.base);
var kfs=(camera.keyframes||[]).slice().sort(function(a,b){return a.time-b.time;});
if(!kfs.length) return base;
if(time<=kfs[0].time) return mergeCameraProps(base,kfs[0].props);
var last=kfs[kfs.length-1];
if(time>=last.time) return mergeCameraProps(base,last.props);
for(var i=0;i<kfs.length-1;i++){
var a=kfs[i], b=kfs[i+1];
if(time>=a.time && time<=b.time){
if(a.hold){
if(time>=b.time) return mergeCameraProps(base,b.props);
return mergeCameraProps(base,a.props);
}
var raw=(time-a.time)/Math.max(1e-9,b.time-a.time);
var tt=easing(b.easing,raw);
return lerpCameraProps(mergeCameraProps(base,a.props), mergeCameraProps(base,b.props), tt);
}
}
return base;
}
function loadImages(assets){
var imgs={};
var list=assets.filter(function(a){return a.kind==='image';});
@@ -267,8 +317,17 @@
function drawFrame(time){
if(!scene) return;
var lw=scene.canvas.width, lh=scene.canvas.height;
var useCamera=!!(scene.camera && scene.camera.enabled);
var cam=useCamera?sampleCamera(scene,time):null;
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.beginPath(); ctx.rect(0,0,lw,lh); ctx.clip();
if(useCamera){
ctx.scale(lw/cam.width, lh/cam.height);
ctx.translate(-cam.x,-cam.y);
ctx.beginPath(); ctx.rect(0,0,lw,lh); ctx.clip();
}
if(!scene.backgroundVideo){
ctx.fillStyle=scene.canvas.background;
ctx.fillRect(0,0,lw,lh);