跪拜 Guibai
← All articles
Three.js · Frontend · JavaScript

ShaderPad: A Zero-Friction GLSL Playground That Ships as an Embeddable React Component

By _lucas ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Shader experimentation has been stuck behind project setup overhead and playgrounds that either break on edge cases or lock features behind logins. ShaderPad removes both barriers and packages the editor as a reusable component, which means documentation authors can embed runnable, editable shaders directly into tutorials without sending readers to a separate site.

Summary

Writing GLSL typically means scaffolding an HTML file, importing Three.js, and running a local dev server just to test a few lines of transformation logic. ShaderPad replaces that loop with a browser-based editor that pairs a Monaco-backed code pane with a live Three.js preview, built-in geometries, and common uniforms like u_time and u_mouse ready to use.

The tool uses RawShaderMaterial deliberately—no hidden Three.js injections—so the source you write is exactly what runs on the GPU, and error line numbers map 1:1 to your code. A share feature compresses the entire shader source into the URL hash via LZString and Base64, making links self-contained and backend-free.

Beyond the standalone site, the Playground is extracted as the `@lucascv/shaderpad-playground` npm package. It slots into any React-based MDX document (Docusaurus, Astro, Nextra) so that technical writing can include live, editable shaders instead of static code blocks or external links. A djb2-hash-based localStorage keying scheme prevents stale drafts from surviving example updates.

Takeaways
Runs a shader in under 30 seconds with zero login, configuration, or local server.
Uses RawShaderMaterial so no hidden uniforms or attributes are injected; error line numbers match the user's source exactly.
Built-in uniforms (u_time, u_resolution, u_mouse, u_random) and geometries (plane, box, sphere) are ready without boilerplate.
Share links encode the full shader source into the URL hash using LZString compression and Base64, requiring no backend.
The Playground is published as an independent npm package (`@lucascv/shaderpad-playground`) that embeds into any MDX-based React documentation site with five lines of code.
LocalStorage persistence uses a djb2 hash of the source content in the key, so author-side example updates automatically invalidate stale user drafts.
The site is built on Astro's island architecture; the documentation shell ships as 6.84 kB of static HTML while the interactive Playground island loads on demand.
ESM/CJS dual-format bundling with tsup required manual extension mapping (.js for ESM, .cjs for CJS) to prevent hydration failures across different host frameworks.
Conclusions

Choosing RawShaderMaterial over ShaderMaterial is a pedagogical decision, not a performance one: it trades convenience for transparency so learners see exactly what runs on the GPU.

Encoding an entire shader into a URL hash via LZString + Base64 is a pragmatic hack that eliminates backend dependency for sharing, but it implicitly enforces brevity since browsers cap URL length around 8–32 KB.

The djb2-hash localStorage keying pattern solves a real content-sync problem that most embedded playgrounds ignore: when the author updates an example, the reader's stale draft silently vanishes instead of causing confusion.

Publishing the editor as an npm package rather than just a hosted site treats the playground as infrastructure, not a destination—this shifts the tool's value from 'another ShaderToy clone' to a documentation primitive.

Astro's island architecture is a genuinely good fit for this class of tool: the heavy WebGL and Monaco editor runtime stays quarantined in a client-only island while the surrounding documentation remains static HTML under 3 kB gzipped.

Concepts & terms
RawShaderMaterial
A Three.js material that applies GLSL source exactly as written, without automatically injecting built-in uniforms (cameraPosition, modelViewMatrix, etc.) or attributes. This gives 1:1 correspondence between source code and GPU execution, making it preferable for learning and debugging.
Astro Island Architecture
A web architecture where a page is primarily static HTML ('the ocean') with interactive components ('islands') that load their JavaScript only when needed. Astro achieves this by stripping all server-side JS at build time and hydrating client components on demand.
MDX
Markdown extended with JSX support, allowing React components to be written directly inside Markdown documents. Documentation frameworks like Docusaurus, Astro, and Nextra compile MDX into React component trees at build time.
LZString
A JavaScript library for string compression designed for short strings and URL-safe output. It exploits redundancy in text (like repeated GLSL keywords) to achieve 3–5x compression ratios, making it practical to embed source code in URL hash parameters.
djb2 hash
A simple, fast non-cryptographic hash function that produces a short numeric hash from a string. Here it is used to fingerprint shader source code so that localStorage keys change when the author updates an example, preventing stale user drafts from persisting.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