Files
Miguel Ángel 63a7ec692f feat(registry): eight more WebGPU shader backgrounds and a bundle with thirty new shaders (#5191)
* feat(registry): eight more WebGPU shader backgrounds and a bundle with thirty new shaders

* refactor(registry): simpler bundle copy step in the shader build

* test(registry): every shader block ships the same bundle and names a shader in it

* refactor(registry): one block loader for the shader block tests

* test(registry): name the stale block and match only shader names

* chore(registry): shorter licence line at the top of the shader bundle

* test(registry): every shader block installs the bundle's licences
2026-10-09 08:52:03 +00:00

65 lines
2.2 KiB
JavaScript

// Drives the page's Shaders-library canvas (shaders@4.0.0, WebGPU) from HyperFrames time, with no clock of its own.
import {
shaderRendererGPU,
createGpuUniformsMap,
rootPassthrough,
resolveBoundingBox,
} from "shaders/core";
import SHADERS from "shader-defs";
const canvas = document.querySelector("canvas[data-shader]");
const def = SHADERS[canvas.dataset.shader];
const renderer = shaderRendererGPU();
let chain = Promise.resolve();
// The library's clock only accumulates the deltas it is given, so each frame steps it to the time asked for. Read
// the clock rather than tracking it: initialize() already drew one frame and moved it by 16 ms.
function renderAt(t) {
chain = chain.then(() =>
renderer.renderSyntheticFrame(t - renderer.__testing.getFrameDiagnostics().globalElapsedTime),
);
return chain;
}
const ready = (async () => {
if (!def) throw new Error(`shaders: no shader named "${canvas.dataset.shader}" in this bundle`);
await renderer.initialize({ canvas, observeElement: false, colorSpace: "srgb" });
const reason = renderer.getFailureReason();
if (reason) throw new Error(`shaders: WebGPU unavailable (${reason})`);
// Synchronous from here to stopAnimation, so the library's own loop draws no frame in between.
renderer.registerNode("root", rootPassthrough.fragment, null, null, {}, rootPassthrough);
const props = JSON.parse(canvas.dataset.shaderProps || "{}");
const values = Object.fromEntries(
Object.entries(def.props).map(([name, prop]) => [
name,
name in props ? props[name] : prop.default,
]),
);
const at = {
blendMode: "normal",
renderOrder: 1,
id: "fx",
boundingBox: resolveBoundingBox(undefined),
};
renderer.registerNode(
"fx",
def.fragment,
"root",
at,
createGpuUniformsMap(def, values, "fx"),
def,
);
renderer.stopAnimation();
await renderAt(window.__hfTypegpuTime ?? 0);
})();
window.__hf = window.__hf || {};
window.__hf.buildReady = window.__hf.buildReady || {};
window.__hf.buildReady.shaders = ready;
ready.catch((err) => console.error(String(err)));
window.addEventListener("hf-seek", (e) => {
const done = ready.then(() => renderAt(e.detail.time));
if (typeof e.detail.waitUntil === "function") e.detail.waitUntil(done);
});