Install any skill in seconds. Free to start, no credit card required.
Get Started Free →A real-time particle galaxy — tens of thousands of additive-blended GPU points spiraling around a bright core, their orbits solved entirely in the vertex shader (from gl_VertexID), so the whole cloud draws in one call. Rendered as a single self-contained `index.html`. Use when the brief asks for a "particle field", "particle galaxy", "point cloud", "instanced points", "starfield", "GPU particles", or a swirling generative point system. Open Design serves this in powered-preview mode so the GPU s
.claude/skills/nexu-io-webgl-particle-galaxy/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 9% | 0% |
| case-23 | ✗→✓ | ▲ Improved | 9% | 0% |
| case-07 | ✓→✗ | ▼ Worse | 64% | 0% |
| case-08 | ✓→✗ | ▼ Worse | 25% | 0% |
| case-18 | ✓→✗ | ▼ Worse | 48% | 0% |
Produce a single self-contained index.html that renders a real-time particle system full-screen, with a clean typographic overlay on top. The signature move: compute each particle's position on the GPU so the CPU never loops over particles.
OpenDesign detects getContext('webgl2') and renders this file in powered preview — a cross-origin-isolated iframe with allow-same-origin. The full GPU pipeline is available; you do not need to work around the opaque sandbox.
webgl-particle-galaxy/
├── SKILL.md ← you're reading this
└── example.html ← a working 50,000-point WebGL2 galaxy (READ FIRST)Read example.html end to end. Note the shape: no vertex buffer — the vertex shader reads gl_VertexID, hashes it into a stable per-particle seed, and derives a log-spiral orbit with an inner-fast rotation curve. Points are drawn with gl.drawArrays(gl.POINTS, 0, N) in one call, additive-blended (blendFunc(ONE, ONE) with premultiplied color) so overlapping points glow.
Choose a field the vertex shader can express cheaply from gl_VertexID + uTime:
speed ≈ k / (r + ε), thin disk.index.htmlgl_PointSize), clamped and DPR-aware; soft round sprites via gl_PointCoord + a gaussian falloff in the fragment shader.blendFunc(ONE, ONE) reads as glow, not double-exposure.getShaderInfoLog / getProgramInfoLog) so a typo fails loudly.#63fe13 for the arms and a white-blue core).webgl2 is unavailable.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 52,699 | 49,143 | -7% | 1 | 1 | 0% | 8,259 | 8,983 | +9% | 0 | 0 | — |
case-02 | fail→fail | 65,993 | 51,249 | -22% | 1 | 1 | 0% | 8,262 | 8,986 | +9% | 0 | 0 | — |
case-03 | fail→fail | 51,979 | 42,340 | -19% | 1 | 1 | 0% | 8,260 | 8,984 | +9% | 0 | 0 | — |
case-04 | fail→fail | 64,407 | 54,436 | -15% | 1 | 1 | 0% | 8,292 | 9,015 | +9% | 0 | 0 | — |
case-05 | fail→pass | 39,034 | 44,950 | +15% | 1 | 1 | 0% | 8,283 | 9,006 | +9% | 0 | 0 | — |
case-06 | pass→pass | 30,961 | 42,420 | +37% | 1 | 1 | 0% | 4,887 | 8,982 | +84% | 0 | 0 | — |
case-07 | pass→fail | 26,267 | 53,068 | +102% | 1 | 1 | 0% | 5,479 | 8,989 | +64% | 0 | 0 | — |
case-08 | pass→fail | 33,638 | 52,188 | +55% | 1 | 1 | 0% | 7,188 | 8,985 | +25% | 0 | 0 | — |
case-09 | fail→fail | 40,397 | 39,463 | -2% | 1 | 1 | 0% | 8,261 | 8,984 | +9% | 0 | 0 | — |
case-10 | fail→fail | 43,780 | 41,746 | -5% | 1 | 1 | 0% | 8,265 | 8,988 | +9% | 0 | 0 | — |
case-11 | fail→fail | 52,097 | 51,320 | -1% | 1 | 1 | 0% | 8,269 | 8,992 | +9% | 0 | 0 | — |
case-12 | fail→fail | 64,104 | 40,761 | -36% | 1 | 1 | 0% | 8,250 | 8,973 | +9% | 0 | 0 | — |
case-13 | fail→fail | 48,134 | 44,336 | -8% | 1 | 1 | 0% | 8,264 | 8,987 | +9% | 0 | 0 | — |
case-14 | fail→fail | 44,305 | 43,228 | -2% | 1 | 1 | 0% | 7,367 | 8,976 | +22% | 0 | 0 | — |
case-15 | fail→fail | 42,202 | 38,808 | -8% | 1 | 1 | 0% | 8,255 | 8,979 | +9% | 0 | 0 | — |
case-16 | pass→pass | 42,403 | 37,323 | -12% | 1 | 1 | 0% | 8,264 | 8,712 | +5% | 0 | 0 | — |
case-17 | fail→fail | 39,391 | 43,164 | +10% | 1 | 1 | 0% | 8,250 | 8,973 | +9% | 0 | 0 | — |
case-18 | pass→fail | 29,219 | 52,905 | +81% | 1 | 1 | 0% | 6,057 | 8,985 | +48% | 0 | 0 | — |
case-19 | pass→fail | 51,657 | 41,953 | -19% | 1 | 1 | 0% | 8,119 | 8,967 | +10% | 0 | 0 | — |
case-20 | pass→pass | 12,541 | 39,064 | +211% | 1 | 1 | 0% | 2,826 | 8,957 | +217% | 0 | 0 | — |
case-21 | pass→pass | 37,512 | 37,819 | +1% | 1 | 1 | 0% | 8,232 | 8,955 | +9% | 0 | 0 | — |
case-22 | pass→fail | 18,598 | 42,831 | +130% | 1 | 1 | 0% | 3,936 | 8,953 | +127% | 0 | 0 | — |
case-23 | fail→pass | 45,351 | 48,191 | +6% | 1 | 1 | 0% | 8,249 | 8,972 | +9% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of -13 percentage points is the difference between those two pass rates over the 23 comparable cases. 5 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.