Monorepo for Aesthetic.Computer
aesthetic.computer
1# Glaze Resize/Reframe Synchronization Plan
2
3## Problem Statement
4During window resize on `prompt.mjs` (dark mode), users occasionally see **both** the glaze canvas and the underlying main canvas, causing a visual "double vision" or layering artifact.
5
6## Root Cause Analysis
7
8### Canvas Stack Architecture (z-index order)
91. **3D canvas** (z-index: 0) - Three.js
102. **WebGPU canvas** (z-index: 1)
113. **Glaze canvas** (z-index: 2) - WebGL2 post-processing
124. **Freeze frame canvas** (z-index: 3, position: fixed)
135. **UI canvas** (z-index: 6)
146. **Main 2D canvas** (z-index: 7)
157. **Debug canvas** (z-index: 8)
16
17### Current Resize Flow (bios.mjs)
18
191. **Window resize event** → debounced (80ms `REFRAME_DELAY`)
202. **`needsReframe = true`** triggers `frame()` call
213. **Freeze frame creation** (lines 1016-1071):
22 - Copy current canvas to `freezeFrameCan`
23 - If glaze is on: `Glaze.freeze(ffCtx)` - draws glaze canvas to freeze frame
24 - Set `canvas.style.opacity = 0` (hide main canvas)
25 - Append freeze frame to wrapper
264. **Canvas resize** (lines 1156-1158):
27 - `canvas.width = width; canvas.height = height`
28 - This clears the canvas!
295. **Glaze reload** (lines 1538-1557):
30 - `Glaze.on()` checks if dimensions changed
31 - If changed: creates new Glaze instance, reloads shaders
32 - Glaze canvas starts with `opacity: 0` (glaze.mjs line 40)
336. **Frame completion** (lines 15938-15951):
34 - Remove freeze frame: `freezeFrameCan.remove()`
35 - Call `Glaze.unfreeze()` - removes opacity property
36 - If glaze off: `canvas.style.removeProperty("opacity")`
37
38### Identified Race Conditions
39
40#### Issue 1: Glaze shader reload timing
41In `glaze.mjs` `on()` function (line 340):
42```javascript
43await glaze.load(() => {
44 offed = false;
45 frame(w, h, rect, nativeWidth, nativeHeight, wrapper);
46 loaded();
47});
48```
49The glaze shaders load **asynchronously**, but `frame()` is called inside the callback. If a resize happens during shader compilation, the canvas dimensions and glaze dimensions can get out of sync.
50
51#### Issue 2: Opacity transition timing (CSS)
52```css
53canvas[data-type="glaze"].first-glaze {
54 transition: 0.5s opacity;
55}
56```
57The `first-glaze` class adds a 500ms opacity transition. During rapid resizes, this transition may not complete before another resize triggers, leaving both canvases partially visible.
58
59#### Issue 3: Freeze frame removal timing
60In `bios.mjs` lines 15938-15951:
61```javascript
62if (freezeFrame && freezeFrameFrozen) {
63 if (glaze.on === false) {
64 canvas.style.removeProperty("opacity");
65 }
66 freezeFrameCan.remove();
67 freezeFrame = false;
68 // ...
69}
70
71if (glaze.on) {
72 Glaze.unfreeze(); // This just removes opacity property
73} else {
74 canvas.style.removeProperty("opacity");
75}
76```
77The freeze frame is removed **before** we can guarantee that:
781. The glaze canvas has finished its shader reload
792. The glaze canvas has been properly positioned/sized
803. The main canvas has been hidden (opacity: 0)
81
82#### Issue 4: Missing synchronization between canvas opacity states
83When glaze is on:
84- Main canvas should have `opacity: 0`
85- Glaze canvas should have `opacity: 1` (no opacity set)
86
87But there's no atomic transition between these states.
88
89## Proposed Solutions
90
91### Solution A: Deferred Freeze Frame Removal (Low Risk)
92Wait for glaze to be fully ready before removing freeze frame.
93
94**Changes in bios.mjs:**
95```javascript
96// Add a flag for glaze readiness
97let glazeReady = false;
98
99// In Glaze.on() callback:
100currentGlaze = Glaze.on(
101 canvas.width,
102 canvas.height,
103 canvasRect,
104 projectedWidth,
105 projectedHeight,
106 wrapper,
107 glaze.type,
108 () => {
109 glazeReady = true; // Mark glaze as ready
110 send({ type: "needs-paint" });
111 },
112);
113
114// In paint loop, before removing freeze frame:
115if (freezeFrame && freezeFrameFrozen && (!glaze.on || glazeReady)) {
116 // ... remove freeze frame
117 glazeReady = false; // Reset for next resize
118}
119```
120
121### Solution B: Eliminate CSS Transition During Resize (Medium Risk)
122Remove the `first-glaze` class during resize operations.
123
124**Changes:**
1251. In glaze.mjs `frame()`: Don't add `first-glaze` class if dimensions are changing
1262. Or: Add `transition: none` inline style during resize, restore after
127
128### Solution C: Atomic Opacity Swap (Higher Risk, Most Robust)
129Ensure main canvas opacity and glaze canvas opacity change atomically.
130
131**Changes in bios.mjs:**
132```javascript
133// Before showing glaze canvas
134requestAnimationFrame(() => {
135 canvas.style.opacity = 0; // Hide main canvas
136 Glaze.unfreeze(); // Show glaze canvas
137 freezeFrameCan.remove(); // Remove freeze frame
138});
139```
140
141### Solution D: Use Visibility Instead of Opacity
142Replace opacity manipulation with visibility for instant switching.
143
144**Changes:**
145- Replace `canvas.style.opacity = 0` with `canvas.style.visibility = "hidden"`
146- Replace `removeProperty("opacity")` with `style.visibility = "visible"`
147
148## Recommended Implementation Order
149
1501. **Phase 1** (Quick Win): Implement Solution A - deferred freeze frame removal
1512. **Phase 2** (If still issues): Add Solution B - disable transition during resize
1523. **Phase 3** (If needed): Implement Solution C - atomic opacity swap
153
154## Testing Checklist
155
156- [ ] Resize window slowly in dark mode (prompt.mjs)
157- [ ] Resize window rapidly in dark mode
158- [ ] Resize while content is actively animating
159- [ ] Test with different screen densities (devicePixelRatio)
160- [ ] Test switching between light/dark mode during resize
161- [ ] Test on macOS, Windows, Linux
162- [ ] Test in VS Code webview (ac-electron)
163
164## Files to Modify
165
1661. [bios.mjs](../system/public/aesthetic.computer/bios.mjs) - Main resize/glaze coordination
1672. [glaze.mjs](../system/public/aesthetic.computer/lib/glaze.mjs) - Shader loading and canvas management
1683. [style.css](../system/public/aesthetic.computer/style.css) - CSS transitions (if Solution B)
169
170## Performance Considerations
171
172- Avoid adding more async operations in the paint loop
173- The current 80ms `REFRAME_DELAY` is already a debounce - don't reduce it
174- Consider using `will-change: opacity` CSS hint on glaze canvas
175- Monitor for memory leaks from repeated shader program creation
176
177## References
178
179- bios.mjs freeze frame logic: lines 1016-1071
180- bios.mjs glaze.on() call: lines 1538-1557
181- bios.mjs freeze frame removal: lines 15938-15951
182- glaze.mjs on() function: lines 326-361
183- glaze.mjs frame() function: lines 120-200
184- glaze.mjs freeze/unfreeze: lines 392-405