Files
hyperframes/registry/components/perspective-marquee/perspective-marquee.html
T
Miguel Ángel 9734578e60 feat(registry): bring back the video-primitive moves (#3169)
Restores the 208 catalog items reverted after their previews 404'd in
production, this time on the payload mechanism rather than the .html files
that caused the outage.

The generator no longer writes a preview document to docs/public. That writer,
and the machinery under it, existed only to produce files the docs host
discards, so it is gone rather than bypassed. Items now embed the composition
itself via a payload, which is what the previous change already does for the
items that were already in the catalog.

The variables explorer is parked, not restored: it drove its preview through
the same unpublished .html path, so it would have shown an empty frame. Items
that declare variables get the live player plus the static variables table, and
reconnecting the explorer to payloads is a follow-up.
2026-08-10 18:46:03 -04:00

137 lines
6.0 KiB
HTML
Vendored

<!--
Perspective Marquee - remocn typography primitive for HyperFrames.
Paste the markup and CSS into a composition. Drive the timeline integration
from a paused GSAP timeline so renders remain deterministic.
Variables. The script reads each one, falls back to the declared default on
anything missing or unrecognised, and writes the result as a custom property
the CSS above consumes. The timeline recipe below is untouched by them: it
keeps driving one horizontal offset, and these decide how far that offset
carries and what the strip looks like while it rolls.
- tilt (flat | standard | steep, default standard): how far the marquee
plane leans back toward the horizon. flat is almost head-on, steep sends
the strip deep into the frame.
- travel (short | standard | long, default standard): scales the offset the
timeline drives, so the strip covers a shorter or longer run in the same
time. short reads as a slow drift, long as a fast roll.
- tone (ink | paper | accent, default ink): pill colour. ink is near-black
with white type for light frames, paper near-white with dark type for
dark ones, accent rides the brand token.
- words (string, default COMPONENTS, PRIMITIVES, TRANSITIONS, AGENTS): the
comma separated list of pill labels. The list is laid down twice so the
strip still reads as a continuous loop.
On every default the result is identical to the original: four near-black
pills, laid down twice, rolling 360px left across an 18 degree tilt.
-->
<div
class="hf-remocn-perspective-marquee"
data-composition-variables='[
{ "id": "tilt", "type": "enum", "role": "style", "label": "Tilt", "description": "How far the marquee plane leans back toward the horizon.", "default": "standard", "options": [{ "value": "flat", "label": "Flat" }, { "value": "standard", "label": "Standard" }, { "value": "steep", "label": "Steep" }] },
{ "id": "travel", "type": "enum", "role": "motion", "label": "Travel", "description": "Scales the offset the timeline drives, so the strip covers a shorter or longer run in the same time.", "default": "standard", "options": [{ "value": "short", "label": "Short" }, { "value": "standard", "label": "Standard" }, { "value": "long", "label": "Long" }] },
{ "id": "tone", "type": "enum", "role": "style", "label": "Tone", "description": "Pill colour: ink for light frames, paper for dark ones, accent rides the brand token.", "default": "ink", "options": [{ "value": "ink", "label": "Ink" }, { "value": "paper", "label": "Paper" }, { "value": "accent", "label": "Accent" }] },
{ "id": "words", "type": "string", "role": "content", "label": "Words", "description": "Comma separated pill labels. The list is laid down twice so the strip still reads as a continuous loop.", "default": "COMPONENTS, PRIMITIVES, TRANSITIONS, AGENTS" }
]'
>
<div>
<span>COMPONENTS</span><span>PRIMITIVES</span><span>TRANSITIONS</span><span>AGENTS</span
><span>COMPONENTS</span><span>PRIMITIVES</span><span>TRANSITIONS</span><span>AGENTS</span>
</div>
</div>
<style>
.hf-remocn-perspective-marquee {
color: #18181b;
font-family: Inter, system-ui, sans-serif;
font-weight: 900;
letter-spacing: -0.04em;
}
.hf-remocn-perspective-marquee {
width: 720px;
perspective: 900px;
overflow: hidden;
transform: rotateX(var(--hf-marquee-tilt, 18deg));
}
.hf-remocn-perspective-marquee div {
display: inline-flex;
gap: 22px;
white-space: nowrap;
transform: translateX(calc(var(--hf-marquee-x, 0px) * var(--hf-marquee-reach, 1)));
}
.hf-remocn-perspective-marquee span {
padding: 12px 18px;
border-radius: 999px;
background: var(--hf-marquee-pill-bg, #18181b);
color: var(--hf-marquee-pill-fg, #fff);
font-size: 28px;
box-shadow: 0 18px 44px rgba(24, 24, 27, 0.18);
}
</style>
<script>
(function () {
"use strict";
var vars =
window.__hyperframes && window.__hyperframes.getVariables
? window.__hyperframes.getVariables()
: {};
// Unrecognised overrides return to their declared defaults.
var tilts = { flat: "6deg", standard: "18deg", steep: "34deg" };
var reaches = { short: 0.55, standard: 1, long: 1.8 };
var tones = {
ink: { bg: "#18181b", fg: "#fff" },
paper: { bg: "#fafafa", fg: "#18181b" },
accent: { bg: "var(--brand, #34d399)", fg: "#fff" },
};
var defaultWords = "COMPONENTS, PRIMITIVES, TRANSITIONS, AGENTS";
function pick(table, value, fallback) {
return Object.prototype.hasOwnProperty.call(table, value) ? value : fallback;
}
function parseWords(value) {
var source = typeof value === "string" ? value : "";
var parts = source.split(",");
var words = [];
for (var i = 0; i < parts.length; i += 1) {
var word = parts[i].trim();
if (word) words.push(word);
}
return words.length ? words : parseWords(defaultWords);
}
var tilt = tilts[pick(tilts, vars.tilt, "standard")];
var reach = reaches[pick(reaches, vars.travel, "standard")];
var tone = tones[pick(tones, vars.tone, "ink")];
var words = parseWords(vars.words);
var roots = document.querySelectorAll(".hf-remocn-perspective-marquee");
for (var i = 0; i < roots.length; i += 1) {
roots[i].style.setProperty("--hf-marquee-tilt", tilt);
roots[i].style.setProperty("--hf-marquee-reach", String(reach));
roots[i].style.setProperty("--hf-marquee-pill-bg", tone.bg);
roots[i].style.setProperty("--hf-marquee-pill-fg", tone.fg);
var strip = roots[i].querySelector("div");
if (!strip) continue;
var markup = "";
for (var pass = 0; pass < 2; pass += 1) {
for (var w = 0; w < words.length; w += 1) {
markup += "<span>" + words[w].replace(/&/g, "&amp;").replace(/</g, "&lt;") + "</span>";
}
}
strip.innerHTML = markup;
}
})();
</script>
<!--
Timeline integration:
tl.fromTo('.hf-remocn-perspective-marquee div', { '--hf-marquee-x': '0px' }, { '--hf-marquee-x': '-360px', duration: 4.5, ease: 'none' }, startTime);
-->