Author an editorial HTML+SVG diagram with the Diagram Design kit - choose the visual type, read its reference, start from an example, and satisfy the safety and accessibility contract that diagram_write({kind:"html"}) enforces.
中文简介正在准备中。当前显示原文说明。
Getting a shader onto a page - the WebGL bootstrap, uniform plumbing, device pixel ratio, resize, pause on hidden tab, reduced motion, the drop-in HTML file, parameter updates over postMessage, and embedding it without a framework. Read this when the shader has to run in a browser.
中文简介正在准备中。当前显示原文说明。
查看安装方法安装前可以查看交给 AI 代理的指令内容。
shader_target target=web writes one self-contained HTML file: no framework, no
build step, no request. That is the deployment model the Radiant corpus uses, and
it is the right default because a page that needs nothing cannot break because
something is missing.
Everything a fragment shader page needs, and nothing else:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shader</title>
<style>
html, body { margin: 0; height: 100%; overflow: hidden; background: #0a0a0a; }
canvas { display: block; width: 100vw; height: 100vh; }
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl', { alpha: false, antialias: false });
if (!gl) throw new Error('no WebGL');
const VERTEX = 'attribute vec2 a_position; void main() { gl_Position = vec4(a_position, 0.0, 1.0); }';
const FRAGMENT = `precision highp float;
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution;
gl_FragColor = vec4(uv.x, uv.y, 0.5 + 0.5 * sin(u_time), 1.0);
}`;
function compile(type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(shader) || 'compile failed');
}
return shader;
}
const program = gl.createProgram();
gl.attachShader(program, compile(gl.VERTEX_SHADER, VERTEX));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, FRAGMENT));
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
throw new Error(gl.getProgramInfoLog(program) || 'link failed');
}
gl.useProgram(program);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
const at = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(at);
gl.vertexAttribPointer(at, 2, gl.FLOAT, false, 0, 0);
const uTime = gl.getUniformLocation(program, 'u_time');
const uRes = gl.getUniformLocation(program, 'u_resolution');
function resize() {
// Cap the pixel ratio: a 3x phone rendering a 4K shader is a battery fire.
const dpr = Math.min(window.devicePixelRatio || 1, 2);
canvas.width = Math.round(canvas.clientWidth * dpr);
canvas.height = Math.round(canvas.clientHeight * dpr);
gl.viewport(0, 0, canvas.width, canvas.height);
}
window.addEventListener('resize', resize);
resize();
let running = true;
const start = performance.now();
function frame(now) {
if (!running) return;
gl.uniform1f(uTime, (now - start) / 1000);
gl.uniform2f(uRes, canvas.width, canvas.height);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
document.addEventListener('visibilitychange', () => {
if (document.hidden) { running = false; }
else if (!running) { running = true; requestAnimationFrame(frame); }
});
</script>
</body>
</html>
Every part of that is load-bearing:
preserveDrawingBuffer is not set here. Leave it off for animation (it costs
performance); turn it ON if you need toDataURL() or a screenshot.canvas.width = clientWidth * devicePixelRatio uncapped
renders four times the pixels on a 2x display for a difference nobody sees.visibilitychange. A background tab that keeps drawing wastes a battery and
is the most common complaint about shader backgrounds.resize sets canvas.width, which resets the drawing buffer - so the
viewport must be set again in the same handler, after the size.| dialect | context | extra |
|---|---|---|
es100 (gl_FragColor) | getContext('webgl') | call getExtension('OES_standard_derivatives') before compiling if you use fwidth |
es300 (#version 300 es) | getContext('webgl2') | none |
shadertoy / shader-skills | getContext('webgl2') | the page must supply iResolution, iTime, iMouse, iFrame |
A WebGL 1 context rejects a #version 300 es shader with
unsupported shader version 300 - which reads like a shader bug and is a context
bug. shader_target target=web picks the right one for you.
A drop-in page has no API, so it takes parameter updates over postMessage. This
is Radiant's own shape, and pages this row emits accept exactly it:
// on the parent page
const frame = document.querySelector('iframe');
frame.contentWindow.postMessage({ type: 'param', name: 'SPEED', value: 0.8 }, '*');
The page listens:
window.addEventListener('message', (event) => {
const data = event.data;
if (!data || data.type !== 'param') return;
if (data.name === 'SPEED') speed = data.value;
});
Match on the parameter name (SPEED, as declared in // @param SPEED ...),
not on the uniform name. The page owns the translation to u_speed.
<iframe
src="my-shader.html"
title="Background"
style="position: fixed; inset: 0; width: 100%; height: 100%; border: 0; z-index: -1;"
aria-hidden="true"
tabindex="-1"
></iframe>
Three habits: aria-hidden="true" (it is decoration, not content), z-index: -1
with the content above it, and no pointer events - an iframe over the page eats
every click. If it must sit behind text, put it in a container with
pointer-events: none.
Do not put a shader behind text without checking contrast: a moving background
behind body copy is a readability failure waiting to happen. Either keep it behind
a scrim (background: rgba(0,0,0,.55) over the canvas) or keep it in a hero band.
If the page already has a canvas, the bootstrap above drops in directly: keep the
program in a module, expose setParam(name, value) and resize(). The iframe is
only needed when the shader is a file - which is the case for a drop-in
background, and which is why the emitted artefact is a whole page.
const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const time = reduced ? 0 : (now - start) / 1000;
An animation that ignores this preference is an accessibility defect, not a feature. The page this row emits freezes time at 0 when the preference is set, so the shader still shows its picture, unmoving.
requestAnimationFrame in the profiler).shader_render at your intended size is the honest measurement.shader_verify proves the GLSL; the page is where the driver, the DPR and the
resize behaviour get their say. Test it in the browser you are shipping to.
还没有评价。欢迎分享你的使用感受。
无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。
还没有评论。来写第一条吧。
Author an editorial HTML+SVG diagram with the Diagram Design kit - choose the visual type, read its reference, start from an example, and satisfy the safety and accessibility contract that diagram_write({kind:"html"}) enforces.
中文简介正在准备中。当前显示原文说明。
Control this machine's Docker or Podman engine through the docker_* tools - read the engine's state first, list containers and images, inspect one, tail its logs, pull an image and start it, then stop, restart or remove what you started. Covers the engine that is asleep behind Docker Desktop and the exact call for each verb, the confirm rule removals obey, and the flags the tools deliberately do not have.
中文简介正在准备中。当前显示原文说明。
Drive ffmpeg through the media_run tool as an argv array - remux instead of re-encode, map streams explicitly, trim at keyframes, scale and crop, extract audio and frames, and build GIFs, contact sheets and concatenations. Covers the flags this pack injects, reading a failure from its exit code and last log lines, and the version-dependent spellings to hedge.
中文简介正在准备中。当前显示原文说明。
Read a media file's real structure with ffprobe through media_run - the JSON invocation and how to read it, what every family of field means, how to count frames, sample without decoding everything, detect HDR and interlacing, and diagnose a missing duration, a stream with no frames or a container that lies. Covers when media_probe's own report is already enough.
中文简介正在准备中。当前显示原文说明。
Writing a fragment shader that looks like something - the full-screen triangle, uv space, signed distance fields, noise and fbm, domain warping, raymarching budgets, tone mapping and banding. Every example compiles. Read this when the task is "make it look good", not "make it compile".
中文简介正在准备中。当前显示原文说明。
Use when the user wants to design, redesign, shape, critique, audit, polish, simplify, harden, animate, or otherwise improve a frontend interface: websites, landing pages, dashboards, product UI, components, forms, settings, onboarding, empty states, and native iOS or Android screens. Handles UX review, hierarchy, layout, typography, color, motion, UX copy, accessibility, responsive behavior, edge cases, and capturing or documenting design systems (DESIGN.md, tokens). Also for making bland UI bolder, loud UI quieter, or ambitious visual effects. Not for backend-only or non-UI tasks.
中文简介正在准备中。当前显示原文说明。