Skip to content

Add render-time color transforms and audio-reactive hooks - #24

Open
avillagran wants to merge 5 commits into
omacom:masterfrom
avillagran:feat/audio-reactive-hook
Open

Add render-time color transforms and audio-reactive hooks#24
avillagran wants to merge 5 commits into
omacom:masterfrom
avillagran:feat/audio-reactive-hook

Conversation

@avillagran

@avillagran avillagran commented Sep 3, 2026

Copy link
Copy Markdown

Summary

Adds two opt-in embedding hooks for applications that drive TTFX as a library:

  1. A render-time color pipeline for live, selective recoloring.
  2. A per-effect audio hook, with Thunderstorm as the first reactive implementation.

Live color transforms

  • Adds set_color_transform(Option<ColorTransform>) for current-thread render control.
  • Applies transforms when cached CharacterVisuals are emitted, so palette changes are visible on the next frame without rebuilding an effect.
  • Composes the selective transform before the existing audio brightness/hue transform.
  • Handles both RGB and xterm colors while preserving indexed 38;5 / 48;5 output in xterm mode.
  • Retains the original cached-symbol fast path when transforms are disabled and for colorless visuals.
  • Uses Rc snapshotting and an owned pooled scratch buffer, so callbacks may replace themselves or construct nested visuals without RefCell borrow panics.

This hook is intentionally policy-free. The embedder decides which colors are semantic and which are theme accents.

Audio hook

Adds a default no-op method to Effect:

fn on_audio(
    &mut self,
    ctx: &mut EngineCtx,
    volume: f32,
    bass: f32,
    beat: bool,
) {}

The built-in CLI has no audio source and does not invoke it. Embedders call it immediately before next_frame.

Thunderstorm uses the hook to:

  • increase strike probability with volume and detected beats;
  • add up to ten simultaneous rays at high volume;
  • scale branch count and strike progression speed;
  • preserve the original non-audio execution path byte-for-byte.

The audio strike path reuses the ordinary flash/fade setup and uses VecDeque for queued rays.

Tests and verification

  • cargo test --all-targets: pass.
  • Registry smoke test discovers every Clap effect, builds all 37, invokes the audio hook, and verifies first-frame emission.
  • High-volume Thunderstorm test runs 500 virtual-clock frames without stalling.
  • Cached RGB visuals change across transform updates without effect rebuild.
  • xterm transforms remain indexed SGR.
  • Self-mutating callbacks and nested visual construction are covered.
  • Non-audio Thunderstorm parity: 352 deterministic frames are byte-identical to origin/master (sha256 860c234f451a005ed5c953eeec41647a3a604d5040d7e2e163ae9e4c6cbaa964).
  • Downstream Omarchy integration: all 35 non-local TTFX effects started and accepted live theme changes; 35/35 passed.

No behavior changes unless an embedder explicitly installs a transform or calls on_audio.

…lti-strike)

Implements the Effect::on_audio reference implementation on thunderstorm:
- Loud passages / detected beats trigger lightning strikes on the beat
- Strike count scales with volume (1..10 thin rays), branches per ray
  capped at 5 for user-controlled jaggedness
- Strike fall speed (batch/delay) follows volume for punchy drops
- Loop the storm phase continuously so external supervisors (background
  rotators) control lifetime without a visible fade-out/fade-in seam
Apply opt-in transforms when cached visuals are emitted so embedders can update
colors without rebuilding effects. Preserve indexed xterm output, keep fast
paths for disabled/colorless visuals, and make callbacks reentrant-safe.

Restore byte-identical non-audio thunderstorm behavior, deduplicate its audio
strike setup, use an O(1) pending queue, and smoke-test every registered effect,
high-volume audio, live cache changes, xterm colors, and callback reentrancy.
@avillagran avillagran changed the title Audio-reactive color hook + live theme recoloring for embedders Add render-time color transforms and audio-reactive hooks Sep 4, 2026
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