Rust stays the front end: it parses arguments, reads the input and seeds the RNG, then offers the run to the assembly engine (asm/, built by build.rs with NASM). The engine declines anything it has not ported, before producing output, so the Rust engine runs it instead. TTFX_ASM=0 forces Rust; TTFX_ASM=force fails instead of falling back, which is what tools/asm/oracle.sh uses to compare the two engines byte for byte. Decrypt is the first effect: 206/206 oracle cases identical, 14.5x faster at 200x50 (371 ms -> 25.5 ms). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
asm/PORTING.md is the working manual for porting effects and utilities: conventions, PIC rules, matching the oracle's compiled float code, and how to verify. tests/asm_diff.rs compares asm functions with their Rust originals, starting with randint, uniform and shuffle. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
asm/utils/pycompat.asm: round_half_even, floor_div, py_mod and the saturating f64_to_i64 cast, with pycompat.rs's non-finite rounding. asm/utils/geometry.asm: every pub function of src/utils/geometry.rs on packed u64 coordinates, plus the streaming ellipse. The float lowering mirrors the compiled oracle: powf(x, 2.0) as x * x, powf(x, 0.5) as sqrtsd with LLVM's fabs and -inf fix-ups, the sin/cos pair as sincos, lengths through glibc hypot, and the bezier length's omitted final span. asm/utils/color.asm: adjust_color_brightness, shift_color_towards and random_color on the u64 color format, in the oracle's operation order. tests/asm_diff.rs compares every function with Rust bit for bit on boundary, degenerate and random inputs, and the color functions over all 256 values of each channel crossed with many factors. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The engine now covers what effects need beyond decrypt: - chars.asm: the character store as fixed-capacity SoA regions, fill characters, neighbors and the input-coordinate map - terminal.asm: get_characters with all seven sorts and get_characters_grouped with all ten groupings, canvas helpers - scene.asm: named scenes with plain, synced and eased playback, looping, gradients (cyclic distribution) and set_appearance - events.asm: the event table with reentrant, append-safe dispatch - motion.asm: paths, waypoints, segments and the exact Path.step walk - update.asm and particles.asm: the active set, update and particle pools - easing.asm (ported by Codex): all 31 easings, EasingTracker and SequenceEaser, bit-identical to the oracle over 4.3M comparisons Decrypt runs on the general engine: 206/206 oracle cases, 32.5 ms against Rust's 371 ms. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Ported on cph-a2 by a Claude agent: every geometry function, pycompat rounding and Python integer division, adjust_color_brightness, shift_color_towards and random_color, each checked against Rust in tests/asm_diff.rs. Motion and gradients now use these instead of the interim path geometry. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
synthgrid_build/synthgrid_next_frame transcribe src/effects/synthgrid.rs: grid lines as consecutive added slots with an extended prefix, blocks as one flat member array, the group tracker as an effect callback, and a memo of the dissolve visuals. marshal packs the grid/text gradients, the grid symbols, the generation symbols and max_active_blocks. oracle synthgrid full: 1766 passed, 0 failed. 200x50: Rust 108 ms, asm 14 ms (best of 5, pinned). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
vhstape_build / vhstape_next_frame transcribe src/effects/vhstape.rs: per-character glitch, restore and wave paths, the six scenes, the glitch wave, glitch lines, noise and the line-by-line redraw, with every RNG draw in Rust's order. Snow visuals are memoized per (color, symbol), and lines are the engine's row groups. oracle.sh vhstape full: 1958 passed, 0 failed. 200x50, best of 5: Rust 190 ms, asm 44 ms. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
blackhole_build / blackhole_next_frame transcribe src/effects/blackhole.rs draw for draw: ring selection, starfield, singularity, collapse and explosion. Starfield visuals and their fades are made once and reused; phase checks use a membership bitmap over the active set. Every option is supported; tools/asm/oracle.sh blackhole full passes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Groups come from get_characters_grouped and are eased with the asm SequenceEaser; each character gets one "wipe" scene whose gradient runs from the final spectrum's first color to its mapped final color (reused while consecutive characters share that color). The dynamic existing-color branch is ported too. Final gradient frames outside the i32 range are declined in marshal; values below 1 fail like Rust. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every option is supported: all ten highlight directions, brightness, width and the final gradient. The highlight spectrum is recomputed only when a character's base color changes from the previous character's. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Both sweeps' scenes are built in Rust's order so every RNG draw lines up; the SequenceEaser walks the first direction's groups, then the second's. Visuals are memoized per (symbol, color). Dynamic color handling is ported (input-color palette with the spectrum fallback). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Transcribes src/effects/random_sequence.rs: the final gradient mapped over the text, one 8-frame fade from the terminal background per character (dynamic color handling included), a shuffled reveal of characters_per_tick characters per frame. Frame durations beyond 32 bits are declined. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Rings gives every ring character one single-waypoint path per ring coordinate, chained in a loop. The port keeps one engine path per ring character that stands in for all of them: activating ring path k points its waypoint at the k-th rotated coordinate and swaps in path k's own total and origin distance, so each path's rounding history is kept exactly. The chain becomes a callback, which keeps event lookups short. The engine gains path_reset (motion.asm) for the "disperse" path that Rust removes and recreates every cycle. oracle.sh rings full: 2342 passed. 200x50, best of 5: Rust 0.577 s, asm 0.145 s. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A screen map keyed by (row, column) replaces the one-row buffer, so cursor movement and overwrites behave as in input.rs: SGR colors (xterm and 24-bit, with its widening quirk), the four ignored private modes, CSI cursor moves, OSC and bare escapes with Rust's error text, input color frequencies, preexisting_colors_present, and existing-color-handling always at creation. Rust still declines ANSI input until the oracle covers it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
matrix.asm transcribes src/effects/matrix.rs: rain columns as fixed records (pending as an index, visible as a start/end window), a pending ring and active/full index arrays, the wall-clock rain deadline through clock_wall, and current symbols/colors read back with visual_meta. The dynamic existing-color branch is ported too. Color == compares hex spellings, so the marshalling tags hex stops spelled unlike Color::from_rgb (bits 48+, ignored by rendering and color math). Engine: RNG_BITS53 and rng_threshold (rng.asm) decide random() < c as an integer compare with the batch read inlined, tested against Rng::random in asm_diff. oracle.sh gains "@global <args>" in case files; matrix uses it for --virtual-clock, since real-clock frame counts are not reproducible. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every option is supported, including the dynamic existing-color branch. oracle expand full: 2726 passed; 200x50 run: Rust 109ms, asm 51ms. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every option is supported: all nine spray positions, volume, speed range, movement easing and the final gradient. The dynamic existing-color branch is ported too, for when the input side lands. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
scattered_build/scattered_next_frame transcribe Scattered::build and next_frame: a random start per character, one auto path home with the SetLayer events, and a distance-synced gradient scene (the last character gradient is reused while the final color repeats). The dynamic color branch is ported too. Frame durations outside i32 are declined in marshal. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>