import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import {smoothMotion,smoothSequence,samplePose} from '../smoothing.js'; import {boundsFor,renderStage} from '../motion.js'; const raw=JSON.parse(fs.readFileSync(new URL('../assets/data/fall-real-synthetic-2.json',import.meta.url))); const acceleration=seq=>{let sum=0,n=0;for(let f=75;f{ const before=JSON.stringify(raw),smooth=smoothMotion(raw); assert.equal(JSON.stringify(raw),before); assert.equal(smooth.sourceA.length,raw.sourceA.length); for(const key of ['1','5','9'])assert.ok(acceleration(smooth.variants[key])p[j][c]); assert.ok(smooth.sourceA[f][j][c]>=Math.min(...neighbors)-1e-12&&smooth.sourceA[f][j][c]<=Math.max(...neighbors)+1e-12); } }); test('Filter preserves constant motion and subframe sampling interpolates safely',()=>{ const constant=Array.from({length:9},()=>[[1,2,3]]); for(const frame of smoothSequence(constant))frame[0].forEach((v,i)=>assert.ok(Math.abs(v-(i+1))<1e-12)); assert.deepEqual(samplePose([[[0,0,0]],[[2,4,6]]],.5),[[1,2,3]]); assert.deepEqual(samplePose([[[0,0,0]],[[2,4,6]]],5),[[2,4,6]]); }); test('Mannequin and skeleton overlay render finite geometry through late fall frames',()=>{ let fills=0;const context=new Proxy({},{get:(t,k)=>t[k]??((...args)=>{for(const arg of args)if(typeof arg==='number')assert.ok(Number.isFinite(arg),k);if(k==='fill')fills++;if(k==='createLinearGradient')return{addColorStop(){}};}),set:(t,k,v)=>(t[k]=v,true)}); const canvas={clientWidth:360,clientHeight:244,getContext:()=>context}; for(const frame of [0,74,90.5,130])for(const yaw of [-90,20,90])for(const skeleton of [false,true])renderStage(canvas,[{key:'sourceA',sequence:raw.sourceA,color:'#587997'}],raw.parents,frame,yaw,1,boundsFor(raw,yaw),{human:true,skeleton}); assert.ok(fills>100); }); console.log('Example 2, frames 76–130: second-difference RMS',JSON.stringify({original:acceleration(raw.variants['5']),smoothed:acceleration(smoothMotion(raw).variants['5'])}));