summaryrefslogtreecommitdiff
path: root/doc/ASSET_SYSTEM.md
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-09 10:43:11 +0100
committerskal <pascal.massimino@gmail.com>2026-02-09 10:43:11 +0100
commit70c64867baa30c83334559d3023153dfe3f9ff79 (patch)
treefa1353eca8f32334286aa4a9fc9c9461a5e56d8b /doc/ASSET_SYSTEM.md
parente952a9d0866a5a2a5f9da72ccbb40e2184da8a6f (diff)
docs: Simplify all design docs (50% reduction, 1687 lines removed)
Consolidated and streamlined all documentation: **Merged:** - PROCEDURAL.md → deleted (content in ASSET_SYSTEM.md) - FETCH_DEPS.md → BUILD.md (dependencies section) **Simplified (line reductions):** - HOWTO.md: 468→219 (53%) - CONTRIBUTING.md: 453→173 (62%) - SPECTRAL_BRUSH_EDITOR.md: 497→195 (61%) - SEQUENCE.md: 355→197 (45%) - CONTEXT_MAINTENANCE.md: 332→200 (40%) - test_demo_README.md: 273→122 (55%) - ASSET_SYSTEM.md: 271→108 (60%) - MASKING_SYSTEM.md: 240→125 (48%) - 3D.md: 196→118 (40%) - TRACKER.md: 124→76 (39%) - SCENE_FORMAT.md: 59→49 (17%) - BUILD.md: 83→69 (17%) **Total:** 3344→1657 lines (50.4% reduction) **Changes:** - Removed verbose examples, redundant explanations, unimplemented features - Moved detailed task plans to TODO.md (single source of truth) - Consolidated coding style rules - Kept essential APIs, syntax references, technical details **PROJECT_CONTEXT.md:** - Added "Design Docs Quick Reference" with 2-3 line summaries - Removed duplicate task entries - All design docs now loaded on-demand via Read tool Result: Context memory files reduced from 31.6k to ~15k tokens.
Diffstat (limited to 'doc/ASSET_SYSTEM.md')
-rw-r--r--doc/ASSET_SYSTEM.md317
1 files changed, 77 insertions, 240 deletions
diff --git a/doc/ASSET_SYSTEM.md b/doc/ASSET_SYSTEM.md
index aea99a2..4e34378 100644
--- a/doc/ASSET_SYSTEM.md
+++ b/doc/ASSET_SYSTEM.md
@@ -1,271 +1,108 @@
-# compact asset system for the 64k demo
+# Compact Asset System for the 64k Demo
-This file describe the features of a compact asset system used in the demo.
+This file describes the asset system architecture and runtime API.
-The idea is the following:
+## Core Concept
-# run-time asset retrieval:
- All assets are const byte arrays. We need a 'const uint8_t* GetAsset(uint16 asset_id)'
- The asset ID is defined in a 'assets.h' header, generated during the final
- compile by our own assembling tool. assets.h needs to be re-generated
- infrequently.
+All assets are const byte arrays embedded in the binary. Runtime retrieval via `GetAsset(AssetId)` returns direct pointers with O(1) lookup.
-# assembling the assets:
+## Runtime Asset Retrieval
-## description file 'assets.txt'
- All assets are just files in the assets/final/ directory
- This directory needs a assets.txt text file to describe the asset files.
- Each line of the assets.txt file contain, comma-separated:
- * the name of the asset (that will be used by the #define in assets.h),
- * the name of the file associated
- * the compression to use for this asset (default NONE. More options later)
- * and optionally the type of assets.
-
-## example For instance, a line in assets.txt will read:
-
-SAMPLE_142, sample_142.spec, NONE, "this is a drum kick sample"
-
-This instructs the final assembled file assets.h to have a code line:
- #define ASSET_SAMPLE_142 6323
+```cpp
+#include "assets.h"
+const uint8_t* mysample = GetAsset(ASSET_SAMPLE_142, &size);
+// ... use asset
+DropAsset(ASSET_SAMPLE_142, mysample); // For lazy decompression cleanup
+```
-(6323 is just an associated id)
+## Asset Manifest Format
-(or an enum instead of #define's)
+File: `assets/final/demo_assets.txt`
-so that we can call
+Format (CSV):
```
-#include "asset.h"
-const uint8_t* mysample = GetAsset(ASSET_SAMPLE_142);
-...etc
+ASSET_NAME, filename.ext, COMPRESSION, "Description"
```
-(if we use enums, GetAssert() signature needs to be changed)
-
-### Lazy decompression
-to save memory some assets can be decompressed 'at retrieval time' but kept
-compressed in memory until then.
-This means that we need a 'void DropAsset(uint16 asset_id, const uint8* asset)'
-method to handle memory disallocation depending on the asset type.
-
-### assembling tool
-
-we need a simple tool that:
- * takes the assets.txt file and parse it
- * generates the assets.h file with asset enums
- * generates the assets_data.cc file with all the data
- * put these in the source tree
- * this process needs a script for automation
-
-## Technical Details
-
-To support diverse usage (binary data, strings, typed structs), the asset packer enforces the following:
-1. **Alignment**: All static asset arrays are declared with `alignas(16)`. This ensures that `reinterpret_cast` to types like `float*` or SIMD vectors is safe (provided the data layout matches).
-2. **String Safety**: Every static asset is appended with a null-terminator (`0x00`). This allows the raw pointer to be safely used as a `const char*` C-string.
-3. **Size Reporting**: The `size` field in `AssetRecord` reflects the *original* file size. However, the underlying buffer is guaranteed to be at least `size + 1` bytes long (due to the null terminator).
-
-# Shader Snippets
-
-Shader code (WGSL) can also be managed as assets.
-1. Create `.wgsl` files in `assets/final/shaders/` (or similar).
-2. Add them to `assets/final/demo_assets.txt` with compression `NONE`.
- Example: `SHADER_COMMON, shaders/common.wgsl, NONE`
-3. In C++, retrieve them using `GetAsset()`. Since they are binary blobs,
- construct a `std::string` or `std::string_view` using the returned pointer
- and size.
-4. Register them with the `ShaderComposer`.
-
----
-
-# Current Implementation Status
-
-## What's Working ✅
-- **Build-Time Packer** (`tools/asset_packer.cc`): Parses `demo_assets.txt`, embeds binary files as C++ arrays
-- **Runtime Manager** (`src/util/asset_manager.{h,cc}`): O(1) retrieval with caching, SIOF fix via singleton
-- **Asset Types**: Static binaries (`.spec`, `.wgsl`), procedural textures (`PROC(func, params)`)
-- **Safety Guarantees**: 16-byte alignment, null-terminator for strings, size reporting
-- **Testing**: `test_assets.cc` validates retrieval, caching, procedural generation
-- **Current Manifest**: 33 assets (15 audio samples, 17 WGSL shaders, 1 procedural texture)
-
-## Design Strengths
-- Enum-based type safety (no magic numbers or strings at runtime)
-- Zero runtime cost for static assets (direct pointer return)
-- Clean separation of build-time and runtime concerns
-- Procedural generation support (saves binary size)
-- Thread-safe for immutable assets (cache is write-once)
-
-## Design Weaknesses
-- **No compression**: Only `NONE` supported, critical blocker for 64k goal
-- **STL dependencies**: `std::map`, `std::string` in runtime code (conflicts with CRT replacement)
-- **Hardcoded procedural dimensions**: Assumes 256×256 RGBA8 (lines 85-86 in `asset_manager.cc`)
-- **No integrity checks**: No CRC/hash validation for asset correctness
-- **Limited asset types**: No mesh/scene format yet (needed for Task #18)
-
----
-
-# Asset System Improvement Tasks
-
-## High Priority (Critical for 64k Goal)
-
-### Task #27: Asset Compression Layer
-**Goal**: Implement runtime decompression to reduce binary size by 30-50%.
-
-**Attack Plan**:
-- [ ] **27.1**: Add compression type enum (`NONE`, `ZLIB`, `RLE`, `CUSTOM`)
-- [ ] **27.2**: Update `asset_packer.cc` to compress assets during build
- - Integrate a lightweight compression library (e.g., miniz for zlib)
- - Store compressed size + original size in `AssetRecord`
-- [ ] **27.3**: Implement runtime decompressor in `asset_manager.cc`
- - Allocate decompressed buffer on first `GetAsset()` call
- - Cache decompressed data, allow `DropAsset()` to free memory
-- [ ] **27.4**: Update `assets.txt` format to specify compression per-asset
- - Example: `KICK_1, ZLIB, kick1.spec, "Compressed kick sample"`
-- [ ] **27.5**: Add tests for compressed asset retrieval and DropAsset
-
-**Size Impact**: Estimated 30-50% reduction on asset blob (shaders compress well, spectrograms moderately).
-
-**Dependency**: None (standalone improvement).
-
----
-
-### Task #28: Spectrogram Quantization
-**Goal**: Compress audio assets from `float32` to `uint16_t` with logarithmic frequency binning.
-
-**Attack Plan**:
-- [ ] **28.1**: Research optimal frequency bin distribution (logarithmic vs linear)
-- [ ] **28.2**: Update `spectool` to export quantized `.spec` format
- - Add `--quantize` flag to `spectool analyze`
- - Map spectral values to `uint16_t` range with configurable dynamic range
-- [ ] **28.3**: Update audio synthesis engine to decode quantized spectrograms
- - Add dequantization step in `src/audio/synth.cc`
-- [ ] **28.4**: Re-generate all `.spec` assets with quantization enabled
-- [ ] **28.5**: Add tests to verify audio quality degradation is acceptable
-
-**Size Impact**: 2-4× reduction on `.spec` files (currently 15 audio assets in manifest).
-
-**Dependency**: Task #27 (compression) for maximum size savings.
-
----
-
-### Task #29: WGSL Shader Minification
-**Goal**: Minify WGSL shaders to reduce text asset size.
-
-**Attack Plan**:
-- [ ] **29.1**: Implement WGSL minifier in `tools/wgsl_minify.py`
- - Remove comments, unnecessary whitespace
- - Rename variables to single-letter identifiers (preserve entry points)
- - Strip debug labels and unused code
-- [ ] **29.2**: Integrate minifier into build pipeline
- - Add `MINIFY` compression type to `asset_packer.cc`
- - Auto-minify all `SHADER_*` assets during build
-- [ ] **29.3**: Validate minified shaders compile correctly
- - Add shader compilation test to CI/CD
-
-**Size Impact**: 40-60% reduction on shader text (currently 17 WGSL shaders in manifest).
-
-**Dependency**: None (standalone improvement).
-
----
-
-## Medium Priority (Code Hygiene & Maintainability)
-
-### Task #20.1: Remove STL from Asset Manager (Part of Task #20) - COMPLETED
-**Goal**: Eliminate `std::map` and `std::string` to prepare for CRT replacement.
-**Status**: Initial removal for `AssetManager` hot paths completed. Full removal across the codebase deferred to Phase 2.
-
----
-
-### Task #30: Procedural Asset Generalization
-**Goal**: Support variable dimensions and formats for procedural textures.
-
-**Attack Plan**:
-- [ ] **30.1**: Update `assets.txt` format to encode dimensions in `proc_params`
- - Example: `NOISE_TEX, PROC(gen_noise, 256, 256, 4, 1234, 16), _, "Width, Height, Channels, Seed, Freq"`
-- [ ] **30.2**: Update `asset_packer.cc` to parse dimension parameters
-- [ ] **30.3**: Update `GetAsset()` to read dimensions from `proc_params`
- - Allocate buffer dynamically based on `width * height * channels`
-- [ ] **30.4**: Add support for grayscale (1 channel) and RGB (3 channels) formats
-
-**Size Impact**: Negligible (unlocks new use cases, no binary size change).
-
-**Dependency**: None.
-
----
-
-### Task #31: Asset Integrity Validation
-**Goal**: Add CRC32/hash checks to detect corrupted or incorrect assets.
-
-**Attack Plan**:
-- [ ] **31.1**: Compute CRC32 for each asset during build (`asset_packer.cc`)
- - Store CRC in `AssetRecord` struct
-- [ ] **31.2**: Add optional validation in `GetAsset()` (debug builds only)
- - Compare computed CRC against stored value
- - Log warnings if mismatch detected
-- [ ] **31.3**: Add `--verify-assets` flag to test suite
- - Run full integrity check on all assets
-
-**Size Impact**: +4 bytes per asset (CRC32), negligible overhead.
+Example:
+```
+SAMPLE_142, sample_142.spec, NONE, "This is a drum kick sample"
+SHADER_COMMON, shaders/common.wgsl, NONE, "Common utilities"
+```
-**Dependency**: None.
+This generates:
+```cpp
+enum class AssetId : uint16_t {
+ ASSET_SAMPLE_142 = 6323,
+ SHADER_COMMON = 6324,
+ // ...
+};
+```
----
+## Build Pipeline
-## Lower Priority (Future Enhancements)
+Tool: `tools/asset_packer.cc`
-### Task #18.1: 3D Asset Format Support (Part of Task #18)
-**Goal**: Extend asset system to handle binary mesh/scene data from Blender.
+1. Parse `demo_assets.txt`
+2. Read binary files from `assets/final/`
+3. Generate `assets.h` (enum definitions)
+4. Generate `assets_data.cc` (embedded byte arrays)
+5. Auto-triggered by CMake on manifest changes
-**Attack Plan**:
-- [ ] **18.1.1**: Define binary mesh format (vertices, indices, normals, UVs)
- - Consider alignment requirements for GPU upload
-- [ ] **18.1.2**: Update `asset_packer.cc` to handle `.mesh` files
- - Add `MESH3D` asset type
-- [ ] **18.1.3**: Implement runtime parser in `src/3d/mesh_loader.cc`
- - Parse binary blob into `Mesh` struct
-- [ ] **18.1.4**: Create Blender export script (`tools/blender_export.py`)
+## Technical Guarantees
-**Size Impact**: Depends on scene complexity (meshes can be large, consider compression).
+1. **Alignment**: All arrays declared `alignas(16)` for safe `reinterpret_cast`
+2. **String Safety**: Null-terminator appended (safe as C-string)
+3. **Size Reporting**: `size` reflects original file size (buffer is `size + 1`)
-**Dependency**: Task #27 (compression) for mesh data.
+## Shader Asset Usage
----
+```cpp
+size_t size;
+const uint8_t* shader_src = GetAsset(AssetId::SHADER_COMMON, &size);
+std::string_view code(reinterpret_cast<const char*>(shader_src), size);
+ShaderComposer::register_snippet("common", code);
+```
-### Task #32: Asset Hot-Reloading (Development Only)
-**Goal**: Enable live asset updates for faster iteration (under `!STRIP_ALL`).
+## Procedural Assets
-**Attack Plan**:
-- [ ] **32.1**: Add file watcher for `assets/final/` directory
- - Monitor `.spec`, `.wgsl` files for changes
-- [ ] **32.2**: Trigger rebuild of `assets_data.cc` on file change
- - Invoke `asset_packer` and recompile
-- [ ] **32.3**: Add API to reload specific assets at runtime
- - `ReloadAsset(AssetId)` for development use
+Format: `PROC(function_name, params...)`
-**Size Impact**: None (stripped from final build).
+Example:
+```
+NOISE_TEX, PROC(gen_noise, 1234, 16), NONE, "Noise texture seed=1234 freq=16"
+```
-**Dependency**: None (development-only feature).
+Runtime: First `GetAsset()` call invokes generator, caches result.
----
+## Design Strengths
-### Task #33: Asset Usage Tracking & Dead Asset Elimination
-**Goal**: Identify and remove unused assets to reduce binary size.
+- Enum-based type safety (no magic numbers)
+- Zero runtime cost for static assets
+- Procedural generation support (size savings)
+- Thread-safe for immutable assets
-**Attack Plan**:
-- [ ] **33.1**: Add instrumentation to track `GetAsset()` calls
- - Log which assets are accessed during a full demo run
-- [ ] **33.2**: Generate report of unused assets
-- [ ] **33.3**: Remove unused entries from `demo_assets.txt`
+## Design Weaknesses
-**Size Impact**: Depends on dead assets (could save 5-15% if unused assets exist).
+- **No compression**: Only `NONE` supported (critical blocker for 64k)
+- **STL dependencies**: `std::map` in runtime code (conflicts with CRT removal)
+- **Hardcoded procedural dimensions**: Assumes 256×256 RGBA8
+- **No integrity checks**: No CRC/hash validation
-**Dependency**: None.
+## Planned Improvements
----
+See **TODO.md** for detailed task breakdown:
+- **Task #27**: Asset compression (zlib, RLE)
+- **Task #28**: Spectrogram quantization (float32 → uint16_t)
+- **Task #29**: WGSL shader minification
+- **Task #30**: Procedural asset generalization
+- **Task #31**: Asset integrity validation (CRC32)
+- **Task #32**: Hot-reloading (dev builds)
+- **Task #33**: Dead asset elimination
-# Priority Recommendation
+## Current Manifest
-For the **64k goal**, prioritize in this order:
-1. **Task #27** (Compression) - Biggest size win
-2. **Task #29** (Shader Minification) - Easy win, low risk
-3. **Task #28** (Spectrogram Quantization) - Medium effort, high impact
-4. **Task #18.1** (3D Assets) - Once size budget allows
-5. **Task #34: Full STL Removal** - Deferred to final optimization phase.
+33 assets total:
+- 15 audio samples (`.spec`)
+- 17 WGSL shaders
+- 1 procedural texture