# Compact Asset System for the 64k Demo This document outlines the architecture for managing assets, which are compiled into the binary for release builds but loaded from disk during development to speed up iteration. ## Asset Manifest Format Files: `workspaces/main/assets.txt`, `workspaces/test/assets.txt` Format (CSV): ``` ASSET_NAME, ASSET_TYPE, path/to/file.ext, "Description" ``` ### Asset Types The `ASSET_TYPE` field explicitly defines how the asset is processed and used at runtime. | Type | Description | |------|-------------| | `WGSL` | WGSL shader source code. | | `SPEC` | Spectrogram data for audio synthesis. | | `TEXTURE` | Image file (PNG, JPG, etc.), converted to a raw RGBA8 buffer with a width/height header. | | `MESH` | 3D model file (.obj), converted to an interleaved vertex/index buffer. | | `BINARY`| Generic raw binary data. | | `MP3` | MP3 audio; decoded to a spectrogram at runtime. | | `PROC(func, ...)` | CPU-based procedural generation at init time. | | `PROC_GPU(func, ...)`| GPU-based compute shader for procedural generation at init time. | ## Dual-Mode Loading Strategy The asset system operates in two modes, controlled by the `DEMO_STRIP_ALL` CMake flag: 1. **Development Mode (`DEMO_STRIP_ALL=OFF`)**: * `WGSL`, `SPEC`, and `MP3` assets are **loaded from disk** at runtime. * The `asset_packer` generates a C-string containing the file path for these assets. * The `AssetManager` reads the file on first access, caches it, and returns the content. * This mode allows for rapid iteration on shaders and audio without requiring a full recompile. 2. **Release Mode (`DEMO_STRIP_ALL=ON`)**: * All assets are **embedded directly into the binary** as `const` byte arrays. * This creates a single, self-contained executable suitable for distribution. * The `asset_packer` generates C++ byte arrays from the asset files. This dual-mode system provides both developer convenience and release-ready packaging. ## AssetType Enum The C++ `AssetType` enum mirrors the types defined in the asset manifest: ```cpp enum class AssetType : uint8_t { WGSL, SPEC, TEXTURE, MESH, BINARY, MP3, PROC, PROC_GPU, }; ``` Query at runtime: ```cpp if (GetAssetType(AssetId::NEVER_MP3) == AssetType::MP3) { ... } ``` ## Runtime API ```cpp #include "util/asset_manager.h" // Retrieve asset data size_t size; const uint8_t* data = GetAsset(AssetId::MY_ASSET, &size); DropAsset(AssetId::MY_ASSET, data); // Release procedural or disk-loaded data // Query type AssetType t = GetAssetType(AssetId::MY_ASSET); ``` ## Build Pipeline Tool: `tools/asset_packer.cc` 1. Parse workspace `assets.txt`. 2. If in **Development Mode**, for `WGSL`, `SPEC`, and `MP3` assets, it generates a C-string with the file path. 3. If in **Release Mode**, it reads and processes all files into byte arrays (images → RGBA8, meshes → vertex/index, etc.). 4. Generate `src/generated/assets.h` (enum + declarations). 5. Generate `src/generated/assets_data.cc` (byte arrays/paths + `AssetRecord` table). 6. Auto-triggered by CMake on manifest changes. ## Technical Guarantees - **Alignment**: All embedded data arrays are declared `alignas(16)` for safe `reinterpret_cast`. - **String Safety**: Embedded assets are null-terminated (safe as C-strings). In disk-load mode, the path itself is a null-terminated C-string. - **Size**: For embedded assets, `size` reflects the original file size (the buffer is `size + 1`). For disk-loaded assets, it reflects the file path's string length. ## Developer Workflow **Add a spectrogram:** ``` MY_KICK, SPEC, music/my_kick.spec, "Description" ``` **Add a shader:** ``` MY_SHADER, WGSL, shaders/my_shader.wgsl, "Description" ``` Rebuild: `cmake --build build -j4` — CMake detects manifest changes automatically. In development mode, changes to `.wgsl`, `.spec`, or `.mp3` files do not require a rebuild.