Skip to content
Buse Turgay Sönmez

Design Engineer, Belgrade

One WebGL context, three leaks

Everything on this site draws in a single WebGL context. Then a piece arrived that brings its own geometry: a galloping horse in 17,022 vertices. Sharing the context with it went wrong in three ways, and fixing them turned up an engine bug that had been there from the start.

W39

The engine owns the loop, the clock, the pointer and the theme. A custom piece writes two functions, draw and dispose, and borrows the rest. That contract was the easy part.

The three leaks

State. The horse turns depth testing on, and whichever shader ran next inherited it. The engine now puts every fixed-function setting back to its base before each frame, whoever drew last.

Vertex arrays. The shared triangle that every other piece draws on has to bind its own array and let it go afterwards, or it picks up the horse's.

Context loss. When the context dies, the horse's buffers die with it. Disposing them again was an error, so a custom scene is no longer disposed on loss.

The old bug

Pointer energy only fell when the pointer left the stage. A pointer resting on it kept every scene at full power forever, and nobody had rested a pointer on a scene long enough to notice.

The cost of the horse: 70 ms of setup, no growth in first-load JavaScript, and no long tasks while moving between pieces.

On stage

GallopGeometry · Open the piece
--ground
oklch(0.985 0.003 85)
--surface
oklch(0.958 0.005 85)
--raised
oklch(1 0 0)
--ink
oklch(0.2 0.006 85)
--muted
oklch(0.43 0.008 85)
--faint
oklch(0.5 0.008 85)
--line
oklch(0.9 0.004 85)
--line-strong
oklch(0.6 0.006 85)
--accent
oklch(0.66 0.22 38)
--accent-ink
oklch(0.52 0.19 38)
--stage
oklch(0.152 0.004 85)
--radius-stage
36px
--radius-stage-sm
28px
--radius-media
24px
--radius-panel
16px
--radius-field
10px
--ease-out-expo
cubic-bezier(0.16, 1, 0.3, 1)

This week · W39One WebGL context, three leaksGeometry · 2026