1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
|
# Handoff: Shader Parametrization System (February 8, 2026)
## Summary
Completed comprehensive shader parametrization system enabling dynamic per-frame parameters for visual effects via uniform buffers and .seq file syntax.
## Work Completed ✅
### Shader Parametrization System (Task #73 Phase 0)
**Goal**: Enable artists to configure visual effects with parameters (color, intensity, decay rates) via .seq files without touching C++ code.
**Use Cases**: Flash effect with custom colors, chromatic aberration strength control, blur radius adjustment, distortion parameters.
**Implementation**:
#### Phase 1: UniformHelper Template
- Created `src/gpu/uniform_helper.h` - Generic type-safe wrapper for WebGPU uniform buffers
- Template class handles buffer creation, updates, and lifetime management
- Zero-overhead abstraction over `gpu_create_buffer()` and `wgpuQueueWriteBuffer()`
```cpp
template <typename T>
class UniformBuffer {
void init(WGPUDevice device);
void update(WGPUQueue queue, const T& data);
GpuBuffer& get();
};
```
#### Phase 2: FlashEffect Parameter Structs
- Added `FlashEffectParams` (constructor-time base parameters):
- `color[3]` - RGB flash color (default: white)
- `decay_rate` - Flash fade rate per frame (default: 0.98)
- `trigger_threshold` - Intensity threshold to trigger flash (default: 0.7)
- Added `FlashUniforms` (GPU buffer layout with WGSL alignment):
- `flash_intensity` (4 bytes, offset 0)
- `intensity` (4 bytes, offset 4)
- `_pad1[2]` (8 bytes, offset 8-15) - **Padding for vec3 alignment**
- `color[3]` (12 bytes, offset 16-27) - **Aligned to 16 bytes**
- `_pad2` (4 bytes, offset 28-31)
- Total: 32 bytes (enforced with `static_assert`)
#### Phase 3: Parameterized WGSL Shader
- Updated `flash_effect.cc` shader to use `uniforms.flash_color` instead of hardcoded white
- Shader bindings: sampler (0), texture (1), uniforms (2)
- Fragment shader mixes input color with parameterized flash color based on flash intensity
```wgsl
struct Uniforms {
flash_intensity: f32,
intensity: f32,
flash_color: vec3<f32>, // Parameterized color
_pad: f32,
};
fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
let color = textureSample(inputTexture, inputSampler, input.uv);
var flashed = mix(color.rgb, uniforms.flash_color, uniforms.flash_intensity);
return vec4<f32>(flashed, color.a);
}
```
#### Phase 4: Per-Frame Parameter Computation
- Implemented dynamic parameter animation in `FlashEffect::render()` method
- Parameters computed each frame based on time, beat, and intensity
- Example: Color modulated by sinusoidal functions of time and beat
```cpp
// Animate color based on time and beat
const float r = params_.color[0] * (0.5f + 0.5f * sinf(time * 0.5f));
const float g = params_.color[1] * (0.5f + 0.5f * cosf(time * 0.7f));
const float b = params_.color[2] * (1.0f + 0.3f * beat);
const FlashUniforms u = {
.flash_intensity = flash_intensity_,
.intensity = intensity,
._pad1 = {0.0f, 0.0f},
.color = {r, g, b},
.pad2 = 0.0f
};
uniforms_.update(ctx_.queue, u);
```
#### Phase 5: .seq Syntax Extension
- Extended `seq_compiler.cc` to parse `key=value` parameters after effect class name
- Added `parse_parameters()` function to extract parameter pairs
- Code generation creates `FlashEffectParams` struct initialization for parameterized effects
- Backward compatibility: Effects without parameters use default constructor
**Syntax Example**:
```
EFFECT + FlashEffect 0 1 color=1.0,0.5,0.5 decay=0.95
```
**Generated Code**:
```cpp
{
FlashEffectParams p;
p.color[0] = 1.0f;
p.color[1] = 0.5f;
p.color[2] = 0.5f;
p.decay_rate = 0.95f;
seq->add_effect(std::make_shared<FlashEffect>(ctx, p), 0.0f, 1.f, 0);
}
```
---
### Critical Bugfix: WGSL Alignment
**Problem**: WebGPU validation error "Buffer is bound with size 24 where the shader expects 32"
**Root Cause**: WGSL alignment rules require `vec3<f32>` to be 16-byte aligned despite having 12-byte size. Initial `FlashUniforms` struct layout was:
```cpp
struct FlashUniforms {
float flash_intensity; // 0-3
float intensity; // 4-7
float color[3]; // 8-19 (WRONG - no padding)
float _pad; // 20-23
}; // Total: 24 bytes (WRONG)
```
**Solution**: Added explicit padding to align `color` array to 16-byte boundary:
```cpp
struct FlashUniforms {
float flash_intensity; // 0-3
float intensity; // 4-7
float _pad1[2]; // 8-15 (padding)
float color[3]; // 16-27 (aligned to 16 bytes)
float _pad2; // 28-31
}; // Total: 32 bytes (CORRECT)
static_assert(sizeof(FlashUniforms) == 32, "FlashUniforms must be 32 bytes");
```
**Impact**: Demo now runs without validation errors, all 32/32 tests pass.
---
## Files Modified
**New Files (3)**:
- `src/gpu/uniform_helper.h` - UniformBuffer template class
- `src/tests/test_uniform_helper.cc` - Unit test for template compilation
- `doc/SHADER_PARAMETRIZATION_PLAN.md` - Complete design document
**Modified Files (11)**:
- `src/gpu/effects/flash_effect.h` - Added FlashEffectParams, FlashUniforms structs, parameterized constructor
- `src/gpu/effects/flash_effect.cc` - Implemented per-frame computation, updated shader with parameterized color
- `src/gpu/demo_effects.h` - Removed duplicate FlashEffect definition, added include
- `tools/seq_compiler.cc` - Added parameter parsing and code generation
- `assets/demo.seq` - Added example with parameters
- `src/generated/timeline.cc` - Generated code with struct initialization
- `CMakeLists.txt` - Added test_uniform_helper target
- `TODO.md` - Added Task #73 (extend to other effects), moved completion to summary
- `PROJECT_CONTEXT.md` - Updated "Recently Completed" section
- `doc/COMPLETED.md` - Added detailed completion entry
- `doc/HANDOFF_2026-02-08.md` - This document
---
## Commits Made
**c7d1dd7** - `feat(gpu): Implement shader parametrization system`
- Phases 1-5 implementation
- 11 files changed (808+ / 40-)
- UniformHelper template + FlashEffect parametrization + .seq syntax
**775c0ea** - `fix(gpu): Correct FlashUniforms struct alignment for WGSL`
- Critical alignment bugfix (24 → 32 bytes)
- Added static_assert for future safety
- Fixed validation error
---
## Test Results
**All 32/32 tests passing (100%)**
**Test Coverage**:
- `test_uniform_helper.cc` - Verifies UniformBuffer template compiles correctly
- `test_demo_effects.cc` - All post-process and scene effects instantiate successfully
- Full shader compilation tests pass with new parameterized shaders
**Verification**:
- Demo runs without WebGPU validation errors
- Visual effects render with parameterized colors
- .seq file parsing generates correct parameter initialization code
- Per-frame animation produces time-dependent color modulation
---
## Current Status
**Completed:**
- ✅ Full shader parametrization infrastructure
- ✅ FlashEffect fully parameterized with color/decay control
- ✅ .seq syntax extension with key=value parsing
- ✅ Per-frame dynamic parameter computation
- ✅ Critical WGSL alignment bug fixed
- ✅ Documentation updated (TODO.md, PROJECT_CONTEXT.md, COMPLETED.md)
**Ready for:**
- Task #73: Extend parametrization to other effects (ChromaAberrationEffect, GaussianBlurEffect, DistortEffect, SolarizeEffect)
- Additional parameter types (vec2, vec4, enums)
- Parameter curve system for keyframe animation (future)
---
## Technical Notes
### WGSL Alignment Rules
**Critical for future implementations:**
- `vec3<f32>` has **size = 12 bytes** but **alignment = 16 bytes**
- Always add padding before vec3 fields to align to 16-byte boundary
- Use `static_assert(sizeof(YourStruct) == expected_size)` to catch misalignment
- Reference: [WebGPU WGSL Spec - Alignment and Size](https://www.w3.org/TR/WGSL/#alignment-and-size)
### UniformHelper Pattern
**Reusable template for any effect parameters:**
```cpp
// 1. Define parameter structs
struct YourEffectParams { /* constructor-time params */ };
struct YourEffectUniforms { /* GPU buffer layout with padding */ };
static_assert(sizeof(YourEffectUniforms) == expected_size);
// 2. Add UniformBuffer member
UniformBuffer<YourEffectUniforms> uniforms_;
// 3. Initialize in constructor
uniforms_.init(ctx_.device);
// 4. Update in render()
const YourEffectUniforms u = { /* compute values */ };
uniforms_.update(ctx_.queue, u);
// 5. Bind in shader
pipeline_ = create_pipeline(...);
bind_group_ = create_bind_group(..., uniforms_.get().buffer, ...);
```
### Backward Compatibility
**All existing effects continue to work:**
- Default parameter constructor delegates to parameterized constructor
- Effects without .seq parameters use default values
- No changes required to existing timeline code
---
## Design Document
**Complete design**: See `doc/SHADER_PARAMETRIZATION_PLAN.md`
**Key Sections**:
- Motivation and use cases
- 5-phase implementation plan
- WGSL alignment rules and solutions
- Per-frame vs constructor-time parameters
- .seq syntax specification
- Migration path for existing effects
- Size budget analysis (~400-500 bytes)
- Alternative approaches considered
---
## Size Impact
**Binary Size**: +400-500 bytes net
- UniformHelper template code: ~200 bytes
- FlashEffectParams/Uniforms structs: ~100 bytes
- Per-effect parameter overhead: ~50-100 bytes each
- .seq compiler parameter parsing: ~100 bytes
**Trade-off**: Acceptable size increase for significant artist workflow improvement (no C++ recompilation for parameter tweaks).
---
## Next Steps (Recommendations)
### Immediate (Task #73)
Extend parametrization to other effects using FlashEffect as template:
1. **ChromaAberrationEffect**:
- Parameters: `offset` (vec2), `strength` (float)
- Syntax: `EFFECT + ChromaAberrationEffect 0 5 offset=0.01,0.02 strength=1.5`
2. **GaussianBlurEffect**:
- Parameters: `radius` (float), `sigma` (float)
- Syntax: `EFFECT + GaussianBlurEffect 2 8 radius=5.0 sigma=2.0`
3. **DistortEffect** (if exists):
- Parameters: `amount` (float), `speed` (float), `scale` (vec2)
4. **SolarizeEffect**:
- Parameters: `threshold` (float), `intensity` (float)
### Future Enhancements
- Parameter curve system (keyframe animation via .seq timeline)
- vec4/mat4 parameter support (color with alpha, transformation matrices)
- Enum parameters (blend modes, filter types)
- Parameter validation and clamping (min/max ranges)
---
## Context for Next Session
### What Works
- Shader parametrization infrastructure fully functional
- FlashEffect demonstrates complete implementation pattern
- .seq syntax parsing robust with backward compatibility
- All tests passing, demo stable
### Known Limitations
- Only FlashEffect parametrized (other effects use hardcoded values)
- No parameter validation or range clamping
- No keyframe animation support (future feature)
### Migration Pattern for Other Effects
1. Copy `FlashEffectParams` / `FlashUniforms` pattern
2. Add `UniformBuffer<YourUniforms>` member
3. Update shader to use uniform values
4. Implement per-frame computation in `render()`
5. Extend `seq_compiler.cc` with effect-specific parameter parsing
6. Test with .seq file, verify alignment with static_assert
---
## User Feedback Summary
**Session Start**: User requested shader parametrization with use cases (flash colors, aberration strength)
**Key Clarifications**:
- User confirmed parameters will be "generated in the code (manually, in effect's C++ code)"
- User emphasized "precision: user change parameter values on a per-frame basis. time-dependent"
- Critical feedback: Per-frame computation required, not just static constructor params
**Critical Bug Report**: User provided log.txt showing GPU validation error (buffer size mismatch)
**Outcome**: User satisfied, requested commit + documentation update (completed)
---
## Handoff Checklist
- [x] All tests passing (32/32)
- [x] Working tree clean
- [x] Documentation updated (TODO.md, PROJECT_CONTEXT.md, COMPLETED.md)
- [x] Commits created with detailed messages (c7d1dd7, 775c0ea)
- [x] No known regressions
- [x] Design document complete (SHADER_PARAMETRIZATION_PLAN.md)
- [x] Extension task noted (Task #73)
- [x] Ready for next session
---
**handoff(Claude):** Shader parametrization system complete. FlashEffect fully parameterized with .seq syntax. Critical alignment bug fixed. 32/32 tests passing. Ready for extension to other effects (Task #73).
---
*Generated: February 8, 2026*
*Claude Sonnet 4.5*
|