diff --git a/docs/web/app/landing/petTick.ts b/docs/web/app/landing/petTick.ts index 53043607..5728c997 100644 --- a/docs/web/app/landing/petTick.ts +++ b/docs/web/app/landing/petTick.ts @@ -2,11 +2,20 @@ import { CLAWD_SHEET, stepPlayer, type PetSheet, type Player } from './data.ts' export type PetMode = { kind: 'wander' } | { kind: 'pose'; pose: string } -const WALK_MS = 2400, IDLE_MS = 3000 +const WALK_MS = 2400, IDLE_MS = 3000, REPLAY_REST_MS = 1500 + +// A play-once pose (hop, fail, scrunch) holds its last frame for as long as the pose lasts, so a card +// showing one alternates it with idle; otherwise it plays once at page load and freezes. +function cardPose(sheet: PetSheet, pose: string, now: number): string { + const anim = sheet.animations[pose] + if (!anim || anim.loop) return pose + const ms = anim.frames.reduce((n, f) => n + f.ms, 0) + return now % (ms + REPLAY_REST_MS) < ms ? pose : 'idle' +} // Wander is a fixed walk/idle cycle keyed off `now`: no Math.random, so a given clock always // gives the same pose and the tests stay stable. export function petTick(p: Player, mode: PetMode, now: number, maxX: number, sheet: PetSheet = CLAWD_SHEET): void { - const pose = mode.kind === 'pose' ? mode.pose : now % (WALK_MS + IDLE_MS) < WALK_MS ? 'walk' : 'idle' + const pose = mode.kind === 'pose' ? cardPose(sheet, mode.pose, now) : now % (WALK_MS + IDLE_MS) < WALK_MS ? 'walk' : 'idle' stepPlayer(p, sheet, pose, now, maxX) } diff --git a/docs/web/test/pet.spec.ts b/docs/web/test/pet.spec.ts index 0c62da8e..097d8c71 100644 --- a/docs/web/test/pet.spec.ts +++ b/docs/web/test/pet.spec.ts @@ -20,6 +20,16 @@ test('pose mode settles into the pose', () => { assert.equal(p.seg!.pose, 'working') }) +test('pose mode replays an animation that plays once', () => { + const p = newPlayer() + const starts = new Set() + for (let t = 0; t < 30_000; t += 50) { + petTick(p, { kind: 'pose', pose: 'scrunch' }, t, 0) + if (p.seg!.pose === 'scrunch' && !p.seg!.clip) starts.add(p.seg!.start) + } + assert.ok(starts.size >= 3, `scrunch started ${starts.size} times`) +}) + test('petTick plays a given sheet', () => { const sheet = { w: 2, h: 2, palette: { A: '#000000' }, animations: { idle: { loop: true, frames: [{ ms: 100, px: ['AA', 'AA'] }] } } } const p = newPlayer()