Files
hyperframes/docs/catalog/components/yt-screen-warp.mdx
miga-heygenandMiguel Ángel 7b5fdb1ad2 fix(docs): emit catalog source accordion titles as plain strings (#4006)
The generated catalog pages rendered the "Source" accordion title as a
JSX expression, `<Accordion title={`name.html`}>`. Mintlify's search
indexer stringifies expression attribute nodes rather than evaluating
them, so every one of the 399 catalog pages surfaced its Source section
in search results as "[object Object]" (visible on the Scroll Feed page,
among others).

The template literal carried no escaping benefit: every title is a
single-segment `name.html` path, and a double-quoted JSX string handles
it directly. Introduce `mdxStringAttribute`, which emits a plain
`name="value"` attribute and escapes `& " < { }` as HTML character
references (MDX decodes references inside quoted attribute values, and
unlike JSON.stringify it does not rely on backslash escapes, which JSX
strings do not honour). Use it for both the Source accordion title and
the preview iframe title, and regenerate the catalog pages.

Regenerated with `npx tsx scripts/generate-catalog-pages.ts`; the only
change across the 399 pages is the one Accordion title line each.

Co-authored-by: Miguel Ángel <miguel.sierra@heygen.com>
2026-09-16 11:55:00 -04:00

169 lines
6.1 KiB
Plaintext

---
title: "On-Screen Display Effect"
description: "Grid, scanline, vignette, and sheen overlay plus a 3D-warp wrapper class that makes footage read as if playing on a physical display"
---
import { InstallCommand } from "/snippets/install-command.jsx";
## Install
<InstallCommand command="npx hyperframes add yt-screen-warp" item="yt-screen-warp" />
That writes one file: `compositions/components/yt-screen-warp.html`.
<iframe
className="w-full aspect-video rounded-xl border-0 bg-zinc-100 dark:bg-zinc-800"
title="yt-screen-warp preview"
loading="lazy"
srcDoc={`<!doctype html><html><head><meta charset="utf-8"><style>html,body{margin:0;height:100%;overflow:hidden;background:transparent}hyperframes-player{display:block;width:100%;height:100%}</style><script src="https://cdn.jsdelivr.net/npm/@hyperframes/player@latest/dist/hyperframes-player.global.js"><\/script></head><body><script>fetch("/public/catalog/components/yt-screen-warp.json").then(function(r){return r.json()}).then(function(d){var p=document.createElement("hyperframes-player");p.setAttribute("srcdoc",d.html);p.setAttribute("controls","");p.setAttribute("autoplay","");p.setAttribute("loop","");p.setAttribute("muted","");p.setAttribute("poster","https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/yt-screen-warp.png");document.body.appendChild(p)});<\/script></body></html>`}
/>
## Paste it into your composition
Open `compositions/components/yt-screen-warp.html` and copy what is inside into your own composition.
A component has no size or duration of its own. It takes both from the composition
you paste it into.
## Source
<Accordion title="yt-screen-warp.html">
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: transparent;
overflow: hidden;
}
/* ---- yt-screen-warp ---------------------------------------------------
Make footage read as a physical display: add .yt-screen-warp3d to the
media WRAPPER (subtle perspective), and place .yt-screen-fx overlay
inside it (pixel grid + scanlines + vignette + sheen). */
.yt-screen-warp3d {
transform: perspective(1400px) rotateY(-3.5deg) rotateX(1.6deg);
}
.yt-screen-fx {
position: absolute;
inset: 0;
pointer-events: none;
opacity: 0;
background:
/* sheen */
linear-gradient(115deg, rgba(255, 255, 255, 0.09) 0%, transparent 30%),
/* scanlines */
repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.1) 0 1px, transparent 1px 3px),
/* pixel grid */
repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.06) 0 1px, transparent 1px 4px);
box-shadow:
inset 0 0 90px rgba(0, 0, 0, 0.4),
inset 0 0 8px rgba(0, 0, 0, 0.5);
}
/* self-preview stand-in */
#yt-sw-wrap {
position: absolute;
left: 360px;
top: 190px;
width: 1200px;
height: 700px;
border-radius: 18px;
overflow: hidden;
}
#yt-sw-fill {
position: absolute;
inset: 0;
/* Placeholder footage: L3 of the ink over the dark ground, plus a 3px
achromatic hatch so the plate reads as a media surface, not an empty box. */
background:
repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 3px),
rgba(255, 255, 255, 0.18);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
display: flex;
align-items: center;
justify-content: center;
font-family: "Inter", ui-sans-serif, sans-serif;
font-weight: 700;
font-size: 92px;
color: rgba(255, 255, 255, 0.93);
}
</style>
</head>
<body>
<!-- Self-preview wrapper. WIRING: copy the two CSS classes; add
class="yt-screen-warp3d" to your media wrapper and
<div class="yt-screen-fx" id="yt-my-fx"></div> as its LAST child. Then:
ytScreenOn(tl, "#yt-my-fx", 2.0);
ytScreenOff(tl, "#yt-my-fx", 8.0);
-->
<div
id="yt-sw-root"
data-composition-id="yt-screen-warp"
data-start="0"
data-duration="4"
data-width="1920"
data-height="1080"
>
<div id="yt-sw-wrap" class="yt-screen-warp3d">
<div id="yt-sw-fill">on screen</div>
<div class="yt-screen-fx" id="yt-sw-fx"></div>
</div>
<div
id="yt-sw-drv"
class="clip"
data-start="0"
data-duration="4"
data-track-index="0"
style="position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none"
></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
// ---- copy these helpers into the host script ----
window.ytScreenOn = function (tl, target, at) {
tl.to(target, { opacity: 1, duration: 0.5, ease: "power2.out" }, at);
};
window.ytScreenOff = function (tl, target, at) {
tl.to(target, { opacity: 0, duration: 0.4, ease: "power2.in" }, at);
};
// Self-preview timeline.
var tl = gsap.timeline({ paused: true });
gsap.set("#yt-sw-wrap", { opacity: 0, scale: 0.96 });
tl.to("#yt-sw-wrap", { opacity: 1, scale: 1, duration: 0.5, ease: "power2.out" }, 0.2);
window.ytScreenOn(tl, "#yt-sw-fx", 0.8);
window.ytScreenOff(tl, "#yt-sw-fx", 3.1);
tl.to("#yt-sw-wrap", { opacity: 0, duration: 0.35, ease: "power2.in" }, 3.5);
tl.set("#yt-sw-root", { visibility: "hidden" }, 3.98);
window.__timelines["yt-screen-warp"] = tl;
})();
</script>
</body>
</html>
```
</Accordion>
{/* hf:generated-footer */}
Tagged `effect` `overlay` `texture`.
## Related topics
- [Browse the complete Catalog](/catalog)
- [Add assets and Catalog items in Studio](/studio/assets-and-blocks)
- [Build a richer composition](/go-further)