fix(registry): glass-shard-title renders when mounted, and 4 skipped blocks install again (#4423)

* fix(registry): glass-shard-title renders when mounted, and 4 skipped blocks install again

* fix(registry): glass-shard-title loads in Studio and ?play, and its docs payload fails loudly

* test(scripts): pin the glass payload's hdr guard for any quote style
This commit is contained in:
Miguel Ángel
2026-09-24 13:08:15 -04:00
committed by GitHub
parent b9e5a16fcf
commit 8dabc8af63
10 changed files with 91 additions and 35 deletions
@@ -1,3 +1,5 @@
import { existsSync, readFileSync, readdirSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { validRegistryName, validRegistryManifest, validRegistryItem } from "./validation.js";
@@ -39,4 +41,21 @@ describe("registry manifest boundary", () => {
validRegistryManifest({ ...manifest, items: Array(10_001).fill(manifest.items[0]) }),
).toBe(false);
});
it("accepts every registry-item.json the repo publishes", () => {
const registry = join(import.meta.dirname, "../../../../registry");
const rejected = readdirSync(registry, { withFileTypes: true })
.filter((dir) => dir.isDirectory())
.flatMap((dir) =>
readdirSync(join(registry, dir.name)).map((name) => ({ dir: dir.name, name })),
)
.filter(({ dir, name }) => existsSync(join(registry, dir, name, "registry-item.json")))
.filter(({ dir, name }) => {
const item = JSON.parse(
readFileSync(join(registry, dir, name, "registry-item.json"), "utf8"),
);
return !validRegistryItem(item, name, item.type);
})
.map(({ dir, name }) => `${dir}/${name}`);
expect(rejected).toEqual([]);
});
});
File diff suppressed because one or more lines are too long
@@ -67,7 +67,7 @@ point.position.set(0, -3, 1);
scene.add(point);
/* ---- Environment + matcap (glass look) ---- */
const hdrTex = await new HDRLoader().loadAsync("assets/ferndale_studio_01_1k.hdr");
const hdrTex = await new HDRLoader().loadAsync(document.getElementById("gst-hdr").href);
const pmrem = new THREE.PMREMGenerator(renderer);
const envRT = pmrem.fromEquirectangular(hdrTex);
scene.environment = envRT.texture;
@@ -75,7 +75,9 @@ scene.environmentRotation = new THREE.Euler(0, 0.6, 0);
hdrTex.dispose();
pmrem.dispose();
const matcapTex = await new THREE.TextureLoader().loadAsync("assets/matcap-1.png");
const matcapTex = await new THREE.TextureLoader().loadAsync(
document.getElementById("gst-matcap").href,
);
matcapTex.colorSpace = THREE.SRGBColorSpace;
matcapTex.wrapS = matcapTex.wrapT = THREE.RepeatWrapping;
const mk = 1 / 0.2;
+15 -7
View File
@@ -4,13 +4,6 @@
data-composition-variables='[{"id":"headline","type":"string","label":"Headline","default":"Designed in glass","maxLength":40},{"id":"tileCount","type":"number","label":"Tiles","default":8,"min":1,"max":400,"step":1},{"id":"roundness","type":"number","label":"Roundness (0-1)","default":0.4,"min":0,"max":1,"step":0.01},{"id":"bevel","type":"number","label":"Bevel (0-1)","default":0.35,"min":0,"max":1,"step":0.01},{"id":"meshSmooth","type":"number","label":"Surface smoothness (0-1)","default":0.6,"min":0,"max":1,"step":0.01},{"id":"flyInTime","type":"number","label":"Fly-in time (s)","default":2.3,"min":0.2,"max":6,"step":0.05},{"id":"flyOutTime","type":"number","label":"Fly-out time (s)","default":2.4,"min":0.2,"max":6,"step":0.05},{"id":"stagger","type":"number","label":"Stagger (0-1)","default":0.27,"min":0,"max":1,"step":0.01},{"id":"flyInRotation","type":"number","label":"Fly-in rotation (0-60)","description":"Amount of inbound tumbling over the entire flight. 0 disables flight rotation; final orientation lands with each shard position.","default":5,"min":0,"max":60,"step":0.1},{"id":"flyOutRotation","type":"number","label":"Fly-out rotation (0-6)","default":6,"min":0,"max":6,"step":0.1},{"id":"chaos","type":"number","label":"Outline chaos (0-1)","default":0.25,"min":0,"max":1,"step":0.01},{"id":"padding","type":"number","label":"Edge padding (0-1)","default":1,"min":0,"max":1,"step":0.01},{"id":"sizeVariance","type":"number","label":"Size variance (0-1)","default":0.35,"min":0,"max":1,"step":0.01},{"id":"gap","type":"number","label":"Tile gap","default":0.03,"min":0,"max":0.3,"step":0.002},{"id":"easePow","type":"number","label":"Fly-in position ease (1-10)","description":"Shapes lateral and depth travel. Rotation uses the same staggered flight window with a gentle settle through arrival.","default":10,"min":1,"max":10,"step":0.1},{"id":"sideDist","type":"number","label":"Side fly distance","default":3,"min":0,"max":60,"step":0.5},{"id":"zDist","type":"number","label":"Z fly-from (negative)","default":-42,"min":-400,"max":0,"step":2},{"id":"zOut","type":"number","label":"Z fly-out to (+ = past camera)","default":14,"min":-400,"max":60,"step":2},{"id":"fog","type":"number","label":"Fog distance (0 = off)","default":36,"min":0,"max":400,"step":2}]'
>
<head>
<script>
/* ?play standalone mode only: this file lives in compositions/ but its
asset paths are project-root-relative (they resolve there when the
runtime inlines it into the host). Never runs for Studio/render. */
if (new URLSearchParams(location.search).has("play")) document.write('<base href="../">');
</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Glass Shard Title</title>
@@ -103,6 +96,21 @@
<span data-hf-id="hf-kqtg" style="font-weight: 400">Aa</span
><span data-hf-id="hf-7bxm" style="font-weight: 600">Aa</span>
</div>
<!-- glass-main.js reads these hrefs: a mounted block's src/href are rebased, strings in its script are not. -->
<link
id="gst-hdr"
rel="preload"
as="fetch"
crossorigin="anonymous"
href="assets/ferndale_studio_01_1k.hdr"
/>
<link
id="gst-matcap"
rel="preload"
as="image"
crossorigin="anonymous"
href="assets/matcap-1.png"
/>
</div>
<script>
@@ -20,12 +20,12 @@
{
"path": "assets/hyperframes-logo-dark.svg",
"target": "compositions/assets/hyperframes-logo-dark.svg",
"type": "registry:asset"
"type": "hyperframes:asset"
},
{
"path": "lib/liquid-glass.iife.js",
"target": "compositions/lib/liquid-glass.iife.js",
"type": "registry:asset"
"type": "hyperframes:asset"
}
],
"preview": {
@@ -20,12 +20,12 @@
{
"path": "assets/hyperframes-logo-dark.svg",
"target": "compositions/assets/hyperframes-logo-dark.svg",
"type": "registry:asset"
"type": "hyperframes:asset"
},
{
"path": "lib/liquid-glass.iife.js",
"target": "compositions/lib/liquid-glass.iife.js",
"type": "registry:asset"
"type": "hyperframes:asset"
}
],
"preview": {
@@ -100,7 +100,8 @@
"files": [
{
"path": "lt-neon-border.html",
"type": "hyperframes:block"
"target": "compositions/lt-neon-border.html",
"type": "hyperframes:composition"
}
],
"params": [
@@ -20,22 +20,22 @@
{
"path": "models/iphone.glb",
"target": "models/iphone.glb",
"type": "asset"
"type": "hyperframes:asset"
},
{
"path": "models/macbook.glb",
"target": "models/macbook.glb",
"type": "asset"
"type": "hyperframes:asset"
},
{
"path": "models/hyperframes-mobile.png",
"target": "models/hyperframes-mobile.png",
"type": "asset"
"type": "hyperframes:asset"
},
{
"path": "models/hyperframes-desktop.png",
"target": "models/hyperframes-desktop.png",
"type": "asset"
"type": "hyperframes:asset"
}
],
"preview": {
+39 -2
View File
@@ -1,9 +1,9 @@
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { withHostedRefs } from "./catalog-script-inlining.ts";
import { inlineCatalogScripts, withHostedRefs } from "./catalog-script-inlining.ts";
const CDN = "https://static.example.com/registry-assets";
@@ -52,3 +52,40 @@ describe("withHostedRefs", () => {
}
});
});
describe("glass-shard-title payload", () => {
const scriptTag = `<script src="assets/glass-main.js"></script>`;
const withGlassMain = (fn: (dir: string) => void) => {
const dir = mkdtempSync(join(tmpdir(), "hf-inlining-"));
try {
mkdirSync(join(dir, "assets"));
writeFileSync(join(dir, "assets/glass-main.js"), "window.GLASS = 1;");
fn(dir);
} finally {
rmSync(dir, { recursive: true, force: true });
}
};
it("inlines glass-main.js once the hdr link is a data URL", () => {
withGlassMain((dir) => {
const html = `<link id="gst-hdr" href="data:image/vnd.radiance;base64,AA">${scriptTag}`;
const out = inlineCatalogScripts("glass-shard-title", html, dir, {});
assert.ok(out.includes("window.GLASS = 1;"));
assert.ok(!out.includes(scriptTag));
});
});
it("refuses a payload whose hdr link still points at the local file", () => {
withGlassMain((dir) => {
for (const link of [
`<link id="gst-hdr" href="assets/ferndale_studio_01_1k.hdr">`,
`<link id='gst-hdr' href='assets/ferndale_studio_01_1k.hdr'>`,
]) {
assert.throws(
() => inlineCatalogScripts("glass-shard-title", link + scriptTag, dir, {}),
/hdr <link> was not inlined/,
);
}
});
});
});
+3 -14
View File
@@ -227,21 +227,10 @@ ${gsapLoaderJs(vendorUrls)}
}
function inlineGlassScripts(html: string, projectDir: string): string {
const hdrRelPath = "assets/ferndale_studio_01_1k.hdr";
let glassText = withHostedRefs(
readFileSync(join(projectDir, "assets/glass-main.js"), "utf-8"),
projectDir,
);
if (!glassText.includes(hdrRelPath)) {
throw new Error(
`catalog-script-inlining: glass-main.js no longer references "${hdrRelPath}"; ` +
`the hdr substitution needs updating.`,
);
if (html.includes("assets/ferndale_studio_01_1k.hdr")) {
throw new Error("catalog-script-inlining: glass-shard-title's hdr <link> was not inlined.");
}
const hdrBytes = readFileSync(join(projectDir, hdrRelPath));
const hdrDataUrl = `data:application/octet-stream;base64,${hdrBytes.toString("base64")}`;
glassText = glassText.split(hdrRelPath).join(hdrDataUrl);
const glassText = readFileSync(join(projectDir, "assets/glass-main.js"), "utf-8");
const bootstrap = `<script>(0,eval)(${jsStringLiteral(glassText)});</script>`;
return replaceOnce(
html,