summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
10 hoursfeat(mq_editor): Implement phase-coherent partial trackingskal
Implements a more robust partial tracking algorithm by using phase coherence to validate and link spectral peaks across frames. This significantly improves tracking accuracy, especially for crossing or closely-spaced partials. Key changes: - : The STFT cache now computes and stores the phase for each frequency bin alongside the magnitude. - : The peak detection logic now interpolates the phase for sub-bin accuracy. - : The core tracking algorithm was replaced with a phase-aware model. It predicts the expected phase for a partial in the next frame and uses a cost function combining both frequency and phase error to find the best match. This implementation follows the design outlined in the new document . handoff(Gemini): Phase prediction implemented. Further tuning of the cost function weights may be beneficial.
10 hoursfeat(mq_editor): implement MQ extraction improvementsskal
- Implement Predictive Kinematic Tracking to improve partial tracking during fast glissandos and vibrato. - Add Peak Prominence Pruning to filter out insignificant local maxima. - Replace heuristic Bezier fitting with a Least-Squares solver for more accurate trajectories. - Update UI to include a Prominence parameter input. - Archive MQ_EXTRACTION_IMPROVEMENTS.md design document. handoff(Gemini): implemented MQ extraction improvements (kinematic tracking, prominence pruning, least-squares bezier)
12 hoursfeat(mq_editor): global r/gain overrides for Resonator (all) modeskal
Add r (pole) and gain sliders with force r/gain checkbox in Synthesis panel, visible when Resonator (all) is active. Restrict r range to [0.75, 0.9999] for both global and per-partial sliders. handoff(Claude): global resonator r/gain override controls added Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 hoursdocs(mq_editor): document LP/HP post-synthesis filter slidersskal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 hoursfeat(mq_editor): LP/HP filter sliders with frequency display in Synthesis panelskal
Add k1/k2 range sliders for post-synthesis LP/HP filters. Display maps coefficients to -3dB cutoff frequency using exact IIR formulas; shows 'bypass' at k=1.0. Uses audioBuffer.sampleRate when loaded, falls back to 44100 Hz. handoff(Claude): LP k1 and HP k2 sliders added to Synthesis panel with Hz display. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 hoursfeat(mq_editor): global resonator test-mode checkbox in Synthesis panelskal
Adds "Resonator (all)" checkbox that forces resonator synthesis for all partials without modifying per-partial mode settings. Fixes null deref when partial.resonator is undefined in forceResonator mode. handoff(Gemini): resonator test-mode checkbox added; no per-partial data mutated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 hoursfeat(mq_editor): post-synthesis LP/HP filter pair in synthesizeMQskal
Add first-order IIR low-pass (options.k1) and high-pass (options.k2) filters applied globally after the synthesis loop and before normalization. Both are bypassed when the key is absent; LP is applied before HP (bandpass configuration when both active). handoff(Claude): LP/HP filters added to synthesizeMQ, no UI yet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 hoursfeat(mq_editor): per-partial two-pole resonator synthesis modeskal
Each partial in the Synth tab now has a Sinusoid/Resonator toggle. Resonator path: y[n] = 2r·cos(ω₀)·y1 − r²·y2 + A(t)·√(1−r²)·noise, coefficients recomputed per-sample from the freq Bezier curve. gainNorm=√(1−r²) normalises steady-state power; gainComp for trim. UI: mode toggle buttons, r + gain jog sliders, RES badge in header. Docs updated in tools/mq_editor/README.md. handoff(Claude): resonator mode complete, coefficients translated from spread params in README, ready for perceptual comparison testing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 hoursfeat(mq_editor): f·Power checkbox, deselect on extract, panel refresh after ↵skal
auto-spread - Add 'f·Power' checkbox: weights spectrum by f before peak detection (f·FFT_Power(f)) to accentuate high-frequency peaks; re-runs extraction on toggle - Deselect partial after Extract Partials run - Fix right panel not refreshing after Auto Spread All: re-call editor.onPartialSelect handoff(Claude): mq_editor UX polish Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 hoursfeat(mq_editor): E key for extract, style cleanup, doc updateskal
- Map 'E' key to Extract Partials - Move extractBtn inline style to CSS rule #extractBtn - Hoist autoSpreadAllBtn DOM ref to top with other refs - Drop unused PADY local var in _renderAmpEditor - Remove redundant comment before extractBtn listener - README: add E/Esc keys, add editor.js to architecture, mark Phase 3 done handoff(Gemini): mq_editor UX polish + doc consolidated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 hoursfeat(mq_editor): jog sliders for synth params, reset partials on WAV load, ↵skal
panel refresh after extract - Clear extractedPartials and editor state when loading a new WAV - After extract, refresh right panels (re-select if index still valid) - Synth fields (decay, jitter, spread) get jog sliders: drag to nudge, spring-back on release - Spread extension limit dashed line: alpha 0.4→0.75, lineWidth 1→1.5, dash [3,4]→[4,3] handoff(Gemini): mq_editor UX polish — jog sliders, WAV reset, panel refresh, spread line visibility Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 hoursfeat(mq_editor): spread autodetection, 50% drop-off line, mini-spectrum peak fixskal
- autodetectSpread(): measures half-power (-3dB) peak width in spectrogram to infer spread_above/below (replaces near-zero bezier residual approach) - 'Auto' button per partial + 'Auto Spread All' toolbar button - Spread panel inputs now trigger viewer refresh on change - 50% drop-off dotted reference lines on spread band (selected partial only) - Mini-spectrum: use max() instead of mean() over bins per pixel column, fixing high-frequency amplitude mismatch between original and synthesis handoff(Gemini): spread autodetection and mini-spectrum fixes done
14 hoursfeat(mq_editor): tabbed freq/amp/synth panel, spread band viz, UI polishskal
- Freq/Amp curve params now in tabs to save vertical space - Add Synth tab: per-partial decay, jitter, spread_above/below controls - Visualize spread band on selected partial (filled band + dashed bounds) - Larger fonts and right panel (14px body, 260px panel width) - Non-kept partials at 0.12 alpha (was 0.5) - Default threshold -20dB (was -60dB) handoff(Claude): mq_editor UI/UX improvements
16 hoursfeat(mq_editor): partial selection, amp bezier editor, and editor.js refactorskal
- Click-to-select partials on canvas (proximity hit test on bezier) - Right panel: peak freq/amp, time range, freq/amp bezier text inputs, mute/delete - Selected partial renders on top with glow + larger control points - Draggable freq curve control points on main canvas (grab/grabbing cursor) - Amplitude bezier editor: 120px canvas below spectrogram, time-synced with main view zoom/scroll via viewer.onRender callback - Amp edits live-affect synthesis (mq_synth.js already uses ampCurve) - PartialEditor class in editor.js owns all editing logic; index.html wires it with 5 calls (setViewer, setPartials, onPartialSelect, onRender, onPartialDeleted) handoff(Gemini): partial editing MVP complete. Next: freq curve drag polish or export (.spec generation). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
17 hoursdocs(mq_editor): update README to reflect current stateskal
- Document UI layout (right panel, mini-spectrum color coding) - Add keyboard shortcuts table - Document viewer.js coordinate API - Update algorithm section (backward expansion pass) - Refresh implementation status checklist handoff(Claude): docs updated
17 hoursrefactor(mq_editor): clean coordinate API and remove UI duplicationskal
viewer.js: - Add timeToX(), freqLogNorm(), normToFreq() coordinate primitives - freqToY/canvasToFreq now delegate to freqLogNorm/normToFreq - normalizeDB() replaces duplicated (magDB-(maxDB-80))/80 formula - partialColor(p) replaces repeated color array - All inline time/freq→pixel math replaced with API calls index.html: - getKeepCount() replaces 3 copies of the same calculation - playAudioBuffer() replaces duplicated playback setup + RAF loop handoff(Claude): refactor complete
17 hoursfeat(mq_editor): UI improvements and partial detection enhancementsskal
- Right panel with synthesis checkboxes (integrate phase, disable jitter, disable spread) - Style file chooser as button; show filename next to page title - Second backward pass in extractPartials to recover partial onsets - Cursor line drawn on overlay canvas (no full redraw on mousemove) handoff(Claude): UI + algo improvements complete
17 hoursfeat(mq_editor): validated dual-sine synthesis pipeline, clean code for real ↵skal
audio - Fix incoherent per-sample jitter/spread: seed by partial index only - Fix || fallback for zero-valued params (use != null checks) - Phase integration: accumulator (2π*f/SR per sample) replaces 2π*f*t - Add 'Integrate phase' checkbox to toggle between modes - Revert Catmull-Rom back to simple bezier (1/3, 2/3 sample points) - Remove all debug logging, clean up trackPartials, fitBezier handoff(Gemini): dual-sine test validates full MQ pipeline (extract→track→synth). Next: real audio loading and partial detection improvements. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
18 hoursfix(mq_editor): mini-spectrum and spectrogram display improvementsskal
- Fix mini-spectrum: log-scale frequency axis, per-pixel bin averaging, red peak bars after extraction - Fix key handlers swallowing digits in input fields - Clamp hop size to min 64 to prevent hang - Store maxDB in STFTCache, use it to normalize both mini-spectrum and main spectrogram (fixes clipping at 0dB for pure tones) - Add Test WAV console validation for 440/660Hz peaks - Grayscale colormap for main spectrogram handoff(Gemini): mq_editor display fixes complete, tests not affected
18 hoursfeat(mq_editor): add Test WAV button for in-browser UI testingskal
Generates 2s of 440+660Hz (A4+E5) at 32kHz without needing a file. Refactors WAV load path into shared loadAudioBuffer() used by both file input and the test button. handoff(Gemini): test button wired, full UI pipeline testable without assets.
18 hourstest(mq_editor): add isolated FFT test page and sine generatorskal
- tools/mq_editor/test_fft.html: browser test for fft.js (12 tests: DC impulse, single tone, STFT magnitude, pairs, triplets) - tools/gen_sine_440.py: generate 1s 440Hz WAV at 32kHz for manual testing handoff(Gemini): FFT isolation tests added, all passing in browser.
18 hoursfeat(mq_editor): log-scale frequency axis with clean freqToY/canvasToFreq APIskal
Replace all inline linear freq→Y math with freqToY()/canvasToFreq() pair. freqStart set to 20Hz (log-safe). Freq axis ticks now log-spaced. handoff(Gemini): log scale done, all render paths use freqToY/canvasToFreq
19 hoursrefactor(mq_editor): store only squared amplitude after FFT, drop re/imskal
handoff(Claude): removed full spectrum storage from STFTCache frames; getFFT() deleted; viewers use squaredAmplitude + 10*log10 directly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
19 hoursfix(mq_editor): Catmull-Rom bezier fit, NaN guard, synth FFT toggleskal
- evalBezier: guard dt<=0 to avoid NaN on degenerate curves - fitBezier: replace nearest-neighbor control points with Catmull-Rom tangents (Hermite->Bezier), curve now passes through endpoints - key 'a': toggle mini-spectrum between original and synth FFT handoff(Claude): bezier fix + synth FFT comparison Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
25 hoursfeat(mq_editor): sort partials by amplitude, keep% slider for reconstructionskal
- Sort extracted partials by decreasing peak amplitude - Add Keep% range slider (1-100%) to toolbar - Viewer draws omitted partials at 50% opacity (live on slider input) - synthesizeMQ uses only the top-N% partials handoff(Claude): partial amplitude filtering complete
26 hoursfeat(mq_editor): peaks display, STFT cache refactor, threshold reactivityskal
- STFTCache: cache squaredAmplitude (re²+im²) per frame, add getSquaredAmplitude(t) - getMagnitudeDB uses cached sq amp (10*log10, no sqrt) - detectPeaks uses squaredAmp from cache instead of recomputing FFT - extractPartials: use cache frames, return {partials, frames} - Press 'p' to toggle raw peak overlay in viewer - threshold input: step=any, change event triggers re-extraction - runExtraction() shared by button and threshold change handoff(Claude): mq_partial peaks/cache refactor complete
27 hoursclean-up pass mq-partialsskal
27 hoursdocs: Archive MQ Editor Phase 2 completionskal
JS synthesizer with replica oscillator bank and STFT cache complete. Ready for Phase 3 (editing UI). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
27 hoursfeat(mq_editor): Complete Phase 2 - JS synthesizer with STFT cacheskal
Phase 2 - JS Synthesizer: - Created mq_synth.js with replica oscillator bank - Bezier curve evaluation (cubic De Casteljau algorithm) - Replica synthesis: frequency spread, amplitude decay, phase jitter - PCM buffer generation from extracted MQ partials - Normalization to prevent clipping - Key '1' plays synthesized audio, key '2' plays original - Playback comparison with animated playhead STFT Cache Optimization: - Created STFTCache class in fft.js for pre-computed windowed FFT frames - Clean interface: getFFT(t), getMagnitudeDB(t, freq), setHopSize() - Pre-computes all frames on WAV load (eliminates redundant FFT calls) - Dynamic cache update when hop size changes - Shared across spectrogram, tooltip, and mini-spectrum viewer - Significant performance improvement Mini-Spectrum Viewer: - Bottom-right overlay (200x100) matching spectral_editor style - Real-time FFT display at playhead or mouse position - 100-bar visualization with cyan-to-yellow gradient - Updates during playback or mouse hover Files: - tools/mq_editor/mq_synth.js (new) - tools/mq_editor/fft.js (STFTCache class added) - tools/mq_editor/index.html (synthesis playback, cache integration) - tools/mq_editor/viewer.js (cache-based rendering, spectrum viewer) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
28 hoursdocs: Archive MQ Editor Phase 1 completionskal
Completed MQ extraction and visualization with improved tracking. Ready for Phase 2 (JS synthesizer). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
28 hoursdocs(mq_editor): Update Phase 1 completion statusskal
Phase 1 deliverables complete: - MQ extraction with improved tracking - Spectrogram visualization with zoom/scroll - Original WAV playback with playhead - Ready for Phase 2 (JS synthesizer) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
28 hoursfeat(mq_editor): Improve partial tracking and add audio playbackskal
Tracking improvements: - Frequency-dependent threshold (5% of freq, min 20 Hz) - Candidate system requiring 3-frame persistence before birth - Extended death tolerance (5 frames) for robust trajectories - Minimum 10-frame length filter for valid partials - Result: cleaner, less scattered partial trajectories Audio playback: - Web Audio API integration for original WAV playback - Play/Stop buttons with proper state management - Animated red playhead bar during playback - Keyboard shortcuts: '2' plays original, '1' reserved for synthesis Visualization: - Power law (gamma=0.3) for improved spectrogram contrast Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
28 hoursfix(mq_editor): Improve spectrogram visualization and navigationskal
- Fixed FFT to 1024 bins for 31.25 Hz resolution (better bass analysis) - Refactored view state to zoom_factor + t_center for cleaner pan/zoom - Mousewheel scrolls horizontally, shift+mousewheel zooms (respects deltaX/Y) - Spectrogram bins now fill complete time/freq buckets at all zoom levels - Extended dB range to -80→0 dB (80 dB) for better high-amplitude granularity - Added real-time intensity tooltip in dB - 50% alpha on spectrogram to reduce clutter over partial trajectories Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
32 hoursfeat(mq_editor): Phase 1 - MQ extraction and visualization (SPECTRAL_BRUSH_2)skal
Implement McAulay-Quatieri sinusoidal analysis tool for audio compression. New files: - doc/SPECTRAL_BRUSH_2.md: Complete design doc (MQ algorithm, data format, synthesis, roadmap) - tools/mq_editor/index.html: Web UI (file loader, params, canvas) - tools/mq_editor/fft.js: Radix-2 Cooley-Tukey FFT (from spectral_editor) - tools/mq_editor/mq_extract.js: MQ algorithm (peak detection, tracking, bezier fitting) - tools/mq_editor/viewer.js: Visualization (spectrogram, partials, zoom, axes) - tools/mq_editor/README.md: Usage and implementation status Features: - Load WAV → extract sinusoidal partials → fit cubic bezier curves - Time-frequency spectrogram with hot colormap (0-16 kHz) - Horizontal zoom (mousewheel) around mouse position - Axis ticks with labels (time: seconds, freq: Hz/kHz) - Mouse tooltip showing time/frequency coordinates - Real-time adjustable MQ parameters (FFT size, hop, threshold) Algorithm: - STFT with Hann windows (2048 FFT, 512 hop) - Peak detection with parabolic interpolation - Birth/death/continuation tracking (50 Hz tolerance) - Cubic bezier fitting (4 control points per trajectory) Next: Phase 2 (JS synthesizer for audio preview) handoff(Claude): MQ editor Phase 1 complete. Ready for synthesis implementation.
34 hoursfeat(uniforms): Add noise field with per-frame random valuesskal
Replace _pad with noise field in UniformsSequenceParams, providing effects with non-deterministic random values [0..1] updated each frame. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
35 hoursrefactor(effects): Streamline uniforms initializationskal
Centralized uniforms_buffer_ initialization and updates to Effect base class: - init_uniforms_buffer() now automatic in Effect::Effect() - uniforms_buffer_.update() now automatic in dispatch_render() - Removed redundant calls from all effect subclasses - Updated effect.h comments to reflect automatic behavior - Updated EFFECT_WORKFLOW.md templates Benefits: - 16 lines removed from effect implementations - Consistent pattern enforced at compile time - Reduced boilerplate for new effects Tests: 34/34 passing handoff(Claude): Effect base class now handles uniforms automatically
35 hoursfeat(test): Add PeakMeter overlay to test_demo timelineskal
Adds audio intensity visualization for debugging audio-visual sync. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
35 hoursrefactor(gpu): Add RAII wrapper for WGPU resources to eliminate manual cleanupskal
Introduces WGPUResource template with automatic release on destruction. Reduces boilerplate in effect destructors and prevents resource leaks. - set() for one-time initialization - replace() for per-frame recreation - Field ordering documented for dependency management Converted 3 effects (Heptagon, Flash, Passthrough) and Effect base class. All tests pass (34/34). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
35 hoursrefactor(effects): Factor shared initialization into Effect base classskal
Eliminate ~100 lines of duplicated code across effect subclasses by moving common resource initialization to the base Effect class. Most effects repeatedly created uniforms buffers, samplers, and dummy textures with identical configurations. Changes: - Add shared members to Effect: uniforms_buffer_, sampler_, dummy_texture_* - Add helpers: init_uniforms_buffer(), create_*_sampler(), create_dummy_scene_texture() - Add gpu_create_*_sampler() and gpu_create_dummy_scene_texture() to gpu.h - Move HEADLESS_RETURN_IF_NULL to Effect constructor - Update 7 effects to use base class helpers (Flash, Heptagon, Passthrough, Placeholder, GaussianBlur, Particles, PeakMeter) Benefits: Improved consistency, easier maintenance, reduced binary size. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
36 hoursfix(build): Resolve clean build failure from generated timeline headerskal
When starting from a clean tree (where `src/generated/` does not exist), the build would fail with a "file not found" error for `generated/timeline.h`. This was due to an incorrect dependency graph where `gpu.cc` was compiled before its required header was generated. This commit fixes the issue by making the dependency explicit: - Modified `tools/seq_compiler.py` to explicitly generate `timeline.h` alongside `timeline.cc`. - Updated `cmake/DemoCodegen.cmake` to declare both files as `OUTPUT`s of the timeline compilation step. - Added a direct dependency from the `gpu` library target to the `generate_timeline` custom target in `cmake/DemoLibraries.cmake`. - Refactored the generated file paths in `DemoCodegen.cmake` into a single `GENERATED_CODE` variable for improved clarity and future-proofing.
37 hoursdocs(gpu): Purge comment bloat from GPU headersskal
Removed redundant and obvious comments from 7 GPU headers: - post_process_helper.h: binding comments, stale UniformsSequenceParams note - shader_composer.h: verbose Compose/VerifyIncludes descriptions - uniform_helper.h: obvious method comments - effect.h: redundant render/resize comments - gpu.h: verbose struct/header comments, GPU perf placeholder - sdf_effect.h: obvious method comments - sequence.h: duplicate header, obvious API comments Kept only non-obvious context (binding conventions, headless mode notes). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
37 hoursrefactor(gpu): Remove stale v2 references from demo_effectsskal
Removed outdated comments referencing old naming conventions and non-existent functions. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
37 hoursdocs(style): Add rule for WGPU object initializationskal
37 hoursrefactor(codegen): Use gpu_init helper in seq_compiler.pyskal
Refactors the timeline code generator (`tools/seq_compiler.py`) to use the `gpu_init_color_attachment` helper function from `src/gpu/gpu.h`. This change removes platform-specific `#if !defined(DEMO_CROSS_COMPILE_WIN32)` directives from the generated C++ files (`timeline.cc`, `test_timeline.cc`) and centralizes the platform-aware initialization logic within the existing helper function. The generated code is now cleaner and easier to maintain. Both native macOS and Windows cross-compilation builds are confirmed to be successful.
37 hoursfix(build): Resolve Windows cross-compilation failuresskal
This commit fixes several issues that caused the Windows cross-compilation build (`scripts/build_win.sh`) to fail. The root causes were platform-specific API differences in the wgpu-native library and incorrect dependency tracking in the CMake build system for generated code. Changes: - **`tools/seq_compiler.py`**: The timeline generator now wraps `depthSlice` assignments in `#if !defined(DEMO_CROSS_COMPILE_WIN32)` directives to handle API differences in `WGPURenderPassColorAttachment`. - **`src/gpu/gpu.h`**: The `gpu_init_color_attachment` helper is now platform-aware, using a preprocessor guard for the `depthSlice` member. - **`src/effects/*.cc`**: All effects are updated to use the new platform-aware helper or have explicit guards for `depthSlice`. Also, replaced `WGPUTexelCopyTextureInfo` with the cross-platform alias `GpuTextureCopyInfo` in `rotating_cube_effect.cc`. - **`cmake`**: Added `tools/seq_compiler.py` as an explicit dependency to the `generate_timeline` and `generate_test_demo_timeline` custom commands. This ensures that changes to the generator script correctly trigger a rebuild of the generated C++ files. - **`scripts/build_win.sh`**: Removed the erroneous attempt to build the `seq_compiler.py` script as a native executable. With these changes, the Windows cross-compilation build now completes successfully.
39 hoursrefactor(3d): SceneLoader to namespaceskal
Refactors the SceneLoader class to a namespace. Since it only contained a single static utility function, a namespace is a more appropriate and idiomatic C++ construct. No functional changes.
39 hoursfeat: Rename GPU stub and headless files and update referencesskal
39 hoursstyle: replace C++ casts with C-style castsskal
Converts all static_cast<>, reinterpret_cast<> to C-style casts per CODING_STYLE.md guidelines. - Modified 12 files across gpu, 3d, util, tests, and tools - All builds passing, 34/34 tests passing - No functional changes, pure style cleanup Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
39 hoursrefactor: centralize platform-specific code in gpu.hskal
Move platform-specific type definitions to gpu.h and establish coding rule that platform ifdefs must be confined to gpu/platform layers. - gpu.h: add GpuTextureCopyInfo, GpuTextureDataLayout type aliases - effect.cc: use GpuTextureCopyInfo instead of platform ifdefs - texture_manager.cc: use type aliases and label_view() helper - CODING_STYLE.md: add platform-specific code section with rule Tests: 34/34 passing Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
39 hoursfeat: add time-based effect activation with auto-passthroughskal
Effects now accept start/end time parameters and automatically passthrough when inactive. Implements buffer chain integrity via compile-time validation. - Effect base class: dispatch_render() checks time bounds, auto-passthroughs 1:1 input/output effects outside [start, end] interval - seq_compiler.py: validates producer/consumer lifespan constraints for multi-output effects, adds --validate flag, always validates before codegen - Updated all 9 effect classes and test fixtures to pass start/end times - check_all.sh: includes timeline validation step - Tests: 34/34 passing, demo runs successfully Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>