summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-09 15:35:14 +0100
committerskal <pascal.massimino@gmail.com>2026-02-09 15:35:14 +0100
commit802e97ee695de1bc8657c5cbca653bb2f13b90a8 (patch)
tree85ecd65f78457ede14d7fbaf85c78280aad01b59 /doc
parentc784f8e1472991b8f4c35136b3468f3bfc6c37a7 (diff)
docs: Condense essential context files (856→599 lines)
Extract detailed examples and untriaged tasks to on-demand docs. Created BACKLOG.md, ARCHITECTURE.md, CODING_STYLE.md, TOOLS_REFERENCE.md. Reduces always-loaded token budget by 30% while preserving all information. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'doc')
-rw-r--r--doc/ARCHITECTURE.md60
-rw-r--r--doc/BACKLOG.md197
-rw-r--r--doc/CODING_STYLE.md109
-rw-r--r--doc/CONTRIBUTING.md69
-rw-r--r--doc/HOWTO.md86
-rw-r--r--doc/TOOLS_REFERENCE.md89
6 files changed, 497 insertions, 113 deletions
diff --git a/doc/ARCHITECTURE.md b/doc/ARCHITECTURE.md
new file mode 100644
index 0000000..1a32300
--- /dev/null
+++ b/doc/ARCHITECTURE.md
@@ -0,0 +1,60 @@
+# Architectural Overview
+
+Detailed system architecture for the 64k demo project.
+
+---
+
+## Hybrid 3D Renderer
+
+**Core Idea**: Uses standard rasterization to draw proxy hulls (boxes), then raymarches inside the fragment shader to find the exact SDF surface.
+
+**Transforms**: Uses `inv_model` matrices to perform all raymarching in local object space, handling rotation and non-uniform scaling correctly.
+
+**Shadows**: Instance-based shadow casting with self-shadowing prevention (`skip_idx`).
+
+---
+
+## Sequence & Effect System
+
+**Effect**: Abstract base for visual elements. Supports `compute` and `render` phases.
+
+**Sequence**: Timeline of effects with start/end times.
+
+**MainSequence**: Top-level coordinator and framebuffer manager.
+
+**seq_compiler**: Transpiles `assets/demo.seq` into C++ `timeline.cc`.
+
+---
+
+## Asset & Build System
+
+**asset_packer**: Embeds binary assets (like `.spec` files) into C++ arrays.
+
+**Runtime Manager**: O(1) retrieval with lazy procedural generation support.
+
+**Automation**: `gen_assets.sh`, `build_win.sh`, and `check_all.sh` for multi-platform validation.
+
+---
+
+## Audio Engine
+
+### Synthesis
+Real-time additive synthesis from spectrograms via FFT-based IDCT (O(N log N)). Stereo output (32kHz, 16-bit, interleaved L/R). Uses orthonormal DCT-II/DCT-III transforms with Numerical Recipes reordering method.
+
+### Variable Tempo
+Music time abstraction with configurable tempo_scale. Tempo changes don't affect pitch.
+
+### Event-Based Tracker
+Individual TrackerEvents trigger as separate voices with dynamic beat calculation. Notes within patterns respect tempo scaling.
+
+### Backend Abstraction
+`AudioBackend` interface with `MiniaudioBackend` (production), `MockAudioBackend` (testing), and `WavDumpBackend` (offline rendering).
+
+### Dynamic Updates
+Double-buffered spectrograms for live thread-safe updates.
+
+### Procedural Library
+Melodies and spectral filters (noise, comb) generated at runtime.
+
+### Pattern System
+TrackerPatterns contain lists of TrackerEvents (beat, sample_id, volume, pan). Events trigger individually based on elapsed music time.
diff --git a/doc/BACKLOG.md b/doc/BACKLOG.md
new file mode 100644
index 0000000..403ecc9
--- /dev/null
+++ b/doc/BACKLOG.md
@@ -0,0 +1,197 @@
+# Future Goals & Ideas (Untriaged)
+
+This file contains low-priority tasks and ideas that have not yet been triaged for active development.
+
+---
+
+## Audio Tools
+
+### Task #64: specplay Enhancements
+Extend audio analysis tool with new features:
+- **Priority 1**: Spectral visualization (ASCII art), waveform display, frequency analysis, dynamic range
+- **Priority 2**: Diff mode (compare .wav vs .spec), batch mode (CSV report, find clipping)
+- **Priority 3**: WAV export (.spec → .wav), normalization
+- **Priority 4**: Spectral envelope, harmonic analysis, onset detection
+- **Priority 5**: Interactive mode (seek, loop, volume control)
+
+See `tools/specplay_README.md` for detailed feature list.
+
+### Task #65: Data-Driven Tempo Control
+Move tempo variation from code to data files.
+
+**Current**: `g_tempo_scale` is hardcoded in `main.cc` with manual animation curves
+
+**Goal**: Define tempo curves in `.seq` or `.track` files
+
+**Approach A**: Add TEMPO directive to `.seq` format
+- Example: `TEMPO 0.0 1.0`, `TEMPO 10.0 2.0`, `TEMPO 20.0 1.0`
+- seq_compiler generates tempo curve array in timeline.cc
+
+**Approach B**: Add tempo column to music.track
+- Each pattern trigger can specify tempo_scale override
+- tracker_compiler generates tempo events in music_data.cc
+
+**Benefits**: Non-programmers can edit tempo, easier iteration, version control friendly
+
+**Priority**: Low (current approach works)
+
+### Task #67: DCT/FFT Performance Benchmarking
+Add timing measurements to audio tests.
+
+**Goal**: Compare performance of different DCT/IDCT implementations
+
+**Location**: Add timing code to `test_dct.cc` or `test_fft.cc`
+
+**Measurements**:
+- Reference IDCT/FDCT (naive O(N²))
+- FFT-based DCT/IDCT (current O(N log N))
+- Future x86_64 SIMD-optimized versions
+
+**Output Format**:
+- Average time per transform (microseconds)
+- Throughput (transforms per second)
+- Speedup factor vs reference
+
+**Test Sizes**: DCT_SIZE=512 (production), plus 128, 256, 1024 for scaling
+
+**Implementation**:
+- Use `std::chrono::high_resolution_clock`
+- Run 1000+ iterations to reduce noise
+- Report min/avg/max times
+- Guard with `#if !defined(STRIP_ALL)`
+
+**Priority**: Very Low (nice-to-have)
+
+### Task #69: Convert Audio Pipeline to Clipped Int16
+Use clipped int16 for all audio processing.
+
+**Current**: Float32 throughout (generation, mixing, synthesis, output)
+
+**Goal**: Convert to int16 for faster processing and reduced memory
+
+**Rationale**:
+- Simpler arithmetic (no float operations)
+- Smaller memory footprint (2 bytes vs 4 bytes)
+- Hardware-native format (most audio devices use int16)
+- Eliminates float→int16 conversion at output
+- Natural clipping behavior
+
+**Scope**:
+- Output path: Definitely convert (backends, WAV dump)
+- Synthesis: Consider keeping float32 for quality
+- Mixing: Could use int16 with overflow handling
+- Asset storage: Already int16 in .spec files
+
+**Implementation Phases**:
+1. **Phase 1: Output Only** (~50 lines) - Convert `synth_render()` output to int16
+2. **Phase 2: Mixing Stage** (~200 lines) - Convert voice mixing to int16 arithmetic
+3. **Phase 3: Full Pipeline** (~500+ lines) - Convert spectrograms to int16 storage
+
+**Trade-offs**:
+- Quality loss: 16-bit vs 32-bit float precision
+- Dynamic range: Limited to [-32768, 32767]
+- Clipping: Must handle overflow carefully
+- Code complexity: Saturation arithmetic
+
+**Testing Requirements**:
+- Verify no audible quality degradation
+- Ensure clipping behavior matches float version
+- Check mixing overflow doesn't cause artifacts
+- Validate WAV dumps bit-identical
+
+**Size Impact**:
+- Phase 1: Negligible (~50 bytes)
+- Phase 2: ~100-200 bytes
+- Phase 3: 50% memory, ~1-2KB code savings
+
+**Priority**: Low (final optimization only if 64k budget requires it)
+
+**Notes**: Quality must be validated - may not be worth trade-off
+
+---
+
+## Developer Tools
+
+### Task #66: External Asset Loading for Debugging
+mmap() asset files instead of embedded data.
+
+**Current**: All assets embedded in `assets_data.cc` (regenerate on every change)
+
+**Goal**: Load assets from external files in debug builds for faster iteration
+
+**Scope**: macOS only, non-STRIP_ALL builds only
+
+**Implementation**:
+- Add `DEMO_ENABLE_EXTERNAL_ASSETS` CMake option
+- Modify `GetAsset()` to check for external file first (e.g., `assets/final/<name>`)
+- Use `mmap()` to map file into memory
+- Fallback to embedded data if file not found
+
+**Benefits**: Edit shaders/assets without regenerating assets_data.cc (~10s rebuild)
+
+**Trade-offs**: Adds runtime file I/O, only useful during development
+
+**Priority**: Low (current workflow acceptable)
+
+---
+
+## Visual Effects
+
+### Task #73: Extend Shader Parametrization [IN PROGRESS - 2/4 complete]
+Extend uniform parameter system to remaining effects.
+
+**Goal**: Add parametrization to DistortEffect, SolarizeEffect
+
+**Pattern**: Follow FlashEffect implementation (UniformHelper, params struct, .seq syntax)
+
+**Completed**: ChromaAberrationEffect (offset_scale, angle), GaussianBlurEffect (strength)
+
+**Priority**: Medium (quality-of-life for artists)
+
+**Estimated Impact**: ~200-300 bytes per effect
+
+### Task #52: Procedural SDF Font
+Minimal bezier/spline set for [A-Z, 0-9] and SDF rendering.
+
+### Task #55: SDF Random Planes Intersection
+Implement `sdPolyhedron` (crystal/gem shapes) via plane intersection.
+
+### Task #54: Tracy Integration
+Integrate Tracy debugger for performance profiling.
+
+### Task #58: Advanced Shader Factorization
+Further factorize WGSL code into smaller, reusable snippets.
+
+### Task #59: Comprehensive RNG Library
+Add WGSL snippets for float/vec2/vec3 noise (Perlin, Gyroid, etc.) and random number generators.
+
+### Task #60: OOP Refactoring
+Investigate if more C++ code can be made object-oriented without size penalty (vs functional style).
+
+### Task #61: GPU Procedural Generation
+Implement system to generate procedural data (textures, geometry) on GPU and read back to CPU.
+
+### Task #62: Physics Engine Enhancements (PBD & Rotation)
+- **Task #62.1**: Quaternion rotation for `Object3D` with angular momentum
+- **Task #62.2**: Position Based Dynamics (PBD) - Re-evaluate velocity after resolving collisions/constraints
+
+### Task #63: Refactor Large Files
+Split `src/gpu/gpu.cc`, `src/3d/visual_debug.cc` and `src/gpu/effect.cc` into sub-functionalities.
+
+---
+
+## Performance Optimization
+
+### Task #70: SIMD x86_64 Implementation
+Implement critical functions using intrinsics for x86_64 platforms.
+
+**Goal**: Optimize hot paths for audio and procedural generation
+
+**Scope**:
+- IDCT/FDCT transforms
+- Audio mixing and voice synthesis
+- CPU-side procedural texture/geometry generation
+
+**Constraint**: Non-critical; fallback to generic C++ must be maintained
+
+**Priority**: Very Low
diff --git a/doc/CODING_STYLE.md b/doc/CODING_STYLE.md
new file mode 100644
index 0000000..533cffb
--- /dev/null
+++ b/doc/CODING_STYLE.md
@@ -0,0 +1,109 @@
+# Coding Style Examples
+
+Detailed examples for the project's C++ coding style.
+
+---
+
+## Core Rules Examples
+
+### Const Placement
+```cpp
+const T* name // Correct
+const T *name // Wrong
+```
+
+### Pre-Increment
+```cpp
+++x // Correct
+x++ // Wrong (except when postfix needed)
+```
+
+### Operator Spacing
+```cpp
+x = (a + b) * c; // Correct - spaces around all operators
+x=(a+b)*c; // Wrong - no spaces
+```
+
+### No Auto (except complex iterators)
+```cpp
+int count = get_count(); // Correct
+auto count = get_count(); // Wrong
+
+for (auto it = map.begin(); ...) // OK - complex iterator type
+```
+
+### No C++ Casts
+```cpp
+(int)value // Correct
+static_cast<int>(value) // Wrong
+```
+
+---
+
+## Preprocessor Style
+
+```cpp
+#if defined(MY_TAG)
+ // code here
+#endif /* defined(MY_TAG) */
+```
+
+Always use `defined()` and closing comment.
+
+---
+
+## Struct Initialization
+
+### Good
+```cpp
+const WGPUDescriptor desc = {
+ .format = g_format,
+ .dimension = WGPUTextureViewDimension_2D,
+};
+```
+
+### Bad
+```cpp
+WGPUDescriptor desc = {};
+desc.format = g_format;
+desc.dimension = WGPUTextureViewDimension_2D;
+```
+
+Use designated initializers, not field-by-field assignment.
+
+---
+
+## Class Keywords Indentation
+
+```cpp
+class MyClass {
+ public: // 1 space indent
+ void foo();
+
+ private: // 1 space indent
+ int field_;
+};
+```
+
+---
+
+## Comments
+
+### Function Comments
+```cpp
+// Initializes the audio engine with default settings.
+void audio_init() {
+ ...
+}
+```
+
+One-line comment for non-obvious functions.
+
+### File Headers
+```cpp
+// demo64k - 64 kilobyte demo
+// src/audio/synth.cc
+// Audio synthesis engine
+```
+
+Three-line header for all source files.
diff --git a/doc/CONTRIBUTING.md b/doc/CONTRIBUTING.md
index 7490fe6..de6378a 100644
--- a/doc/CONTRIBUTING.md
+++ b/doc/CONTRIBUTING.md
@@ -1,5 +1,7 @@
# Contributing Guidelines
+---
+
## Commit Policy
### Verify Before Committing
@@ -8,7 +10,6 @@
```bash
./scripts/check_all.sh
```
-Runs tests, builds tools, cross-compiles Windows.
**Manual:**
```bash
@@ -26,18 +27,9 @@ cd build && ctest --output-on-failure
cmake -S . -B build_debug_check -DDEMO_ENABLE_DEBUG_LOGS=ON
cmake --build build_debug_check -j4
```
-Must compile without errors.
**Debug macros** (`src/util/debug.h`):
-- `DEBUG_LOG_AUDIO`, `DEBUG_LOG_RING_BUFFER`, `DEBUG_LOG_TRACKER`
-- `DEBUG_LOG_SYNTH`, `DEBUG_LOG_3D`, `DEBUG_LOG_ASSETS`, `DEBUG_LOG_GPU`
-
-Example:
-```cpp
-#if defined(DEBUG_LOG_AUDIO)
- DEBUG_AUDIO("[CALLBACK #%d] frames=%d\n", ++count, frames);
-#endif
-```
+- `DEBUG_LOG_AUDIO`, `DEBUG_LOG_RING_BUFFER`, `DEBUG_LOG_TRACKER`, `DEBUG_LOG_SYNTH`, `DEBUG_LOG_3D`, `DEBUG_LOG_ASSETS`, `DEBUG_LOG_GPU`
### Code Formatting
```bash
@@ -50,6 +42,8 @@ Never format `third_party/`.
- 3-line header comment
- Max 500 lines (split if larger)
+---
+
## Coding Style
### Core Rules
@@ -61,36 +55,9 @@ Never format `third_party/`.
- No `auto` (except complex iterators)
- No C++ casts (`static_cast`, `reinterpret_cast`)
-### Preprocessor
-```cpp
-#if defined(MY_TAG)
- ...
-#endif /* defined(MY_TAG) */
-```
-
-### Struct Initialization
-```cpp
-// Good
-const WGPUDescriptor desc = {
- .format = g_format,
- .dimension = WGPUTextureViewDimension_2D,
-};
-
-// Bad
-WGPUDescriptor desc = {};
-desc.format = g_format;
-desc.dimension = WGPUTextureViewDimension_2D;
-```
-
-### Class Keywords
-```cpp
- private: // 1 space indent
- int field_;
-```
+See `doc/CODING_STYLE.md` for detailed examples.
-### Comments
-- 1-line comment for non-obvious functions
-- 3-line header for all source files
+---
## Development Protocols
@@ -170,18 +137,18 @@ After hierarchy changes (moving files, renaming), verify:
./scripts/gen_coverage_report.sh
```
-Update scripts with hardcoded paths.
+---
## Uniform Buffer Checklist
-To ensure consistency and prevent alignment-related issues, follow these guidelines when working with uniform buffers:
+To ensure consistency and prevent alignment-related issues:
-1. **Define WGSL Structs:** Clearly define uniform structs in WGSL, paying close attention to type alignment (`f32`, `vec2`, `vec3`, `vec4`) and using explicit padding (`_pad0: vec2<f32>`) where necessary.
-2. **Mirror in C++:** Create corresponding C++ structs that mirror the WGSL struct's definitions.
-3. **`static_assert` for Size:** Every C++ struct corresponding to a WGSL uniform buffer **must** have a `static_assert` verifying its size matches the expected WGSL size. Use `sizeof(MyStruct) == EXPECTED_SIZE`.
-4. **Standard Bindings:**
- * **Binding 2:** Always use `CommonPostProcessUniforms` (or a similar common structure) for general per-frame data (resolution, time, beat, etc.).
- * **Binding 3:** Use effect-specific parameter structs for unique effect data.
-5. **Shader Consistency:** Ensure WGSL shaders correctly declare and use uniforms at the specified bindings (`@group(0) @binding(2)` for common uniforms, `@group(0) @binding(3)` for effect parameters).
-6. **Validation Script:** Run `tools/validate_uniforms.py` as part of your development workflow to catch any discrepancies in size or alignment between C++ and WGSL definitions. Ensure this script passes without errors.
-7. **Documentation:** Refer to `doc/UNIFORM_BUFFER_GUIDELINES.md` for detailed information on WGSL alignment rules and best practices.
+1. **Define WGSL Structs:** Pay attention to type alignment (`f32`, `vec2`, `vec3`, `vec4`) and use explicit padding where necessary.
+2. **Mirror in C++:** Create corresponding C++ structs that mirror WGSL definitions.
+3. **`static_assert` for Size:** Every C++ struct must have a `static_assert` verifying size matches WGSL.
+4. **Standard Bindings:**
+ - **Binding 2:** Always use `CommonPostProcessUniforms` for per-frame data (resolution, time, beat).
+ - **Binding 3:** Use effect-specific parameter structs for unique data.
+5. **Shader Consistency:** Ensure WGSL shaders correctly declare uniforms at specified bindings.
+6. **Validation Script:** Run `tools/validate_uniforms.py` to catch discrepancies.
+7. **Documentation:** Refer to `doc/UNIFORM_BUFFER_GUIDELINES.md` for detailed alignment rules.
diff --git a/doc/HOWTO.md b/doc/HOWTO.md
index 2595258..876d7dc 100644
--- a/doc/HOWTO.md
+++ b/doc/HOWTO.md
@@ -2,6 +2,8 @@
Common commands for building and testing.
+---
+
## Building
### Debug Build
@@ -11,10 +13,7 @@ cmake --build build -j4
./build/demo64k
```
-Options:
-- `--fullscreen`: Run in fullscreen
-- `--resolution WxH`: Set window size (e.g., 1024x768)
-- `--seek TIME`: Jump to timestamp (debug builds only)
+Options: `--fullscreen`, `--resolution WxH`, `--seek TIME` (debug only)
Keyboard: `Esc` (exit), `F` (toggle fullscreen)
@@ -50,24 +49,29 @@ cmake --build build_final -j4
cmake -S . -B build -DDEMO_BUILD_TESTS=ON -DDEMO_BUILD_TOOLS=ON
cmake --build build -j4
```
-Enables tests and tools without stripping debug features.
-**Note**: `DEMO_ALL_OPTIONS=ON` enables tests, tools, AND `STRIP_ALL`, which removes debug-only code (e.g., `test_demo` PeakMeterEffect). Use selective flags for debugging.
+**Note:** `DEMO_ALL_OPTIONS=ON` enables tests, tools, AND `STRIP_ALL`, which removes debug-only code. Use selective flags for debugging.
+
+---
## Build System
-**Dependency Tracking**: CMake tracks 42 demo + 17 test assets. Editing shaders/audio auto-triggers rebuild.
+**Dependency Tracking:** CMake tracks 42 demo + 17 test assets. Editing shaders/audio auto-triggers rebuild.
-**Header Organization**:
+**Header Organization:**
- `asset_manager_dcl.h`: Forward declarations
- `asset_manager.h`: Core API (GetAsset/DropAsset)
- `asset_manager_utils.h`: Typed helpers
+---
+
## Git Clone
```bash
git clone ssh://git@51.38.51.127/~/demo.git
```
+---
+
## Audio System
### AudioEngine API
@@ -92,10 +96,7 @@ audio_shutdown();
- `seek(time)`: Jump to timestamp (debug only)
**Direct Synth APIs** (performance-critical):
-- `synth_register_spectrogram()`: Register samples
-- `synth_trigger_voice()`: Trigger playback
-- `synth_get_output_peak()`: Get audio level
-- `synth_render()`: Low-level rendering
+- `synth_register_spectrogram()`, `synth_trigger_voice()`, `synth_get_output_peak()`, `synth_render()`
**Testing:**
```cpp
@@ -105,6 +106,8 @@ engine.update(1.0f);
engine.shutdown();
```
+---
+
## Auxiliary Texture Masking
Share textures between effects:
@@ -118,6 +121,8 @@ WGPUTextureView view = demo_->get_auxiliary_view("mask_name");
```
See `doc/MASKING_SYSTEM.md` for details.
+---
+
## Demo Timeline
Edit `assets/demo.seq`:
@@ -127,6 +132,8 @@ SEQUENCE 0.0 0
```
Rebuild to update timeline.
+---
+
## Testing
**Run all tests:**
@@ -142,56 +149,7 @@ cd build && ctest
- `SynthEngineTest`: Audio synthesis
- `SequenceSystemTest`: Timeline logic
-## Code Coverage (macOS)
-```bash
-brew install lcov
-./scripts/gen_coverage_report.sh [target_dir]
-```
-
-## Tools
-
-### Windows Cross-Compilation
-```bash
-./scripts/fetch_win_deps.sh
-./scripts/build_win.sh
-./scripts/run_win.sh
-```
-
-### spectool (Audio Analysis)
-```bash
-cmake -S . -B build -DDEMO_BUILD_TOOLS=ON
-cmake --build build -j4
-
-# Analyze
-./build/spectool analyze input.wav output.spec
-
-# Play
-./build/spectool play input.spec
-```
-
-### specview (Visualization)
-```bash
-./build/specview input.spec
-```
-
-### specplay (Diagnostic)
-```bash
-./build/specplay input.spec
-# or
-./build/specplay input.wav
-```
-Output: Peak, RMS, clipping detection.
-
-### Submodule Updates
-```bash
-cd third_party/wgpu-native
-git fetch
-git checkout trunk
-git reset --hard origin/trunk
-cd ../..
-git add third_party/wgpu-native
-git commit -m "chore: Update wgpu-native"
-```
+---
## Asset Management
@@ -218,3 +176,7 @@ const uint8_t* data = GetAsset(AssetId::KICK_1, &size);
```
Build system auto-runs `asset_packer` when asset lists change.
+
+---
+
+For developer tools reference (spectool, Windows cross-compilation, code coverage), see `doc/TOOLS_REFERENCE.md`.
diff --git a/doc/TOOLS_REFERENCE.md b/doc/TOOLS_REFERENCE.md
new file mode 100644
index 0000000..61412a9
--- /dev/null
+++ b/doc/TOOLS_REFERENCE.md
@@ -0,0 +1,89 @@
+# Developer Tools Reference
+
+Comprehensive reference for all developer tools in the project.
+
+---
+
+## Windows Cross-Compilation
+
+```bash
+# Fetch dependencies
+./scripts/fetch_win_deps.sh
+
+# Build Windows binary
+./scripts/build_win.sh
+
+# Run with Wine
+./scripts/run_win.sh
+```
+
+---
+
+## spectool (Audio Analysis)
+
+```bash
+# Build
+cmake -S . -B build -DDEMO_BUILD_TOOLS=ON
+cmake --build build -j4
+
+# Analyze WAV → .spec
+./build/spectool analyze input.wav output.spec
+
+# Play .spec file
+./build/spectool play input.spec
+```
+
+---
+
+## specview (Visualization)
+
+```bash
+# View spectrogram
+./build/specview input.spec
+```
+
+Displays spectrogram visualization.
+
+---
+
+## specplay (Diagnostic)
+
+```bash
+# Analyze .spec file
+./build/specplay input.spec
+
+# Or analyze .wav file
+./build/specplay input.wav
+```
+
+Output: Peak, RMS, clipping detection.
+
+---
+
+## Code Coverage (macOS)
+
+```bash
+# Install lcov
+brew install lcov
+
+# Generate coverage report
+./scripts/gen_coverage_report.sh [target_dir]
+```
+
+Creates HTML coverage report.
+
+---
+
+## Submodule Updates
+
+```bash
+cd third_party/wgpu-native
+git fetch
+git checkout trunk
+git reset --hard origin/trunk
+cd ../..
+git add third_party/wgpu-native
+git commit -m "chore: Update wgpu-native"
+```
+
+Updates wgpu-native to latest trunk.