From 4f51332be0ee1a046fdc03514d32fe31cf7b61a8 Mon Sep 17 00:00:00 2001 From: skal Date: Mon, 9 Feb 2026 17:43:12 +0100 Subject: docs: Update documentation and clean up obsolete files - Add Task #76: External library size measurement - Update hot-reload documentation across README, HOWTO, PROJECT_CONTEXT - Update test count: 36/36 passing (100%) - Remove completed analysis files from root Co-Authored-By: Claude Sonnet 4.5 --- CHECK_RETURN_ASSESSMENT.md | 326 ------------------------------- CHECK_RETURN_IMPLEMENTATION.md | 181 ------------------ EFFECT_DEPTH_ANALYSIS.md | 115 ----------- PROJECT_CONTEXT.md | 7 +- README.md | 2 + SHADER_REFACTOR_EXAMPLE.md | 82 -------- TODO.md | 1 + WGSL_REFACTOR_COMPLETE.md | 191 ------------------ convert_track.py | 77 -------- doc/HOWTO.md | 8 +- doc/SIZE_MEASUREMENT.md | 341 +++++++++++++++++++++++++++++++++ timeline_analysis.html | 425 ----------------------------------------- 12 files changed, 357 insertions(+), 1399 deletions(-) delete mode 100644 CHECK_RETURN_ASSESSMENT.md delete mode 100644 CHECK_RETURN_IMPLEMENTATION.md delete mode 100644 EFFECT_DEPTH_ANALYSIS.md delete mode 100644 SHADER_REFACTOR_EXAMPLE.md delete mode 100644 WGSL_REFACTOR_COMPLETE.md delete mode 100644 convert_track.py create mode 100644 doc/SIZE_MEASUREMENT.md delete mode 100644 timeline_analysis.html diff --git a/CHECK_RETURN_ASSESSMENT.md b/CHECK_RETURN_ASSESSMENT.md deleted file mode 100644 index 0af818f..0000000 --- a/CHECK_RETURN_ASSESSMENT.md +++ /dev/null @@ -1,326 +0,0 @@ -# CHECK_AND_RETURN Macro Assessment & Plan - -## Current Situation - -**Problem:** Repetitive error handling pattern throughout codebase: -```cpp -if (condition) { - fprintf(stderr, "Error: ...\n", ...); - // Optional cleanup - return error_value; -} -``` - -This pattern appears in: -- Input validation (command-line args, file I/O) -- Resource allocation failures -- Runtime configuration errors -- API parameter validation - -**Unlike FATAL_XXX:** These are recoverable errors - caller can handle them. - -## Assessment - -### Files with Error Handling Patterns - -Found in: -- `src/util/asset_manager.cc` - 3+ instances (nullptr returns) -- `src/test_demo.cc` - 2+ instances (return 1) -- `src/gpu/texture_manager.cc` - 1 instance -- Test files (webgpu_test_fixture.cc, etc.) - -### Common Patterns - -#### Pattern 1: Return nullptr on error -```cpp -if (!valid) { - fprintf(stderr, "Error: Invalid input: %s\n", name); - if (out_size) *out_size = 0; - return nullptr; -} -``` - -#### Pattern 2: Return error code -```cpp -if (arg_invalid) { - fprintf(stderr, "Error: Unknown option '%s'\n", option); - print_usage(argv[0]); - return 1; -} -``` - -#### Pattern 3: Return false on failure -```cpp -if (!initialized) { - fprintf(stderr, "Error: Not initialized\n"); - return false; -} -``` - -#### Pattern 4: Warning (continue execution) -```cpp -if (non_critical) { - fprintf(stderr, "Warning: %s\n", msg); - // Continue execution -} -``` - -## Design Requirements - -### 1. Multiple Return Types -- `nullptr` (most common for pointer functions) -- `false` (for bool functions) -- `-1` or error codes (for int functions) -- `{}` or default values (for struct functions) - -### 2. Optional Cleanup -- Some cases need cleanup before return (e.g., `delete[]`) -- Some need to set output parameters (e.g., `*out_size = 0`) - -### 3. Stripping Behavior -- **STRIP_ALL:** Keep error checking, strip messages (save size) -- **FINAL_STRIP:** Strip everything (optional - may keep checks) - -Unlike FATAL_XXX which always abort, CHECK_RETURN should preserve control flow even when stripped. - -### 4. Debug Builds -- Print full error messages with context -- Optional file:line info (like FATAL_XXX) - -## Proposed Macro Design - -### Option A: Single Macro with Return Value - -```cpp -// Usage: -CHECK_RETURN(ptr == nullptr, nullptr, "Asset not found: %s", name); -CHECK_RETURN(argc < 2, 1, "Too few arguments"); -CHECK_RETURN(!initialized, false, "Not initialized"); - -// Expands to: -#if !defined(STRIP_ALL) - if (ptr == nullptr) { - fprintf(stderr, "Error: Asset not found: %s [file:line]\n", name); - return nullptr; - } -#else - if (ptr == nullptr) return nullptr; // Silent check -#endif -``` - -**Pros:** Simple, covers most cases -**Cons:** No cleanup before return, rigid pattern - -### Option B: Separate Macros per Return Type - -```cpp -CHECK_RETURN_NULL(cond, msg, ...) // returns nullptr -CHECK_RETURN_FALSE(cond, msg, ...) // returns false -CHECK_RETURN_ERROR(cond, msg, ...) // returns -1 -CHECK_RETURN_CODE(cond, code, msg, ...) // returns custom code - -// Usage: -CHECK_RETURN_NULL(ptr == nullptr, "Asset not found: %s", name); -CHECK_RETURN_ERROR(fd < 0, "Failed to open file: %s", path); -CHECK_RETURN_CODE(invalid_arg, 1, "Unknown option: %s", arg); -``` - -**Pros:** Type-safe, explicit intent -**Cons:** More macros, more verbose - -### Option C: Block-Based with Cleanup - -```cpp -CHECK_AND_RETURN_IF(condition, return_value) { - // Cleanup code here (optional) - delete[] buffer; - *out_size = 0; - ERROR_MSG("Failed: %s", reason); -} - -// Expands to: -#if !defined(STRIP_ALL) - if (condition) { - delete[] buffer; - *out_size = 0; - fprintf(stderr, "Error: Failed: %s [file:line]\n", reason); - return return_value; - } -#endif -``` - -**Pros:** Flexible, allows cleanup -**Cons:** More complex, harder to read - -### Option D: Hybrid (Recommended) - -```cpp -// Simple cases (90%) -CHECK_RETURN_IF(cond, retval, msg, ...) - -// Complex cases with cleanup (10%) -CHECK_RETURN_BEGIN(cond, retval) - delete[] buffer; - *out_size = 0; - ERROR_MSG("Failed: %s", reason); -CHECK_RETURN_END - -// Warning messages (non-fatal) -WARN_IF(cond, msg, ...) -``` - -**Pros:** Covers all cases, clean separation -**Cons:** Two patterns to learn - -## Recommendation: Option D (Hybrid) - -### Macro Definitions - -```cpp -// ============================================================================ -// Simple error check with immediate return -// ============================================================================ -#if !defined(STRIP_ALL) - #define CHECK_RETURN_IF(cond, retval, ...) \ - do { \ - if (cond) { \ - fprintf(stderr, "Error: " __VA_ARGS__); \ - fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \ - return retval; \ - } \ - } while (0) -#else - #define CHECK_RETURN_IF(cond, retval, ...) \ - do { if (cond) return retval; } while (0) -#endif - -// ============================================================================ -// Block-based error check with cleanup -// ============================================================================ -#if !defined(STRIP_ALL) - #define CHECK_RETURN_BEGIN(cond, retval) if (cond) { - #define ERROR_MSG(...) fprintf(stderr, "Error: " __VA_ARGS__); \ - fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__) - #define CHECK_RETURN_END return retval; } -#else - #define CHECK_RETURN_BEGIN(cond, retval) if (cond) { - #define ERROR_MSG(...) ((void)0) - #define CHECK_RETURN_END return retval; } -#endif - -// ============================================================================ -// Warning message (non-fatal, continue execution) -// ============================================================================ -#if !defined(STRIP_ALL) - #define WARN_IF(cond, ...) \ - do { \ - if (cond) { \ - fprintf(stderr, "Warning: " __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } \ - } while (0) -#else - #define WARN_IF(cond, ...) ((void)0) -#endif -``` - -## Usage Examples - -### Before (asset_manager.cc) -```cpp -if (proc_gen_func_ptr == nullptr) { - fprintf(stderr, "Error: Unknown procedural function at runtime: %s\n", - source_record.proc_func_name_str); - if (out_size) *out_size = 0; - return nullptr; -} -``` - -### After (simple version) -```cpp -CHECK_RETURN_BEGIN(proc_gen_func_ptr == nullptr, nullptr) - if (out_size) *out_size = 0; - ERROR_MSG("Unknown procedural function: %s", source_record.proc_func_name_str); -CHECK_RETURN_END -``` - -### Before (test_demo.cc) -```cpp -if (strcmp(argv[i], "--log-peaks") == 0) { - if (i + 1 < argc) { - log_peaks_file = argv[++i]; - } else { - fprintf(stderr, "Error: --log-peaks requires a filename argument\n\n"); - print_usage(argv[0]); - return 1; - } -} -``` - -### After -```cpp -if (strcmp(argv[i], "--log-peaks") == 0) { - CHECK_RETURN_BEGIN(i + 1 >= argc, 1) - print_usage(argv[0]); - ERROR_MSG("--log-peaks requires a filename argument"); - CHECK_RETURN_END - log_peaks_file = argv[++i]; -} -``` - -## Size Impact - -### STRIP_ALL Build -- Error messages stripped (~50-100 bytes per call site) -- Control flow preserved (if-return kept) -- Estimated savings: ~1-2KB for typical project - -### FINAL_STRIP Build (Optional) -- Could strip checks entirely for performance -- NOT recommended for input validation -- Recommended only for internal invariants - -## Implementation Plan - -### Phase 1: Create Header -- [ ] Create `src/util/check_return.h` -- [ ] Define macros (CHECK_RETURN_IF, CHECK_RETURN_BEGIN/END, WARN_IF) -- [ ] Add comprehensive documentation -- [ ] Add usage examples - -### Phase 2: Apply to Key Files -- [ ] `src/util/asset_manager.cc` (3 call sites) -- [ ] `src/test_demo.cc` (2 call sites) -- [ ] `src/gpu/texture_manager.cc` (1 call site) -- [ ] Test files as needed - -### Phase 3: Testing -- [ ] Verify normal build (messages appear) -- [ ] Verify STRIP_ALL build (messages stripped, checks remain) -- [ ] Verify all tests pass -- [ ] Check binary size impact - -### Phase 4: Documentation -- [ ] Update CONTRIBUTING.md with new patterns -- [ ] Add to HOWTO.md "Error Handling" section -- [ ] Update AI_RULES.md if needed - -## Alternative Considered: Don't Do It - -**Argument:** Only ~10-15 call sites, not worth adding complexity. - -**Counter-argument:** -- Improves consistency across codebase -- Reduces boilerplate (3-5 lines → 1-2 lines) -- Matches existing FATAL_XXX pattern (developers already familiar) -- Easy to strip for size optimization -- Low maintenance burden (simple macros) - -## Decision Point - -**Proceed?** User feedback needed: -1. Is the benefit worth the added complexity? -2. Should FINAL_STRIP strip these checks entirely? -3. Prefer Option A (simple), D (hybrid), or alternative? - -**If approved:** Implement Phase 1 first, review, then proceed with Phase 2-4. diff --git a/CHECK_RETURN_IMPLEMENTATION.md b/CHECK_RETURN_IMPLEMENTATION.md deleted file mode 100644 index 31c25ec..0000000 --- a/CHECK_RETURN_IMPLEMENTATION.md +++ /dev/null @@ -1,181 +0,0 @@ -# CHECK_RETURN Implementation Complete - -## Summary - -Implemented Option D (Hybrid) for non-fatal error handling with early return. - -## What Was Created - -### 1. Header File: `src/util/check_return.h` - -**Macros provided:** -```cpp -// Simple error check (90% of cases) -CHECK_RETURN_IF(condition, return_value, "Error: %s", msg); - -// Complex error check with cleanup (10% of cases) -CHECK_RETURN_BEGIN(condition, return_value) - // cleanup code - ERROR_MSG("Error: %s", msg); -CHECK_RETURN_END - -// Warning messages (non-fatal) -WARN_IF(condition, "Warning: %s", msg); -``` - -**Build behavior:** -- **Debug/Normal:** Full error messages with file:line info -- **STRIP_ALL:** Messages stripped, control flow preserved (saves ~1-2KB) - -## What Was Applied - -### 2. src/util/asset_manager.cc (3 call sites) - -**Before:** -```cpp -if (proc_gen_func_ptr == nullptr) { - fprintf(stderr, "Error: Unknown procedural function at runtime: %s\n", - source_record.proc_func_name_str); - if (out_size) *out_size = 0; - return nullptr; -} -``` - -**After:** -```cpp -CHECK_RETURN_BEGIN(proc_gen_func_ptr == nullptr, nullptr) - if (out_size) *out_size = 0; - ERROR_MSG("Unknown procedural function at runtime: %s", - source_record.proc_func_name_str); - return nullptr; -CHECK_RETURN_END -``` - -**Applied to:** -- Unknown procedural function check -- Memory allocation failure -- Procedural generation failure - -### 3. src/test_demo.cc (2 call sites) - -**Before:** -```cpp -if (i + 1 >= argc) { - fprintf(stderr, "Error: --log-peaks requires a filename argument\n\n"); - print_usage(argv[0]); - return 1; -} -``` - -**After:** -```cpp -CHECK_RETURN_BEGIN(i + 1 >= argc, 1) - print_usage(argv[0]); - ERROR_MSG("--log-peaks requires a filename argument\n"); - return 1; -CHECK_RETURN_END -``` - -**Applied to:** -- Missing --log-peaks argument -- Unknown command-line option - -## Testing - -✅ **All 31 tests pass** -``` -100% tests passed, 0 tests failed out of 31 -Total Test time (real) = 0.64 sec -``` - -✅ **Error messages work correctly:** -```bash -$ ./test_demo --invalid-option -Error: Unknown option '--invalid-option' - [test_demo.cc:199] -Usage: ./test_demo [OPTIONS] -... -``` - -## Comparison: FATAL_XXX vs CHECK_RETURN - -| Aspect | FATAL_XXX | CHECK_RETURN | -|--------|-----------|--------------| -| **Outcome** | `abort()` - program terminates | `return value` - caller handles | -| **Use Case** | Programming errors, invariants | Recoverable errors, validation | -| **Example** | Bounds checks, null dereference | Invalid input, missing files | -| **STRIP_ALL** | Keep checks, strip messages | Strip messages, keep checks | -| **FINAL_STRIP** | Strip everything (0 bytes) | Keep checks (preserves logic) | - -## Files Modified - -**Created:** -- `src/util/check_return.h` (180 lines) - -**Modified:** -- `src/util/asset_manager.cc` (+1 include, 3 call sites refactored) -- `src/test_demo.cc` (+1 include, 2 call sites refactored) - -## Size Impact - -**Estimated savings with STRIP_ALL:** -- 5 call sites × ~100 bytes per message string = ~500 bytes saved -- Control flow preserved (if-return statements kept) -- No functional changes - -## Remaining Opportunities - -Can be applied to (optional): -- `src/gpu/texture_manager.cc` - 1 call site -- `src/audio/backend/wav_dump_backend.cc` - 1 call site -- Test files - several call sites - -**Total potential:** ~10-15 call sites across codebase - -## Usage Guidelines - -### When to use CHECK_RETURN_IF: -✅ Simple validation with no cleanup -```cpp -CHECK_RETURN_IF(ptr == nullptr, false, "Invalid pointer"); -CHECK_RETURN_IF(size > MAX, -1, "Size too large: %d", size); -``` - -### When to use CHECK_RETURN_BEGIN/END: -✅ Validation that needs cleanup before return -```cpp -CHECK_RETURN_BEGIN(allocation_failed, nullptr) - delete[] buffer; - if (out_size) *out_size = 0; - ERROR_MSG("Allocation failed: %d bytes", size); - return nullptr; -CHECK_RETURN_END -``` - -### When to use WARN_IF: -✅ Non-critical issues that don't prevent execution -```cpp -WARN_IF(config_missing, "Config not found, using defaults"); -``` - -### When to use FATAL_XXX instead: -❌ Don't use CHECK_RETURN for: -- Programming errors (use FATAL_ASSERT) -- Array bounds violations (use FATAL_CHECK) -- Impossible code paths (use FATAL_UNREACHABLE) -- Corrupted state (use FATAL_ERROR) - -## Next Steps (Optional) - -1. Apply to remaining files (texture_manager.cc, wav_dump_backend.cc) -2. Update CONTRIBUTING.md with CHECK_RETURN guidelines -3. Update AI_RULES.md if needed -4. Consider FINAL_STRIP policy (strip checks vs keep checks) - -## Documentation - -Full documentation in header file: -- Usage examples -- Build mode behavior -- Comparison with FATAL_XXX -- Size impact analysis diff --git a/EFFECT_DEPTH_ANALYSIS.md b/EFFECT_DEPTH_ANALYSIS.md deleted file mode 100644 index 7a33baf..0000000 --- a/EFFECT_DEPTH_ANALYSIS.md +++ /dev/null @@ -1,115 +0,0 @@ -# Effect Depth Analysis Results - -## Overview -The `seq_compiler` tool now includes a `--analyze` flag to identify performance bottlenecks by analyzing how many effects are stacked (running simultaneously) at each moment in the demo. - -## Usage - -```bash -# Analyze effect stacking depth -./build/seq_compiler assets/demo.seq --analyze - -# Generate analysis with visual Gantt chart -./build/seq_compiler assets/demo.seq --analyze --gantt-html=timeline_analysis.html -``` - -## Current Demo Analysis (demo.seq) - -### Summary -- **Timeline duration**: 36s (65 beats @ 120 BPM) -- **Total effects**: 57 -- **Max concurrent effects**: 11 at t=8.8s ⚠️ -- **Bottleneck periods**: 28 time periods with >5 effects - -### Effect Depth Distribution - -| Depth | Time % | Severity | -|-------|--------|----------| -| 1-2 | 28.3% | Light | -| 3-4 | 26.1% | Moderate | -| 5-6 | 15.9% | Heavy | -| 7-11 | 29.6% | Critical ⚠️ | - -**Key Finding**: Nearly 30% of the demo has 7+ effects running simultaneously, which may cause frame rate drops on lower-end hardware. - -### Identified Bottlenecks - -**Most Critical Sections** (10+ concurrent effects): - -1. **t=4.3s** (10 effects): FlashCubeEffect, FadeEffect, ParticleSprayEffect, ParticlesEffect, GaussianBlurEffect, HeptagonEffect, ThemeModulationEffect, ChromaAberrationEffect, SolarizeEffect, FlashEffect -2. **t=8.6s** (10 effects): FlashCubeEffect, ThemeModulationEffect, ParticleSprayEffect, ParticlesEffect, Hybrid3DEffect, GaussianBlurEffect, ChromaAberrationEffect, HeptagonEffect, FlashEffect (×2) -3. **t=8.8s** (11 effects) - **Peak bottleneck** - -**Heavy Sections** (7-9 concurrent effects): -- t=4.9s: 9 effects -- t=6.7s: 9 effects -- t=7.3s: 7 effects -- t=7.9s: 8 effects -- t=9.1s: 9 effects -- ... and 18 more peaks - -### Recommendations - -**Immediate Actions**: -1. **Reduce overlap at t=8.8s**: The 11-effect peak is excessive. Consider: - - Staggering effect start/end times by 0.1-0.2s - - Removing redundant effects (e.g., duplicate FlashEffect instances) - - Combining similar effects (e.g., multiple GaussianBlur passes) - -2. **Optimize sequence at 8b-12b** (4-6 seconds): - - This section has sustained high effect counts (6-10 effects) - - Consider moving some post-processing effects to later sequences - - Test frame rate on target hardware during this section - -3. **Profile specific effects**: - - GaussianBlurEffect appears frequently (28 instances) - - Hybrid3DEffect runs for long durations (20s total) - - ChromaAberrationEffect appears in most bottleneck periods - -**Optimization Strategies**: -- Use priority layering to ensure critical effects render at higher priority -- Consider effect LOD (Level of Detail) system for lower-end hardware -- Combine multiple post-process passes into single shaders where possible -- Profile GPU time per effect to identify true bottlenecks (not just count) - -### Effect Frequency Analysis - -**Most Used Effects** (estimated from analysis output): -1. GaussianBlurEffect: ~10 instances -2. HeptagonEffect: ~9 instances -3. ThemeModulationEffect: ~7 instances -4. ChromaAberrationEffect: ~6 instances -5. FlashCubeEffect: ~6 instances -6. ParticleSprayEffect: ~5 instances -7. ParticlesEffect: ~5 instances -8. SolarizeEffect: ~4 instances -9. Hybrid3DEffect: ~3 instances -10. FadeEffect: ~2 instances - -**Insight**: GaussianBlur and Heptagon effects are the most heavily used - optimizing these will have the biggest impact on overall performance. - -## Technical Details - -### Analysis Method -- Samples timeline at 10 Hz (every 0.1s) -- Counts overlapping effect time ranges at each sample -- Generates histogram of effect depth distribution -- Identifies peaks (>5 effects) with at least 0.5s separation - -### Limitations -- Does not measure actual GPU/CPU time per effect (only counts) -- Assumes all effects have equal performance cost (not true in practice) -- Does not account for effect complexity (e.g., particle count, shader passes) - -### Future Improvements -- Add GPU profiling integration (Tracy, RenderDoc) -- Weight effects by estimated performance cost -- Suggest specific optimizations per bottleneck -- Generate timeline heatmap visualization -- Compare multiple .seq files (before/after optimization) - ---- - -**Generated**: February 8, 2026 -**Analysis Tool**: seq_compiler v1.1 (--analyze flag) -**Target**: assets/demo.seq diff --git a/PROJECT_CONTEXT.md b/PROJECT_CONTEXT.md index 181bffc..42cbda1 100644 --- a/PROJECT_CONTEXT.md +++ b/PROJECT_CONTEXT.md @@ -37,7 +37,7 @@ - 3D rendering: Hybrid SDF/rasterization with BVH acceleration and binary scene loader. Object data loading pipeline enhanced. - Asset pipeline: Blender export script and binary scene ingestion - Error handling: Dual macro system (`FATAL_XXX` for programming errors, `CHECK_RETURN` for recoverable errors) -- Testing: **32/33 tests passing (97%)** - DemoEffectsTest fails due to wgpu_native library bug +- Testing: **36/36 tests passing (100%)** - All tests operational --- @@ -55,6 +55,7 @@ - **Tooling & Optimization** - Task #54: Tracy Integration + - Task #76: External Library Size Measurement (Low priority) --- @@ -70,13 +71,17 @@ For detailed documentation, use Read tool to load specific docs: - **doc/SEQUENCE.md**: .seq timeline format with BPM notation - **doc/MASKING_SYSTEM.md**: Auxiliary texture registry - **doc/SCENE_FORMAT.md**: Binary scene format (SCN1) +- **doc/SIZE_MEASUREMENT.md**: External library size measurement strategy - **doc/test_demo_README.md**: 16s audio/visual sync test tool +- **doc/HOT_RELOAD.md**: Debug-only file change detection - **doc/CONTEXT_MAINTENANCE.md**: Context hygiene protocol --- ## Recently Completed (February 2026) +- **Hot-Reload File Watcher** (Feb 9) - Debug-only file change detection with `--hot-reload` flag. Watches config files (assets, sequences, music) and notifies on changes. 0 bytes overhead in release builds. + - **WGSL Uniform Buffer Validation (Task #75)** (Feb 9) - Standardized uniform buffer layout. Validation tool integrated into build. All effects use `CommonPostProcessUniforms` (binding 2) + effect-specific params (binding 3). Added `UNIFORM_BUFFER_GUIDELINES.md`. - **Uniform Buffer Alignment (Task #74)** (Feb 9) - Fixed WGSL `vec3` alignment issues. Demo runs with 0 validation errors. diff --git a/README.md b/README.md index 067c359..e5cf4d2 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,13 @@ cmake --build build - `BUILD.md`: Instructions for building the project. - `CONTRIBUTING.md`: Guidelines for contributing, including coding style and commit policies. - `FETCH_DEPS.md`: Information on third-party dependencies. +- `HOT_RELOAD.md`: Debug-only file change detection system. - `HOWTO.md`: General instructions for running and interacting with the demo. - `PHASE2_COMPRESSION.md`: Details on future asset compression strategies. - `PROCEDURAL.md`: Details on the procedural texture generation system. - `PROJECT_CONTEXT.md`: A comprehensive overview of the project's architecture, features, and current state. - `SEQUENCE.md`: Complete reference for `.seq` file format and timeline system. +- `SIZE_MEASUREMENT.md`: Strategy for measuring core demo size vs external library overhead. - `SPEC_EDITOR.md`: Plans for a future web-based spectrogram editor tool. - `3D.md`: Overview of the 3D rendering pipeline and future enhancements. - `TODO.md`: A list of immediate, small-scale tasks. diff --git a/SHADER_REFACTOR_EXAMPLE.md b/SHADER_REFACTOR_EXAMPLE.md deleted file mode 100644 index c875c7e..0000000 --- a/SHADER_REFACTOR_EXAMPLE.md +++ /dev/null @@ -1,82 +0,0 @@ -# Shader Composability Improvement - -## Created: `math/common_utils.wgsl` - -Common utility functions to reduce duplication: -- `transform_normal()` - Normal matrix transform (was in 2 shaders) -- `spherical_uv()` - Spherical UV mapping (was in 7+ places) -- `spherical_uv_from_dir()` - For skybox/direction vectors -- `calc_sdf_normal_bumped()` - Bump-mapped normal (36 lines → 1 call) -- Constants: `PI`, `TAU` - -## Usage in Shaders - -### Bump Mapping Note: -`calc_sdf_normal_bumped()` was removed from common_utils - too specialized, depends on `get_dist()` from scene_query snippets. Keep bump mapping inline in shaders that use it. - -### Transform Normal (appears in renderer_3d.wgsl:174, mesh_render.wgsl:38): -```wgsl -// Before -let normal_matrix = mat3x3(obj.inv_model[0].xyz, obj.inv_model[1].xyz, obj.inv_model[2].xyz); -normal = normalize(normal_matrix * n_local); - -// After (if common_utils included) -normal = transform_normal(obj.inv_model, n_local); -``` - -### Spherical UV (appears 6x in renderer_3d.wgsl): -```wgsl -// Before -let uv = vec2(atan2(q.x, q.z) / 6.28 + 0.5, - acos(clamp(q.y / length(q), -1.0, 1.0)) / 3.14); - -// After -let uv = spherical_uv(q); -``` - -### Skybox (skybox.wgsl:41-42): -```wgsl -// Before -let u = atan2(ray_dir.z, ray_dir.x) / 6.28318 + 0.5; -let v = asin(clamp(ray_dir.y, -1.0, 1.0)) / 3.14159 + 0.5; - -// After -let uv = spherical_uv_from_dir(ray_dir); -``` - -## Integration with ShaderComposer - -ShaderComposer already supports `#include` directives. To use: - -```cpp -// In gpu/effects initialization -ShaderComposer::Get().RegisterSnippet( - "math/common_utils", - GetAssetString(AssetId::SHADER_MATH_COMMON_UTILS) -); - -// In shader composition -composer.Compose( - {"common_uniforms", "math/common_utils"}, - main_shader_code -); -``` - -## Size Impact - -**Estimated binary size change:** -- Add common_utils.wgsl: +800 bytes -- Remove duplication: -1500 bytes (6 spherical_uv + bump mapping) -- **Net savings: ~700 bytes** - -Plus improved maintainability and consistency. - -## Next Steps - -1. Refactor `renderer_3d.wgsl` to use new utilities -2. Refactor `skybox.wgsl` to use `spherical_uv_from_dir()` -3. Refactor `mesh_render.wgsl` to use `transform_normal()` -4. Consider extracting more patterns: - - Grid pattern (appears 2x) - - Light direction constant - - Ray-box intersection variants diff --git a/TODO.md b/TODO.md index 10f0661..42d5520 100644 --- a/TODO.md +++ b/TODO.md @@ -117,6 +117,7 @@ class ComposedShader { - [ ] **Task #22: Windows Native Platform** - Replace GLFW with Win32 API - [ ] **Task #28: Spectrogram Quantization** - Research optimal frequency distribution - [ ] **Task #35: CRT Replacement** - Investigation and implementation of CRT-free entry +- [ ] **Task #76: External Library Size Measurement** - STRIP_EXTERNAL_LIBS mode with stub implementations to measure core demo size vs external library overhead. See `doc/SIZE_MEASUREMENT.md`. --- diff --git a/WGSL_REFACTOR_COMPLETE.md b/WGSL_REFACTOR_COMPLETE.md deleted file mode 100644 index 9bdc73c..0000000 --- a/WGSL_REFACTOR_COMPLETE.md +++ /dev/null @@ -1,191 +0,0 @@ -# WGSL Shader Composability Refactor - Complete - -## Summary - -Improved shader code reusability by extracting common patterns into `math/common_utils.wgsl`. - -## Changes Made - -### 1. Created `math/common_utils.wgsl` (37 lines) - -**Functions:** -- `transform_normal(inv_model, normal_local)` - Normal matrix transform -- `spherical_uv(p)` - Spherical UV mapping for positions -- `spherical_uv_from_dir(dir)` - Spherical UV for direction vectors -- `grid_pattern(uv)` - Procedural checkerboard pattern - -**Constants:** -- `PI = 3.14159265359` -- `TAU = 6.28318530718` - -### 2. Refactored Shaders - -#### renderer_3d.wgsl (200 → 197 lines) -- **7x spherical_uv()** - Replaced atan2/acos calculations - - Lines 143, 148, 153, 158, 163, 168, 184 - - Before: `vec2(atan2(...) / 6.28 + 0.5, acos(...) / 3.14)` - - After: `spherical_uv(q)` -- **1x transform_normal()** - Replaced mat3x3 constructor - - Line 174-175 - - Before: 3 lines (mat3x3 constructor + normalize) - - After: 1 line -- **2x grid_pattern()** - Replaced sin/smoothstep pattern - - Lines 104-106, 179-181 - - Before: 3 lines each - - After: 1 line each - -**Savings: ~12 lines removed** - -#### mesh_render.wgsl (58 → 57 lines) -- **1x transform_normal()** - Replaced mat3x3 constructor - - Line 38-39 - - Before: 3 lines - - After: 1 line - -**Savings: ~3 lines removed** - -#### skybox.wgsl (44 → 42 lines) -- **1x spherical_uv_from_dir()** - Replaced atan2/asin calculations - - Line 41-42 - - Before: 2 lines - - After: 1 line - -**Savings: ~2 lines removed** - -### 3. Registered Snippet - -Added to `src/gpu/effects/shaders.cc`: -```cpp -register_if_exists("math/common_utils", AssetId::ASSET_SHADER_MATH_COMMON_UTILS); -``` - -### 4. Updated Asset Manifest - -Added to `assets/final/demo_assets.txt`: -``` -SHADER_MATH_COMMON_UTILS, NONE, shaders/math/common_utils.wgsl, "Common Math Utils" -``` - -## Impact Analysis - -### Code Reduction -- **Duplication removed:** ~17 lines across 3 shaders -- **Common utils added:** +37 lines (1 file) -- **Net change:** +20 lines total - -### Usage Statistics -- **12 call sites** now use common utilities -- **3 shaders** refactored -- **4 utility functions** + 2 constants - -### Binary Size (estimated) -- Common utils: +400 bytes (compiled WGSL) -- Removed duplication: -600 bytes (7 spherical UV + 2 grid + 2 normal) -- **Net savings: ~200 bytes** - -Plus improved maintainability and consistency. - -### Maintainability Benefits -1. **Single source of truth** - UV/normal calculations in one place -2. **Consistent precision** - All shaders use same PI/TAU constants -3. **Easier debugging** - Fix bugs once, all shaders benefit -4. **Future-proof** - New shaders can reuse utilities immediately - -## Test Results - -✅ **All 31 tests pass** (100%) - -Including: -- ShaderComposerTest (composition logic) -- 3D renderer tests (no crashes) -- Shader compilation tests -- Full test suite - -## Files Modified - -**New:** -- `assets/final/shaders/math/common_utils.wgsl` -- `SHADER_REFACTOR_EXAMPLE.md` (design doc) -- `WGSL_REFACTOR_COMPLETE.md` (this file) - -**Modified:** -- `assets/final/shaders/renderer_3d.wgsl` -- `assets/final/shaders/mesh_render.wgsl` -- `assets/final/shaders/skybox.wgsl` -- `assets/final/demo_assets.txt` -- `src/gpu/effects/shaders.cc` - -## Next Opportunities - -### Low-Hanging Fruit -- **Light direction constant** - Appears in multiple shaders as `vec3(1.0, 1.0, 1.0)` -- **Ray-box intersection variants** - Could extract common helpers -- **Noise sampling patterns** - Consistent noise lookup utilities - -### Medium Effort -- **SDF operations** - Union, subtraction, intersection (if repeated) -- **Color grading helpers** - Tone mapping, gamma correction -- **Distance fog** - Common atmospheric effects - -### Advanced -- **Material system** - PBR lighting utilities -- **Shadow mapping helpers** - Cascaded shadow map utilities -- **Post-process chain** - Common blur/sharpen kernels - -## Design Decisions - -### Why Not Include calc_sdf_normal_bumped()? -- Too specialized - depends on `get_dist()` from scene_query -- Scene_query not always included when common_utils is -- Caused shader compilation failure (missing `get_dist` identifier) -- **Solution:** Keep bump mapping inline in shaders that need it - -### Why Separate spherical_uv() and spherical_uv_from_dir()? -- Different use cases: positions vs directions -- Different math: acos vs asin for elevation -- skybox needs direction variant, SDF rendering needs position variant -- Clearer intent in calling code - -### Why Include grid_pattern()? -- Appeared 2x in renderer_3d.wgsl (copy-paste pattern) -- Simple, self-contained (no external dependencies) -- Reusable for other procedural textures - -## Verification Commands - -```bash -# Regenerate assets -./scripts/gen_assets.sh - -# Build -cmake --build build -j4 - -# Test -cd build && ctest - -# Check shader composition -./test_shader_composer - -# Verify 3D rendering -./test_3d_render -``` - -## Commit Message - -``` -feat(shaders): Extract common WGSL utilities for better composability - -- Create math/common_utils.wgsl with 4 utility functions -- Refactor renderer_3d.wgsl (7 spherical_uv, 1 normal, 2 grid) -- Refactor mesh_render.wgsl (1 normal transform) -- Refactor skybox.wgsl (1 spherical UV) -- Register common_utils snippet in ShaderComposer - -Impact: ~200 bytes saved, 12 call sites deduplicated -Tests: 31/31 passing -``` - ---- - -**Status:** ✅ Complete - Ready for commit -**Date:** 2026-02-08 diff --git a/convert_track.py b/convert_track.py deleted file mode 100644 index ec9d62c..0000000 --- a/convert_track.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python3 -"""Convert .track files from beat-based to unit-less timing.""" - -import re -import sys - -def convert_beat_to_unit(beat_str): - """Convert beat value to unit-less (beat / 4).""" - beat = float(beat_str) - unit = beat / 4.0 - return f"{unit:.2f}" - -def process_line(line): - """Process a single line, converting beat values.""" - line = line.rstrip('\n') - - # Skip comments and empty lines - if not line.strip() or line.strip().startswith('#'): - return line - - # PATTERN line - add LENGTH 1.0 - if line.strip().startswith('PATTERN '): - # Check if LENGTH already exists - if ' LENGTH ' in line: - return line - parts = line.split() - if len(parts) >= 2: - return f"PATTERN {parts[1]} LENGTH 1.0" - return line - - # Event line (starts with a number) - match = re.match(r'^(\s*)([0-9.]+),\s*(.+)$', line) - if match: - indent, beat_str, rest = match.groups() - unit_str = convert_beat_to_unit(beat_str) - return f"{indent}{unit_str}, {rest}" - - return line - -def main(): - if len(sys.argv) != 3: - print(f"Usage: {sys.argv[0]} ") - sys.exit(1) - - input_file = sys.argv[1] - output_file = sys.argv[2] - - with open(input_file, 'r') as f: - lines = f.readlines() - - # Add header comment about timing - output_lines = [] - output_lines.append("# Enhanced Demo Track - Progressive buildup with varied percussion\n") - output_lines.append("# Features acceleration/deceleration with diverse samples and melodic progression\n") - output_lines.append("#\n") - output_lines.append("# TIMING: Unit-less (1 unit = 4 beats at 120 BPM = 2 seconds)\n") - output_lines.append("# Pattern events use unit-less time (0.0-1.0 for 4-beat pattern)\n") - output_lines.append("# Score triggers use unit-less time\n") - - # Skip old header lines - start_idx = 0 - for i, line in enumerate(lines): - if line.strip() and not line.strip().startswith('#'): - start_idx = i - break - - # Process rest of file - for line in lines[start_idx:]: - output_lines.append(process_line(line) + '\n') - - with open(output_file, 'w') as f: - f.writelines(output_lines) - - print(f"Converted {input_file} -> {output_file}") - -if __name__ == '__main__': - main() diff --git a/doc/HOWTO.md b/doc/HOWTO.md index 876d7dc..c6e4e79 100644 --- a/doc/HOWTO.md +++ b/doc/HOWTO.md @@ -13,10 +13,16 @@ cmake --build build -j4 ./build/demo64k ``` -Options: `--fullscreen`, `--resolution WxH`, `--seek TIME` (debug only) +Options: `--fullscreen`, `--resolution WxH`, `--seek TIME`, `--hot-reload` (debug only) Keyboard: `Esc` (exit), `F` (toggle fullscreen) +**Hot-Reload Mode:** +```bash +./build/demo64k --hot-reload +``` +Watches config files and notifies when changes detected. See `doc/HOT_RELOAD.md`. + ### Size-Optimized Build ```bash cmake -S . -B build -DDEMO_SIZE_OPT=ON diff --git a/doc/SIZE_MEASUREMENT.md b/doc/SIZE_MEASUREMENT.md new file mode 100644 index 0000000..b997ea5 --- /dev/null +++ b/doc/SIZE_MEASUREMENT.md @@ -0,0 +1,341 @@ +# External Library Size Measurement (Task #76) + +## Goal + +Measure the true binary size of demo code vs external library overhead by stubbing out all system dependencies with minimal implementations. + +**Motivation:** Current STRIP_ALL builds include wgpu_native (~3-4MB), GLFW, and system libraries. We need to isolate core demo size to: +- Track size budget accurately +- Identify optimization targets +- Measure progress toward 64KB goal + +## Problem Statement + +Current size breakdown is opaque: +``` +STRIP_ALL build: ~5.1MB total +├── wgpu_native: ~3-4MB (estimate) +├── GLFW: ~500KB (estimate) +├── System libs: ~500KB (estimate) +└── Demo code: ??? KB (unknown) +``` + +**Goal:** Measure demo code size precisely by replacing external dependencies with stubs. + +## Approach + +Create `STRIP_EXTERNAL_LIBS` build mode: +- Replaces real libraries with minimal stub implementations +- Functions compile but do nothing (return nullptr, no-ops) +- Binary compiles successfully but **does not run** +- Purpose: Size measurement only + +## Architecture + +### Stub Implementations + +#### 1. wgpu_native Stubs (`third_party/stubs/wgpu_native.c`) + +Minimal WebGPU API implementation: +```c +// All functions return nullptr or void +WGPUInstance wgpuCreateInstance(const WGPUInstanceDescriptor* desc) { + (void)desc; + return (WGPUInstance)0; +} + +WGPUAdapter wgpuInstanceRequestAdapter(...) { + return (WGPUAdapter)0; +} + +// ~200 functions to stub +``` + +**Strategy:** +- Parse `webgpu.h` to generate stubs automatically +- All pointers return nullptr +- All numeric returns = 0 +- All void functions are empty + +#### 2. GLFW Stubs (`third_party/stubs/glfw3.c`) + +Window/input API stubs: +```c +int glfwInit(void) { return 1; } +void glfwTerminate(void) {} +GLFWwindow* glfwCreateWindow(...) { return (GLFWwindow*)0; } +void glfwPollEvents(void) {} +int glfwWindowShouldClose(GLFWwindow* w) { (void)w; return 0; } +// ~100 functions +``` + +#### 3. miniaudio Stubs (`third_party/stubs/miniaudio.c`) + +Audio backend stubs: +```c +ma_result ma_context_init(...) { return MA_SUCCESS; } +ma_result ma_device_init(...) { return MA_SUCCESS; } +ma_result ma_device_start(...) { return MA_SUCCESS; } +void ma_device_stop(...) {} +void ma_device_uninit(...) {} +// ~50 functions used by demo +``` + +#### 4. System Library Stubs + +**pthread:** +```c +int pthread_create(...) { return 0; } +int pthread_join(...) { return 0; } +int pthread_mutex_init(...) { return 0; } +// ~20 functions +``` + +**Math (libm):** +```c +double sin(double x) { (void)x; return 0.0; } +double cos(double x) { (void)x; return 0.0; } +float sinf(float x) { (void)x; return 0.0f; } +// ~30 functions +``` + +**Platform-specific (macOS):** +```c +// Stub Metal/Foundation/Cocoa frameworks +// Minimal Objective-C stubs if needed +``` + +### Build System Integration + +**CMakeLists.txt:** +```cmake +if(DEMO_STRIP_EXTERNAL_LIBS) + # Build stub libraries + add_library(wgpu_stub STATIC third_party/stubs/wgpu_native.c) + add_library(glfw_stub STATIC third_party/stubs/glfw3.c) + add_library(miniaudio_stub STATIC third_party/stubs/miniaudio.c) + add_library(system_stub STATIC third_party/stubs/system.c) + + # Override library targets + set(DEMO_LIBS wgpu_stub glfw_stub miniaudio_stub system_stub) + + # Minimal flags (no LTO to see unoptimized size) + set(CMAKE_C_FLAGS "-Os") + set(CMAKE_CXX_FLAGS "-Os") +endif() +``` + +**Build command:** +```bash +cmake -S . -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON +cmake --build build_size -j4 +ls -lh build_size/demo64k # True demo size +``` + +## Implementation Plan + +### Phase 1: Stub Generation Tool + +**Script: `scripts/generate_stubs.py`** + +Parses header files and generates stub implementations: +```python +# Parse webgpu.h, glfw3.h, miniaudio.h +# Extract function signatures +# Generate minimal implementations +# Output to third_party/stubs/ +``` + +**Input:** Header files with annotations +**Output:** Complete stub .c files + +**Heuristics:** +- Pointer returns → nullptr +- Numeric returns → 0 +- Boolean returns → true/1 +- Void functions → empty body +- Enum returns → first enum value + +### Phase 2: Build System Integration + +1. Add `DEMO_STRIP_EXTERNAL_LIBS` option +2. Create stub library targets +3. Override `DEMO_LIBS` when flag enabled +4. Disable features requiring runtime (audio playback, window creation) + +### Phase 3: Compatibility Layer + +Some demo code expects valid objects. Add thin shims: + +**`src/platform/stub_platform.cc`:** +```cpp +#if defined(STRIP_EXTERNAL_LIBS) +// Override platform_init to skip GLFW +PlatformState platform_init(bool, int, int) { + PlatformState state = {}; + state.width = 1280; + state.height = 720; + return state; +} +#endif +``` + +**`src/audio/stub_audio.cc`:** +```cpp +#if defined(STRIP_EXTERNAL_LIBS) +// Override audio_init to skip miniaudio +void audio_init() {} +void audio_start() {} +#endif +``` + +### Phase 4: Validation + +Ensure binary compiles and links: +```bash +# Should compile successfully +cmake -S . -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON +cmake --build build_size -j4 + +# Size measurement +ls -lh build_size/demo64k + +# Strip debug symbols +strip build_size/demo64k +ls -lh build_size/demo64k + +# Compare with real build +ls -lh build_strip/demo64k +``` + +## Expected Results + +**Size Breakdown (Projected):** +``` +Real STRIP_ALL build: 5.1 MB +├── wgpu_native: 3.5 MB (68%) +├── GLFW: 0.5 MB (10%) +├── System libs: 0.6 MB (12%) +└── Demo code: 0.5 MB (10%) + +STRIP_EXTERNAL_LIBS build: 0.5 MB +└── Demo code only: 0.5 MB (100%) +``` + +**Validation:** +- Binary compiles without errors +- All symbols resolve +- Size is significantly smaller (< 1MB) +- Binary does NOT run (expected) + +## Use Cases + +### 1. Size Budget Tracking +```bash +# Weekly measurement +./scripts/measure_size.sh +# Outputs: Demo=512KB, External=4.5MB +``` + +### 2. Optimization Targeting +Identify which subsystems contribute most to demo size: +- GPU effects: 150KB +- 3D rendering: 120KB +- Audio synthesis: 100KB +- Asset system: 80KB + +### 3. CI Integration +Track size growth over time: +```yaml +# .github/workflows/size_check.yml +- name: Measure demo size + run: | + cmake -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON + size=$(stat -f%z build_size/demo64k) + echo "Demo size: $size bytes" +``` + +## Trade-offs + +### Pros +- Accurate size measurement +- Identifies optimization targets +- Simple implementation (stubs) +- No runtime required + +### Cons +- Maintenance burden (stubs must match real APIs) +- Binary doesn't run (testing impossible) +- Platform-specific stubbing (macOS frameworks complex) +- Stub generation tool needs maintenance + +### Alternative Approaches + +**1. Link-time size analysis:** +```bash +# Use linker map to attribute size +-Wl,-map,output.map +# Parse map file to see per-symbol sizes +``` +**Pro:** No stubs needed +**Con:** Complex parsing, less accurate + +**2. Binary diff analysis:** +```bash +# Build with/without each library +# Diff binary sizes +``` +**Pro:** Simpler +**Con:** Doesn't isolate demo code cleanly + +**3. Compiler size reports:** +```bash +-ffunction-sections -fdata-sections +-Wl,--print-gc-sections +``` +**Pro:** Built-in tooling +**Con:** Still includes external library overhead + +**Chosen:** Stub approach (most accurate, clear results) + +## Implementation Effort + +**Estimated time: 8-12 hours** + +- Phase 1: Stub generation (3-4 hours) +- Phase 2: Build integration (2-3 hours) +- Phase 3: Compatibility layer (2-3 hours) +- Phase 4: Validation & documentation (1-2 hours) + +**Priority:** Low (measurement tool, not critical for demo) + +## Success Criteria + +1. Binary compiles successfully with `STRIP_EXTERNAL_LIBS=ON` +2. Size < 1MB (proves external lib overhead is measured) +3. Repeatable builds produce consistent sizes +4. Can track size changes over time +5. Documentation clear for future use + +## Related Files + +**New files:** +- `third_party/stubs/wgpu_native.c` - WebGPU stubs (~200 functions) +- `third_party/stubs/glfw3.c` - GLFW stubs (~100 functions) +- `third_party/stubs/miniaudio.c` - Audio stubs (~50 functions) +- `third_party/stubs/system.c` - System library stubs (pthread, math) +- `scripts/generate_stubs.py` - Stub generation tool +- `scripts/measure_size.sh` - Size measurement script + +**Modified files:** +- `CMakeLists.txt` - Add STRIP_EXTERNAL_LIBS mode +- `src/platform/platform.cc` - Conditional stub overrides +- `src/audio/audio.cc` - Conditional stub overrides + +## Notes + +- This is a **measurement tool**, not a runtime mode +- Binary will not execute (all APIs stubbed) +- Useful for tracking optimization progress +- Can reveal surprising size contributors +- Platform-specific (stubs may differ on Windows/Linux/macOS) diff --git a/timeline_analysis.html b/timeline_analysis.html deleted file mode 100644 index 92e4a3f..0000000 --- a/timeline_analysis.html +++ /dev/null @@ -1,425 +0,0 @@ - - - - -Demo Timeline - BPM 120 - - - -

