feat: version campaigns and document original puzzle design
Restore v0.1 and v0.2 archives with separate progress, publish the curved v0.3 campaign, and document the original 24-level design with reproducible evidence. Refine board presentation and movement, and keep video lab tooling within its own directory.
This commit is contained in:
+13
-7
@@ -5,13 +5,10 @@ import { routePoints } from './geometry.js';
|
||||
export function exitTiming(route) {
|
||||
const points=routePoints({...route,end:null},{size:1,ox:0,oy:0});
|
||||
const distance=points.slice(1).reduce((sum,p,i)=>sum+Math.hypot(p.x-points[i].x,p.y-points[i].y),0);
|
||||
const travelMs=Math.max(MOTION.exitMinTravelMs,Math.min(MOTION.exitMaxTravelMs,distance*MOTION.exitMsPerUnit));
|
||||
const shortDuration=travelMs+MOTION.exitEffectMs;
|
||||
const longDuration=Math.min(MOTION.exitLongMaxMs,MOTION.exitLongBaseMs+route.steps.length*MOTION.exitLongCellMs);
|
||||
// Blend into the original long-route pacing without slowing edge departures.
|
||||
const blend=smoothMotion((route.steps.length-MOTION.exitLongStartCells)/(MOTION.exitLongFullCells-MOTION.exitLongStartCells));
|
||||
const duration=shortDuration+(longDuration-shortDuration)*blend;
|
||||
return {duration,travelFraction:(duration-MOTION.exitEffectMs)/duration};
|
||||
const rampMs=Math.min(MOTION.exitRampMs,distance*MOTION.exitMsPerUnit/3);
|
||||
const travelMs=distance*MOTION.exitMsPerUnit+rampMs;
|
||||
const duration=travelMs+MOTION.exitEffectMs;
|
||||
return {duration,travelMs,distance,travelFraction:travelMs/duration};
|
||||
}
|
||||
|
||||
// Zero endpoint velocity: a soft launch and a settled finish, without overshoot.
|
||||
@@ -19,3 +16,12 @@ export function smoothMotion(value) {
|
||||
const t=Math.max(0,Math.min(1,value));
|
||||
return t*t*(3-2*t);
|
||||
}
|
||||
|
||||
// Fixed-duration acceleration and braking; the middle travels at a shared speed.
|
||||
export function travelProgress(progress,travelMs){
|
||||
const t=Math.max(0,Math.min(1,progress))*travelMs;
|
||||
const ramp=Math.min(MOTION.exitRampMs,travelMs/4),area=travelMs-ramp;
|
||||
if(t<ramp)return t*t/(2*ramp*area);
|
||||
if(t>travelMs-ramp)return 1-(travelMs-t)**2/(2*ramp*area);
|
||||
return (t-ramp/2)/area;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user