feat: expand campaign and refine puzzle visuals and controls
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import { MOTION } from './design-tokens.js';
|
||||
import { routePoints } from './geometry.js';
|
||||
|
||||
// Timing follows actual path length, so a piece beside an exit has no fixed wait.
|
||||
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};
|
||||
}
|
||||
|
||||
// Zero endpoint velocity: a soft launch and a settled finish, without overshoot.
|
||||
export function smoothMotion(value) {
|
||||
const t=Math.max(0,Math.min(1,value));
|
||||
return t*t*(3-2*t);
|
||||
}
|
||||
Reference in New Issue
Block a user