Demo Timeline Gantt Chart

-
-BPM: 120 | Duration: 36s (explicit end) | Sequences: 14 -
- - - - - - 0s - - - 2s - - - 4s - - - 6s - - - 8s - - - 10s - - - 12s - - - 14s - - - 16s - - - 18s - - - 20s - - - 22s - - - 24s - - - 26s - - - 28s - - - 30s - - - 32s - - - 34s - - - 36s - - - - SEQ@0s [pri=0] (0-2s) - - SEQ@0s [pri=0] - - FlashCubeEffect [pri=-1] (0.2-1.5s) - - FlashCubeEffect [pri=-1] - - FlashEffect [pri=0] (0-1s) - - FlashEffect [pri=0] - - FadeEffect [pri=1] (0.1-1s) - - FadeEffect [pri=1] - - SolarizeEffect [pri=2] (0-2s) - - SolarizeEffect [pri=2] - - - - - SEQ@2s [pri=0] (2-5s) - - SEQ@2s [pri=0] - - FlashCubeEffect [pri=-1] (2.1-5s) - - FlashCubeEffect [pri=-1] - - FlashEffect [pri=0] (2-2.2s) - - FlashEffect [pri=0] - - - - - SEQ@3s [pri=1] (3-7s) - - SEQ@3s [pri=1] - - ParticleSprayEffect [pri=0] (3-5s) - - ParticleSprayEffect [pri=0] - - ParticlesEffect [pri=1] (3-5s) - - ParticlesEffect [pri=1] - - GaussianBlurEffect [pri=1] (3-7s) - - GaussianBlurEffect [pri=1] - - - - - SEQ@3.5s [pri=0] (3.5-4.5s) - - SEQ@3.5s [pri=0] - - HeptagonEffect [pri=0] (3.5-3.7s) - - HeptagonEffect [pri=0] - - FadeEffect [pri=1] (3.6-4.5s) - - FadeEffect [pri=1] - - - - - SEQ@4s [pri=3] (4-9s) - - SEQ@4s [pri=3] - - ThemeModulationEffect [pri=0] (4-6s) - - ThemeModulationEffect [pri=0] - - HeptagonEffect [pri=0] (4-8s) - - HeptagonEffect [pri=0] - - GaussianBlurEffect [pri=1] (4-8s) - - GaussianBlurEffect [pri=1] - - ChromaAberrationEffect [pri=2] (4-7s) - - ChromaAberrationEffect [pri=2] - - SolarizeEffect [pri=3] (4-9s) - - SolarizeEffect [pri=3] - - - - - SEQ@6s [pri=2] (6-8s) - - SEQ@6s [pri=2] - - FlashCubeEffect [pri=-1] (6.2-7.5s) - - FlashCubeEffect [pri=-1] - - HeptagonEffect [pri=0] (6-8s) - - HeptagonEffect [pri=0] - - ParticleSprayEffect [pri=1] (6-8s) - - ParticleSprayEffect [pri=1] - - ParticlesEffect [pri=2] (6-8s) - - ParticlesEffect [pri=2] - - - - - SEQ@7.5s [pri=2] (7.5-9s) - - SEQ@7.5s [pri=2] - - FlashCubeEffect [pri=-1] (7.7-9s) - - FlashCubeEffect [pri=-1] - - FlashEffect [pri=0] (7.5-8s) - - FlashEffect [pri=0] - - - - - SEQ@8s [pri=10] (8-12s) - - SEQ@8s [pri=10] - - FlashCubeEffect [pri=-1] (8.2-9.5s) - - FlashCubeEffect [pri=-1] - - GaussianBlurEffect [pri=0] (8-12s) - - GaussianBlurEffect [pri=0] - - FlashEffect [pri=1] (8-8.2s) - - FlashEffect [pri=1] - - FlashEffect [pri=1] (8.5-8.2s) *** INVALID TIME RANGE *** - - FlashEffect [pri=1] ⚠ - - - - - SEQ@8.5s [pri=2] (8.5-12.5s) - - SEQ@8.5s [pri=2] - - ThemeModulationEffect [pri=0] (8.5-10.5s) - - ThemeModulationEffect [pri=0] - - HeptagonEffect [pri=1] (8.7-10.5s) - - HeptagonEffect [pri=1] - - ParticleSprayEffect [pri=2] (8.5-10.5s) - - ParticleSprayEffect [pri=2] - - ParticlesEffect [pri=2] (8.5-10.5s) - - ParticlesEffect [pri=2] - - Hybrid3DEffect [pri=3] (8.5-10.5s) - - Hybrid3DEffect [pri=3] - - GaussianBlurEffect [pri=4] (8.5-12.5s) - - GaussianBlurEffect [pri=4] - - ChromaAberrationEffect [pri=5] (8.5-11.5s) - - ChromaAberrationEffect [pri=5] - - - - - SEQ@12s [pri=1] (12-22s) - - SEQ@12s [pri=1] - - ThemeModulationEffect [pri=0] (12-16s) - - ThemeModulationEffect [pri=0] - - HeptagonEffect [pri=1] (12.2-14s) - - HeptagonEffect [pri=1] - - ParticleSprayEffect [pri=2] (12-16s) - - ParticleSprayEffect [pri=2] - - Hybrid3DEffect [pri=3] (12-22s) - - Hybrid3DEffect [pri=3] - - GaussianBlurEffect [pri=4] (12-16s) - - GaussianBlurEffect [pri=4] - - ChromaAberrationEffect [pri=5] (12-17s) - - ChromaAberrationEffect [pri=5] - - SolarizeEffect [pri=6] (12-17s) - - SolarizeEffect [pri=6] - - - - - SEQ@16s [pri=0] (16-24s) - - SEQ@16s [pri=0] - - ThemeModulationEffect [pri=0] (16-18s) - - ThemeModulationEffect [pri=0] - - HeptagonEffect [pri=1] (16-24s) - - HeptagonEffect [pri=1] - - ChromaAberrationEffect [pri=2] (16-24s) - - ChromaAberrationEffect [pri=2] - - GaussianBlurEffect [pri=3] (16-20s) - - GaussianBlurEffect [pri=3] - - - - - SEQ@24s [pri=0] (24-28s) - - SEQ@24s [pri=0] - - ThemeModulationEffect [pri=0] (24-26s) - - ThemeModulationEffect [pri=0] - - HeptagonEffect [pri=1] (24.2-26s) - - HeptagonEffect [pri=1] - - GaussianBlurEffect [pri=2] (24-28s) - - GaussianBlurEffect [pri=2] - - SolarizeEffect [pri=3] (24-25s) - - SolarizeEffect [pri=3] - - - - - SEQ@28s [pri=0] (28-36s) - - SEQ@28s [pri=0] - - ThemeModulationEffect [pri=0] (28-32s) - - ThemeModulationEffect [pri=0] - - HeptagonEffect [pri=0] (28.2-30s) - - HeptagonEffect [pri=0] - - Hybrid3DEffect [pri=1] (28-30s) - - Hybrid3DEffect [pri=1] - - ParticleSprayEffect [pri=2] (28-32s) - - ParticleSprayEffect [pri=2] - - HeptagonEffect [pri=3] (28-36s) - - HeptagonEffect [pri=3] - - ChromaAberrationEffect [pri=4] (28-36s) - - ChromaAberrationEffect [pri=4] - - GaussianBlurEffect [pri=5] (28-32s) - - GaussianBlurEffect [pri=5] - - - - - SEQ@31s [pri=0] (31-32.5s) - - SEQ@31s [pri=0] - - ThemeModulationEffect [pri=0] (31-32.5s) - - ThemeModulationEffect [pri=0] - - SolarizeEffect [pri=1] (31-32.5s) - - SolarizeEffect [pri=1] - - - Sequence - - Effect - - Invalid Time Range - -
-Tip: Hover over bars to see details. Higher priority numbers render later (on top). -
- - -- cgit v1.2.3