Files
hyperframes/packages/core/src/runtime
Vance IngallsandClaude Sonnet 5 e1c9b50948 feat(studio,core): a volume and a living meter on the group row
B7: the group bus strip — droppable, and deliberately minimal per the
casual-user design constraints (groups doc §5): a volume slider, a level
bar that moves with the sound, and the words "Too loud" when it clips. No
dB numbers, no peak-hold readout, no routing row.

Transport (core): groupInput() now routes each group through input -> [FX
chain or dry passthrough] -> output -> master, with one AnalyserNode per
group tapped off `output` (post-FX, so the meter reads what the bus
actually outputs) — fftSize 256, level not spectrum. groupLevel(groupId)
returns RMS-ish level 0..1 + a clipped flag off a reused per-group buffer
(no per-frame allocation), or null when the group is idle/unknown. The
runtime posts group-levels messages only while playing, piggybacking the
existing message channel rather than adding a new poll loop.

Studio: groupLevels.ts is a plain pub-sub store (mirrors liveTime.ts's
shape) fed by useTimelinePlayer's message handler via
parseGroupLevelsMessage; useGroupLevel throttles re-renders to ~33ms.
TimelineGroupBusStrip renders in the group row's own `∿` lane area
(STRIP_H, already sized in B2's row-height pipeline) — drag writes live
via onSetAudioGroupAttributeLive, release commits one undo entry via
onSetAudioGroupAttributeQuiet (packages/studio/src/hooks/
timelineAudioGroupVolume.ts, extracted from timelineTrackVisibility.ts to
stay under the 600-line cap; mirrors FxParamRow's live/commit split).
"Too loud" holds for ~2s after the last clipped block, tracked in the
component, not the transport. volumeByGroup mirrors labelByGroup in
useTimelineTrackDerivations.ts so the strip's slider round-trips the
group's own data-volume.

Fixed two pre-existing group-routing tests in webAudioTransport.test.ts
that hardcoded gain-node creation order/count — B7 inserts an extra
`output` gain node between the group's input and master (for the meter to
tap), which shifted node indices the tests asserted on directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 16:39:30 -07:00
..

Hyperframe Runtime Engine

This folder owns the runtime that powers preview and producer parity.

Current Direction

  • Runtime source of truth is converging on hyperframe.ts.
  • Build produces:
    • dist/hyperframe.runtime.iife.js (browser bootstrap)
    • dist/hyperframe.runtime.mjs (tooling/tests)
    • dist/hyperframe.manifest.json (version + sha256 + artifact map)
  • FE owns iframe runtime injection.
  • BE persists raw generated HTML without injecting runtime scripts.
  • Producer validates pinned runtime checksum from manifest before render.

Runtime Contract (Stable Surface)

Globals:

  • window.__player
  • window.__playerReady
  • window.__renderReady
  • window.__timelines
  • window.__clipManifest

postMessage:

  • parent -> runtime control:
    • source: "hf-parent"
    • type: "control"
    • actions: play, pause, seek, set-muted, set-playback-rate, enable-pick-mode, disable-pick-mode
  • runtime -> parent events:
    • source: "hf-preview"
    • type: "state" and type: "timeline"
    • type: "ready" — emitted once when installRuntimeControlBridge registers the control-message listener. The parent uses it to replay current playback state (set-muted, set-volume, set-playback-rate) so any control message sent before the listener was installed isn't lost. Emitted again on every iframe reload because the new runtime instance starts with no state.

Determinism baseline:

  • renderSeek is the producer-canonical seek path.
  • 30fps quantization and readiness gates are correctness requirements.

Build

bun run --filter @hyperframes/core build:hyperframes-runtime

Security Expectations

  • Runtime bootstrap URL must be version-pinned and host-allowlisted.
  • Iframe bridge payloads must be schema-validated.
  • Unsafe URL schemes (javascript: and unapproved data:) are rejected.
  • Fail closed if runtime bootstrap/handshake is not healthy.

Product Editing Model

  • Primary mode: prompt + element picking.
  • Secondary mode: manual precision controls.
  • Avoid timeline-first manual workflows as default product path.