Files
hyperframes/docs/catalog/blocks/ai-chat-reveal.mdx
T

2121 lines
73 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "AI Chat Reveal"
description: "A question is typed on a rising keyboard, sent, and answered by an AI that streams its reply word by word on a measured token rhythm - thinking dot, uneven bursts, bulleted list - before the app cuts to a branded closing card"
---
import { InstallCommand } from "/snippets/install-command.jsx";
import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
<VariablesExplorer
previewSrc="/public/catalog/blocks/ai-chat-reveal.json"
compositionId="ai-chat-reveal"
compositionSrc="compositions/ai-chat-reveal.html"
variables={[{"id":"botName","type":"string","role":"content","label":"Assistant name","description":"Title in the chat header.","default":"Assistant"},{"id":"userMessage","type":"string","role":"content","label":"User message","description":"The question typed on the keyboard and sent. Around 40 characters keeps the measured pacing.","default":"How do I turn my HTML into real video?"},{"id":"answer1","type":"string","role":"content","label":"Answer paragraph 1","description":"First streamed paragraph.","default":"You do not need an editor. HyperFrames renders the HTML you already write into deterministic, pixel-perfect video."},{"id":"answer2","type":"string","role":"content","label":"Answer paragraph 2","description":"Short second beat.","default":"It is markup, not magic."},{"id":"answer3","type":"string","role":"content","label":"Answer paragraph 3","description":"Lead-in to the list.","default":"What you get out of the box:"},{"id":"bullet1","type":"string","role":"content","label":"Bullet 1","description":"First list item.","default":"A catalog of motion primitives you install and own"},{"id":"bullet2","type":"string","role":"content","label":"Bullet 2","description":"Second list item.","default":"GSAP timelines that seek to any frame"},{"id":"bullet3","type":"string","role":"content","label":"Bullet 3","description":"Third list item.","default":"4K renders from a single CLI command"},{"id":"ecHeadline","type":"string","role":"content","label":"End-card headline","description":"Closing card headline. A | breaks the line.","default":"It's not magic.|It's HTML."},{"id":"ecSub","type":"string","role":"content","label":"End-card subline","description":"Supporting sentence on the closing card.","default":"Open-source video rendering — write HTML, ship pixel-perfect video."},{"id":"ecCta","type":"string","role":"content","label":"End-card CTA","description":"Label on the closing card button.","default":"Try HyperFrames"},{"id":"ecFooter","type":"string","role":"content","label":"End-card footer","description":"Letter-spaced line at the very bottom.","default":"HYPERFRAMES.HEYGEN.COM"}]}
>
```html ai-chat-reveal.html
<!doctype html>
<html
lang="en"
data-composition-variables='[
{ "id": "botName", "type": "string", "role": "content", "label": "Assistant name", "description": "Title in the chat header.", "default": "Assistant" },
{ "id": "userMessage", "type": "string", "role": "content", "label": "User message", "description": "The question typed on the keyboard and sent. Around 40 characters keeps the measured pacing.", "default": "How do I turn my HTML into real video?" },
{ "id": "answer1", "type": "string", "role": "content", "label": "Answer paragraph 1", "description": "First streamed paragraph.", "default": "You do not need an editor. HyperFrames renders the HTML you already write into deterministic, pixel-perfect video." },
{ "id": "answer2", "type": "string", "role": "content", "label": "Answer paragraph 2", "description": "Short second beat.", "default": "It is markup, not magic." },
{ "id": "answer3", "type": "string", "role": "content", "label": "Answer paragraph 3", "description": "Lead-in to the list.", "default": "What you get out of the box:" },
{ "id": "bullet1", "type": "string", "role": "content", "label": "Bullet 1", "description": "First list item.", "default": "A catalog of motion primitives you install and own" },
{ "id": "bullet2", "type": "string", "role": "content", "label": "Bullet 2", "description": "Second list item.", "default": "GSAP timelines that seek to any frame" },
{ "id": "bullet3", "type": "string", "role": "content", "label": "Bullet 3", "description": "Third list item.", "default": "4K renders from a single CLI command" },
{ "id": "ecHeadline", "type": "string", "role": "content", "label": "End-card headline", "description": "Closing card headline. A | breaks the line.", "default": "It&#39;s not magic.|It&#39;s HTML." },
{ "id": "ecSub", "type": "string", "role": "content", "label": "End-card subline", "description": "Supporting sentence on the closing card.", "default": "Open-source video rendering — write HTML, ship pixel-perfect video." },
{ "id": "ecCta", "type": "string", "role": "content", "label": "End-card CTA", "description": "Label on the closing card button.", "default": "Try HyperFrames" },
{ "id": "ecFooter", "type": "string", "role": "content", "label": "End-card footer", "description": "Letter-spaced line at the very bottom.", "default": "HYPERFRAMES.HEYGEN.COM" }
]'
>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1080, height=1920" />
<title>AI Chat Reveal</title>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 1080px;
height: 1920px;
overflow: hidden;
background: #000;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
/* The measured 750x1624 device UI is scaled uniformly into a standard
1080x1920 portrait canvas so its keyboard geometry stays pixel-true. */
#acr-root {
position: relative;
width: 1080px;
height: 1920px;
overflow: hidden;
}
.clip {
position: absolute;
inset: 0;
overflow: hidden;
}
#acr-chat {
background: #fdfdfd;
}
.acr-stage {
position: absolute;
left: 96.6502px;
top: 0;
width: 750px;
height: 1624px;
transform: scale(1.18226601);
transform-origin: top left;
}
#acr-chat-bg {
position: absolute;
inset: 0;
background: #fdfdfd;
}
/* status bar */
#acr-statusbar {
position: absolute;
top: 14px;
left: 0;
right: 0;
height: 44px;
}
#acr-clock {
position: absolute;
left: 39px;
top: 9px;
font-size: 22px;
font-weight: 600;
letter-spacing: 2.4px;
font-variant-numeric: tabular-nums;
color: #0d0d0d;
}
#acr-sicons {
position: absolute;
right: 26px;
top: 8px;
display: flex;
gap: 9px;
align-items: center;
}
/* header */
#acr-header {
position: absolute;
top: 64px;
left: 0;
right: 0;
height: 52px;
}
#acr-hleft {
position: absolute;
left: 28px;
top: 12px;
}
#acr-htitle {
position: absolute;
left: 0;
right: 48px;
text-align: center;
top: 13px;
font-size: 22px;
font-weight: 600;
color: #0d0d0d;
}
.acr-hicons {
position: absolute;
right: 28px;
top: 14px;
display: flex;
gap: 26px;
align-items: center;
}
#acr-hicons-b {
visibility: hidden;
opacity: 0;
}
/* user bubble */
#acr-bubble {
position: absolute;
top: 129px;
right: 32px;
max-width: 544px;
background: #f3f3f3;
border-radius: 34px;
padding: 20px 30px;
font-size: 27px;
line-height: 38.6px;
color: #111;
letter-spacing: 1.25px;
visibility: hidden;
opacity: 0;
}
/* answer */
#acr-answer {
position: absolute;
top: 267px;
left: 33px;
width: 662px;
font-size: 27px;
line-height: 38.6px;
color: #141414;
letter-spacing: 1.25px;
}
#acr-answer .acr-ap {
margin: 0 0 15.5px 0;
}
#acr-answer .acr-ali {
display: flex;
margin: 0 0 6.5px 0;
}
#acr-answer .acr-mark {
width: 30px;
flex: 0 0 30px;
text-align: center;
font-size: 18px;
line-height: 38.6px;
}
#acr-answer .acr-alitext {
flex: 1;
}
.acr-w {
opacity: 0;
}
#acr-dot {
position: absolute;
left: 32px;
top: 279px;
width: 15px;
height: 15px;
border-radius: 50%;
background: #646464;
visibility: hidden;
opacity: 0;
}
/* composer (rest dock; rides keyboard via transform) */
#acr-composer {
position: absolute;
left: 30px;
right: 30px;
bottom: 31px;
}
#acr-pill {
position: relative;
width: 100%;
min-height: 81px;
background: #fff;
border: 2px solid #ececec;
border-radius: 41px;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.04);
display: flex;
align-items: center;
padding: 13px 160px 13px 78px;
}
#acr-plusi {
position: absolute;
left: 30px;
top: 50%;
transform: translateY(-50%);
}
#acr-ph {
position: absolute;
left: 78px;
top: 50%;
transform: translateY(-50%);
color: #767676;
font-size: 28px;
letter-spacing: 1.25px;
}
#acr-ctextwrap {
width: 100%;
min-height: 38px;
}
#acr-ctext {
font-size: 29px;
line-height: 38px;
color: #0d0d0d;
letter-spacing: 1.25px;
visibility: hidden;
opacity: 0;
}
#acr-caret {
display: inline-block;
width: 3px;
height: 30px;
margin-left: 2px;
border-radius: 1.5px;
background: #0d0d0d;
vertical-align: -4px;
visibility: hidden;
opacity: 0;
}
#acr-cmic {
position: absolute;
right: 80px;
top: 50%;
transform: translateY(-50%);
}
.acr-cbtn {
position: absolute;
right: 14px;
top: 50%;
transform: translateY(-50%);
width: 52px;
height: 52px;
border-radius: 50%;
display: grid;
place-items: center;
}
#acr-btn-send-grey {
background: #ececec;
}
#acr-btn-send-black {
background: #0d0d0d;
visibility: hidden;
opacity: 0;
}
#acr-btn-stop {
background: #0d0d0d;
visibility: hidden;
opacity: 0;
}
#acr-btn-stop .acr-sq {
width: 19px;
height: 19px;
border-radius: 5px;
background: #fff;
}
/* keyboard: geometry and #d2d5e0 ground measured from the reference */
#acr-keyboard {
position: absolute;
left: 0;
bottom: 0;
width: 750px;
height: 482px;
background: #d2d5e0;
}
#acr-suggest {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 74px;
display: flex;
}
#acr-suggest .acr-sug {
flex: 1;
display: grid;
place-items: center;
font-size: 29px;
color: #0d0d0d;
position: relative;
}
#acr-suggest .acr-sug + .acr-sug::before {
content: "";
position: absolute;
left: 0;
top: 16px;
bottom: 16px;
width: 1.5px;
background: #bcbabf;
}
.acr-key {
position: absolute;
height: 74px;
background: #fdfdfd;
border-radius: 10px;
box-shadow: 0 2px 0 #8b8a8f;
display: grid;
place-items: center;
font-size: 32px;
color: #000;
}
.acr-gkey {
background: #aeacaf;
}
.acr-num,
.acr-spc {
font-size: 27px;
}
.acr-kbstrip {
position: absolute;
bottom: 10px;
left: 0;
right: 0;
height: 52px;
}
.acr-kglobe {
position: absolute;
left: 48px;
top: 21px;
}
.acr-kmic {
position: absolute;
right: 52px;
top: 23px;
}
/* end card: the HyperFrames closing card, on the family's dark ground */
#acr-endcard-inner {
position: absolute;
inset: 0;
background: linear-gradient(180deg, #14110e 0%, #221b13 100%);
opacity: 0;
}
#acr-eclogo {
position: absolute;
left: 255px;
top: 112px;
width: 240px;
height: 72px;
}
#acr-ecstar {
position: absolute;
left: 610px;
top: 230px;
}
#acr-ecvideo {
position: absolute;
left: 222px;
top: 336px;
width: 283px;
height: 454px;
border-radius: 36px;
background: linear-gradient(165deg, #0f3a2c 0%, #0a9c6b 78%, #3ce6ac 100%);
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
}
#acr-ecvideo .acr-play {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 108px;
height: 108px;
border-radius: 50%;
background: rgba(253, 253, 253, 0.94);
display: grid;
place-items: center;
}
#acr-echead {
position: absolute;
top: 946px;
left: 0;
right: 0;
text-align: center;
font-weight: 700;
font-size: 57px;
line-height: 58px;
color: #f7ece5;
letter-spacing: 0.5px;
}
#acr-ecsub {
position: absolute;
top: 1084px;
left: 65px;
right: 65px;
text-align: center;
font-weight: 500;
font-size: 31px;
line-height: 40px;
color: #cfc4b8;
}
#acr-eccta {
position: absolute;
left: 160px;
top: 1406px;
width: 429px;
height: 87px;
background: #3ce6ac;
border-radius: 44px;
display: flex;
align-items: center;
justify-content: center;
gap: 22px;
}
#acr-eccta .acr-lbl {
color: #0d0d0d;
font-weight: 700;
font-size: 33px;
letter-spacing: 0.3px;
}
#acr-ecfoot {
position: absolute;
top: 1536px;
left: 0;
right: 0;
text-align: center;
font-weight: 700;
font-size: 25px;
letter-spacing: 4px;
color: #3ce6ac;
}
</style>
</head>
<body>
<div
id="acr-root"
data-composition-id="ai-chat-reveal"
data-start="0"
data-width="1080"
data-height="1920"
data-duration="19.3333"
>
<section id="acr-chat" class="clip" data-start="0" data-duration="16.9" data-track-index="1">
<div class="acr-stage">
<div id="acr-chat-bg"></div>
<div id="acr-statusbar">
<div id="acr-clock">11:42</div>
<div id="acr-sicons">
<svg width="30" height="20" viewBox="0 0 20 12" fill="#0d0d0d">
<rect x="0" y="7" width="3" height="4" rx="1" />
<rect x="5" y="5" width="3" height="6" rx="1" />
<rect x="10" y="2.6" width="3" height="8.4" rx="1" />
<rect x="15" y="0.5" width="3" height="10.5" rx="1" /></svg
><svg
width="30"
height="21"
viewBox="0 0 22 15"
fill="none"
stroke="#0d0d0d"
stroke-width="2.2"
stroke-linecap="round"
>
<path d="M2 5 C7 -0.5 15 -0.5 20 5" fill="none" />
<path d="M5.5 8.6 C9 5 13 5 16.5 8.6" />
<path d="M9.2 12 C10.4 11 11.6 11 12.8 12" /></svg
><svg width="46" height="22" viewBox="0 0 30 14" fill="none">
<rect
x="0.8"
y="0.8"
width="25"
height="12.4"
rx="3.6"
stroke="#0d0d0d"
stroke-opacity="0.32"
stroke-width="1.2"
/>
<rect x="2.4" y="2.4" width="22.4" height="9.2" rx="2.4" fill="#0d0d0d" />
<path d="M28 4.6 v4.8 a2.4 2.4 0 0 0 0 -4.8" fill="#0d0d0d" fill-opacity="0.45" />
</svg>
</div>
</div>
<div id="acr-header">
<div id="acr-hleft">
<svg
width="29"
height="29"
viewBox="0 0 24 24"
fill="none"
stroke="#0d0d0d"
stroke-width="1.9"
stroke-linecap="round"
>
<path d="M4 8 H20 M4 15 H12" />
</svg>
</div>
<div id="acr-htitle">Assistant</div>
<div class="acr-hicons" id="acr-hicons-a">
<svg
width="28"
height="28"
viewBox="0 0 26 24"
fill="none"
stroke="#0d0d0d"
stroke-width="1.7"
stroke-linecap="round"
>
<circle cx="10" cy="8" r="4" />
<path d="M3 21 C3 16 6.5 14 10 14 C13.5 14 17 16 17 21" />
<path d="M20 6 V12 M17 9 H23" /></svg
><svg
width="26"
height="26"
viewBox="0 0 24 24"
fill="none"
stroke="#0d0d0d"
stroke-width="1.7"
stroke-linecap="round"
stroke-dasharray="2.4 3.4"
>
<circle cx="12" cy="12" r="9" />
</svg>
</div>
<div class="acr-hicons" id="acr-hicons-b">
<svg
width="23"
height="23"
viewBox="0 0 24 24"
fill="none"
stroke="#0d0d0d"
stroke-width="1.7"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M4 20 L5 15.5 L16.5 4 C17.6 2.9 19.4 2.9 20.5 4 C21.6 5.1 21.6 6.9 20.5 8 L9 19.5 L4 20 Z"
/></svg
><svg width="34" height="34" viewBox="0 0 24 24" fill="#0d0d0d">
<circle cx="5" cy="12" r="1.7" />
<circle cx="12" cy="12" r="1.7" />
<circle cx="19" cy="12" r="1.7" />
</svg>
</div>
</div>
<div id="acr-bubble">How do I turn my HTML into real video?</div>
<div id="acr-dot"></div>
<div id="acr-answer" data-layout-allow-occlusion></div>
<div id="acr-composer">
<div id="acr-pill">
<div id="acr-plusi">
<svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#0d0d0d"
stroke-width="1.9"
stroke-linecap="round"
>
<path d="M12 5 V19 M5 12 H19" />
</svg>
</div>
<div id="acr-ph" data-layout-allow-overlap data-layout-allow-occlusion>
Ask anything
</div>
<div id="acr-ctextwrap"><span id="acr-ctext"></span><span id="acr-caret"></span></div>
<div id="acr-cmic">
<svg
width="15"
height="22"
viewBox="0 0 24 34"
fill="none"
stroke="#0d0d0d"
stroke-width="2"
stroke-linecap="round"
>
<rect x="8" y="2" width="8" height="16" rx="4" fill="#0d0d0d" stroke="none" />
<path d="M4 14 a8 8 0 0 0 16 0 M12 22 V28 M7 31 H17" stroke-width="2.2" />
</svg>
</div>
<div class="acr-cbtn" id="acr-btn-send-grey">
<svg
width="26"
height="26"
viewBox="0 0 24 24"
fill="none"
stroke="#b6b6b6"
stroke-width="2.6"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 19 V6 M6.5 11 L12 5.5 L17.5 11" />
</svg>
</div>
<div class="acr-cbtn" id="acr-btn-send-black">
<svg
width="26"
height="26"
viewBox="0 0 24 24"
fill="none"
stroke="#fff"
stroke-width="2.6"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 19 V6 M6.5 11 L12 5.5 L17.5 11" />
</svg>
</div>
<div class="acr-cbtn" id="acr-btn-stop"><div class="acr-sq"></div></div>
</div>
</div>
<div id="acr-keyboard">
<div id="acr-suggest">
<div class="acr-sug">How</div>
<div class="acr-sug">Can</div>
<div class="acr-sug">My</div>
</div>
<div id="acr-keys"></div>
<div class="acr-kbstrip">
<span class="acr-kglobe"
><svg
width="30"
height="30"
viewBox="0 0 24 24"
fill="none"
stroke="#000"
stroke-width="2.6"
>
<circle cx="12" cy="12" r="9.6" />
<path
d="M2.4 12 H21.6 M12 2.4 C7.8 6.8 7.8 17.2 12 21.6 C16.2 17.2 16.2 6.8 12 2.4 M4 7 H20 M4 17 H20"
stroke-width="2.2"
/></svg></span
><span class="acr-kmic"
><svg
width="16"
height="25"
viewBox="0 0 24 34"
preserveAspectRatio="none"
fill="none"
stroke="#0d0d0d"
stroke-width="3.9"
stroke-linecap="round"
>
<rect
x="5.5"
y="1"
width="13"
height="17.5"
rx="6.5"
fill="#0d0d0d"
stroke="none"
/>
<path d="M2.5 14 a9.5 9.5 0 0 0 19 0 M12 23.5 V28.5 M5.5 32 H18.5" /></svg
></span>
</div>
</div>
</div>
</section>
<section
id="acr-endcard"
class="clip"
data-start="15.8"
data-duration="3.5333"
data-track-index="2"
>
<div id="acr-endcard-inner">
<div class="acr-stage">
<img id="acr-eclogo" src="assets/hyperframes-logo-white.svg" alt="HyperFrames" />
<svg id="acr-ecstar" width="80" height="80" viewBox="0 0 80 80">
<g stroke="#2f6b57" stroke-width="8.5" stroke-linecap="round">
<line x1="47" y1="40" x2="77" y2="40" />
<line x1="46.5" y1="42.7" x2="74.2" y2="54.2" />
<line x1="44.9" y1="44.9" x2="66.2" y2="66.2" />
<line x1="42.7" y1="46.5" x2="54.2" y2="74.2" />
<line x1="40" y1="47" x2="40" y2="77" />
<line x1="37.3" y1="46.5" x2="25.8" y2="74.2" />
<line x1="35.1" y1="44.9" x2="13.8" y2="66.2" />
<line x1="33.5" y1="42.7" x2="5.8" y2="54.2" />
<line x1="33" y1="40" x2="3" y2="40" />
<line x1="33.5" y1="37.3" x2="5.8" y2="25.8" />
<line x1="35.1" y1="35.1" x2="13.8" y2="13.8" />
<line x1="37.3" y1="33.5" x2="25.8" y2="5.8" />
<line x1="40" y1="33" x2="40" y2="3" />
<line x1="42.7" y1="33.5" x2="54.2" y2="5.8" />
<line x1="44.9" y1="35.1" x2="66.2" y2="13.8" />
<line x1="46.5" y1="37.3" x2="74.2" y2="25.8" />
</g>
</svg>
<div id="acr-ecvideo">
<div class="acr-play">
<svg width="40" height="46" viewBox="0 0 44 48" fill="none">
<path
d="M40.5 20.6 C43.2 22.1 43.2 25.9 40.5 27.4 L6.2 46.6 C3.5 48.1 0.2 46.2 0.2 43.2 L0.2 4.8 C0.2 1.8 3.5 -0.1 6.2 1.4 Z"
fill="#0d0d0d"
/>
</svg>
</div>
</div>
<div id="acr-echead">It's not magic.<br />It's HTML.</div>
<div id="acr-ecsub">
Open-source video rendering — write HTML, ship pixel-perfect video.
</div>
<div id="acr-eccta">
<span class="acr-lbl">Try HyperFrames</span
><svg
width="30"
height="34"
viewBox="0 0 16 24"
fill="none"
stroke="#0d0d0d"
stroke-width="2.6"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M4 3 L13 12 L4 21" />
</svg>
</div>
<div id="acr-ecfoot">HYPERFRAMES.HEYGEN.COM</div>
</div>
</div>
</section>
</div>
<script>
(function () {
"use strict";
/* -------- variables -------- */
var vars =
window.__hyperframes && typeof window.__hyperframes.getVariables === "function"
? window.__hyperframes.getVariables()
: {};
function text(value, fallback, max) {
if (typeof value !== "string") return fallback;
var t = value.trim();
if (!t) return fallback;
return t.length > max ? t.slice(0, max) : t;
}
var botName = text(vars.botName, "Assistant", 24);
var userMessage = text(vars.userMessage, "How do I turn my HTML into real video?", 60);
var answer1 = text(
vars.answer1,
"You do not need an editor. HyperFrames renders the HTML you already write into deterministic, pixel-perfect video.",
220,
);
var answer2 = text(vars.answer2, "It is markup, not magic.", 120);
var answer3 = text(vars.answer3, "What you get out of the box:", 120);
var bullets = [
text(vars.bullet1, "A catalog of motion primitives you install and own", 90),
text(vars.bullet2, "GSAP timelines that seek to any frame", 90),
text(vars.bullet3, "4K renders from a single CLI command", 90),
];
document.getElementById("acr-htitle").textContent = botName;
document.getElementById("acr-bubble").textContent = userMessage;
document.getElementById("acr-echead").innerHTML = "";
text(vars.ecHeadline, "It's not magic.|It's HTML.", 60)
.split("|")
.forEach(function (line, i) {
var head = document.getElementById("acr-echead");
if (i > 0) head.appendChild(document.createElement("br"));
head.appendChild(document.createTextNode(line));
});
document.getElementById("acr-ecsub").textContent = text(
vars.ecSub,
"Open-source video rendering — write HTML, ship pixel-perfect video.",
140,
);
document.querySelector("#acr-eccta .acr-lbl").textContent = text(
vars.ecCta,
"Try HyperFrames",
30,
);
document.getElementById("acr-ecfoot").textContent = text(
vars.ecFooter,
"HYPERFRAMES.HEYGEN.COM",
40,
);
/* -------- build the answer DOM: paragraphs of word spans, then bullets -------- */
var answerEl = document.getElementById("acr-answer");
var wordEls = [];
function addPara(str) {
var p = document.createElement("p");
p.className = "acr-ap";
str.split(/\s+/).forEach(function (word, i) {
if (i > 0) p.appendChild(document.createTextNode(" "));
var s = document.createElement("span");
s.className = "acr-w";
s.textContent = word;
p.appendChild(s);
wordEls.push(s);
});
answerEl.appendChild(p);
}
addPara(answer1);
addPara(answer2);
addPara(answer3);
bullets.forEach(function (b) {
var row = document.createElement("div");
row.className = "acr-ali";
var mark = document.createElement("span");
mark.className = "acr-mark acr-w";
mark.textContent = "•";
row.appendChild(mark);
wordEls.push(mark);
var body = document.createElement("div");
body.className = "acr-alitext";
b.split(/\s+/).forEach(function (word, i) {
if (i > 0) body.appendChild(document.createTextNode(" "));
var s = document.createElement("span");
s.className = "acr-w";
s.textContent = word;
body.appendChild(s);
wordEls.push(s);
});
row.appendChild(body);
answerEl.appendChild(row);
});
/* -------- build the keyboard: measured key geometry -------- */
var keysEl = document.getElementById("acr-keys");
var ROWS = [
{ top: 83, left: 13, letters: "qwertyuiop" },
{ top: 173, left: 48, letters: "asdfghjkl" },
{ top: 263, left: 123, letters: "zxcvbnm" },
];
ROWS.forEach(function (row) {
row.letters.split("").forEach(function (ch, i) {
var k = document.createElement("div");
k.className = "acr-key";
k.style.left = row.left + i * 73.7 + "px";
k.style.top = row.top + "px";
k.style.width = "62px";
k.textContent = ch;
keysEl.appendChild(k);
});
});
[
{
left: 13,
top: 263,
width: 97,
cls: " acr-gkey",
html: '<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="1.6" stroke-linejoin="round"><path d="M12 4 L4.5 12 H8.5 V17 H15.5 V12 H19.5 Z"/></svg>',
},
{
left: 640,
top: 263,
width: 98,
cls: " acr-gkey",
html: '<svg width="31" height="24" viewBox="0 0 28 20" fill="none" stroke="#000" stroke-width="1.6" stroke-linejoin="round" stroke-linecap="round"><path d="M9 2 H26 V18 H9 L1.5 10 Z"/><path d="M13 6.5 L20 13.5 M20 6.5 L13 13.5"/></svg>',
},
{ left: 13, top: 353, width: 97, cls: " acr-gkey acr-num", html: "123" },
{
left: 118,
top: 353,
width: 86,
cls: "",
html: '<svg width="27" height="27" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="1.4" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><circle cx="9" cy="10" r="0.6" fill="#000"/><circle cx="15" cy="10" r="0.6" fill="#000"/><path d="M8 14.5 C9.5 16.5 14.5 16.5 16 14.5"/></svg>',
},
{ left: 217, top: 353, width: 389, cls: " acr-spc", html: "space" },
{
left: 614,
top: 353,
width: 124,
cls: " acr-gkey",
html: '<svg width="27" height="27" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M19 5 V11 H6"/><path d="M9.5 7.5 L6 11 L9.5 14.5"/></svg>',
},
].forEach(function (spec) {
var k = document.createElement("div");
k.className = "acr-key" + spec.cls;
k.style.left = spec.left + "px";
k.style.top = spec.top + "px";
k.style.width = spec.width + "px";
k.innerHTML = spec.html;
keysEl.appendChild(k);
});
/* -------- timeline -------- */
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
/* keystroke and token rhythms, measured from the reference and cycled */
var KEY_GAPS = [
0.1, 0.033, 0.2, 0.133, 0.2, 0.033, 0.067, 0.033, 0.1, 0.067, 0.033, 0.067, 0.067, 0.067,
0.133, 0.067, 0.033, 0.067, 0.1, 0.1, 0.067, 0.133, 0.1, 0.033, 0.1, 0.033, 0.167, 0.033,
0.1, 0.1, 0.067, 0.133, 0.033, 0.067, 0.1, 0.033, 0.1, 0.067,
];
var WORD_GAPS = [
0.167, 0.1, 0.0, 0.367, 0.0, 0.167, 0.133, 0.1, 0.1, 0.133, 0.167, 0.133, 0.0, 0.233,
0.167, 0.1, 0.0, 0.133, 0.133, 0.1, 0.167, 0.133, 0.1, 0.133, 0.167, 0.1, 0.133, 0.1,
0.133,
];
/* keyboard rises, composer rides it (verbatim anchors) */
tl.fromTo("#acr-keyboard", { y: 482 }, { y: 0, duration: 0.2667, ease: "power2.out" }, 0.2);
tl.fromTo(
"#acr-composer",
{ y: 0 },
{ y: -497, duration: 0.2667, ease: "power2.out" },
0.2,
);
/* typing: two characters land on the first beat, then the measured gaps */
tl.set("#acr-ctext", { textContent: "", autoAlpha: 0 }, 0.001);
var TYPE_START = 0.8637;
tl.set("#acr-ctext", { autoAlpha: 1 }, TYPE_START);
tl.set("#acr-ph", { autoAlpha: 0 }, TYPE_START);
tl.set("#acr-btn-send-grey", { autoAlpha: 0 }, TYPE_START);
tl.set("#acr-btn-send-black", { autoAlpha: 1 }, TYPE_START);
var t = TYPE_START;
for (var n = 2; n <= userMessage.length; n += 1) {
tl.set("#acr-ctext", { textContent: userMessage.slice(0, n) }, t);
t += KEY_GAPS[(n - 2) % KEY_GAPS.length];
}
var typeEnd = t;
/* caret blinks on a steady half-second while typing */
tl.set("#acr-caret", { autoAlpha: 0 }, 0.001);
for (var c = TYPE_START, on = true; c < typeEnd; c += 0.5333, on = !on) {
tl.set("#acr-caret", { autoAlpha: on ? 1 : 0 }, c);
}
/* send: bubble pops, keyboard drops, stream begins */
var SEND = typeEnd + 0.1667;
tl.set("#acr-caret", { autoAlpha: 0 }, SEND);
tl.set("#acr-ctext", { textContent: "" }, SEND);
tl.set("#acr-ph", { autoAlpha: 1 }, SEND);
tl.set("#acr-btn-send-black", { autoAlpha: 0 }, SEND);
tl.set("#acr-btn-stop", { autoAlpha: 1 }, SEND);
tl.fromTo(
"#acr-bubble",
{ autoAlpha: 0 },
{ autoAlpha: 1, duration: 0.1667, ease: "power1.out" },
SEND - 0.03,
);
tl.set("#acr-hicons-a", { autoAlpha: 0 }, SEND);
tl.set("#acr-hicons-b", { autoAlpha: 1 }, SEND);
tl.to("#acr-keyboard", { y: 482, duration: 0.2667, ease: "power1.inOut" }, SEND - 0.03);
tl.to("#acr-composer", { y: 0, duration: 0.2667, ease: "power1.inOut" }, SEND - 0.03);
/* thinking dot: the measured alpha ramp, then it yields to the words */
var DOT_RAMP = [
0.488, 0.53, 0.53, 0.56, 0.608, 0.687, 0.729, 0.771, 0.813, 0.867, 0.904, 0.988, 1,
];
var dotStart = SEND + 0.4333;
tl.set("#acr-dot", { autoAlpha: 0 }, 0.001);
DOT_RAMP.forEach(function (a, i) {
tl.set("#acr-dot", { autoAlpha: a }, dotStart + i * 0.0333);
});
tl.set("#acr-dot", { autoAlpha: 0 }, dotStart + 0.5667);
/* the stream: measured token rhythm, fresh grey inking to full colour */
var w = dotStart + 0.6333;
wordEls.forEach(function (el, i) {
if (i > 0) w += WORD_GAPS[i % WORD_GAPS.length];
tl.set(el, { opacity: 1 }, w);
tl.fromTo(
el,
{ color: "#767676" },
{ color: "#141414", duration: 0.2667, ease: "none" },
w,
);
});
/* stream ends: stop button returns to send */
tl.set("#acr-btn-stop", { autoAlpha: 0 }, w + 0.4667);
tl.set("#acr-btn-send-black", { autoAlpha: 1 }, w + 0.4667);
/* end card */
tl.set("#acr-endcard-inner", { opacity: 0 }, 0.001);
tl.fromTo(
"#acr-endcard-inner",
{ opacity: 0 },
{ opacity: 1, duration: 0.3167, ease: "none" },
15.8333,
);
window.__timelines["ai-chat-reveal"] = tl;
})();
</script>
</body>
</html>
```
</VariablesExplorer>
## Install
<InstallCommand command="npx hyperframes add ai-chat-reveal" item="ai-chat-reveal" />
That writes `compositions/ai-chat-reveal.html`, plus 1 supporting file under `assets/`.
## Add it to your video
It runs for 19.3333 seconds at 1080×1920. Paste this into your composition:
```html index.html
<div
data-composition-id="ai-chat-reveal"
data-composition-src="compositions/ai-chat-reveal.html"
data-start="0"
data-duration="19.3333"
data-track-index="1"
data-width="1080"
data-height="1920"
></div>
```
Move it in time with `data-start`. Put it on a different timeline row with
`data-track-index`. See [data attributes](/concepts/data-attributes) for the rest.
## Variables
Every one of these has a default, so the piece works untouched. Set the ones you
want to change on the element:
| Variable | Default | Accepts | What it does |
| --- | --- | --- | --- |
| `botName` | `Assistant` | string | Title in the chat header. |
| `userMessage` | `How do I turn my HTML into real video?` | string | The question typed on the keyboard and sent. Around 40 characters keeps the measured pacing. |
| `answer1` | `You do not need an editor. HyperFrames renders the HTML you already write into deterministic, pixel-perfect video.` | string | First streamed paragraph. |
| `answer2` | `It is markup, not magic.` | string | Short second beat. |
| `answer3` | `What you get out of the box:` | string | Lead-in to the list. |
| `bullet1` | `A catalog of motion primitives you install and own` | string | First list item. |
| `bullet2` | `GSAP timelines that seek to any frame` | string | Second list item. |
| `bullet3` | `4K renders from a single CLI command` | string | Third list item. |
| `ecHeadline` | `It's not magic.|It's HTML.` | string | Closing card headline. A | breaks the line. |
| `ecSub` | `Open-source video rendering — write HTML, ship pixel-perfect video.` | string | Supporting sentence on the closing card. |
| `ecCta` | `Try HyperFrames` | string | Label on the closing card button. |
| `ecFooter` | `HYPERFRAMES.HEYGEN.COM` | string | Letter-spaced line at the very bottom. |
Set them with `data-variable-values` on the element that mounts it. These are the
defaults, so this behaves exactly like the preview above until you change one:
```html wrap
<div
data-composition-id="ai-chat-reveal"
data-composition-src="compositions/ai-chat-reveal.html"
data-variable-values='{"botName":"Assistant","userMessage":"How do I turn my HTML into real video?","answer1":"You do not need an editor. HyperFrames renders the HTML you already write into deterministic, pixel-perfect video.","answer2":"It is markup, not magic.","answer3":"What you get out of the box:","bullet1":"A catalog of motion primitives you install and own","bullet2":"GSAP timelines that seek to any frame","bullet3":"4K renders from a single CLI command","ecHeadline":"It's not magic.|It's HTML.","ecSub":"Open-source video rendering — write HTML, ship pixel-perfect video.","ecCta":"Try HyperFrames","ecFooter":"HYPERFRAMES.HEYGEN.COM"}'
></div>
```
## Source
<Accordion title={`ai-chat-reveal.html`}>
```html
<!doctype html>
<html
lang="en"
data-composition-variables='[
{ "id": "botName", "type": "string", "role": "content", "label": "Assistant name", "description": "Title in the chat header.", "default": "Assistant" },
{ "id": "userMessage", "type": "string", "role": "content", "label": "User message", "description": "The question typed on the keyboard and sent. Around 40 characters keeps the measured pacing.", "default": "How do I turn my HTML into real video?" },
{ "id": "answer1", "type": "string", "role": "content", "label": "Answer paragraph 1", "description": "First streamed paragraph.", "default": "You do not need an editor. HyperFrames renders the HTML you already write into deterministic, pixel-perfect video." },
{ "id": "answer2", "type": "string", "role": "content", "label": "Answer paragraph 2", "description": "Short second beat.", "default": "It is markup, not magic." },
{ "id": "answer3", "type": "string", "role": "content", "label": "Answer paragraph 3", "description": "Lead-in to the list.", "default": "What you get out of the box:" },
{ "id": "bullet1", "type": "string", "role": "content", "label": "Bullet 1", "description": "First list item.", "default": "A catalog of motion primitives you install and own" },
{ "id": "bullet2", "type": "string", "role": "content", "label": "Bullet 2", "description": "Second list item.", "default": "GSAP timelines that seek to any frame" },
{ "id": "bullet3", "type": "string", "role": "content", "label": "Bullet 3", "description": "Third list item.", "default": "4K renders from a single CLI command" },
{ "id": "ecHeadline", "type": "string", "role": "content", "label": "End-card headline", "description": "Closing card headline. A | breaks the line.", "default": "It&#39;s not magic.|It&#39;s HTML." },
{ "id": "ecSub", "type": "string", "role": "content", "label": "End-card subline", "description": "Supporting sentence on the closing card.", "default": "Open-source video rendering — write HTML, ship pixel-perfect video." },
{ "id": "ecCta", "type": "string", "role": "content", "label": "End-card CTA", "description": "Label on the closing card button.", "default": "Try HyperFrames" },
{ "id": "ecFooter", "type": "string", "role": "content", "label": "End-card footer", "description": "Letter-spaced line at the very bottom.", "default": "HYPERFRAMES.HEYGEN.COM" }
]'
>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1080, height=1920" />
<title>AI Chat Reveal</title>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 1080px;
height: 1920px;
overflow: hidden;
background: #000;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
/* The measured 750x1624 device UI is scaled uniformly into a standard
1080x1920 portrait canvas so its keyboard geometry stays pixel-true. */
#acr-root {
position: relative;
width: 1080px;
height: 1920px;
overflow: hidden;
}
.clip {
position: absolute;
inset: 0;
overflow: hidden;
}
#acr-chat {
background: #fdfdfd;
}
.acr-stage {
position: absolute;
left: 96.6502px;
top: 0;
width: 750px;
height: 1624px;
transform: scale(1.18226601);
transform-origin: top left;
}
#acr-chat-bg {
position: absolute;
inset: 0;
background: #fdfdfd;
}
/* status bar */
#acr-statusbar {
position: absolute;
top: 14px;
left: 0;
right: 0;
height: 44px;
}
#acr-clock {
position: absolute;
left: 39px;
top: 9px;
font-size: 22px;
font-weight: 600;
letter-spacing: 2.4px;
font-variant-numeric: tabular-nums;
color: #0d0d0d;
}
#acr-sicons {
position: absolute;
right: 26px;
top: 8px;
display: flex;
gap: 9px;
align-items: center;
}
/* header */
#acr-header {
position: absolute;
top: 64px;
left: 0;
right: 0;
height: 52px;
}
#acr-hleft {
position: absolute;
left: 28px;
top: 12px;
}
#acr-htitle {
position: absolute;
left: 0;
right: 48px;
text-align: center;
top: 13px;
font-size: 22px;
font-weight: 600;
color: #0d0d0d;
}
.acr-hicons {
position: absolute;
right: 28px;
top: 14px;
display: flex;
gap: 26px;
align-items: center;
}
#acr-hicons-b {
visibility: hidden;
opacity: 0;
}
/* user bubble */
#acr-bubble {
position: absolute;
top: 129px;
right: 32px;
max-width: 544px;
background: #f3f3f3;
border-radius: 34px;
padding: 20px 30px;
font-size: 27px;
line-height: 38.6px;
color: #111;
letter-spacing: 1.25px;
visibility: hidden;
opacity: 0;
}
/* answer */
#acr-answer {
position: absolute;
top: 267px;
left: 33px;
width: 662px;
font-size: 27px;
line-height: 38.6px;
color: #141414;
letter-spacing: 1.25px;
}
#acr-answer .acr-ap {
margin: 0 0 15.5px 0;
}
#acr-answer .acr-ali {
display: flex;
margin: 0 0 6.5px 0;
}
#acr-answer .acr-mark {
width: 30px;
flex: 0 0 30px;
text-align: center;
font-size: 18px;
line-height: 38.6px;
}
#acr-answer .acr-alitext {
flex: 1;
}
.acr-w {
opacity: 0;
}
#acr-dot {
position: absolute;
left: 32px;
top: 279px;
width: 15px;
height: 15px;
border-radius: 50%;
background: #646464;
visibility: hidden;
opacity: 0;
}
/* composer (rest dock; rides keyboard via transform) */
#acr-composer {
position: absolute;
left: 30px;
right: 30px;
bottom: 31px;
}
#acr-pill {
position: relative;
width: 100%;
min-height: 81px;
background: #fff;
border: 2px solid #ececec;
border-radius: 41px;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.04);
display: flex;
align-items: center;
padding: 13px 160px 13px 78px;
}
#acr-plusi {
position: absolute;
left: 30px;
top: 50%;
transform: translateY(-50%);
}
#acr-ph {
position: absolute;
left: 78px;
top: 50%;
transform: translateY(-50%);
color: #767676;
font-size: 28px;
letter-spacing: 1.25px;
}
#acr-ctextwrap {
width: 100%;
min-height: 38px;
}
#acr-ctext {
font-size: 29px;
line-height: 38px;
color: #0d0d0d;
letter-spacing: 1.25px;
visibility: hidden;
opacity: 0;
}
#acr-caret {
display: inline-block;
width: 3px;
height: 30px;
margin-left: 2px;
border-radius: 1.5px;
background: #0d0d0d;
vertical-align: -4px;
visibility: hidden;
opacity: 0;
}
#acr-cmic {
position: absolute;
right: 80px;
top: 50%;
transform: translateY(-50%);
}
.acr-cbtn {
position: absolute;
right: 14px;
top: 50%;
transform: translateY(-50%);
width: 52px;
height: 52px;
border-radius: 50%;
display: grid;
place-items: center;
}
#acr-btn-send-grey {
background: #ececec;
}
#acr-btn-send-black {
background: #0d0d0d;
visibility: hidden;
opacity: 0;
}
#acr-btn-stop {
background: #0d0d0d;
visibility: hidden;
opacity: 0;
}
#acr-btn-stop .acr-sq {
width: 19px;
height: 19px;
border-radius: 5px;
background: #fff;
}
/* keyboard: geometry and #d2d5e0 ground measured from the reference */
#acr-keyboard {
position: absolute;
left: 0;
bottom: 0;
width: 750px;
height: 482px;
background: #d2d5e0;
}
#acr-suggest {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 74px;
display: flex;
}
#acr-suggest .acr-sug {
flex: 1;
display: grid;
place-items: center;
font-size: 29px;
color: #0d0d0d;
position: relative;
}
#acr-suggest .acr-sug + .acr-sug::before {
content: "";
position: absolute;
left: 0;
top: 16px;
bottom: 16px;
width: 1.5px;
background: #bcbabf;
}
.acr-key {
position: absolute;
height: 74px;
background: #fdfdfd;
border-radius: 10px;
box-shadow: 0 2px 0 #8b8a8f;
display: grid;
place-items: center;
font-size: 32px;
color: #000;
}
.acr-gkey {
background: #aeacaf;
}
.acr-num,
.acr-spc {
font-size: 27px;
}
.acr-kbstrip {
position: absolute;
bottom: 10px;
left: 0;
right: 0;
height: 52px;
}
.acr-kglobe {
position: absolute;
left: 48px;
top: 21px;
}
.acr-kmic {
position: absolute;
right: 52px;
top: 23px;
}
/* end card: the HyperFrames closing card, on the family's dark ground */
#acr-endcard-inner {
position: absolute;
inset: 0;
background: linear-gradient(180deg, #14110e 0%, #221b13 100%);
opacity: 0;
}
#acr-eclogo {
position: absolute;
left: 255px;
top: 112px;
width: 240px;
height: 72px;
}
#acr-ecstar {
position: absolute;
left: 610px;
top: 230px;
}
#acr-ecvideo {
position: absolute;
left: 222px;
top: 336px;
width: 283px;
height: 454px;
border-radius: 36px;
background: linear-gradient(165deg, #0f3a2c 0%, #0a9c6b 78%, #3ce6ac 100%);
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
}
#acr-ecvideo .acr-play {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 108px;
height: 108px;
border-radius: 50%;
background: rgba(253, 253, 253, 0.94);
display: grid;
place-items: center;
}
#acr-echead {
position: absolute;
top: 946px;
left: 0;
right: 0;
text-align: center;
font-weight: 700;
font-size: 57px;
line-height: 58px;
color: #f7ece5;
letter-spacing: 0.5px;
}
#acr-ecsub {
position: absolute;
top: 1084px;
left: 65px;
right: 65px;
text-align: center;
font-weight: 500;
font-size: 31px;
line-height: 40px;
color: #cfc4b8;
}
#acr-eccta {
position: absolute;
left: 160px;
top: 1406px;
width: 429px;
height: 87px;
background: #3ce6ac;
border-radius: 44px;
display: flex;
align-items: center;
justify-content: center;
gap: 22px;
}
#acr-eccta .acr-lbl {
color: #0d0d0d;
font-weight: 700;
font-size: 33px;
letter-spacing: 0.3px;
}
#acr-ecfoot {
position: absolute;
top: 1536px;
left: 0;
right: 0;
text-align: center;
font-weight: 700;
font-size: 25px;
letter-spacing: 4px;
color: #3ce6ac;
}
</style>
</head>
<body>
<div
id="acr-root"
data-composition-id="ai-chat-reveal"
data-start="0"
data-width="1080"
data-height="1920"
data-duration="19.3333"
>
<section id="acr-chat" class="clip" data-start="0" data-duration="16.9" data-track-index="1">
<div class="acr-stage">
<div id="acr-chat-bg"></div>
<div id="acr-statusbar">
<div id="acr-clock">11:42</div>
<div id="acr-sicons">
<svg width="30" height="20" viewBox="0 0 20 12" fill="#0d0d0d">
<rect x="0" y="7" width="3" height="4" rx="1" />
<rect x="5" y="5" width="3" height="6" rx="1" />
<rect x="10" y="2.6" width="3" height="8.4" rx="1" />
<rect x="15" y="0.5" width="3" height="10.5" rx="1" /></svg
><svg
width="30"
height="21"
viewBox="0 0 22 15"
fill="none"
stroke="#0d0d0d"
stroke-width="2.2"
stroke-linecap="round"
>
<path d="M2 5 C7 -0.5 15 -0.5 20 5" fill="none" />
<path d="M5.5 8.6 C9 5 13 5 16.5 8.6" />
<path d="M9.2 12 C10.4 11 11.6 11 12.8 12" /></svg
><svg width="46" height="22" viewBox="0 0 30 14" fill="none">
<rect
x="0.8"
y="0.8"
width="25"
height="12.4"
rx="3.6"
stroke="#0d0d0d"
stroke-opacity="0.32"
stroke-width="1.2"
/>
<rect x="2.4" y="2.4" width="22.4" height="9.2" rx="2.4" fill="#0d0d0d" />
<path d="M28 4.6 v4.8 a2.4 2.4 0 0 0 0 -4.8" fill="#0d0d0d" fill-opacity="0.45" />
</svg>
</div>
</div>
<div id="acr-header">
<div id="acr-hleft">
<svg
width="29"
height="29"
viewBox="0 0 24 24"
fill="none"
stroke="#0d0d0d"
stroke-width="1.9"
stroke-linecap="round"
>
<path d="M4 8 H20 M4 15 H12" />
</svg>
</div>
<div id="acr-htitle">Assistant</div>
<div class="acr-hicons" id="acr-hicons-a">
<svg
width="28"
height="28"
viewBox="0 0 26 24"
fill="none"
stroke="#0d0d0d"
stroke-width="1.7"
stroke-linecap="round"
>
<circle cx="10" cy="8" r="4" />
<path d="M3 21 C3 16 6.5 14 10 14 C13.5 14 17 16 17 21" />
<path d="M20 6 V12 M17 9 H23" /></svg
><svg
width="26"
height="26"
viewBox="0 0 24 24"
fill="none"
stroke="#0d0d0d"
stroke-width="1.7"
stroke-linecap="round"
stroke-dasharray="2.4 3.4"
>
<circle cx="12" cy="12" r="9" />
</svg>
</div>
<div class="acr-hicons" id="acr-hicons-b">
<svg
width="23"
height="23"
viewBox="0 0 24 24"
fill="none"
stroke="#0d0d0d"
stroke-width="1.7"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M4 20 L5 15.5 L16.5 4 C17.6 2.9 19.4 2.9 20.5 4 C21.6 5.1 21.6 6.9 20.5 8 L9 19.5 L4 20 Z"
/></svg
><svg width="34" height="34" viewBox="0 0 24 24" fill="#0d0d0d">
<circle cx="5" cy="12" r="1.7" />
<circle cx="12" cy="12" r="1.7" />
<circle cx="19" cy="12" r="1.7" />
</svg>
</div>
</div>
<div id="acr-bubble">How do I turn my HTML into real video?</div>
<div id="acr-dot"></div>
<div id="acr-answer" data-layout-allow-occlusion></div>
<div id="acr-composer">
<div id="acr-pill">
<div id="acr-plusi">
<svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#0d0d0d"
stroke-width="1.9"
stroke-linecap="round"
>
<path d="M12 5 V19 M5 12 H19" />
</svg>
</div>
<div id="acr-ph" data-layout-allow-overlap data-layout-allow-occlusion>
Ask anything
</div>
<div id="acr-ctextwrap"><span id="acr-ctext"></span><span id="acr-caret"></span></div>
<div id="acr-cmic">
<svg
width="15"
height="22"
viewBox="0 0 24 34"
fill="none"
stroke="#0d0d0d"
stroke-width="2"
stroke-linecap="round"
>
<rect x="8" y="2" width="8" height="16" rx="4" fill="#0d0d0d" stroke="none" />
<path d="M4 14 a8 8 0 0 0 16 0 M12 22 V28 M7 31 H17" stroke-width="2.2" />
</svg>
</div>
<div class="acr-cbtn" id="acr-btn-send-grey">
<svg
width="26"
height="26"
viewBox="0 0 24 24"
fill="none"
stroke="#b6b6b6"
stroke-width="2.6"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 19 V6 M6.5 11 L12 5.5 L17.5 11" />
</svg>
</div>
<div class="acr-cbtn" id="acr-btn-send-black">
<svg
width="26"
height="26"
viewBox="0 0 24 24"
fill="none"
stroke="#fff"
stroke-width="2.6"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 19 V6 M6.5 11 L12 5.5 L17.5 11" />
</svg>
</div>
<div class="acr-cbtn" id="acr-btn-stop"><div class="acr-sq"></div></div>
</div>
</div>
<div id="acr-keyboard">
<div id="acr-suggest">
<div class="acr-sug">How</div>
<div class="acr-sug">Can</div>
<div class="acr-sug">My</div>
</div>
<div id="acr-keys"></div>
<div class="acr-kbstrip">
<span class="acr-kglobe"
><svg
width="30"
height="30"
viewBox="0 0 24 24"
fill="none"
stroke="#000"
stroke-width="2.6"
>
<circle cx="12" cy="12" r="9.6" />
<path
d="M2.4 12 H21.6 M12 2.4 C7.8 6.8 7.8 17.2 12 21.6 C16.2 17.2 16.2 6.8 12 2.4 M4 7 H20 M4 17 H20"
stroke-width="2.2"
/></svg></span
><span class="acr-kmic"
><svg
width="16"
height="25"
viewBox="0 0 24 34"
preserveAspectRatio="none"
fill="none"
stroke="#0d0d0d"
stroke-width="3.9"
stroke-linecap="round"
>
<rect
x="5.5"
y="1"
width="13"
height="17.5"
rx="6.5"
fill="#0d0d0d"
stroke="none"
/>
<path d="M2.5 14 a9.5 9.5 0 0 0 19 0 M12 23.5 V28.5 M5.5 32 H18.5" /></svg
></span>
</div>
</div>
</div>
</section>
<section
id="acr-endcard"
class="clip"
data-start="15.8"
data-duration="3.5333"
data-track-index="2"
>
<div id="acr-endcard-inner">
<div class="acr-stage">
<img id="acr-eclogo" src="assets/hyperframes-logo-white.svg" alt="HyperFrames" />
<svg id="acr-ecstar" width="80" height="80" viewBox="0 0 80 80">
<g stroke="#2f6b57" stroke-width="8.5" stroke-linecap="round">
<line x1="47" y1="40" x2="77" y2="40" />
<line x1="46.5" y1="42.7" x2="74.2" y2="54.2" />
<line x1="44.9" y1="44.9" x2="66.2" y2="66.2" />
<line x1="42.7" y1="46.5" x2="54.2" y2="74.2" />
<line x1="40" y1="47" x2="40" y2="77" />
<line x1="37.3" y1="46.5" x2="25.8" y2="74.2" />
<line x1="35.1" y1="44.9" x2="13.8" y2="66.2" />
<line x1="33.5" y1="42.7" x2="5.8" y2="54.2" />
<line x1="33" y1="40" x2="3" y2="40" />
<line x1="33.5" y1="37.3" x2="5.8" y2="25.8" />
<line x1="35.1" y1="35.1" x2="13.8" y2="13.8" />
<line x1="37.3" y1="33.5" x2="25.8" y2="5.8" />
<line x1="40" y1="33" x2="40" y2="3" />
<line x1="42.7" y1="33.5" x2="54.2" y2="5.8" />
<line x1="44.9" y1="35.1" x2="66.2" y2="13.8" />
<line x1="46.5" y1="37.3" x2="74.2" y2="25.8" />
</g>
</svg>
<div id="acr-ecvideo">
<div class="acr-play">
<svg width="40" height="46" viewBox="0 0 44 48" fill="none">
<path
d="M40.5 20.6 C43.2 22.1 43.2 25.9 40.5 27.4 L6.2 46.6 C3.5 48.1 0.2 46.2 0.2 43.2 L0.2 4.8 C0.2 1.8 3.5 -0.1 6.2 1.4 Z"
fill="#0d0d0d"
/>
</svg>
</div>
</div>
<div id="acr-echead">It's not magic.<br />It's HTML.</div>
<div id="acr-ecsub">
Open-source video rendering — write HTML, ship pixel-perfect video.
</div>
<div id="acr-eccta">
<span class="acr-lbl">Try HyperFrames</span
><svg
width="30"
height="34"
viewBox="0 0 16 24"
fill="none"
stroke="#0d0d0d"
stroke-width="2.6"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M4 3 L13 12 L4 21" />
</svg>
</div>
<div id="acr-ecfoot">HYPERFRAMES.HEYGEN.COM</div>
</div>
</div>
</section>
</div>
<script>
(function () {
"use strict";
/* -------- variables -------- */
var vars =
window.__hyperframes && typeof window.__hyperframes.getVariables === "function"
? window.__hyperframes.getVariables()
: {};
function text(value, fallback, max) {
if (typeof value !== "string") return fallback;
var t = value.trim();
if (!t) return fallback;
return t.length > max ? t.slice(0, max) : t;
}
var botName = text(vars.botName, "Assistant", 24);
var userMessage = text(vars.userMessage, "How do I turn my HTML into real video?", 60);
var answer1 = text(
vars.answer1,
"You do not need an editor. HyperFrames renders the HTML you already write into deterministic, pixel-perfect video.",
220,
);
var answer2 = text(vars.answer2, "It is markup, not magic.", 120);
var answer3 = text(vars.answer3, "What you get out of the box:", 120);
var bullets = [
text(vars.bullet1, "A catalog of motion primitives you install and own", 90),
text(vars.bullet2, "GSAP timelines that seek to any frame", 90),
text(vars.bullet3, "4K renders from a single CLI command", 90),
];
document.getElementById("acr-htitle").textContent = botName;
document.getElementById("acr-bubble").textContent = userMessage;
document.getElementById("acr-echead").innerHTML = "";
text(vars.ecHeadline, "It's not magic.|It's HTML.", 60)
.split("|")
.forEach(function (line, i) {
var head = document.getElementById("acr-echead");
if (i > 0) head.appendChild(document.createElement("br"));
head.appendChild(document.createTextNode(line));
});
document.getElementById("acr-ecsub").textContent = text(
vars.ecSub,
"Open-source video rendering — write HTML, ship pixel-perfect video.",
140,
);
document.querySelector("#acr-eccta .acr-lbl").textContent = text(
vars.ecCta,
"Try HyperFrames",
30,
);
document.getElementById("acr-ecfoot").textContent = text(
vars.ecFooter,
"HYPERFRAMES.HEYGEN.COM",
40,
);
/* -------- build the answer DOM: paragraphs of word spans, then bullets -------- */
var answerEl = document.getElementById("acr-answer");
var wordEls = [];
function addPara(str) {
var p = document.createElement("p");
p.className = "acr-ap";
str.split(/\s+/).forEach(function (word, i) {
if (i > 0) p.appendChild(document.createTextNode(" "));
var s = document.createElement("span");
s.className = "acr-w";
s.textContent = word;
p.appendChild(s);
wordEls.push(s);
});
answerEl.appendChild(p);
}
addPara(answer1);
addPara(answer2);
addPara(answer3);
bullets.forEach(function (b) {
var row = document.createElement("div");
row.className = "acr-ali";
var mark = document.createElement("span");
mark.className = "acr-mark acr-w";
mark.textContent = "•";
row.appendChild(mark);
wordEls.push(mark);
var body = document.createElement("div");
body.className = "acr-alitext";
b.split(/\s+/).forEach(function (word, i) {
if (i > 0) body.appendChild(document.createTextNode(" "));
var s = document.createElement("span");
s.className = "acr-w";
s.textContent = word;
body.appendChild(s);
wordEls.push(s);
});
row.appendChild(body);
answerEl.appendChild(row);
});
/* -------- build the keyboard: measured key geometry -------- */
var keysEl = document.getElementById("acr-keys");
var ROWS = [
{ top: 83, left: 13, letters: "qwertyuiop" },
{ top: 173, left: 48, letters: "asdfghjkl" },
{ top: 263, left: 123, letters: "zxcvbnm" },
];
ROWS.forEach(function (row) {
row.letters.split("").forEach(function (ch, i) {
var k = document.createElement("div");
k.className = "acr-key";
k.style.left = row.left + i * 73.7 + "px";
k.style.top = row.top + "px";
k.style.width = "62px";
k.textContent = ch;
keysEl.appendChild(k);
});
});
[
{
left: 13,
top: 263,
width: 97,
cls: " acr-gkey",
html: '<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="1.6" stroke-linejoin="round"><path d="M12 4 L4.5 12 H8.5 V17 H15.5 V12 H19.5 Z"/></svg>',
},
{
left: 640,
top: 263,
width: 98,
cls: " acr-gkey",
html: '<svg width="31" height="24" viewBox="0 0 28 20" fill="none" stroke="#000" stroke-width="1.6" stroke-linejoin="round" stroke-linecap="round"><path d="M9 2 H26 V18 H9 L1.5 10 Z"/><path d="M13 6.5 L20 13.5 M20 6.5 L13 13.5"/></svg>',
},
{ left: 13, top: 353, width: 97, cls: " acr-gkey acr-num", html: "123" },
{
left: 118,
top: 353,
width: 86,
cls: "",
html: '<svg width="27" height="27" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="1.4" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><circle cx="9" cy="10" r="0.6" fill="#000"/><circle cx="15" cy="10" r="0.6" fill="#000"/><path d="M8 14.5 C9.5 16.5 14.5 16.5 16 14.5"/></svg>',
},
{ left: 217, top: 353, width: 389, cls: " acr-spc", html: "space" },
{
left: 614,
top: 353,
width: 124,
cls: " acr-gkey",
html: '<svg width="27" height="27" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M19 5 V11 H6"/><path d="M9.5 7.5 L6 11 L9.5 14.5"/></svg>',
},
].forEach(function (spec) {
var k = document.createElement("div");
k.className = "acr-key" + spec.cls;
k.style.left = spec.left + "px";
k.style.top = spec.top + "px";
k.style.width = spec.width + "px";
k.innerHTML = spec.html;
keysEl.appendChild(k);
});
/* -------- timeline -------- */
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
/* keystroke and token rhythms, measured from the reference and cycled */
var KEY_GAPS = [
0.1, 0.033, 0.2, 0.133, 0.2, 0.033, 0.067, 0.033, 0.1, 0.067, 0.033, 0.067, 0.067, 0.067,
0.133, 0.067, 0.033, 0.067, 0.1, 0.1, 0.067, 0.133, 0.1, 0.033, 0.1, 0.033, 0.167, 0.033,
0.1, 0.1, 0.067, 0.133, 0.033, 0.067, 0.1, 0.033, 0.1, 0.067,
];
var WORD_GAPS = [
0.167, 0.1, 0.0, 0.367, 0.0, 0.167, 0.133, 0.1, 0.1, 0.133, 0.167, 0.133, 0.0, 0.233,
0.167, 0.1, 0.0, 0.133, 0.133, 0.1, 0.167, 0.133, 0.1, 0.133, 0.167, 0.1, 0.133, 0.1,
0.133,
];
/* keyboard rises, composer rides it (verbatim anchors) */
tl.fromTo("#acr-keyboard", { y: 482 }, { y: 0, duration: 0.2667, ease: "power2.out" }, 0.2);
tl.fromTo(
"#acr-composer",
{ y: 0 },
{ y: -497, duration: 0.2667, ease: "power2.out" },
0.2,
);
/* typing: two characters land on the first beat, then the measured gaps */
tl.set("#acr-ctext", { textContent: "", autoAlpha: 0 }, 0.001);
var TYPE_START = 0.8637;
tl.set("#acr-ctext", { autoAlpha: 1 }, TYPE_START);
tl.set("#acr-ph", { autoAlpha: 0 }, TYPE_START);
tl.set("#acr-btn-send-grey", { autoAlpha: 0 }, TYPE_START);
tl.set("#acr-btn-send-black", { autoAlpha: 1 }, TYPE_START);
var t = TYPE_START;
for (var n = 2; n <= userMessage.length; n += 1) {
tl.set("#acr-ctext", { textContent: userMessage.slice(0, n) }, t);
t += KEY_GAPS[(n - 2) % KEY_GAPS.length];
}
var typeEnd = t;
/* caret blinks on a steady half-second while typing */
tl.set("#acr-caret", { autoAlpha: 0 }, 0.001);
for (var c = TYPE_START, on = true; c < typeEnd; c += 0.5333, on = !on) {
tl.set("#acr-caret", { autoAlpha: on ? 1 : 0 }, c);
}
/* send: bubble pops, keyboard drops, stream begins */
var SEND = typeEnd + 0.1667;
tl.set("#acr-caret", { autoAlpha: 0 }, SEND);
tl.set("#acr-ctext", { textContent: "" }, SEND);
tl.set("#acr-ph", { autoAlpha: 1 }, SEND);
tl.set("#acr-btn-send-black", { autoAlpha: 0 }, SEND);
tl.set("#acr-btn-stop", { autoAlpha: 1 }, SEND);
tl.fromTo(
"#acr-bubble",
{ autoAlpha: 0 },
{ autoAlpha: 1, duration: 0.1667, ease: "power1.out" },
SEND - 0.03,
);
tl.set("#acr-hicons-a", { autoAlpha: 0 }, SEND);
tl.set("#acr-hicons-b", { autoAlpha: 1 }, SEND);
tl.to("#acr-keyboard", { y: 482, duration: 0.2667, ease: "power1.inOut" }, SEND - 0.03);
tl.to("#acr-composer", { y: 0, duration: 0.2667, ease: "power1.inOut" }, SEND - 0.03);
/* thinking dot: the measured alpha ramp, then it yields to the words */
var DOT_RAMP = [
0.488, 0.53, 0.53, 0.56, 0.608, 0.687, 0.729, 0.771, 0.813, 0.867, 0.904, 0.988, 1,
];
var dotStart = SEND + 0.4333;
tl.set("#acr-dot", { autoAlpha: 0 }, 0.001);
DOT_RAMP.forEach(function (a, i) {
tl.set("#acr-dot", { autoAlpha: a }, dotStart + i * 0.0333);
});
tl.set("#acr-dot", { autoAlpha: 0 }, dotStart + 0.5667);
/* the stream: measured token rhythm, fresh grey inking to full colour */
var w = dotStart + 0.6333;
wordEls.forEach(function (el, i) {
if (i > 0) w += WORD_GAPS[i % WORD_GAPS.length];
tl.set(el, { opacity: 1 }, w);
tl.fromTo(
el,
{ color: "#767676" },
{ color: "#141414", duration: 0.2667, ease: "none" },
w,
);
});
/* stream ends: stop button returns to send */
tl.set("#acr-btn-stop", { autoAlpha: 0 }, w + 0.4667);
tl.set("#acr-btn-send-black", { autoAlpha: 1 }, w + 0.4667);
/* end card */
tl.set("#acr-endcard-inner", { opacity: 0 }, 0.001);
tl.fromTo(
"#acr-endcard-inner",
{ opacity: 0 },
{ opacity: 1, duration: 0.3167, ease: "none" },
15.8333,
);
window.__timelines["ai-chat-reveal"] = tl;
})();
</script>
</body>
</html>
```
</Accordion>
{/* hf:generated-footer */}
Tagged `showcase` `mock-ui` `ai` `chat` `vertical` `ad-template`.
Created by Miao Yang.
## Related topics
- [Browse the complete Catalog](/catalog)
- [Add assets and Catalog items in Studio](/studio/assets-and-blocks)
- [Build a richer composition](/go-further)