Jump to a section
System overview
Webglo is a browser-rendered video-art project in which each artwork can be represented as an HTML inscription containing native JavaScript and GLSL. The browser provides the WebGL API, the GPU executes the shaders, and the Ordinals content server returns the inscribed HTML as web content.
Runtime layer
HTML canvas, native JavaScript, WebGL context, GPU buffers, uniforms, and shaders.
Bitcoin layer
On-chain inscription content, commit/reveal transactions, a carrier sat, and an inscription ID.
Rendering architecture
element
Context
program
geometry
output
Core objects
| Object | Responsibility |
|---|---|
HTMLCanvasElement | Defines the browser surface and CSS display size. |
WebGLRenderingContext | Exposes WebGL 1 state, resources, shader compilation, and draw calls. |
WebGLShader | Stores a compiled vertex or fragment shader. |
WebGLProgram | Links compatible vertex and fragment stages into an executable GPU program. |
WebGLBuffer | Stores fullscreen vertex positions. |
WebGLUniformLocation | Addresses per-frame values such as time, resolution, and pointer position. |
Why fullscreen triangles
The runtime draws two triangles covering clip space from -1 to 1. Every covered pixel invokes the fragment shader, allowing the shader to generate the entire image without textures or scene geometry.
Single-file contract
A Webglo inscription should remain understandable as one web response with a valid HTML MIME type. The simplest portable form embeds all CSS, JavaScript, vertex GLSL, and fragment GLSL directly in the HTML document.
- One HTML document is the entry point.
- No npm bundle or build artifact is required at viewing time.
- No ordinary off-chain resources are required for the core render.
- The canvas has an explicit backing resolution before drawing.
- Shader compile and program link failures are surfaced visibly.
- The page remains functional inside an iframe-based inscription viewer.
Recommended MIME type
text/html;charset=utf-8
Runtime lifecycle
- Resolve the canvas.
- Create the WebGL context and stop with a visible fallback if unavailable.
- Compile the vertex shader.
- Compile the fragment shader.
- Link both shaders into a program.
- Create and upload fullscreen geometry.
- Resolve attribute and uniform locations once.
- On each frame, resize, set the viewport, update uniforms, and draw.
- Handle context loss or recover by reinitializing resources.
Shader interface
WebGL 1 vertex shader
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0.0, 1.0);
}
WebGL 1 fragment shader contract
precision highp float;
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
gl_FragColor = vec4(uv, 0.5 + 0.5 * sin(u_time), 1.0);
}
| Name | Direction | Notes |
|---|---|---|
a_position | JavaScript → vertex shader | Two-component clip-space coordinate. |
u_resolution | JavaScript → fragment shader | Use backing pixels, not only CSS pixels. |
u_time | JavaScript → fragment shader | Seconds from requestAnimationFrame. |
u_mouse | JavaScript → fragment shader | Normalized input; optional for noninteractive work. |
gl_FragCoord | Built-in fragment input | Current fragment coordinate in window space. |
gl_FragColor | Fragment shader output | WebGL 1 / GLSL ES 1.00 output variable. |
WebGL 1 versus WebGL 2
WebGL 1 shaders commonly use attribute, varying, and
gl_FragColor. WebGL 2 uses GLSL ES 3.00 conventions such as
#version 300 es, in, out, and an explicit fragment
output. Do not mix the two syntaxes.
Resolution, aspect ratio, and input
CSS controls how large the canvas appears. The width and height
properties control the actual backing buffer. A high-DPI display needs a larger backing
buffer than its CSS size to avoid blur.
function resizeCanvasToDisplaySize(canvas) {
const dpr = Math.min(window.devicePixelRatio || 1, 2);
const width = Math.max(1, Math.round(canvas.clientWidth * dpr));
const height = Math.max(1, Math.round(canvas.clientHeight * dpr));
if (canvas.width !== width || canvas.height !== height) {
canvas.width = width;
canvas.height = height;
return true;
}
return false;
}
// Call before drawing:
resizeCanvasToDisplaySize(canvas);
gl.viewport(0, 0, canvas.width, canvas.height);
Aspect-correct coordinates
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
vec2 p = uv - 0.5;
p.x *= u_resolution.x / u_resolution.y;
Device-pixel-ratio cap
Capping DPR at 2 is a practical performance guard for generative shaders. Removing the cap improves sharpness on very dense displays but can multiply fragment workload.
Compilation and link diagnostics
Shader compiler logs are the primary diagnostic source. Always inspect
COMPILE_STATUS and LINK_STATUS; do not assume a created object is
valid.
function compileShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
const log = gl.getShaderInfoLog(shader);
gl.deleteShader(shader);
throw new Error(log || "Shader compilation failed.");
}
return shader;
}
Common compiler failures
| Error class | Typical cause |
|---|---|
| Syntax | Missing semicolon, unbalanced bracket, malformed numeric literal. |
| Type mismatch | Combining scalar, vector, or matrix types without a valid conversion. |
| Precision | No default float precision in a fragment shader. |
| Version mismatch | Using WebGL 2 GLSL syntax in a WebGL 1 context or the reverse. |
| Link mismatch | Vertex outputs and fragment inputs disagree in name, type, or precision. |
| Uniform optimized out | A declared value is unused, producing a null uniform location. |
Ordinals HTML runtime
Ordinals content uses a web-style model: an inscription has a MIME content type and a byte body that can be returned by a content server. HTML and SVG inscriptions are sandboxed in iframes and served with content-security restrictions intended to prevent ordinary off-chain dependencies.
Implications for WebGL work
- Inline JavaScript and GLSL are the most portable base.
- Remote CDN scripts, web fonts, images, and APIs should not be required.
- Audio autoplay and user-input behavior may differ by browser and viewer.
- The direct content view is the authoritative rendering test, not only a marketplace card.
- Viewer implementations can differ, so graceful fallback behavior matters.
Commit and reveal model
Inscriptions use a two-transaction process. The commit creates a Taproot output committing to the script that contains the inscription. The reveal spends that output and publishes the inscription content in the witness.
wallet
transaction
output
transaction
inscription
Inscription ID
An inscription ID has the form TXIDiN. TXID is the reveal
transaction ID and N is the zero-based index of the inscription inside that
reveal.
Content envelope
The content type and body are serialized in an unexecuted Taproot script conditional. Large bodies are split across data pushes because individual pushes are limited to 520 bytes.
Practical limits and fee model
The current ord wallet guide states that inscription transactions must be
below 400,000 weight units to be relayed by Bitcoin Core and recommends keeping content
below roughly 390,000 bytes to leave room for transaction overhead.
| Constraint | Meaning |
|---|---|
| Bitcoin block weight | Upper capacity of a block; not a safe target for a standard individual inscription transaction. |
| Standard relay policy | Determines whether ordinary Bitcoin Core nodes relay the transaction. |
| Tool/service limit | May be lower or use a specialized workflow; follow the active interface. |
| Browser/GPU limit | A tiny file can still be too computationally expensive to render smoothly. |
Approximate content fee
The ord guide gives the approximation:
(content bytes ÷ 4) × fee rate. The total transaction cost is higher because
commit/reveal overhead and outputs also consume weight.
Recursive content
Recursion is the allowed exception to the ordinary inscription sandbox. Whitelisted endpoints can load content and data from other inscriptions, making it possible to share code, textures, audio, stylesheets, or generative assets without copying them into every child HTML file.
<!-- On an Ordinals-compatible content server -->
<script src="/content/<INSCRIPTION_ID>"></script>
<!-- Or load an on-chain image -->
<img src="/content/<INSCRIPTION_ID>" alt="">
Use cases
- One shared JavaScript or shader library referenced by many artworks.
- Texture atlases or visual layers assembled by a smaller HTML inscription.
- Generative collections using inscription IDs or chain data as seeds.
- Remixes that explicitly depend on previously inscribed media.
Portability and resilience
- Prefer WebGL 1 when the artwork does not require WebGL 2-only features.
- Use explicit precision declarations and avoid undefined GLSL behavior.
- Compute aspect ratio from the current resolution rather than hard-coded 640×480 values.
- Cap device pixel ratio or dynamically reduce quality for expensive shaders.
- Keep the render meaningful without pointer input.
- Provide a visible WebGL failure message instead of a silent black page.
- Handle context loss and recreate GPU resources after restoration.
- Do not depend on explorer-specific DOM access or unsandboxed behavior.
- Preserve an unminified source version and inscribe only a tested optimized build.
Browser and device support
WebGL is implemented by modern desktop and mobile browsers, but actual availability still depends on the device GPU, browser settings, driver blocklists, power state, and viewer environment.
| Test | Minimum recommendation |
|---|---|
| Desktop browsers | Current Chrome or Edge plus current Firefox. |
| Safari | Test separately, especially inscription-service controls and mobile behavior. |
| Mobile | At least one iOS Safari device and one Android Chrome device. |
| Orientation | Portrait and landscape. |
| DPI | 1× and high-DPI displays. |
| Input | No pointer, touch pointer, and mouse pointer. |
| Long run | Several minutes to detect thermal throttling or context loss. |
Webglo inscriptions
The original Webglo inscription was created on June 12, 2023 at 23:05:38 UTC. Its known
record includes inscription number #11635450, inscription ID
5518d36079b3cc854dba0bd6497ec078fbaa996ebd53e908150c845d6a56a463i0,
and sat number 849910637619339.
| Inscription | Explorer |
|---|---|
| #11635450 | Open inscription |
| #11637749 | Open inscription |
| #11805310 | Open inscription |
| #11875520 | Open inscription |
| #11875521 | Open inscription |
| #11875522 | Open inscription |
| #11875523 | Open inscription |
| #11875524 | Open inscription |
| #11875525 | Open inscription |
| #11875526 | Open inscription |
| #12077747 | Open inscription |
| #12077748 | Open inscription |
| #12077749 | Open inscription |
| #12077750 | Open inscription |
| #12077751 | Open inscription |
| #12077752 | Open inscription |
| #12077753 | Open inscription |
| #12077754 | Open inscription |
| #12077755 | Open inscription |
| #12077756 | Open inscription |
| #12102422 | Open inscription |
| #12102423 | Open inscription |
| #12102424 | Open inscription |
| #12102425 | Open inscription |
| #12102426 | Open inscription |
Glossary
| Term | Definition |
|---|---|
| Bitcoin Ordinal | A sat tracked under ordinal theory; it may carry an inscription. |
| Inscription | Content associated with a sat through a reveal transaction. |
| Commit transaction | Creates the Taproot output that commits to the inscription script. |
| Reveal transaction | Spends the commit output and exposes the inscription content. |
| WebGL | Browser API for GPU-accelerated graphics based on OpenGL ES. |
| GLSL | Shader language executed by the graphics pipeline. |
| Vertex shader | Transforms vertex inputs and produces clip-space positions. |
| Fragment shader | Computes the output color for covered pixels/fragments. |
| Uniform | A constant value supplied to a shader for a draw call. |
| Recursion | Loading whitelisted on-chain content or data from other inscriptions. |
| MIME type | Content type used to describe how the inscription body should be served. |
Technical references
- Ordinal Theory Handbook — Inscriptions
- Ordinal Theory Handbook — Wallet and inscription commands
- Ordinal Theory Handbook — Recursion
- Khronos — WebGL standard and resources
- MDN — WebGL API reference
- Webglo repository
- Original Webglo wiki tutorial
- Original 2023 WebGL Ordinal article
- LooksOrdinal inscription interface
- mempool.space transaction explorer