Skip to content

feat: v0.3.7 — idle drift cruise (ambient field baseline) - #59

Open
Jess Sullivan (Jesssullivan) wants to merge 1 commit into
mainfrom
feat/v0.3.7-idle-drift-cruise
Open

feat: v0.3.7 — idle drift cruise (ambient field baseline)#59
Jess Sullivan (Jesssullivan) wants to merge 1 commit into
mainfrom
feat/v0.3.7-idle-drift-cruise

Conversation

@Jesssullivan

Copy link
Copy Markdown
Contributor

Root cause

driftAngle/driftSpeed have been initialized per blob since the pre-Phase-A baseline but were never read by the physics loop — dead code. With no pointer, scroll, or device-motion input, idle motion was only a zero-mean jitter random walk (territorial jitter, neutral drift, brownian, escape kicks) that the per-substep *= 0.992 damping erases with a ~1.4s half-life: blobs jiggled near their territory instead of drifting. The only sustained forcing was gravity from devicemotion, which desktops never emit. Separately, the component rAF clamp of 0.033s pre-empted the 0.3.6 fixed-timestep accumulator: sustained rendering below 30fps dilated simulated time proportionally (~3x slower at 11fps).

Fix

  • updateScreensaverPhysics now steers each blob's velocity toward its own driftAngle heading at driftSpeed * DRIFT_CRUISE_SPEED_SCALE every substep (DRIFT_CRUISE_STEERING = 0.05, scale 3). The settled cruise (~1.5-3.9 units/s in the -40..140 physics space) is the "idle blobs drift" / "ambient field: always on" baseline of docs/physics-feel-contract.md; the existing ~8s re-heading roll and wall-bounce re-randomization keep paths wandering, and pointer/scroll/gravity fields still bias motion on top exactly as before.
  • rAF frame-delta clamp raised 0.033 -> 8/60 to match BlobPhysics.tick()'s own catch-up ceiling (8 substeps of 1/60s); sustained rendering down to ~7.5fps now keeps real-time motion speed, tab-resume jumps still bounded by the engine substep cap.

How verified

  • New tests/unit/blob-physics-idle-drift.test.ts (seeded xorshift32, same pattern as the timestep test): idle mean net displacement rises from ~4.3-5.0 to ~16.4-25.5 units over 12 simulated seconds vs a driftSpeed-zeroed baseline; speeds and positions stay bounded. Full suite: 214 passed.
  • 300-simulated-second bounds run: positions stay inside the physics walls, peak speed ~0.15 units/substep, 346 wall bounces across 8 blobs (blobs now actually reach and bounce off walls).
  • Headed-Chrome A/B probe of the built package (12s, bbox-center waypoints at 1Hz, 60fps): idle net/path coherence rises from ~0.50-0.64 (decorrelating jitter) to ~0.72-0.81 (directed travel) with mean net displacement ~20 units/12s in the 133-unit viewBox.
  • check:release-metadata, svelte-check (0 errors), build, check:package lint, bundle size 11.79 KiB gzip (12 KiB gate; +0.06 over 0.3.6).

Reduced motion

prefers-reduced-motion: reduce behavior is untouched: the component still renders the static frame and never starts the rAF loop. Headed-Chrome probe with a reducedMotion: 'reduce' context confirms 0 of 15 paths move.

…matches engine catch-up cap

Wire each blob's driftAngle/driftSpeed — initialized since the pre-Phase-A
baseline but never read by the loop — into updateScreensaverPhysics as a
per-substep steering toward a gentle cruise velocity. With no pointer,
scroll, or device-motion input the only idle motion was a zero-mean jitter
random walk erased by the *=0.992 damping in ~1.4s; blobs jiggled near
their territory instead of drifting. The settled cruise delivers the
'idle blobs drift' baseline of docs/physics-feel-contract.md on every
environment with no permission grant or sensor, while pointer/scroll/
gravity fields still bias motion on top exactly as before and
prefers-reduced-motion still freezes the frame entirely.

Also raise TinyVectors' rAF frame-delta clamp from 0.033s to 8/60s to
match BlobPhysics.tick()'s own catch-up ceiling: the old clamp pre-empted
the 0.3.6 fixed-timestep accumulator and dilated simulated time ~3x at
11fps (software raster / heavy blur scenes).

Seeded sims: idle mean net displacement 4.3-5.0 -> 16.4-25.5 units/12s,
speeds bounded near 0.15 units/substep over 300s. Headed-Chrome A/B probe:
idle net/path coherence 0.5-0.64 -> 0.72-0.81 at 60fps; reducedMotion
'reduce' context still renders a fully frozen frame.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant