mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-08-31 02:41:44 +00:00
fix: expose promoted template media slots
This commit is contained in:
@@ -10,7 +10,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
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"}]}
|
||||
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"},{"id":"brandLogo","type":"image","role":"content","label":"Brand logo","description":"Transparent logo in the closing-card header.","default":"assets/hyperframes-logo-white.svg"}]}
|
||||
>
|
||||
|
||||
```html ai-chat-reveal.html
|
||||
@@ -29,7 +29,8 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
{ "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" }
|
||||
{ "id": "ecFooter", "type": "string", "role": "content", "label": "End-card footer", "description": "Letter-spaced line at the very bottom.", "default": "HYPERFRAMES.HEYGEN.COM" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent logo in the closing-card header.", "default": "assets/hyperframes-logo-white.svg" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
@@ -708,7 +709,12 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
>
|
||||
<div id="acr-endcard-inner">
|
||||
<div class="acr-stage">
|
||||
<img id="acr-eclogo" src="assets/hyperframes-logo-white.svg" alt="HyperFrames" />
|
||||
<img
|
||||
id="acr-eclogo"
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-white.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<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" />
|
||||
@@ -1034,7 +1040,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
|
||||
<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/`.
|
||||
That writes `compositions/ai-chat-reveal.html`, plus 2 supporting files under `assets/`.
|
||||
|
||||
## Add it to your video
|
||||
|
||||
@@ -1074,6 +1080,7 @@ want to change on the element:
|
||||
| `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. |
|
||||
| `brandLogo` | `assets/hyperframes-logo-white.svg` | image | Transparent logo in the closing-card header. |
|
||||
|
||||
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:
|
||||
@@ -1082,7 +1089,7 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
<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"}'
|
||||
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","brandLogo":"assets/hyperframes-logo-white.svg"}'
|
||||
></div>
|
||||
```
|
||||
|
||||
@@ -1106,7 +1113,8 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
{ "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" }
|
||||
{ "id": "ecFooter", "type": "string", "role": "content", "label": "End-card footer", "description": "Letter-spaced line at the very bottom.", "default": "HYPERFRAMES.HEYGEN.COM" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent logo in the closing-card header.", "default": "assets/hyperframes-logo-white.svg" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
@@ -1785,7 +1793,12 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
>
|
||||
<div id="acr-endcard-inner">
|
||||
<div class="acr-stage">
|
||||
<img id="acr-eclogo" src="assets/hyperframes-logo-white.svg" alt="HyperFrames" />
|
||||
<img
|
||||
id="acr-eclogo"
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-white.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<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" />
|
||||
|
||||
@@ -16,7 +16,7 @@ import { InstallCommand } from "/snippets/install-command.jsx";
|
||||
|
||||
<InstallCommand command="npx hyperframes add chatgpt-exchange" item="chatgpt-exchange" />
|
||||
|
||||
That writes `compositions/chatgpt-exchange.html`, plus 4 supporting files under `assets/fonts/`.
|
||||
That writes `compositions/chatgpt-exchange.html`, plus 5 supporting files under `assets/fonts/`.
|
||||
|
||||
## Add it to your video
|
||||
|
||||
@@ -43,7 +43,34 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en" data-resolution="portrait">
|
||||
<html
|
||||
lang="en"
|
||||
data-resolution="portrait"
|
||||
data-composition-variables='[
|
||||
{ "id": "prompt", "type": "string", "role": "content", "label": "User prompt", "description": "Prompt typed into ChatGPT; keep close to the original length.", "default": "Hey what's the best tool for ai avatars" },
|
||||
{ "id": "intro1", "type": "string", "role": "content", "label": "Answer introduction 1", "description": "First streamed answer paragraph.", "default": "It really depends on what you're trying to do, because “AI avatars” has split into a few different categories." },
|
||||
{ "id": "intro2", "type": "string", "role": "content", "label": "Answer introduction 2", "description": "Second streamed answer paragraph.", "default": "For **most creators and marketers**, here's how I'd rank them today:" },
|
||||
{ "id": "tableHeadUse", "type": "string", "role": "content", "label": "Table heading 1", "description": "Use-case column heading.", "default": "Use case" },
|
||||
{ "id": "tableHeadTool", "type": "string", "role": "content", "label": "Table heading 2", "description": "Tool column heading.", "default": "Best tool" },
|
||||
{ "id": "tableHeadWhy", "type": "string", "role": "content", "label": "Table heading 3", "description": "Explanation column heading.", "default": "Why" },
|
||||
{ "id": "row1Use", "type": "string", "role": "content", "label": "Row 1 use case", "description": "First comparison use case.", "default": "Overall realism" },
|
||||
{ "id": "row1Tool", "type": "string", "role": "content", "label": "Row 1 tool", "description": "First recommended product.", "default": "HeyGen" },
|
||||
{ "id": "row1Why", "type": "string", "role": "content", "label": "Row 1 explanation", "description": "First recommendation explanation.", "default": "Most natural facial expressions, lip sync, gestures, voice cloning and localization. Benchmark for talking head videos." },
|
||||
{ "id": "row1Chip", "type": "string", "role": "content", "label": "Row 1 source", "description": "First source-chip label.", "default": "Official A.I Ranking" },
|
||||
{ "id": "row2Use", "type": "string", "role": "content", "label": "Row 2 use case", "description": "Second comparison use case.", "default": "Enterprise/training" },
|
||||
{ "id": "row2Tool", "type": "string", "role": "content", "label": "Row 2 tool", "description": "Second recommended product.", "default": "Synthesia" },
|
||||
{ "id": "row2Why", "type": "string", "role": "content", "label": "Row 2 explanation", "description": "Second recommendation explanation.", "default": "Better collaboration, SCORM, compliance, team workflows; less creator-focused." },
|
||||
{ "id": "row2Chip", "type": "string", "role": "content", "label": "Row 2 source", "description": "Second source-chip label.", "default": "Official A.I Ranking" },
|
||||
{ "id": "row3Use", "type": "string", "role": "content", "label": "Row 3 use case", "description": "Third comparison use case.", "default": "Mobile UGC" },
|
||||
{ "id": "row3Tool", "type": "string", "role": "content", "label": "Row 3 tool", "description": "Third recommended product.", "default": "Captions" },
|
||||
{ "id": "row3Why", "type": "string", "role": "content", "label": "Row 3 explanation", "description": "Third recommendation explanation.", "default": "Extremely fast mobile workflow and social editing. Great for Reels creators." },
|
||||
{ "id": "row3Chip", "type": "string", "role": "content", "label": "Row 3 source", "description": "Third source-chip label.", "default": "Creator Stack" },
|
||||
{ "id": "row4Use", "type": "string", "role": "content", "label": "Row 4 use case", "description": "Fourth comparison use case.", "default": "Real-time conversations" },
|
||||
{ "id": "row4Tool", "type": "string", "role": "content", "label": "Row 4 tool", "description": "Fourth recommended product.", "default": "Tavus" },
|
||||
{ "id": "row4Why", "type": "string", "role": "content", "label": "Row 4 explanation", "description": "Fourth recommendation explanation.", "default": "Interactive avatars that can hold live conversations." },
|
||||
{ "id": "row4Chip", "type": "string", "role": "content", "label": "Row 4 source", "description": "Fourth source-chip label.", "default": "Creator Stack" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=1080, height=1920" />
|
||||
@@ -670,12 +697,16 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ==================================================================
|
||||
TEMPLATE CONFIG — edit only this block to re-skin the exchange.
|
||||
================================================================== */
|
||||
const variables =
|
||||
window.__hyperframes && typeof window.__hyperframes.getVariables === "function"
|
||||
? window.__hyperframes.getVariables()
|
||||
: {};
|
||||
const content = (id, fallback) =>
|
||||
typeof variables[id] === "string" && variables[id].trim() ? variables[id] : fallback;
|
||||
|
||||
const CONFIG = {
|
||||
status: { clock: "1:29", clockLate: "1:30", net: "5G+", battery: 89, batteryLate: 88 },
|
||||
prompt: "Hey what's the best tool for ai avatars",
|
||||
prompt: content("prompt", "Hey what's the best tool for ai avatars"),
|
||||
suggestions: [
|
||||
{ icon: "slack", label: "Summarize my to-dos" },
|
||||
{ icon: "gmail", label: "Draft follow-up emails" },
|
||||
@@ -687,39 +718,55 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
end: ['"avatars"', "avatar sick", "avatar stressed"],
|
||||
},
|
||||
paragraphs: [
|
||||
"It really depends on what you're trying to do, because “AI avatars” has split into a few different categories.",
|
||||
"For **most creators and marketers**, here's how I'd rank them today:",
|
||||
content(
|
||||
"intro1",
|
||||
"It really depends on what you're trying to do, because “AI avatars” has split into a few different categories.",
|
||||
),
|
||||
content("intro2", "For **most creators and marketers**, here's how I'd rank them today:"),
|
||||
],
|
||||
table: {
|
||||
head: ["Use case", "Best tool", "Why"],
|
||||
head: [
|
||||
content("tableHeadUse", "Use case"),
|
||||
content("tableHeadTool", "Best tool"),
|
||||
content("tableHeadWhy", "Why"),
|
||||
],
|
||||
rows: [
|
||||
{
|
||||
emoji: "🥇",
|
||||
use: "Overall realism",
|
||||
tool: "HeyGen",
|
||||
why: "Most natural facial expressions, lip sync, gestures, voice cloning and localization. Benchmark for talking head videos.",
|
||||
chip: "Official A.I Ranking",
|
||||
use: content("row1Use", "Overall realism"),
|
||||
tool: content("row1Tool", "HeyGen"),
|
||||
why: content(
|
||||
"row1Why",
|
||||
"Most natural facial expressions, lip sync, gestures, voice cloning and localization. Benchmark for talking head videos.",
|
||||
),
|
||||
chip: content("row1Chip", "Official A.I Ranking"),
|
||||
},
|
||||
{
|
||||
emoji: "🏢",
|
||||
use: "Enterprise/training",
|
||||
tool: "Synthesia",
|
||||
why: "Better collaboration, SCORM, compliance, team workflows; less creator-focused.",
|
||||
chip: "Official A.I Ranking",
|
||||
use: content("row2Use", "Enterprise/training"),
|
||||
tool: content("row2Tool", "Synthesia"),
|
||||
why: content(
|
||||
"row2Why",
|
||||
"Better collaboration, SCORM, compliance, team workflows; less creator-focused.",
|
||||
),
|
||||
chip: content("row2Chip", "Official A.I Ranking"),
|
||||
},
|
||||
{
|
||||
emoji: "📱",
|
||||
use: "Mobile UGC",
|
||||
tool: "Captions",
|
||||
why: "Extremely fast mobile workflow and social editing. Great for Reels creators.",
|
||||
chip: "Creator Stack",
|
||||
use: content("row3Use", "Mobile UGC"),
|
||||
tool: content("row3Tool", "Captions"),
|
||||
why: content(
|
||||
"row3Why",
|
||||
"Extremely fast mobile workflow and social editing. Great for Reels creators.",
|
||||
),
|
||||
chip: content("row3Chip", "Creator Stack"),
|
||||
},
|
||||
{
|
||||
emoji: "💬",
|
||||
use: "Real-time conversations",
|
||||
tool: "Tavus",
|
||||
why: "Interactive avatars that can hold live conversations.",
|
||||
chip: "Creator Stack",
|
||||
use: content("row4Use", "Real-time conversations"),
|
||||
tool: content("row4Tool", "Tavus"),
|
||||
why: content("row4Why", "Interactive avatars that can hold live conversations."),
|
||||
chip: content("row4Chip", "Creator Stack"),
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -843,6 +890,7 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
const el = (cls, html, tag) => {
|
||||
const n = document.createElement(tag || "div");
|
||||
if (cls) n.className = cls;
|
||||
// Editable strings reach innerHTML; the template delivery gate rejects angle brackets.
|
||||
if (html != null) n.innerHTML = html;
|
||||
return n;
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ import { InstallCommand } from "/snippets/install-command.jsx";
|
||||
|
||||
<InstallCommand command="npx hyperframes add claude-exchange" item="claude-exchange" />
|
||||
|
||||
That writes `compositions/claude-exchange.html`, plus 7 supporting files under `assets/fonts/`.
|
||||
That writes `compositions/claude-exchange.html`, plus 8 supporting files under `assets/fonts/`.
|
||||
|
||||
## Add it to your video
|
||||
|
||||
@@ -43,7 +43,26 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en" data-resolution="portrait">
|
||||
<html
|
||||
lang="en"
|
||||
data-resolution="portrait"
|
||||
data-composition-variables='[
|
||||
{ "id": "prompt", "type": "string", "role": "content", "label": "User prompt", "description": "Prompt typed into Claude; keep close to the original length.", "default": "What's the best tool for ai avatars?" },
|
||||
{ "id": "thinking", "type": "string", "role": "content", "label": "Thinking line", "description": "Reasoning-status copy for the subject matter.", "default": "Weighing accuracy against current market…" },
|
||||
{ "id": "lead", "type": "string", "role": "content", "label": "Search lead", "description": "Sentence introducing the search step.", "default": "I'll search for the current state of this space since AI avatar tools move fast." },
|
||||
{ "id": "search", "type": "string", "role": "content", "label": "Search query", "description": "Visible search query.", "default": "best AI avatar video generator 2026" },
|
||||
{ "id": "answer1", "type": "string", "role": "content", "label": "Answer paragraph 1", "description": "First answer paragraph.", "default": "It depends on what you're making, but the field has consolidated fast and one platform now covers most of it." },
|
||||
{ "id": "answer2", "type": "string", "role": "content", "label": "Answer paragraph 2", "description": "Second answer paragraph.", "default": "**HeyGen** is where most teams land. Independent testing, not just vendor blogs, puts **Avatar IV** highest for talking-head realism, with facial micro-expressions and gesture control that hold up at a full-screen crop {HeyGen}. It also has the deepest enterprise adoption of the group, including a large share of the Fortune 100, which matters if you need the same presenter on brand across a year of campaigns." },
|
||||
{ "id": "answer3", "type": "string", "role": "content", "label": "Answer paragraph 3", "description": "Lead-in to the use-case list.", "default": "By use case, the pieces shake out roughly like this:" },
|
||||
{ "id": "answer4", "type": "string", "role": "content", "label": "Answer bullet 1", "description": "First use-case bullet.", "default": "**Marketing / hyper-realistic talking heads** → Avatar IV" },
|
||||
{ "id": "answer5", "type": "string", "role": "content", "label": "Answer bullet 2", "description": "Second use-case bullet.", "default": "**Enterprise training** → Video Translate for every locale" },
|
||||
{ "id": "answer6", "type": "string", "role": "content", "label": "Answer bullet 3", "description": "Third use-case bullet.", "default": "**UGC-style performance ads** → Instant Avatar from one selfie, then batch the variants" },
|
||||
{ "id": "answer7", "type": "string", "role": "content", "label": "Answer bullet 4", "description": "Fourth use-case bullet.", "default": "**Real-time conversational / interactive** → Interactive Avatar" },
|
||||
{ "id": "answer8", "type": "string", "role": "content", "label": "Answer bullet 5", "description": "Fifth use-case bullet.", "default": "**Custom digital twin from a selfie** → Instant Avatar in about five minutes" },
|
||||
{ "id": "answer9", "type": "string", "role": "content", "label": "Answer paragraph 4", "description": "Product-category distinction paragraph.", "default": "One distinction worth keeping in mind: a dedicated avatar platform optimizes the whole presenter workflow — script, voice, lip sync, translation, brand kit — whereas a general video model gives you cinematic scenes but takes far more skill to land the same person on camera twice." },
|
||||
{ "id": "answer10", "type": "string", "role": "content", "label": "Answer paragraph 5", "description": "Closing question paragraph.", "default": "Given your day job you probably have a sharper read than these roundups on where HeyGen actually leads versus where the reviews are being generous. Is this for a specific project, or comparing for positioning?" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=1080, height=1920" />
|
||||
@@ -700,9 +719,13 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ==================================================================
|
||||
TEMPLATE CONFIG — edit only this block to re-skin the exchange.
|
||||
================================================================== */
|
||||
const variables =
|
||||
window.__hyperframes && typeof window.__hyperframes.getVariables === "function"
|
||||
? window.__hyperframes.getVariables()
|
||||
: {};
|
||||
const content = (id, fallback) =>
|
||||
typeof variables[id] === "string" && variables[id].trim() ? variables[id] : fallback;
|
||||
|
||||
const CONFIG = {
|
||||
status: { clock: "2:36", clockLate: "2:37", net: "5G+", battery: 87 },
|
||||
emptyHeading: "What can we tackle together?",
|
||||
@@ -710,43 +733,79 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
model: { name: "Opus 4.8", effort: "High" },
|
||||
placeholder: "Chat with Claude",
|
||||
placeholderReply: "Reply to Claude",
|
||||
prompt: "What's the best tool for ai avatars?",
|
||||
prompt: content("prompt", "What's the best tool for ai avatars?"),
|
||||
predict: {
|
||||
start: ["I", "The", "I'm"],
|
||||
end: ["I", "Do", "How"],
|
||||
},
|
||||
thinking: "Weighing accuracy against current market…",
|
||||
lead: "I'll search for the current state of this space since AI avatar tools move fast.",
|
||||
search: "best AI avatar video generator 2026",
|
||||
thinking: content("thinking", "Weighing accuracy against current market…"),
|
||||
lead: content(
|
||||
"lead",
|
||||
"I'll search for the current state of this space since AI avatar tools move fast.",
|
||||
),
|
||||
search: content("search", "best AI avatar video generator 2026"),
|
||||
collapsed: "2 steps",
|
||||
answer: [
|
||||
{
|
||||
t: "p",
|
||||
text: "It depends on what you're making, but the field has consolidated fast and one platform now covers most of it.",
|
||||
text: content(
|
||||
"answer1",
|
||||
"It depends on what you're making, but the field has consolidated fast and one platform now covers most of it.",
|
||||
),
|
||||
},
|
||||
{
|
||||
t: "p",
|
||||
text: "**HeyGen** is where most teams land. Independent testing, not just vendor blogs, puts **Avatar IV** highest for talking-head realism, with facial micro-expressions and gesture control that hold up at a full-screen crop {HeyGen}. It also has the deepest enterprise adoption of the group, including a large share of the Fortune 100, which matters if you need the same presenter on brand across a year of campaigns.",
|
||||
text: content(
|
||||
"answer2",
|
||||
"**HeyGen** is where most teams land. Independent testing, not just vendor blogs, puts **Avatar IV** highest for talking-head realism, with facial micro-expressions and gesture control that hold up at a full-screen crop {HeyGen}. It also has the deepest enterprise adoption of the group, including a large share of the Fortune 100, which matters if you need the same presenter on brand across a year of campaigns.",
|
||||
),
|
||||
},
|
||||
{
|
||||
t: "p",
|
||||
text: content("answer3", "By use case, the pieces shake out roughly like this:"),
|
||||
},
|
||||
{ t: "p", text: "By use case, the pieces shake out roughly like this:" },
|
||||
{ t: "b", text: "**Marketing / hyper-realistic talking heads** → Avatar IV" },
|
||||
{ t: "b", text: "**Enterprise training** → Video Translate for every locale" },
|
||||
{
|
||||
t: "b",
|
||||
text: "**UGC-style performance ads** → Instant Avatar from one selfie, then batch the variants",
|
||||
text: content("answer4", "**Marketing / hyper-realistic talking heads** → Avatar IV"),
|
||||
},
|
||||
{ t: "b", text: "**Real-time conversational / interactive** → Interactive Avatar" },
|
||||
{
|
||||
t: "b",
|
||||
text: "**Custom digital twin from a selfie** → Instant Avatar in about five minutes",
|
||||
text: content("answer5", "**Enterprise training** → Video Translate for every locale"),
|
||||
},
|
||||
{
|
||||
t: "b",
|
||||
text: content(
|
||||
"answer6",
|
||||
"**UGC-style performance ads** → Instant Avatar from one selfie, then batch the variants",
|
||||
),
|
||||
},
|
||||
{
|
||||
t: "b",
|
||||
text: content(
|
||||
"answer7",
|
||||
"**Real-time conversational / interactive** → Interactive Avatar",
|
||||
),
|
||||
},
|
||||
{
|
||||
t: "b",
|
||||
text: content(
|
||||
"answer8",
|
||||
"**Custom digital twin from a selfie** → Instant Avatar in about five minutes",
|
||||
),
|
||||
},
|
||||
{
|
||||
t: "p",
|
||||
text: "One distinction worth keeping in mind: a dedicated avatar platform optimizes the whole presenter workflow — script, voice, lip sync, translation, brand kit — whereas a general video model gives you cinematic scenes but takes far more skill to land the same person on camera twice.",
|
||||
text: content(
|
||||
"answer9",
|
||||
"One distinction worth keeping in mind: a dedicated avatar platform optimizes the whole presenter workflow — script, voice, lip sync, translation, brand kit — whereas a general video model gives you cinematic scenes but takes far more skill to land the same person on camera twice.",
|
||||
),
|
||||
},
|
||||
{
|
||||
t: "p",
|
||||
text: "Given your day job you probably have a sharper read than these roundups on where HeyGen actually leads versus where the reviews are being generous. Is this for a specific project, or comparing for positioning?",
|
||||
text: content(
|
||||
"answer10",
|
||||
"Given your day job you probably have a sharper read than these roundups on where HeyGen actually leads versus where the reviews are being generous. Is this for a specific project, or comparing for positioning?",
|
||||
),
|
||||
},
|
||||
],
|
||||
sources: { count: 7, dots: ["#1b6ac9", "#2b7fff", "#0f4fa8"] },
|
||||
@@ -908,6 +967,7 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
const el = (cls, html, tag) => {
|
||||
const n = document.createElement(tag || "div");
|
||||
if (cls) n.className = cls;
|
||||
// Editable strings reach innerHTML; the template delivery gate rejects angle brackets.
|
||||
if (html != null) n.innerHTML = html;
|
||||
return n;
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ import { InstallCommand } from "/snippets/install-command.jsx";
|
||||
|
||||
<InstallCommand command="npx hyperframes add heygen-avatar-promo-card" item="heygen-avatar-promo-card" />
|
||||
|
||||
That writes `compositions/heygen-avatar-promo-card.html`, plus 14 supporting files under `assets/` and `assets/fonts/`.
|
||||
That writes `compositions/heygen-avatar-promo-card.html`, plus 15 supporting files under `assets/` and `assets/fonts/`.
|
||||
|
||||
## Add it to your video
|
||||
|
||||
@@ -38,7 +38,29 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en" data-resolution="portrait">
|
||||
<html
|
||||
lang="en"
|
||||
data-resolution="portrait"
|
||||
data-composition-variables='[
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Horizontal transparent wordmark used in the header and belt.", "default": "assets/heygen-logo.svg" },
|
||||
{ "id": "titleLine1", "type": "string", "role": "content", "label": "Headline line 1", "description": "First headline line.", "default": "Your avatar," },
|
||||
{ "id": "titleLine2", "type": "string", "role": "content", "label": "Headline line 2", "description": "Second headline line.", "default": "by HeyGen." },
|
||||
{ "id": "subhead", "type": "string", "role": "content", "label": "Subhead", "description": "Supporting line under the headline.", "default": "AI video, camera-free." },
|
||||
{ "id": "pill1", "type": "string", "role": "content", "label": "Pill 1", "description": "First feature pill.", "default": "4K AVATARS" },
|
||||
{ "id": "pill2", "type": "string", "role": "content", "label": "Pill 2", "description": "Second feature pill.", "default": "NO CAMERA NEEDED" },
|
||||
{ "id": "offerValue", "type": "string", "role": "content", "label": "Offer value", "description": "Large offer value in the light tile.", "default": "25%" },
|
||||
{ "id": "offerSuffix", "type": "string", "role": "content", "label": "Offer suffix", "description": "Large offer suffix in the adjacent light tile.", "default": "OFF" },
|
||||
{ "id": "codeLabel", "type": "string", "role": "content", "label": "Promo code label", "description": "Small label above the promo code.", "default": "CODE" },
|
||||
{ "id": "promoPrefix", "type": "string", "role": "content", "label": "Promo code prefix", "description": "Accent-colored promo-code prefix.", "default": "GEN" },
|
||||
{ "id": "promoSuffix", "type": "string", "role": "content", "label": "Promo code suffix", "description": "Light promo-code suffix.", "default": "25" },
|
||||
{ "id": "canvasColor", "type": "color", "role": "style", "label": "Canvas color", "description": "Main card background.", "default": "#eaf6fa" },
|
||||
{ "id": "inkColor", "type": "color", "role": "style", "label": "Ink color", "description": "Primary headline, pill, and offer ink.", "default": "#0a1418" },
|
||||
{ "id": "mutedInkColor", "type": "color", "role": "style", "label": "Muted ink color", "description": "Subhead ink.", "default": "#47545b" },
|
||||
{ "id": "accentColor", "type": "color", "role": "style", "label": "Accent color", "description": "Brand accent used by tiles and promo-code prefix.", "default": "#00c3ff" },
|
||||
{ "id": "lightTileColor", "type": "color", "role": "style", "label": "Light tile color", "description": "Light belt-tile surface.", "default": "#f7fcfe" },
|
||||
{ "id": "darkTileColor", "type": "color", "role": "style", "label": "Dark tile color", "description": "Dark belt-tile surface.", "default": "#0b1215" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=1080, height=1920" />
|
||||
@@ -91,11 +113,17 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
width: 1080px;
|
||||
height: 1920px;
|
||||
overflow: hidden;
|
||||
--apc-canvas: #eaf6fa;
|
||||
--apc-ink: #0a1418;
|
||||
--apc-muted: #47545b;
|
||||
--apc-accent: #00c3ff;
|
||||
--apc-light-tile: #f7fcfe;
|
||||
--apc-dark-tile: #0b1215;
|
||||
}
|
||||
.bgfill {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: #eaf6fa;
|
||||
background: var(--apc-canvas);
|
||||
}
|
||||
|
||||
.hdr {
|
||||
@@ -103,7 +131,7 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
left: 0;
|
||||
width: 1080px;
|
||||
text-align: center;
|
||||
color: #0a1418;
|
||||
color: var(--apc-ink);
|
||||
}
|
||||
#apc-hdr-logo {
|
||||
top: 118px;
|
||||
@@ -125,7 +153,7 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
font-family: "AvatarSans", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 37px;
|
||||
color: #47545b;
|
||||
color: var(--apc-muted);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
#apc-hdr-pills {
|
||||
@@ -135,7 +163,7 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
gap: 28px;
|
||||
}
|
||||
.pill {
|
||||
border: 2px solid #0a1418;
|
||||
border: 2px solid var(--apc-ink);
|
||||
border-radius: 999px;
|
||||
padding: 0 42px;
|
||||
height: 92px;
|
||||
@@ -144,7 +172,7 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
font-weight: 600;
|
||||
font-size: 27px;
|
||||
letter-spacing: 0.12em;
|
||||
color: #0a1418;
|
||||
color: var(--apc-ink);
|
||||
}
|
||||
|
||||
#apc-belt-linear {
|
||||
@@ -179,13 +207,13 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
display: block;
|
||||
}
|
||||
.light {
|
||||
background: #f7fcfe;
|
||||
background: var(--apc-light-tile);
|
||||
}
|
||||
.dark {
|
||||
background: #0b1215;
|
||||
background: var(--apc-dark-tile);
|
||||
}
|
||||
.cyan {
|
||||
background: #00c3ff;
|
||||
background: var(--apc-accent);
|
||||
}
|
||||
.serif-tile {
|
||||
display: flex;
|
||||
@@ -194,7 +222,7 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
font-family: "AvatarDisplay", serif;
|
||||
font-weight: 500;
|
||||
font-size: 165px;
|
||||
color: #0a1418;
|
||||
color: var(--apc-ink);
|
||||
}
|
||||
.brand-tile {
|
||||
display: flex;
|
||||
@@ -226,7 +254,7 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.code-tile .promo .gen {
|
||||
color: #00c3ff;
|
||||
color: var(--apc-accent);
|
||||
}
|
||||
.code-tile .promo .n25 {
|
||||
color: #fbfcfc;
|
||||
@@ -263,7 +291,9 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
muted
|
||||
playsinline
|
||||
></video>
|
||||
<div class="tile row1 light serif-tile" style="left: 907.7px">25%</div>
|
||||
<div id="apc-offer-value" class="tile row1 light serif-tile" style="left: 907.7px">
|
||||
25%
|
||||
</div>
|
||||
<video
|
||||
class="tile row1 clip"
|
||||
id="apc-v-r1k3"
|
||||
@@ -299,7 +329,13 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
muted
|
||||
playsinline
|
||||
></video>
|
||||
<div class="tile row2 light serif-tile" style="left: 523.4px; font-size: 146px">OFF</div>
|
||||
<div
|
||||
id="apc-offer-suffix"
|
||||
class="tile row2 light serif-tile"
|
||||
style="left: 523.4px; font-size: 146px"
|
||||
>
|
||||
OFF
|
||||
</div>
|
||||
<video
|
||||
class="tile row2 clip"
|
||||
id="apc-v-r2k2"
|
||||
@@ -312,8 +348,11 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
playsinline
|
||||
></video>
|
||||
<div class="tile row2 dark code-tile" style="left: 1292px">
|
||||
<div class="code">CODE</div>
|
||||
<div class="promo"><span class="gen">GEN</span><span class="n25">25</span></div>
|
||||
<div id="apc-code-label" class="code">CODE</div>
|
||||
<div class="promo">
|
||||
<span id="apc-promo-prefix" class="gen">GEN</span
|
||||
><span id="apc-promo-suffix" class="n25">25</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tile row2 light brand-tile" style="left: 1676.3px">
|
||||
<img src="assets/heygen-logo.svg?t=2" alt="" />
|
||||
@@ -326,12 +365,12 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
<div class="hdr" id="apc-hdr-logo"><img src="assets/heygen-logo.svg" alt="HeyGen" /></div>
|
||||
<div class="hdr" id="apc-hdr-title">
|
||||
Your avatar,
|
||||
<div>by HeyGen.</div>
|
||||
<div id="apc-title-line-2">by HeyGen.</div>
|
||||
</div>
|
||||
<div class="hdr" id="apc-hdr-subhead">AI video, camera-free.</div>
|
||||
<div class="hdr" id="apc-hdr-pills">
|
||||
<div class="pill">4K AVATARS</div>
|
||||
<div class="pill">NO CAMERA NEEDED</div>
|
||||
<div id="apc-pill-1" class="pill">4K AVATARS</div>
|
||||
<div id="apc-pill-2" class="pill">NO CAMERA NEEDED</div>
|
||||
</div>
|
||||
|
||||
<audio
|
||||
@@ -345,6 +384,41 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const variables =
|
||||
window.__hyperframes && typeof window.__hyperframes.getVariables === "function"
|
||||
? window.__hyperframes.getVariables()
|
||||
: {};
|
||||
const root = document.getElementById("heygen-avatar-promo-card");
|
||||
const text = (id, fallback) =>
|
||||
typeof variables[id] === "string" && variables[id].trim() ? variables[id] : fallback;
|
||||
const color = (id, fallback) => text(id, fallback);
|
||||
|
||||
root.style.setProperty("--apc-canvas", color("canvasColor", "#eaf6fa"));
|
||||
root.style.setProperty("--apc-ink", color("inkColor", "#0a1418"));
|
||||
root.style.setProperty("--apc-muted", color("mutedInkColor", "#47545b"));
|
||||
root.style.setProperty("--apc-accent", color("accentColor", "#00c3ff"));
|
||||
root.style.setProperty("--apc-light-tile", color("lightTileColor", "#f7fcfe"));
|
||||
root.style.setProperty("--apc-dark-tile", color("darkTileColor", "#0b1215"));
|
||||
document.querySelectorAll(".brand-tile img, #apc-hdr-logo img").forEach((image) => {
|
||||
image.src = text("brandLogo", "assets/heygen-logo.svg");
|
||||
});
|
||||
document.getElementById("apc-hdr-title").firstChild.nodeValue = text(
|
||||
"titleLine1",
|
||||
"Your avatar,",
|
||||
);
|
||||
document.getElementById("apc-title-line-2").textContent = text("titleLine2", "by HeyGen.");
|
||||
document.getElementById("apc-hdr-subhead").textContent = text(
|
||||
"subhead",
|
||||
"AI video, camera-free.",
|
||||
);
|
||||
document.getElementById("apc-pill-1").textContent = text("pill1", "4K AVATARS");
|
||||
document.getElementById("apc-pill-2").textContent = text("pill2", "NO CAMERA NEEDED");
|
||||
document.getElementById("apc-offer-value").textContent = text("offerValue", "25%");
|
||||
document.getElementById("apc-offer-suffix").textContent = text("offerSuffix", "OFF");
|
||||
document.getElementById("apc-code-label").textContent = text("codeLabel", "CODE");
|
||||
document.getElementById("apc-promo-prefix").textContent = text("promoPrefix", "GEN");
|
||||
document.getElementById("apc-promo-suffix").textContent = text("promoSuffix", "25");
|
||||
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
// Belt conveyor — measured from reference: 93.601 px/s constant, leftward
|
||||
@@ -395,7 +469,7 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
|
||||
{/* hf:generated-footer */}
|
||||
|
||||
Tagged `showcase` `avatar` `promotion` `vertical` `ad-template`.
|
||||
Tagged `showcase` `avatar` `promotion` `vertical`.
|
||||
|
||||
Created by HeyGen.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
previewSrc="/public/catalog/blocks/message-thread-reveal.json"
|
||||
compositionId="message-thread-reveal"
|
||||
compositionSrc="compositions/message-thread-reveal.html"
|
||||
variables={[{"id":"contactName","type":"string","role":"content","label":"Contact name","description":"Name pill in the chat header; the avatar shows its first letter.","default":"Rachel"},{"id":"cardTitle","type":"string","role":"content","label":"Link card title","description":"Title on the shared link card.","default":"HyperFrames | Write HTML, render pixel-perfect video"},{"id":"cardDomain","type":"string","role":"content","label":"Link card domain","description":"Domain line under the card title.","default":"hyperframes.heygen.com"},{"id":"ecProof","type":"string","role":"content","label":"End-card proof","description":"Social-proof line under the stars.","default":"12,000+ creators"},{"id":"ecCta","type":"string","role":"content","label":"End-card CTA","description":"Label on the closing card button.","default":"Start rendering free"}]}
|
||||
variables={[{"id":"contactName","type":"string","role":"content","label":"Contact name","description":"Name pill in the chat header; the avatar shows its first letter.","default":"Rachel"},{"id":"questionMessage","type":"string","role":"content","label":"Opening question","description":"First incoming message that establishes what the conversation is about.","default":"what r u using for the launch video??"},{"id":"teaserMessage","type":"string","role":"content","label":"Teaser reply","description":"First typed outgoing reply before the shared link card.","default":"wait look 👀"},{"id":"cardImage","type":"image","role":"content","label":"Link card image","description":"Preview image on the shared link card.","default":"assets/card-image.jpg"},{"id":"cardTitle","type":"string","role":"content","label":"Link card title","description":"Title on the shared link card.","default":"HyperFrames | Write HTML, render pixel-perfect video"},{"id":"cardDomain","type":"string","role":"content","label":"Link card domain","description":"Domain line under the card title.","default":"hyperframes.heygen.com"},{"id":"reactionMessage","type":"string","role":"content","label":"Link reaction","description":"Incoming reaction immediately after the shared link.","default":"OMG IT'S HTML"},{"id":"reactionEmoji","type":"string","role":"content","label":"Reaction emoji","description":"Emoji-only reaction after the shared link.","default":"🤯🤯🤯"},{"id":"benefitMessage","type":"string","role":"content","label":"Benefit reply","description":"Typed outgoing reply that names the primary benefit.","default":"renders in 4K. no editor"},{"id":"discoveryMessage","type":"string","role":"content","label":"Discovery question","description":"Incoming question asking where the product was found.","default":"where did u find this"},{"id":"sourceMessage","type":"string","role":"content","label":"Source reply","description":"Typed outgoing reply naming where to find the product.","default":"on heygen"},{"id":"workflowMessage","type":"string","role":"content","label":"Workflow reply","description":"Typed outgoing reply describing how the product works.","default":"u just write plain html tags"},{"id":"ownershipMessage","type":"string","role":"content","label":"Ownership reply","description":"Typed outgoing reply that closes the product explanation.","default":"the code is yours forever"},{"id":"installMessage","type":"string","role":"content","label":"Intent reply","description":"Incoming message expressing intent to try the product.","default":"installing rn"},{"id":"thanksMessage","type":"string","role":"content","label":"Closing reply","description":"Final incoming message in the conversation.","default":"ty bestie 💚"},{"id":"brandLogo","type":"image","role":"content","label":"Brand logo","description":"Transparent horizontal wordmark on the closing card.","default":"assets/hyperframes-logo-black.svg"},{"id":"ecProof","type":"string","role":"content","label":"End-card proof","description":"Social-proof line under the stars.","default":"12,000+ creators"},{"id":"ecFeature1","type":"string","role":"content","label":"End-card feature 1","description":"First two-line benefit; use | to break the line.","default":"Write|plain HTML"},{"id":"ecFeature2","type":"string","role":"content","label":"End-card feature 2","description":"Second two-line benefit; use | to break the line.","default":"Render|pixel-perfect"},{"id":"ecFeature3","type":"string","role":"content","label":"End-card feature 3","description":"Third two-line benefit; use | to break the line.","default":"Own|every line"},{"id":"ecCta","type":"string","role":"content","label":"End-card CTA","description":"Label on the closing card button.","default":"Start rendering free"}]}
|
||||
>
|
||||
|
||||
```html message-thread-reveal.html
|
||||
@@ -19,9 +19,25 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
lang="en"
|
||||
data-composition-variables='[
|
||||
{ "id": "contactName", "type": "string", "role": "content", "label": "Contact name", "description": "Name pill in the chat header; the avatar shows its first letter.", "default": "Rachel" },
|
||||
{ "id": "questionMessage", "type": "string", "role": "content", "label": "Opening question", "description": "First incoming message that establishes what the conversation is about.", "default": "what r u using for the launch video??" },
|
||||
{ "id": "teaserMessage", "type": "string", "role": "content", "label": "Teaser reply", "description": "First typed outgoing reply before the shared link card.", "default": "wait look 👀" },
|
||||
{ "id": "cardImage", "type": "image", "role": "content", "label": "Link card image", "description": "Preview image on the shared link card.", "default": "assets/card-image.jpg" },
|
||||
{ "id": "cardTitle", "type": "string", "role": "content", "label": "Link card title", "description": "Title on the shared link card.", "default": "HyperFrames | Write HTML, render pixel-perfect video" },
|
||||
{ "id": "cardDomain", "type": "string", "role": "content", "label": "Link card domain", "description": "Domain line under the card title.", "default": "hyperframes.heygen.com" },
|
||||
{ "id": "reactionMessage", "type": "string", "role": "content", "label": "Link reaction", "description": "Incoming reaction immediately after the shared link.", "default": "OMG IT'S HTML" },
|
||||
{ "id": "reactionEmoji", "type": "string", "role": "content", "label": "Reaction emoji", "description": "Emoji-only reaction after the shared link.", "default": "🤯🤯🤯" },
|
||||
{ "id": "benefitMessage", "type": "string", "role": "content", "label": "Benefit reply", "description": "Typed outgoing reply that names the primary benefit.", "default": "renders in 4K. no editor" },
|
||||
{ "id": "discoveryMessage", "type": "string", "role": "content", "label": "Discovery question", "description": "Incoming question asking where the product was found.", "default": "where did u find this" },
|
||||
{ "id": "sourceMessage", "type": "string", "role": "content", "label": "Source reply", "description": "Typed outgoing reply naming where to find the product.", "default": "on heygen" },
|
||||
{ "id": "workflowMessage", "type": "string", "role": "content", "label": "Workflow reply", "description": "Typed outgoing reply describing how the product works.", "default": "u just write plain html tags" },
|
||||
{ "id": "ownershipMessage", "type": "string", "role": "content", "label": "Ownership reply", "description": "Typed outgoing reply that closes the product explanation.", "default": "the code is yours forever" },
|
||||
{ "id": "installMessage", "type": "string", "role": "content", "label": "Intent reply", "description": "Incoming message expressing intent to try the product.", "default": "installing rn" },
|
||||
{ "id": "thanksMessage", "type": "string", "role": "content", "label": "Closing reply", "description": "Final incoming message in the conversation.", "default": "ty bestie 💚" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent horizontal wordmark on the closing card.", "default": "assets/hyperframes-logo-black.svg" },
|
||||
{ "id": "ecProof", "type": "string", "role": "content", "label": "End-card proof", "description": "Social-proof line under the stars.", "default": "12,000+ creators" },
|
||||
{ "id": "ecFeature1", "type": "string", "role": "content", "label": "End-card feature 1", "description": "First two-line benefit; use | to break the line.", "default": "Write|plain HTML" },
|
||||
{ "id": "ecFeature2", "type": "string", "role": "content", "label": "End-card feature 2", "description": "Second two-line benefit; use | to break the line.", "default": "Render|pixel-perfect" },
|
||||
{ "id": "ecFeature3", "type": "string", "role": "content", "label": "End-card feature 3", "description": "Third two-line benefit; use | to break the line.", "default": "Own|every line" },
|
||||
{ "id": "ecCta", "type": "string", "role": "content", "label": "End-card CTA", "description": "Label on the closing card button.", "default": "Start rendering free" }
|
||||
]'
|
||||
>
|
||||
@@ -572,7 +588,14 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv">
|
||||
<div class="bubble recv">what r u using for the launch video??</div>
|
||||
<div
|
||||
class="bubble recv"
|
||||
id="mtr-message-question"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
what r u using for the launch video??
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -600,7 +623,14 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent tail-sent">wait look 👀</div>
|
||||
<div
|
||||
class="bubble sent tail-sent"
|
||||
id="mtr-message-teaser"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
wait look 👀
|
||||
</div>
|
||||
<div class="delivered">Delivered</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -613,7 +643,12 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="card">
|
||||
<img class="cardimg" src="assets/card-image.jpg" alt="" />
|
||||
<img
|
||||
class="cardimg"
|
||||
data-var-src="cardImage"
|
||||
src="assets/card-image.jpg"
|
||||
alt=""
|
||||
/>
|
||||
<div class="cardmeta">
|
||||
<div class="cardtxt">
|
||||
<div class="cardtitle">
|
||||
@@ -633,7 +668,16 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="bubble recv">OMG IT'S HTML</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="bubble recv"
|
||||
id="mtr-message-reaction"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
OMG IT'S HTML
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item recv"
|
||||
@@ -642,7 +686,16 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="emojirow">🤯🤯🤯</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="emojirow"
|
||||
id="mtr-message-emoji"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
🤯🤯🤯
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item sent"
|
||||
@@ -652,7 +705,14 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent tail-sent">renders in 4K. no editor</div>
|
||||
<div
|
||||
class="bubble sent tail-sent"
|
||||
id="mtr-message-benefit"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
renders in 4K. no editor
|
||||
</div>
|
||||
<div class="delivered">Delivered</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -681,7 +741,14 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv">
|
||||
<div class="bubble recv tail-recv">where did u find this</div>
|
||||
<div
|
||||
class="bubble recv tail-recv"
|
||||
id="mtr-message-discovery"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
where did u find this
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -691,7 +758,16 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent"><div class="bubble sent">on heygen</div></div>
|
||||
<div class="pop pop-sent">
|
||||
<div
|
||||
class="bubble sent"
|
||||
id="mtr-message-source"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
on heygen
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item sent"
|
||||
@@ -701,7 +777,14 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent">u just write plain html tags</div>
|
||||
<div
|
||||
class="bubble sent"
|
||||
id="mtr-message-workflow"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
u just write plain html tags
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -712,7 +795,14 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent tail-sent">the code is yours forever</div>
|
||||
<div
|
||||
class="bubble sent tail-sent"
|
||||
id="mtr-message-ownership"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
the code is yours forever
|
||||
</div>
|
||||
<div class="delivered">Delivered</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -723,7 +813,16 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="bubble recv">installing rn</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="bubble recv"
|
||||
id="mtr-message-install"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
installing rn
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item recv"
|
||||
@@ -732,7 +831,16 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="bubble recv tail-recv">ty bestie 💚</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="bubble recv tail-recv"
|
||||
id="mtr-message-thanks"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
ty bestie 💚
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mtr-plusbtn">+</div>
|
||||
@@ -924,7 +1032,12 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
style="z-index: 5"
|
||||
>
|
||||
<div id="mtr-ec-wrap" data-layout-allow-overlap data-layout-allow-occlusion>
|
||||
<img id="mtr-ec-logo" src="assets/hyperframes-logo-black.svg" alt="HyperFrames" />
|
||||
<img
|
||||
id="mtr-ec-logo"
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-black.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<div id="mtr-ec-stars">
|
||||
<svg width="55" height="53" viewBox="0 0 24 23">
|
||||
<path
|
||||
@@ -982,15 +1095,15 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ec-label" style="left: 100px">
|
||||
<div class="ec-label" id="mtr-ec-feature-1" style="left: 100px">
|
||||
<div>Write</div>
|
||||
<div>plain HTML</div>
|
||||
</div>
|
||||
<div class="ec-label" style="left: 420px">
|
||||
<div class="ec-label" id="mtr-ec-feature-2" style="left: 420px">
|
||||
<div>Render</div>
|
||||
<div>pixel-perfect</div>
|
||||
</div>
|
||||
<div class="ec-label" style="left: 740px">
|
||||
<div class="ec-label" id="mtr-ec-feature-3" style="left: 740px">
|
||||
<div>Own</div>
|
||||
<div>every line</div>
|
||||
</div>
|
||||
@@ -1021,6 +1134,58 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
chev.className = "chev";
|
||||
chev.textContent = "\u203A";
|
||||
namePill.appendChild(chev);
|
||||
function setText(id, value) {
|
||||
document.getElementById(id).textContent = value;
|
||||
}
|
||||
function setTyped(group, value) {
|
||||
var frames = Array.from(document.querySelectorAll('[id^="mtr-ty-' + group + '-"]')).sort(
|
||||
function (a, b) {
|
||||
return Number(a.id.split("-").pop()) - Number(b.id.split("-").pop());
|
||||
},
|
||||
);
|
||||
var characters = Array.from(value);
|
||||
frames.forEach(function (frame, index) {
|
||||
var prefixLength = Math.max(
|
||||
1,
|
||||
Math.ceil((characters.length * (index + 1)) / frames.length),
|
||||
);
|
||||
var textNode = Array.from(frame.childNodes).find(function (node) {
|
||||
return node.nodeType === 3;
|
||||
});
|
||||
if (textNode) textNode.nodeValue = characters.slice(0, prefixLength).join("");
|
||||
});
|
||||
}
|
||||
function setTwoLines(id, value) {
|
||||
var lines = value.split("|").slice(0, 2);
|
||||
var container = document.getElementById(id);
|
||||
Array.from(container.children).forEach(function (line, index) {
|
||||
line.textContent = lines[index] || lines[0] || "";
|
||||
});
|
||||
}
|
||||
var teaserMessage = text(vars.teaserMessage, "wait look 👀", 20);
|
||||
var benefitMessage = text(vars.benefitMessage, "renders in 4K. no editor", 32);
|
||||
var sourceMessage = text(vars.sourceMessage, "on heygen", 20);
|
||||
var workflowMessage = text(vars.workflowMessage, "u just write plain html tags", 34);
|
||||
var ownershipMessage = text(vars.ownershipMessage, "the code is yours forever", 32);
|
||||
setText(
|
||||
"mtr-message-question",
|
||||
text(vars.questionMessage, "what r u using for the launch video??", 46),
|
||||
);
|
||||
setText("mtr-message-teaser", teaserMessage);
|
||||
setText("mtr-message-reaction", text(vars.reactionMessage, "OMG IT'S HTML", 24));
|
||||
setText("mtr-message-emoji", text(vars.reactionEmoji, "🤯🤯🤯", 12));
|
||||
setText("mtr-message-benefit", benefitMessage);
|
||||
setText("mtr-message-discovery", text(vars.discoveryMessage, "where did u find this", 28));
|
||||
setText("mtr-message-source", sourceMessage);
|
||||
setText("mtr-message-workflow", workflowMessage);
|
||||
setText("mtr-message-ownership", ownershipMessage);
|
||||
setText("mtr-message-install", text(vars.installMessage, "installing rn", 20));
|
||||
setText("mtr-message-thanks", text(vars.thanksMessage, "ty bestie 💚", 20));
|
||||
setTyped(1, teaserMessage);
|
||||
setTyped(2, benefitMessage);
|
||||
setTyped(3, sourceMessage);
|
||||
setTyped(4, workflowMessage);
|
||||
setTyped(5, ownershipMessage);
|
||||
document.querySelector(".cardtitle").textContent = text(
|
||||
vars.cardTitle,
|
||||
"HyperFrames | Write HTML, render pixel-perfect video",
|
||||
@@ -1036,6 +1201,9 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
"12,000+ creators",
|
||||
30,
|
||||
);
|
||||
setTwoLines("mtr-ec-feature-1", text(vars.ecFeature1, "Write|plain HTML", 32));
|
||||
setTwoLines("mtr-ec-feature-2", text(vars.ecFeature2, "Render|pixel-perfect", 32));
|
||||
setTwoLines("mtr-ec-feature-3", text(vars.ecFeature3, "Own|every line", 32));
|
||||
document.getElementById("mtr-ec-cta").textContent = text(
|
||||
vars.ecCta,
|
||||
"Start rendering free",
|
||||
@@ -1477,7 +1645,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
|
||||
<InstallCommand command="npx hyperframes add message-thread-reveal" item="message-thread-reveal" />
|
||||
|
||||
That writes `compositions/message-thread-reveal.html`, plus 2 supporting files under `assets/`.
|
||||
That writes `compositions/message-thread-reveal.html`, plus 3 supporting files under `assets/`.
|
||||
|
||||
## Add it to your video
|
||||
|
||||
@@ -1506,9 +1674,25 @@ want to change on the element:
|
||||
| Variable | Default | Accepts | What it does |
|
||||
| --- | --- | --- | --- |
|
||||
| `contactName` | `Rachel` | string | Name pill in the chat header; the avatar shows its first letter. |
|
||||
| `questionMessage` | `what r u using for the launch video??` | string | First incoming message that establishes what the conversation is about. |
|
||||
| `teaserMessage` | `wait look 👀` | string | First typed outgoing reply before the shared link card. |
|
||||
| `cardImage` | `assets/card-image.jpg` | image | Preview image on the shared link card. |
|
||||
| `cardTitle` | `HyperFrames | Write HTML, render pixel-perfect video` | string | Title on the shared link card. |
|
||||
| `cardDomain` | `hyperframes.heygen.com` | string | Domain line under the card title. |
|
||||
| `reactionMessage` | `OMG IT'S HTML` | string | Incoming reaction immediately after the shared link. |
|
||||
| `reactionEmoji` | `🤯🤯🤯` | string | Emoji-only reaction after the shared link. |
|
||||
| `benefitMessage` | `renders in 4K. no editor` | string | Typed outgoing reply that names the primary benefit. |
|
||||
| `discoveryMessage` | `where did u find this` | string | Incoming question asking where the product was found. |
|
||||
| `sourceMessage` | `on heygen` | string | Typed outgoing reply naming where to find the product. |
|
||||
| `workflowMessage` | `u just write plain html tags` | string | Typed outgoing reply describing how the product works. |
|
||||
| `ownershipMessage` | `the code is yours forever` | string | Typed outgoing reply that closes the product explanation. |
|
||||
| `installMessage` | `installing rn` | string | Incoming message expressing intent to try the product. |
|
||||
| `thanksMessage` | `ty bestie 💚` | string | Final incoming message in the conversation. |
|
||||
| `brandLogo` | `assets/hyperframes-logo-black.svg` | image | Transparent horizontal wordmark on the closing card. |
|
||||
| `ecProof` | `12,000+ creators` | string | Social-proof line under the stars. |
|
||||
| `ecFeature1` | `Write|plain HTML` | string | First two-line benefit; use | to break the line. |
|
||||
| `ecFeature2` | `Render|pixel-perfect` | string | Second two-line benefit; use | to break the line. |
|
||||
| `ecFeature3` | `Own|every line` | string | Third two-line benefit; use | to break the line. |
|
||||
| `ecCta` | `Start rendering free` | string | Label on the closing card button. |
|
||||
|
||||
Set them with `data-variable-values` on the element that mounts it. These are the
|
||||
@@ -1518,7 +1702,7 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
<div
|
||||
data-composition-id="message-thread-reveal"
|
||||
data-composition-src="compositions/message-thread-reveal.html"
|
||||
data-variable-values='{"contactName":"Rachel","cardTitle":"HyperFrames | Write HTML, render pixel-perfect video","cardDomain":"hyperframes.heygen.com","ecProof":"12,000+ creators","ecCta":"Start rendering free"}'
|
||||
data-variable-values='{"contactName":"Rachel","questionMessage":"what r u using for the launch video??","teaserMessage":"wait look 👀","cardImage":"assets/card-image.jpg","cardTitle":"HyperFrames | Write HTML, render pixel-perfect video","cardDomain":"hyperframes.heygen.com","reactionMessage":"OMG IT'S HTML","reactionEmoji":"🤯🤯🤯","benefitMessage":"renders in 4K. no editor","discoveryMessage":"where did u find this","sourceMessage":"on heygen","workflowMessage":"u just write plain html tags","ownershipMessage":"the code is yours forever","installMessage":"installing rn","thanksMessage":"ty bestie 💚","brandLogo":"assets/hyperframes-logo-black.svg","ecProof":"12,000+ creators","ecFeature1":"Write|plain HTML","ecFeature2":"Render|pixel-perfect","ecFeature3":"Own|every line","ecCta":"Start rendering free"}'
|
||||
></div>
|
||||
```
|
||||
|
||||
@@ -1532,9 +1716,25 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
lang="en"
|
||||
data-composition-variables='[
|
||||
{ "id": "contactName", "type": "string", "role": "content", "label": "Contact name", "description": "Name pill in the chat header; the avatar shows its first letter.", "default": "Rachel" },
|
||||
{ "id": "questionMessage", "type": "string", "role": "content", "label": "Opening question", "description": "First incoming message that establishes what the conversation is about.", "default": "what r u using for the launch video??" },
|
||||
{ "id": "teaserMessage", "type": "string", "role": "content", "label": "Teaser reply", "description": "First typed outgoing reply before the shared link card.", "default": "wait look 👀" },
|
||||
{ "id": "cardImage", "type": "image", "role": "content", "label": "Link card image", "description": "Preview image on the shared link card.", "default": "assets/card-image.jpg" },
|
||||
{ "id": "cardTitle", "type": "string", "role": "content", "label": "Link card title", "description": "Title on the shared link card.", "default": "HyperFrames | Write HTML, render pixel-perfect video" },
|
||||
{ "id": "cardDomain", "type": "string", "role": "content", "label": "Link card domain", "description": "Domain line under the card title.", "default": "hyperframes.heygen.com" },
|
||||
{ "id": "reactionMessage", "type": "string", "role": "content", "label": "Link reaction", "description": "Incoming reaction immediately after the shared link.", "default": "OMG IT'S HTML" },
|
||||
{ "id": "reactionEmoji", "type": "string", "role": "content", "label": "Reaction emoji", "description": "Emoji-only reaction after the shared link.", "default": "🤯🤯🤯" },
|
||||
{ "id": "benefitMessage", "type": "string", "role": "content", "label": "Benefit reply", "description": "Typed outgoing reply that names the primary benefit.", "default": "renders in 4K. no editor" },
|
||||
{ "id": "discoveryMessage", "type": "string", "role": "content", "label": "Discovery question", "description": "Incoming question asking where the product was found.", "default": "where did u find this" },
|
||||
{ "id": "sourceMessage", "type": "string", "role": "content", "label": "Source reply", "description": "Typed outgoing reply naming where to find the product.", "default": "on heygen" },
|
||||
{ "id": "workflowMessage", "type": "string", "role": "content", "label": "Workflow reply", "description": "Typed outgoing reply describing how the product works.", "default": "u just write plain html tags" },
|
||||
{ "id": "ownershipMessage", "type": "string", "role": "content", "label": "Ownership reply", "description": "Typed outgoing reply that closes the product explanation.", "default": "the code is yours forever" },
|
||||
{ "id": "installMessage", "type": "string", "role": "content", "label": "Intent reply", "description": "Incoming message expressing intent to try the product.", "default": "installing rn" },
|
||||
{ "id": "thanksMessage", "type": "string", "role": "content", "label": "Closing reply", "description": "Final incoming message in the conversation.", "default": "ty bestie 💚" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent horizontal wordmark on the closing card.", "default": "assets/hyperframes-logo-black.svg" },
|
||||
{ "id": "ecProof", "type": "string", "role": "content", "label": "End-card proof", "description": "Social-proof line under the stars.", "default": "12,000+ creators" },
|
||||
{ "id": "ecFeature1", "type": "string", "role": "content", "label": "End-card feature 1", "description": "First two-line benefit; use | to break the line.", "default": "Write|plain HTML" },
|
||||
{ "id": "ecFeature2", "type": "string", "role": "content", "label": "End-card feature 2", "description": "Second two-line benefit; use | to break the line.", "default": "Render|pixel-perfect" },
|
||||
{ "id": "ecFeature3", "type": "string", "role": "content", "label": "End-card feature 3", "description": "Third two-line benefit; use | to break the line.", "default": "Own|every line" },
|
||||
{ "id": "ecCta", "type": "string", "role": "content", "label": "End-card CTA", "description": "Label on the closing card button.", "default": "Start rendering free" }
|
||||
]'
|
||||
>
|
||||
@@ -2085,7 +2285,14 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv">
|
||||
<div class="bubble recv">what r u using for the launch video??</div>
|
||||
<div
|
||||
class="bubble recv"
|
||||
id="mtr-message-question"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
what r u using for the launch video??
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -2113,7 +2320,14 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent tail-sent">wait look 👀</div>
|
||||
<div
|
||||
class="bubble sent tail-sent"
|
||||
id="mtr-message-teaser"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
wait look 👀
|
||||
</div>
|
||||
<div class="delivered">Delivered</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2126,7 +2340,12 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="card">
|
||||
<img class="cardimg" src="assets/card-image.jpg" alt="" />
|
||||
<img
|
||||
class="cardimg"
|
||||
data-var-src="cardImage"
|
||||
src="assets/card-image.jpg"
|
||||
alt=""
|
||||
/>
|
||||
<div class="cardmeta">
|
||||
<div class="cardtxt">
|
||||
<div class="cardtitle">
|
||||
@@ -2146,7 +2365,16 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="bubble recv">OMG IT'S HTML</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="bubble recv"
|
||||
id="mtr-message-reaction"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
OMG IT'S HTML
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item recv"
|
||||
@@ -2155,7 +2383,16 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="emojirow">🤯🤯🤯</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="emojirow"
|
||||
id="mtr-message-emoji"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
🤯🤯🤯
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item sent"
|
||||
@@ -2165,7 +2402,14 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent tail-sent">renders in 4K. no editor</div>
|
||||
<div
|
||||
class="bubble sent tail-sent"
|
||||
id="mtr-message-benefit"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
renders in 4K. no editor
|
||||
</div>
|
||||
<div class="delivered">Delivered</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2194,7 +2438,14 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv">
|
||||
<div class="bubble recv tail-recv">where did u find this</div>
|
||||
<div
|
||||
class="bubble recv tail-recv"
|
||||
id="mtr-message-discovery"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
where did u find this
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -2204,7 +2455,16 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent"><div class="bubble sent">on heygen</div></div>
|
||||
<div class="pop pop-sent">
|
||||
<div
|
||||
class="bubble sent"
|
||||
id="mtr-message-source"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
on heygen
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item sent"
|
||||
@@ -2214,7 +2474,14 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent">u just write plain html tags</div>
|
||||
<div
|
||||
class="bubble sent"
|
||||
id="mtr-message-workflow"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
u just write plain html tags
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -2225,7 +2492,14 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent tail-sent">the code is yours forever</div>
|
||||
<div
|
||||
class="bubble sent tail-sent"
|
||||
id="mtr-message-ownership"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
the code is yours forever
|
||||
</div>
|
||||
<div class="delivered">Delivered</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2236,7 +2510,16 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="bubble recv">installing rn</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="bubble recv"
|
||||
id="mtr-message-install"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
installing rn
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item recv"
|
||||
@@ -2245,7 +2528,16 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="bubble recv tail-recv">ty bestie 💚</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="bubble recv tail-recv"
|
||||
id="mtr-message-thanks"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
ty bestie 💚
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mtr-plusbtn">+</div>
|
||||
@@ -2437,7 +2729,12 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
style="z-index: 5"
|
||||
>
|
||||
<div id="mtr-ec-wrap" data-layout-allow-overlap data-layout-allow-occlusion>
|
||||
<img id="mtr-ec-logo" src="assets/hyperframes-logo-black.svg" alt="HyperFrames" />
|
||||
<img
|
||||
id="mtr-ec-logo"
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-black.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<div id="mtr-ec-stars">
|
||||
<svg width="55" height="53" viewBox="0 0 24 23">
|
||||
<path
|
||||
@@ -2495,15 +2792,15 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ec-label" style="left: 100px">
|
||||
<div class="ec-label" id="mtr-ec-feature-1" style="left: 100px">
|
||||
<div>Write</div>
|
||||
<div>plain HTML</div>
|
||||
</div>
|
||||
<div class="ec-label" style="left: 420px">
|
||||
<div class="ec-label" id="mtr-ec-feature-2" style="left: 420px">
|
||||
<div>Render</div>
|
||||
<div>pixel-perfect</div>
|
||||
</div>
|
||||
<div class="ec-label" style="left: 740px">
|
||||
<div class="ec-label" id="mtr-ec-feature-3" style="left: 740px">
|
||||
<div>Own</div>
|
||||
<div>every line</div>
|
||||
</div>
|
||||
@@ -2534,6 +2831,58 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
chev.className = "chev";
|
||||
chev.textContent = "\u203A";
|
||||
namePill.appendChild(chev);
|
||||
function setText(id, value) {
|
||||
document.getElementById(id).textContent = value;
|
||||
}
|
||||
function setTyped(group, value) {
|
||||
var frames = Array.from(document.querySelectorAll('[id^="mtr-ty-' + group + '-"]')).sort(
|
||||
function (a, b) {
|
||||
return Number(a.id.split("-").pop()) - Number(b.id.split("-").pop());
|
||||
},
|
||||
);
|
||||
var characters = Array.from(value);
|
||||
frames.forEach(function (frame, index) {
|
||||
var prefixLength = Math.max(
|
||||
1,
|
||||
Math.ceil((characters.length * (index + 1)) / frames.length),
|
||||
);
|
||||
var textNode = Array.from(frame.childNodes).find(function (node) {
|
||||
return node.nodeType === 3;
|
||||
});
|
||||
if (textNode) textNode.nodeValue = characters.slice(0, prefixLength).join("");
|
||||
});
|
||||
}
|
||||
function setTwoLines(id, value) {
|
||||
var lines = value.split("|").slice(0, 2);
|
||||
var container = document.getElementById(id);
|
||||
Array.from(container.children).forEach(function (line, index) {
|
||||
line.textContent = lines[index] || lines[0] || "";
|
||||
});
|
||||
}
|
||||
var teaserMessage = text(vars.teaserMessage, "wait look 👀", 20);
|
||||
var benefitMessage = text(vars.benefitMessage, "renders in 4K. no editor", 32);
|
||||
var sourceMessage = text(vars.sourceMessage, "on heygen", 20);
|
||||
var workflowMessage = text(vars.workflowMessage, "u just write plain html tags", 34);
|
||||
var ownershipMessage = text(vars.ownershipMessage, "the code is yours forever", 32);
|
||||
setText(
|
||||
"mtr-message-question",
|
||||
text(vars.questionMessage, "what r u using for the launch video??", 46),
|
||||
);
|
||||
setText("mtr-message-teaser", teaserMessage);
|
||||
setText("mtr-message-reaction", text(vars.reactionMessage, "OMG IT'S HTML", 24));
|
||||
setText("mtr-message-emoji", text(vars.reactionEmoji, "🤯🤯🤯", 12));
|
||||
setText("mtr-message-benefit", benefitMessage);
|
||||
setText("mtr-message-discovery", text(vars.discoveryMessage, "where did u find this", 28));
|
||||
setText("mtr-message-source", sourceMessage);
|
||||
setText("mtr-message-workflow", workflowMessage);
|
||||
setText("mtr-message-ownership", ownershipMessage);
|
||||
setText("mtr-message-install", text(vars.installMessage, "installing rn", 20));
|
||||
setText("mtr-message-thanks", text(vars.thanksMessage, "ty bestie 💚", 20));
|
||||
setTyped(1, teaserMessage);
|
||||
setTyped(2, benefitMessage);
|
||||
setTyped(3, sourceMessage);
|
||||
setTyped(4, workflowMessage);
|
||||
setTyped(5, ownershipMessage);
|
||||
document.querySelector(".cardtitle").textContent = text(
|
||||
vars.cardTitle,
|
||||
"HyperFrames | Write HTML, render pixel-perfect video",
|
||||
@@ -2549,6 +2898,9 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
"12,000+ creators",
|
||||
30,
|
||||
);
|
||||
setTwoLines("mtr-ec-feature-1", text(vars.ecFeature1, "Write|plain HTML", 32));
|
||||
setTwoLines("mtr-ec-feature-2", text(vars.ecFeature2, "Render|pixel-perfect", 32));
|
||||
setTwoLines("mtr-ec-feature-3", text(vars.ecFeature3, "Own|every line", 32));
|
||||
document.getElementById("mtr-ec-cta").textContent = text(
|
||||
vars.ecCta,
|
||||
"Start rendering free",
|
||||
|
||||
@@ -1474,7 +1474,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
|
||||
<InstallCommand command="npx hyperframes add notes-reveal" item="notes-reveal" />
|
||||
|
||||
That writes `compositions/notes-reveal.html`, plus 3 supporting files under `assets/`.
|
||||
That writes `compositions/notes-reveal.html`, plus 4 supporting files under `assets/`.
|
||||
|
||||
## Add it to your video
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
previewSrc="/public/catalog/blocks/notification-cascade.json"
|
||||
compositionId="notification-cascade"
|
||||
compositionSrc="compositions/notification-cascade.html"
|
||||
variables={[{"id":"notifTitle","type":"string","role":"content","label":"Notification title","description":"Bold first line on every banner.","default":"New render"},{"id":"message1","type":"string","role":"content","label":"Message 1","description":"Subtitle of the first banner to land.","default":"Launch video is ready."},{"id":"message2","type":"string","role":"content","label":"Message 2","description":"Subtitle of the second banner.","default":"All checks passed."},{"id":"message3","type":"string","role":"content","label":"Message 3","description":"Subtitle of the third banner.","default":"4K render done in 92s."},{"id":"message4","type":"string","role":"content","label":"Message 4","description":"Subtitle of the fourth banner.","default":"Published to the catalog."},{"id":"appName","type":"string","role":"content","label":"App name","description":"Small credit in the corner of every banner.","default":"HyperFrames"},{"id":"headlineTop","type":"string","role":"content","label":"End-card line 1","description":"First line of the closing card.","default":"SHIP VIDEO"},{"id":"headlineAccent","type":"string","role":"content","label":"End-card line 2","description":"Accented second line of the closing card.","default":"FROM HTML"},{"id":"footerText","type":"string","role":"content","label":"End-card footer","description":"URL or call to action under the headline.","default":"hyperframes.heygen.com"}]}
|
||||
variables={[{"id":"notifTitle","type":"string","role":"content","label":"Notification title","description":"Bold first line on every banner.","default":"New render"},{"id":"message1","type":"string","role":"content","label":"Message 1","description":"Subtitle of the first banner to land.","default":"Launch video is ready."},{"id":"message2","type":"string","role":"content","label":"Message 2","description":"Subtitle of the second banner.","default":"All checks passed."},{"id":"message3","type":"string","role":"content","label":"Message 3","description":"Subtitle of the third banner.","default":"4K render done in 92s."},{"id":"message4","type":"string","role":"content","label":"Message 4","description":"Subtitle of the fourth banner.","default":"Published to the catalog."},{"id":"appName","type":"string","role":"content","label":"App name","description":"Small credit in the corner of every banner.","default":"HyperFrames"},{"id":"headlineTop","type":"string","role":"content","label":"End-card line 1","description":"First line of the closing card.","default":"SHIP VIDEO"},{"id":"headlineAccent","type":"string","role":"content","label":"End-card line 2","description":"Accented second line of the closing card.","default":"FROM HTML"},{"id":"footerText","type":"string","role":"content","label":"End-card footer","description":"URL or call to action under the headline.","default":"hyperframes.heygen.com"},{"id":"brandLogo","type":"image","role":"content","label":"Brand logo","description":"Transparent logo centered on the closing card.","default":"assets/hyperframes-logo-white.svg"}]}
|
||||
>
|
||||
|
||||
```html notification-cascade.html
|
||||
@@ -26,7 +26,8 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
{ "id": "appName", "type": "string", "role": "content", "label": "App name", "description": "Small credit in the corner of every banner.", "default": "HyperFrames" },
|
||||
{ "id": "headlineTop", "type": "string", "role": "content", "label": "End-card line 1", "description": "First line of the closing card.", "default": "SHIP VIDEO" },
|
||||
{ "id": "headlineAccent", "type": "string", "role": "content", "label": "End-card line 2", "description": "Accented second line of the closing card.", "default": "FROM HTML" },
|
||||
{ "id": "footerText", "type": "string", "role": "content", "label": "End-card footer", "description": "URL or call to action under the headline.", "default": "hyperframes.heygen.com" }
|
||||
{ "id": "footerText", "type": "string", "role": "content", "label": "End-card footer", "description": "URL or call to action under the headline.", "default": "hyperframes.heygen.com" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent logo centered on the closing card.", "default": "assets/hyperframes-logo-white.svg" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
@@ -374,7 +375,12 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
<div id="nc-endcard-inner">
|
||||
<div id="nc-ec-top">SHIP VIDEO</div>
|
||||
<div id="nc-ec-accent">FROM HTML</div>
|
||||
<img id="nc-ec-mark" src="assets/hyperframes-logo-white.svg" alt="HyperFrames" />
|
||||
<img
|
||||
id="nc-ec-mark"
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-white.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<div id="nc-ec-footer">hyperframes.heygen.com</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -536,7 +542,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
|
||||
<InstallCommand command="npx hyperframes add notification-cascade" item="notification-cascade" />
|
||||
|
||||
That writes `compositions/notification-cascade.html`, plus 2 supporting files under `assets/`.
|
||||
That writes `compositions/notification-cascade.html`, plus 3 supporting files under `assets/`.
|
||||
|
||||
## Add it to your video
|
||||
|
||||
@@ -573,6 +579,7 @@ want to change on the element:
|
||||
| `headlineTop` | `SHIP VIDEO` | string | First line of the closing card. |
|
||||
| `headlineAccent` | `FROM HTML` | string | Accented second line of the closing card. |
|
||||
| `footerText` | `hyperframes.heygen.com` | string | URL or call to action under the headline. |
|
||||
| `brandLogo` | `assets/hyperframes-logo-white.svg` | image | Transparent logo centered on the closing card. |
|
||||
|
||||
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:
|
||||
@@ -581,7 +588,7 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
<div
|
||||
data-composition-id="notification-cascade"
|
||||
data-composition-src="compositions/notification-cascade.html"
|
||||
data-variable-values='{"notifTitle":"New render","message1":"Launch video is ready.","message2":"All checks passed.","message3":"4K render done in 92s.","message4":"Published to the catalog.","appName":"HyperFrames","headlineTop":"SHIP VIDEO","headlineAccent":"FROM HTML","footerText":"hyperframes.heygen.com"}'
|
||||
data-variable-values='{"notifTitle":"New render","message1":"Launch video is ready.","message2":"All checks passed.","message3":"4K render done in 92s.","message4":"Published to the catalog.","appName":"HyperFrames","headlineTop":"SHIP VIDEO","headlineAccent":"FROM HTML","footerText":"hyperframes.heygen.com","brandLogo":"assets/hyperframes-logo-white.svg"}'
|
||||
></div>
|
||||
```
|
||||
|
||||
@@ -602,7 +609,8 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
{ "id": "appName", "type": "string", "role": "content", "label": "App name", "description": "Small credit in the corner of every banner.", "default": "HyperFrames" },
|
||||
{ "id": "headlineTop", "type": "string", "role": "content", "label": "End-card line 1", "description": "First line of the closing card.", "default": "SHIP VIDEO" },
|
||||
{ "id": "headlineAccent", "type": "string", "role": "content", "label": "End-card line 2", "description": "Accented second line of the closing card.", "default": "FROM HTML" },
|
||||
{ "id": "footerText", "type": "string", "role": "content", "label": "End-card footer", "description": "URL or call to action under the headline.", "default": "hyperframes.heygen.com" }
|
||||
{ "id": "footerText", "type": "string", "role": "content", "label": "End-card footer", "description": "URL or call to action under the headline.", "default": "hyperframes.heygen.com" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent logo centered on the closing card.", "default": "assets/hyperframes-logo-white.svg" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
@@ -950,7 +958,12 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
<div id="nc-endcard-inner">
|
||||
<div id="nc-ec-top">SHIP VIDEO</div>
|
||||
<div id="nc-ec-accent">FROM HTML</div>
|
||||
<img id="nc-ec-mark" src="assets/hyperframes-logo-white.svg" alt="HyperFrames" />
|
||||
<img
|
||||
id="nc-ec-mark"
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-white.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<div id="nc-ec-footer">hyperframes.heygen.com</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
previewSrc="/public/catalog/blocks/share-sheet-carousel.json"
|
||||
compositionId="share-sheet-carousel"
|
||||
compositionSrc="compositions/share-sheet-carousel.html"
|
||||
variables={[{"id":"shareTitle","type":"string","role":"content","label":"Sheet title","description":"Heading at the top of the share sheet.","default":"Share"},{"id":"senderName","type":"string","role":"content","label":"Sender","description":"Bold name in the sheet subtitle.","default":"HyperFrames"},{"id":"itemLabel","type":"string","role":"content","label":"Item","description":"What the sender is offering, completing the sentence \"… would like to share …\".","default":"a video"},{"id":"stripText","type":"string","role":"content","label":"Brand strip","description":"Small-caps line under the preview, beside the logo.","default":"OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML"},{"id":"acceptLabel","type":"string","role":"content","label":"Accept label","description":"Right-hand action button.","default":"Accept"},{"id":"declineLabel","type":"string","role":"content","label":"Decline label","description":"Left-hand action button.","default":"Decline"}]}
|
||||
variables={[{"id":"shareTitle","type":"string","role":"content","label":"Sheet title","description":"Heading at the top of the share sheet.","default":"Share"},{"id":"senderName","type":"string","role":"content","label":"Sender","description":"Bold name in the sheet subtitle.","default":"HyperFrames"},{"id":"itemLabel","type":"string","role":"content","label":"Item","description":"What the sender is offering, completing the sentence \"… would like to share …\".","default":"a video"},{"id":"stripText","type":"string","role":"content","label":"Brand strip","description":"Small-caps line under the preview, beside the logo.","default":"OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML"},{"id":"acceptLabel","type":"string","role":"content","label":"Accept label","description":"Right-hand action button.","default":"Accept"},{"id":"declineLabel","type":"string","role":"content","label":"Decline label","description":"Left-hand action button.","default":"Decline"},{"id":"slideImage1","type":"image","role":"content","label":"Slide image 1","description":"First carousel image; also fills the blurred background.","default":"assets/slide-01.jpg"},{"id":"slideImage2","type":"image","role":"content","label":"Slide image 2","description":"Second carousel image; also fills the blurred background.","default":"assets/slide-02.jpg"},{"id":"slideImage3","type":"image","role":"content","label":"Slide image 3","description":"Third carousel image; also fills the blurred background.","default":"assets/slide-03.jpg"},{"id":"slideImage4","type":"image","role":"content","label":"Slide image 4","description":"Fourth carousel image; also fills the blurred background.","default":"assets/slide-04.jpg"},{"id":"brandLogo","type":"image","role":"content","label":"Brand logo","description":"Transparent horizontal wordmark in the preview strip.","default":"assets/hyperframes-logo-black.svg"}]}
|
||||
>
|
||||
|
||||
```html share-sheet-carousel.html
|
||||
@@ -23,7 +23,12 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
{ "id": "itemLabel", "type": "string", "role": "content", "label": "Item", "description": "What the sender is offering, completing the sentence \"… would like to share …\".", "default": "a video" },
|
||||
{ "id": "stripText", "type": "string", "role": "content", "label": "Brand strip", "description": "Small-caps line under the preview, beside the logo.", "default": "OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML" },
|
||||
{ "id": "acceptLabel", "type": "string", "role": "content", "label": "Accept label", "description": "Right-hand action button.", "default": "Accept" },
|
||||
{ "id": "declineLabel", "type": "string", "role": "content", "label": "Decline label", "description": "Left-hand action button.", "default": "Decline" }
|
||||
{ "id": "declineLabel", "type": "string", "role": "content", "label": "Decline label", "description": "Left-hand action button.", "default": "Decline" },
|
||||
{ "id": "slideImage1", "type": "image", "role": "content", "label": "Slide image 1", "description": "First carousel image; also fills the blurred background.", "default": "assets/slide-01.jpg" },
|
||||
{ "id": "slideImage2", "type": "image", "role": "content", "label": "Slide image 2", "description": "Second carousel image; also fills the blurred background.", "default": "assets/slide-02.jpg" },
|
||||
{ "id": "slideImage3", "type": "image", "role": "content", "label": "Slide image 3", "description": "Third carousel image; also fills the blurred background.", "default": "assets/slide-03.jpg" },
|
||||
{ "id": "slideImage4", "type": "image", "role": "content", "label": "Slide image 4", "description": "Fourth carousel image; also fills the blurred background.", "default": "assets/slide-04.jpg" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent horizontal wordmark in the preview strip.", "default": "assets/hyperframes-logo-black.svg" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
@@ -218,10 +223,38 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
data-duration="7.2333"
|
||||
data-track-index="1"
|
||||
>
|
||||
<img class="ssc-bg" id="ssc-bg-1" src="assets/slide-01.jpg" alt="" style="opacity: 1" />
|
||||
<img class="ssc-bg" id="ssc-bg-2" src="assets/slide-02.jpg" alt="" style="opacity: 0" />
|
||||
<img class="ssc-bg" id="ssc-bg-3" src="assets/slide-03.jpg" alt="" style="opacity: 0" />
|
||||
<img class="ssc-bg" id="ssc-bg-4" src="assets/slide-04.jpg" alt="" style="opacity: 0" />
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-1"
|
||||
data-var-src="slideImage1"
|
||||
src="assets/slide-01.jpg"
|
||||
alt=""
|
||||
style="opacity: 1"
|
||||
/>
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-2"
|
||||
data-var-src="slideImage2"
|
||||
src="assets/slide-02.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-3"
|
||||
data-var-src="slideImage3"
|
||||
src="assets/slide-03.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-4"
|
||||
data-var-src="slideImage4"
|
||||
src="assets/slide-04.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<div id="ssc-card">
|
||||
<div id="ssc-cardclipper">
|
||||
<div id="ssc-title">Share</div>
|
||||
@@ -230,6 +263,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-1"
|
||||
data-var-src="slideImage1"
|
||||
src="assets/slide-01.jpg"
|
||||
alt=""
|
||||
style="opacity: 1"
|
||||
@@ -237,6 +271,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-2"
|
||||
data-var-src="slideImage2"
|
||||
src="assets/slide-02.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
@@ -244,6 +279,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-3"
|
||||
data-var-src="slideImage3"
|
||||
src="assets/slide-03.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
@@ -251,12 +287,17 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-4"
|
||||
data-var-src="slideImage4"
|
||||
src="assets/slide-04.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<div id="ssc-strip">
|
||||
<img src="assets/hyperframes-logo-black.svg" alt="HyperFrames" />
|
||||
<img
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-black.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<div id="ssc-strip-text">OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -373,7 +414,7 @@ import { VariablesExplorer } from "/snippets/variables-explorer.jsx";
|
||||
|
||||
<InstallCommand command="npx hyperframes add share-sheet-carousel" item="share-sheet-carousel" />
|
||||
|
||||
That writes `compositions/share-sheet-carousel.html`, plus 5 supporting files under `assets/`.
|
||||
That writes `compositions/share-sheet-carousel.html`, plus 6 supporting files under `assets/`.
|
||||
|
||||
## Add it to your video
|
||||
|
||||
@@ -407,6 +448,11 @@ want to change on the element:
|
||||
| `stripText` | `OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML` | string | Small-caps line under the preview, beside the logo. |
|
||||
| `acceptLabel` | `Accept` | string | Right-hand action button. |
|
||||
| `declineLabel` | `Decline` | string | Left-hand action button. |
|
||||
| `slideImage1` | `assets/slide-01.jpg` | image | First carousel image; also fills the blurred background. |
|
||||
| `slideImage2` | `assets/slide-02.jpg` | image | Second carousel image; also fills the blurred background. |
|
||||
| `slideImage3` | `assets/slide-03.jpg` | image | Third carousel image; also fills the blurred background. |
|
||||
| `slideImage4` | `assets/slide-04.jpg` | image | Fourth carousel image; also fills the blurred background. |
|
||||
| `brandLogo` | `assets/hyperframes-logo-black.svg` | image | Transparent horizontal wordmark in the preview strip. |
|
||||
|
||||
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:
|
||||
@@ -415,7 +461,7 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
<div
|
||||
data-composition-id="share-sheet-carousel"
|
||||
data-composition-src="compositions/share-sheet-carousel.html"
|
||||
data-variable-values='{"shareTitle":"Share","senderName":"HyperFrames","itemLabel":"a video","stripText":"OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML","acceptLabel":"Accept","declineLabel":"Decline"}'
|
||||
data-variable-values='{"shareTitle":"Share","senderName":"HyperFrames","itemLabel":"a video","stripText":"OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML","acceptLabel":"Accept","declineLabel":"Decline","slideImage1":"assets/slide-01.jpg","slideImage2":"assets/slide-02.jpg","slideImage3":"assets/slide-03.jpg","slideImage4":"assets/slide-04.jpg","brandLogo":"assets/hyperframes-logo-black.svg"}'
|
||||
></div>
|
||||
```
|
||||
|
||||
@@ -433,7 +479,12 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
{ "id": "itemLabel", "type": "string", "role": "content", "label": "Item", "description": "What the sender is offering, completing the sentence \"… would like to share …\".", "default": "a video" },
|
||||
{ "id": "stripText", "type": "string", "role": "content", "label": "Brand strip", "description": "Small-caps line under the preview, beside the logo.", "default": "OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML" },
|
||||
{ "id": "acceptLabel", "type": "string", "role": "content", "label": "Accept label", "description": "Right-hand action button.", "default": "Accept" },
|
||||
{ "id": "declineLabel", "type": "string", "role": "content", "label": "Decline label", "description": "Left-hand action button.", "default": "Decline" }
|
||||
{ "id": "declineLabel", "type": "string", "role": "content", "label": "Decline label", "description": "Left-hand action button.", "default": "Decline" },
|
||||
{ "id": "slideImage1", "type": "image", "role": "content", "label": "Slide image 1", "description": "First carousel image; also fills the blurred background.", "default": "assets/slide-01.jpg" },
|
||||
{ "id": "slideImage2", "type": "image", "role": "content", "label": "Slide image 2", "description": "Second carousel image; also fills the blurred background.", "default": "assets/slide-02.jpg" },
|
||||
{ "id": "slideImage3", "type": "image", "role": "content", "label": "Slide image 3", "description": "Third carousel image; also fills the blurred background.", "default": "assets/slide-03.jpg" },
|
||||
{ "id": "slideImage4", "type": "image", "role": "content", "label": "Slide image 4", "description": "Fourth carousel image; also fills the blurred background.", "default": "assets/slide-04.jpg" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent horizontal wordmark in the preview strip.", "default": "assets/hyperframes-logo-black.svg" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
@@ -628,10 +679,38 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
data-duration="7.2333"
|
||||
data-track-index="1"
|
||||
>
|
||||
<img class="ssc-bg" id="ssc-bg-1" src="assets/slide-01.jpg" alt="" style="opacity: 1" />
|
||||
<img class="ssc-bg" id="ssc-bg-2" src="assets/slide-02.jpg" alt="" style="opacity: 0" />
|
||||
<img class="ssc-bg" id="ssc-bg-3" src="assets/slide-03.jpg" alt="" style="opacity: 0" />
|
||||
<img class="ssc-bg" id="ssc-bg-4" src="assets/slide-04.jpg" alt="" style="opacity: 0" />
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-1"
|
||||
data-var-src="slideImage1"
|
||||
src="assets/slide-01.jpg"
|
||||
alt=""
|
||||
style="opacity: 1"
|
||||
/>
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-2"
|
||||
data-var-src="slideImage2"
|
||||
src="assets/slide-02.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-3"
|
||||
data-var-src="slideImage3"
|
||||
src="assets/slide-03.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-4"
|
||||
data-var-src="slideImage4"
|
||||
src="assets/slide-04.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<div id="ssc-card">
|
||||
<div id="ssc-cardclipper">
|
||||
<div id="ssc-title">Share</div>
|
||||
@@ -640,6 +719,7 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-1"
|
||||
data-var-src="slideImage1"
|
||||
src="assets/slide-01.jpg"
|
||||
alt=""
|
||||
style="opacity: 1"
|
||||
@@ -647,6 +727,7 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-2"
|
||||
data-var-src="slideImage2"
|
||||
src="assets/slide-02.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
@@ -654,6 +735,7 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-3"
|
||||
data-var-src="slideImage3"
|
||||
src="assets/slide-03.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
@@ -661,12 +743,17 @@ defaults, so this behaves exactly like the preview above until you change one:
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-4"
|
||||
data-var-src="slideImage4"
|
||||
src="assets/slide-04.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<div id="ssc-strip">
|
||||
<img src="assets/hyperframes-logo-black.svg" alt="HyperFrames" />
|
||||
<img
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-black.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<div id="ssc-strip-text">OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ import { InstallCommand } from "/snippets/install-command.jsx";
|
||||
|
||||
<InstallCommand command="npx hyperframes add slack-notification-ad" item="slack-notification-ad" />
|
||||
|
||||
That writes `compositions/slack-notification-ad.html`, plus 6 supporting files under `assets/img/` and `assets/fonts/`.
|
||||
That writes `compositions/slack-notification-ad.html`, plus 7 supporting files under `assets/img/` and `assets/fonts/`.
|
||||
|
||||
## Add it to your video
|
||||
|
||||
@@ -38,7 +38,37 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en" data-resolution="portrait">
|
||||
<html
|
||||
lang="en"
|
||||
data-resolution="portrait"
|
||||
data-composition-variables='[
|
||||
{ "id": "request1Title", "type": "string", "role": "content", "label": "Request 1 sender", "description": "First Slack notification sender or channel.", "default": "Sarah Chen" },
|
||||
{ "id": "request1Text", "type": "string", "role": "content", "label": "Request 1 message", "description": "First Slack notification message.", "default": "Hey! Any chance you could get the launch video done by Friday?" },
|
||||
{ "id": "request2Title", "type": "string", "role": "content", "label": "Request 2 sender", "description": "Second Slack notification sender or channel.", "default": "Marcus Webb" },
|
||||
{ "id": "request2Text", "type": "string", "role": "content", "label": "Request 2 message", "description": "Second Slack notification message.", "default": "also need a 30s demo cut for the keynote" },
|
||||
{ "id": "request3Title", "type": "string", "role": "content", "label": "Request 3 sender", "description": "Third Slack notification sender or channel.", "default": "#social" },
|
||||
{ "id": "request3Text", "type": "string", "role": "content", "label": "Request 3 message", "description": "Third Slack notification message.", "default": "Priya: can we get the launch video resized for TikTok + Reels?" },
|
||||
{ "id": "request4Title", "type": "string", "role": "content", "label": "Request 4 sender", "description": "Fourth Slack notification sender or channel.", "default": "Dana Okafor" },
|
||||
{ "id": "request4Text", "type": "string", "role": "content", "label": "Request 4 message", "description": "Fourth Slack notification message.", "default": "onboarding video needs a v2 with the new UI" },
|
||||
{ "id": "request5Title", "type": "string", "role": "content", "label": "Request 5 sender", "description": "Fifth Slack notification sender or channel.", "default": "#sales" },
|
||||
{ "id": "request5Text", "type": "string", "role": "content", "label": "Request 5 message", "description": "Fifth Slack notification message.", "default": "Tom: customer wants a 1-min walkthrough by EOD" },
|
||||
{ "id": "request6Title", "type": "string", "role": "content", "label": "Request 6 sender", "description": "Sixth Slack notification sender or channel.", "default": "Leila Haddad" },
|
||||
{ "id": "request6Text", "type": "string", "role": "content", "label": "Request 6 message", "description": "Sixth Slack notification message.", "default": "CEO is asking for a sizzle reel for the board deck" },
|
||||
{ "id": "request7Title", "type": "string", "role": "content", "label": "Request 7 sender", "description": "Seventh Slack notification sender or channel.", "default": "#events" },
|
||||
{ "id": "request7Text", "type": "string", "role": "content", "label": "Request 7 message", "description": "Seventh Slack notification message.", "default": "Jordan: offsite recap video??" },
|
||||
{ "id": "request8Title", "type": "string", "role": "content", "label": "Request 8 sender", "description": "Eighth Slack notification sender or channel.", "default": "Miguel Reyes" },
|
||||
{ "id": "request8Text", "type": "string", "role": "content", "label": "Request 8 message", "description": "Eighth Slack notification message.", "default": "can you do a Spanish version of the demo too?" },
|
||||
{ "id": "request9Title", "type": "string", "role": "content", "label": "Request 9 sender", "description": "Ninth Slack notification sender or channel.", "default": "#marketing" },
|
||||
{ "id": "request9Text", "type": "string", "role": "content", "label": "Request 9 message", "description": "Ninth Slack notification message.", "default": "Ava: we need 3 ad variants — portrait, square, landscape" },
|
||||
{ "id": "request10Title", "type": "string", "role": "content", "label": "Request 10 sender", "description": "Tenth Slack notification sender or channel.", "default": "Raj Patel" },
|
||||
{ "id": "request10Text", "type": "string", "role": "content", "label": "Request 10 message", "description": "Tenth Slack notification message.", "default": "investor update needs a quick video walkthrough" },
|
||||
{ "id": "request11Title", "type": "string", "role": "content", "label": "Request 11 sender", "description": "Eleventh Slack notification sender or channel.", "default": "Ben Liu" },
|
||||
{ "id": "request11Text", "type": "string", "role": "content", "label": "Request 11 message", "description": "Eleventh Slack notification message.", "default": "one more: Product Hunt launch video" },
|
||||
{ "id": "payoffTitle", "type": "string", "role": "content", "label": "Payoff sender", "description": "Final brand payoff title.", "default": "HeyGen" },
|
||||
{ "id": "payoffText", "type": "string", "role": "content", "label": "Payoff message", "description": "Final brand payoff message.", "default": "Heard you needed some videos?" },
|
||||
{ "id": "payoffIcon", "type": "image", "role": "content", "label": "Payoff logo", "description": "Logo shown only in the final payoff notification.", "default": "assets/img/heygen-mark.svg" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=1080, height=1920" />
|
||||
@@ -452,31 +482,74 @@ Move it in time with `data-start`. Put it on a different timeline row with
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ---------------- CONFIG — every content-facing string ---------------- */
|
||||
var variables =
|
||||
window.__hyperframes && typeof window.__hyperframes.getVariables === "function"
|
||||
? window.__hyperframes.getVariables()
|
||||
: {};
|
||||
function content(id, fallback) {
|
||||
return typeof variables[id] === "string" && variables[id].trim() ? variables[id] : fallback;
|
||||
}
|
||||
|
||||
var CONFIG = {
|
||||
icon: "assets/img/slack-mark.svg",
|
||||
notifs: [
|
||||
{
|
||||
title: "Sarah Chen",
|
||||
text: "Hey! Any chance you could get the launch video done by Friday?",
|
||||
title: content("request1Title", "Sarah Chen"),
|
||||
text: content(
|
||||
"request1Text",
|
||||
"Hey! Any chance you could get the launch video done by Friday?",
|
||||
),
|
||||
},
|
||||
{ title: "Marcus Webb", text: "also need a 30s demo cut for the keynote" },
|
||||
{
|
||||
title: "#social",
|
||||
text: "Priya: can we get the launch video resized for TikTok + Reels?",
|
||||
title: content("request2Title", "Marcus Webb"),
|
||||
text: content("request2Text", "also need a 30s demo cut for the keynote"),
|
||||
},
|
||||
{ title: "Dana Okafor", text: "onboarding video needs a v2 with the new UI" },
|
||||
{ title: "#sales", text: "Tom: customer wants a 1-min walkthrough by EOD" },
|
||||
{ title: "Leila Haddad", text: "CEO is asking for a sizzle reel for the board deck" },
|
||||
{ title: "#events", text: "Jordan: offsite recap video??" },
|
||||
{ title: "Miguel Reyes", text: "can you do a Spanish version of the demo too?" },
|
||||
{ title: "#marketing", text: "Ava: we need 3 ad variants — portrait, square, landscape" },
|
||||
{ title: "Raj Patel", text: "investor update needs a quick video walkthrough" },
|
||||
{ title: "Ben Liu", text: "one more: Product Hunt launch video" },
|
||||
{
|
||||
title: "HeyGen",
|
||||
text: "Heard you needed some videos?",
|
||||
icon: "assets/img/heygen-mark.svg",
|
||||
title: content("request3Title", "#social"),
|
||||
text: content(
|
||||
"request3Text",
|
||||
"Priya: can we get the launch video resized for TikTok + Reels?",
|
||||
),
|
||||
},
|
||||
{
|
||||
title: content("request4Title", "Dana Okafor"),
|
||||
text: content("request4Text", "onboarding video needs a v2 with the new UI"),
|
||||
},
|
||||
{
|
||||
title: content("request5Title", "#sales"),
|
||||
text: content("request5Text", "Tom: customer wants a 1-min walkthrough by EOD"),
|
||||
},
|
||||
{
|
||||
title: content("request6Title", "Leila Haddad"),
|
||||
text: content("request6Text", "CEO is asking for a sizzle reel for the board deck"),
|
||||
},
|
||||
{
|
||||
title: content("request7Title", "#events"),
|
||||
text: content("request7Text", "Jordan: offsite recap video??"),
|
||||
},
|
||||
{
|
||||
title: content("request8Title", "Miguel Reyes"),
|
||||
text: content("request8Text", "can you do a Spanish version of the demo too?"),
|
||||
},
|
||||
{
|
||||
title: content("request9Title", "#marketing"),
|
||||
text: content(
|
||||
"request9Text",
|
||||
"Ava: we need 3 ad variants — portrait, square, landscape",
|
||||
),
|
||||
},
|
||||
{
|
||||
title: content("request10Title", "Raj Patel"),
|
||||
text: content("request10Text", "investor update needs a quick video walkthrough"),
|
||||
},
|
||||
{
|
||||
title: content("request11Title", "Ben Liu"),
|
||||
text: content("request11Text", "one more: Product Hunt launch video"),
|
||||
},
|
||||
{
|
||||
title: content("payoffTitle", "HeyGen"),
|
||||
text: content("payoffText", "Heard you needed some videos?"),
|
||||
icon: content("payoffIcon", "assets/img/heygen-mark.svg"),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1937,8 +1937,7 @@
|
||||
"showcase",
|
||||
"avatar",
|
||||
"promotion",
|
||||
"vertical",
|
||||
"ad-template"
|
||||
"vertical"
|
||||
],
|
||||
"href": "/catalog/blocks/heygen-avatar-promo-card",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/heygen-avatar-promo-card.png"
|
||||
|
||||
@@ -40,7 +40,7 @@ function findMissingLocalScripts(itemDir: string, manifest: RegistryManifest): s
|
||||
}
|
||||
|
||||
describe("registry blocks", () => {
|
||||
it("ships an editing contract and declared variables for every promoted template", () => {
|
||||
it("ships a safe editing contract and declared variables for every promoted template", () => {
|
||||
const promotedManifests = readdirSync(blocksDir, { withFileTypes: true })
|
||||
.filter((entry) => entry.isDirectory())
|
||||
.map((entry) => ({
|
||||
@@ -66,8 +66,26 @@ describe("registry blocks", () => {
|
||||
const { document } = parseHTML(html);
|
||||
const declarations = JSON.parse(
|
||||
document.documentElement.getAttribute("data-composition-variables") ?? "[]",
|
||||
) as unknown[];
|
||||
) as Array<{ id?: unknown; type?: unknown }>;
|
||||
expect(declarations.length, templateId).toBeGreaterThan(0);
|
||||
expect(document.querySelectorAll("video"), `${templateId}: fixed video media`).toHaveLength(
|
||||
0,
|
||||
);
|
||||
|
||||
const imageVariableIds = declarations
|
||||
.filter(
|
||||
(variable): variable is { id: string; type: "image" } =>
|
||||
variable.type === "image" && typeof variable.id === "string",
|
||||
)
|
||||
.map((variable) => variable.id);
|
||||
for (const variableId of imageVariableIds) {
|
||||
const escapedId = variableId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
const occurrenceCount = html.match(new RegExp(`\\b${escapedId}\\b`, "g"))?.length ?? 0;
|
||||
expect(
|
||||
document.querySelector(`[data-var-src="${variableId}"]`) !== null || occurrenceCount > 1,
|
||||
`${templateId}: unbound image variable ${variableId}`,
|
||||
).toBe(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -11,9 +11,10 @@ Only defaults declared in `data-composition-variables` are editable:
|
||||
- `botName`, `userMessage`, `answer1` through `answer3`
|
||||
- `bullet1` through `bullet3`
|
||||
- `ecHeadline`, `ecSub`, `ecCta`, and `ecFooter`
|
||||
- `brandLogo`, using a transparent mark that remains legible on the dark header
|
||||
|
||||
Typed and streamed copy is length-locked to within 20% of the original.
|
||||
|
||||
## Protected
|
||||
|
||||
Do not change chat chrome, keyboard, layout, logo asset, palette, fonts, scene order, duration, timing, easing, typing cadence, or reveal logic. This contract declares no image or color variables.
|
||||
Do not change chat chrome, keyboard, layout, palette, fonts, scene order, duration, timing, easing, typing cadence, or reveal logic. Do not replace any image outside the declared closing-card logo slot, and do not restyle the assistant interface to match the supplied website. This contract declares no color variables.
|
||||
|
||||
+8
-2
@@ -13,7 +13,8 @@
|
||||
{ "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" }
|
||||
{ "id": "ecFooter", "type": "string", "role": "content", "label": "End-card footer", "description": "Letter-spaced line at the very bottom.", "default": "HYPERFRAMES.HEYGEN.COM" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent logo in the closing-card header.", "default": "assets/hyperframes-logo-white.svg" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
@@ -692,7 +693,12 @@
|
||||
>
|
||||
<div id="acr-endcard-inner">
|
||||
<div class="acr-stage">
|
||||
<img id="acr-eclogo" src="assets/hyperframes-logo-white.svg" alt="HyperFrames" />
|
||||
<img
|
||||
id="acr-eclogo"
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-white.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<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" />
|
||||
|
||||
@@ -107,6 +107,14 @@
|
||||
"label": "End-card footer",
|
||||
"description": "Letter-spaced line at the very bottom.",
|
||||
"default": "HYPERFRAMES.HEYGEN.COM"
|
||||
},
|
||||
{
|
||||
"id": "brandLogo",
|
||||
"type": "image",
|
||||
"role": "content",
|
||||
"label": "Brand logo",
|
||||
"description": "Transparent logo in the closing-card header.",
|
||||
"default": "assets/hyperframes-logo-white.svg"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"type": "hyperframes:block",
|
||||
"title": "HeyGen Avatar Promo Card",
|
||||
"description": "A portrait HeyGen offer card pairs a moving avatar mosaic with bold promotional typography and a branded callout",
|
||||
"tags": ["showcase", "avatar", "promotion", "vertical", "ad-template"],
|
||||
"tags": ["showcase", "avatar", "promotion", "vertical"],
|
||||
"author": "HeyGen",
|
||||
"dimensions": {
|
||||
"width": 1080,
|
||||
|
||||
@@ -2,17 +2,19 @@
|
||||
|
||||
## Surface ownership
|
||||
|
||||
This template depicts a phone messaging interface. The supplied website is content shared inside the thread and on the closing card; it does not own the messaging application chrome.
|
||||
This template depicts a phone messaging interface. The supplied website is the subject of the conversation, shared link, and closing card; it does not own the messaging application chrome.
|
||||
|
||||
## Editable slots
|
||||
|
||||
Only defaults declared in `data-composition-variables` are editable:
|
||||
|
||||
- `contactName`, `cardTitle`, and `cardDomain`
|
||||
- `ecProof` and `ecCta`
|
||||
- `contactName`
|
||||
- The complete conversation: `questionMessage`, `teaserMessage`, `reactionMessage`, `reactionEmoji`, `benefitMessage`, `discoveryMessage`, `sourceMessage`, `workflowMessage`, `ownershipMessage`, `installMessage`, and `thanksMessage`
|
||||
- The shared link: `cardImage`, `cardTitle`, and `cardDomain`
|
||||
- The closing card: `brandLogo`, `ecProof`, `ecFeature1` through `ecFeature3`, and `ecCta`
|
||||
|
||||
Keep replacement copy within 20% of the original length.
|
||||
|
||||
## Protected
|
||||
|
||||
Preserve messaging chrome, bubbles, receipts, emoji, fixed conversation beats, link-card image, logo asset, palette, typography, geometry, scene structure, duration, timing, easing, and reveal behavior.
|
||||
Preserve messaging chrome, bubble styling, receipts, palette, typography, geometry, scene structure, duration, timing, easing, and reveal behavior. Do not replace any image outside the declared link-card and closing-card logo slots, and do not recolor the messaging interface to match the supplied website.
|
||||
|
||||
+184
-16
@@ -3,9 +3,25 @@
|
||||
lang="en"
|
||||
data-composition-variables='[
|
||||
{ "id": "contactName", "type": "string", "role": "content", "label": "Contact name", "description": "Name pill in the chat header; the avatar shows its first letter.", "default": "Rachel" },
|
||||
{ "id": "questionMessage", "type": "string", "role": "content", "label": "Opening question", "description": "First incoming message that establishes what the conversation is about.", "default": "what r u using for the launch video??" },
|
||||
{ "id": "teaserMessage", "type": "string", "role": "content", "label": "Teaser reply", "description": "First typed outgoing reply before the shared link card.", "default": "wait look 👀" },
|
||||
{ "id": "cardImage", "type": "image", "role": "content", "label": "Link card image", "description": "Preview image on the shared link card.", "default": "assets/card-image.jpg" },
|
||||
{ "id": "cardTitle", "type": "string", "role": "content", "label": "Link card title", "description": "Title on the shared link card.", "default": "HyperFrames | Write HTML, render pixel-perfect video" },
|
||||
{ "id": "cardDomain", "type": "string", "role": "content", "label": "Link card domain", "description": "Domain line under the card title.", "default": "hyperframes.heygen.com" },
|
||||
{ "id": "reactionMessage", "type": "string", "role": "content", "label": "Link reaction", "description": "Incoming reaction immediately after the shared link.", "default": "OMG IT'S HTML" },
|
||||
{ "id": "reactionEmoji", "type": "string", "role": "content", "label": "Reaction emoji", "description": "Emoji-only reaction after the shared link.", "default": "🤯🤯🤯" },
|
||||
{ "id": "benefitMessage", "type": "string", "role": "content", "label": "Benefit reply", "description": "Typed outgoing reply that names the primary benefit.", "default": "renders in 4K. no editor" },
|
||||
{ "id": "discoveryMessage", "type": "string", "role": "content", "label": "Discovery question", "description": "Incoming question asking where the product was found.", "default": "where did u find this" },
|
||||
{ "id": "sourceMessage", "type": "string", "role": "content", "label": "Source reply", "description": "Typed outgoing reply naming where to find the product.", "default": "on heygen" },
|
||||
{ "id": "workflowMessage", "type": "string", "role": "content", "label": "Workflow reply", "description": "Typed outgoing reply describing how the product works.", "default": "u just write plain html tags" },
|
||||
{ "id": "ownershipMessage", "type": "string", "role": "content", "label": "Ownership reply", "description": "Typed outgoing reply that closes the product explanation.", "default": "the code is yours forever" },
|
||||
{ "id": "installMessage", "type": "string", "role": "content", "label": "Intent reply", "description": "Incoming message expressing intent to try the product.", "default": "installing rn" },
|
||||
{ "id": "thanksMessage", "type": "string", "role": "content", "label": "Closing reply", "description": "Final incoming message in the conversation.", "default": "ty bestie 💚" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent horizontal wordmark on the closing card.", "default": "assets/hyperframes-logo-black.svg" },
|
||||
{ "id": "ecProof", "type": "string", "role": "content", "label": "End-card proof", "description": "Social-proof line under the stars.", "default": "12,000+ creators" },
|
||||
{ "id": "ecFeature1", "type": "string", "role": "content", "label": "End-card feature 1", "description": "First two-line benefit; use | to break the line.", "default": "Write|plain HTML" },
|
||||
{ "id": "ecFeature2", "type": "string", "role": "content", "label": "End-card feature 2", "description": "Second two-line benefit; use | to break the line.", "default": "Render|pixel-perfect" },
|
||||
{ "id": "ecFeature3", "type": "string", "role": "content", "label": "End-card feature 3", "description": "Third two-line benefit; use | to break the line.", "default": "Own|every line" },
|
||||
{ "id": "ecCta", "type": "string", "role": "content", "label": "End-card CTA", "description": "Label on the closing card button.", "default": "Start rendering free" }
|
||||
]'
|
||||
>
|
||||
@@ -556,7 +572,14 @@
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv">
|
||||
<div class="bubble recv">what r u using for the launch video??</div>
|
||||
<div
|
||||
class="bubble recv"
|
||||
id="mtr-message-question"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
what r u using for the launch video??
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -584,7 +607,14 @@
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent tail-sent">wait look 👀</div>
|
||||
<div
|
||||
class="bubble sent tail-sent"
|
||||
id="mtr-message-teaser"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
wait look 👀
|
||||
</div>
|
||||
<div class="delivered">Delivered</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -597,7 +627,12 @@
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="card">
|
||||
<img class="cardimg" src="assets/card-image.jpg" alt="" />
|
||||
<img
|
||||
class="cardimg"
|
||||
data-var-src="cardImage"
|
||||
src="assets/card-image.jpg"
|
||||
alt=""
|
||||
/>
|
||||
<div class="cardmeta">
|
||||
<div class="cardtxt">
|
||||
<div class="cardtitle">
|
||||
@@ -617,7 +652,16 @@
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="bubble recv">OMG IT'S HTML</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="bubble recv"
|
||||
id="mtr-message-reaction"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
OMG IT'S HTML
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item recv"
|
||||
@@ -626,7 +670,16 @@
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="emojirow">🤯🤯🤯</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="emojirow"
|
||||
id="mtr-message-emoji"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
🤯🤯🤯
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item sent"
|
||||
@@ -636,7 +689,14 @@
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent tail-sent">renders in 4K. no editor</div>
|
||||
<div
|
||||
class="bubble sent tail-sent"
|
||||
id="mtr-message-benefit"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
renders in 4K. no editor
|
||||
</div>
|
||||
<div class="delivered">Delivered</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -665,7 +725,14 @@
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv">
|
||||
<div class="bubble recv tail-recv">where did u find this</div>
|
||||
<div
|
||||
class="bubble recv tail-recv"
|
||||
id="mtr-message-discovery"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
where did u find this
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -675,7 +742,16 @@
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent"><div class="bubble sent">on heygen</div></div>
|
||||
<div class="pop pop-sent">
|
||||
<div
|
||||
class="bubble sent"
|
||||
id="mtr-message-source"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
on heygen
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item sent"
|
||||
@@ -685,7 +761,14 @@
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent">u just write plain html tags</div>
|
||||
<div
|
||||
class="bubble sent"
|
||||
id="mtr-message-workflow"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
u just write plain html tags
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -696,7 +779,14 @@
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-sent">
|
||||
<div class="bubble sent tail-sent">the code is yours forever</div>
|
||||
<div
|
||||
class="bubble sent tail-sent"
|
||||
id="mtr-message-ownership"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
the code is yours forever
|
||||
</div>
|
||||
<div class="delivered">Delivered</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -707,7 +797,16 @@
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="bubble recv">installing rn</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="bubble recv"
|
||||
id="mtr-message-install"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
installing rn
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item recv"
|
||||
@@ -716,7 +815,16 @@
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
<div class="pop pop-recv"><div class="bubble recv tail-recv">ty bestie 💚</div></div>
|
||||
<div class="pop pop-recv">
|
||||
<div
|
||||
class="bubble recv tail-recv"
|
||||
id="mtr-message-thanks"
|
||||
data-layout-allow-overlap
|
||||
data-layout-allow-occlusion
|
||||
>
|
||||
ty bestie 💚
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mtr-plusbtn">+</div>
|
||||
@@ -908,7 +1016,12 @@
|
||||
style="z-index: 5"
|
||||
>
|
||||
<div id="mtr-ec-wrap" data-layout-allow-overlap data-layout-allow-occlusion>
|
||||
<img id="mtr-ec-logo" src="assets/hyperframes-logo-black.svg" alt="HyperFrames" />
|
||||
<img
|
||||
id="mtr-ec-logo"
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-black.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<div id="mtr-ec-stars">
|
||||
<svg width="55" height="53" viewBox="0 0 24 23">
|
||||
<path
|
||||
@@ -966,15 +1079,15 @@
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ec-label" style="left: 100px">
|
||||
<div class="ec-label" id="mtr-ec-feature-1" style="left: 100px">
|
||||
<div>Write</div>
|
||||
<div>plain HTML</div>
|
||||
</div>
|
||||
<div class="ec-label" style="left: 420px">
|
||||
<div class="ec-label" id="mtr-ec-feature-2" style="left: 420px">
|
||||
<div>Render</div>
|
||||
<div>pixel-perfect</div>
|
||||
</div>
|
||||
<div class="ec-label" style="left: 740px">
|
||||
<div class="ec-label" id="mtr-ec-feature-3" style="left: 740px">
|
||||
<div>Own</div>
|
||||
<div>every line</div>
|
||||
</div>
|
||||
@@ -1005,6 +1118,58 @@
|
||||
chev.className = "chev";
|
||||
chev.textContent = "\u203A";
|
||||
namePill.appendChild(chev);
|
||||
function setText(id, value) {
|
||||
document.getElementById(id).textContent = value;
|
||||
}
|
||||
function setTyped(group, value) {
|
||||
var frames = Array.from(document.querySelectorAll('[id^="mtr-ty-' + group + '-"]')).sort(
|
||||
function (a, b) {
|
||||
return Number(a.id.split("-").pop()) - Number(b.id.split("-").pop());
|
||||
},
|
||||
);
|
||||
var characters = Array.from(value);
|
||||
frames.forEach(function (frame, index) {
|
||||
var prefixLength = Math.max(
|
||||
1,
|
||||
Math.ceil((characters.length * (index + 1)) / frames.length),
|
||||
);
|
||||
var textNode = Array.from(frame.childNodes).find(function (node) {
|
||||
return node.nodeType === 3;
|
||||
});
|
||||
if (textNode) textNode.nodeValue = characters.slice(0, prefixLength).join("");
|
||||
});
|
||||
}
|
||||
function setTwoLines(id, value) {
|
||||
var lines = value.split("|").slice(0, 2);
|
||||
var container = document.getElementById(id);
|
||||
Array.from(container.children).forEach(function (line, index) {
|
||||
line.textContent = lines[index] || lines[0] || "";
|
||||
});
|
||||
}
|
||||
var teaserMessage = text(vars.teaserMessage, "wait look 👀", 20);
|
||||
var benefitMessage = text(vars.benefitMessage, "renders in 4K. no editor", 32);
|
||||
var sourceMessage = text(vars.sourceMessage, "on heygen", 20);
|
||||
var workflowMessage = text(vars.workflowMessage, "u just write plain html tags", 34);
|
||||
var ownershipMessage = text(vars.ownershipMessage, "the code is yours forever", 32);
|
||||
setText(
|
||||
"mtr-message-question",
|
||||
text(vars.questionMessage, "what r u using for the launch video??", 46),
|
||||
);
|
||||
setText("mtr-message-teaser", teaserMessage);
|
||||
setText("mtr-message-reaction", text(vars.reactionMessage, "OMG IT'S HTML", 24));
|
||||
setText("mtr-message-emoji", text(vars.reactionEmoji, "🤯🤯🤯", 12));
|
||||
setText("mtr-message-benefit", benefitMessage);
|
||||
setText("mtr-message-discovery", text(vars.discoveryMessage, "where did u find this", 28));
|
||||
setText("mtr-message-source", sourceMessage);
|
||||
setText("mtr-message-workflow", workflowMessage);
|
||||
setText("mtr-message-ownership", ownershipMessage);
|
||||
setText("mtr-message-install", text(vars.installMessage, "installing rn", 20));
|
||||
setText("mtr-message-thanks", text(vars.thanksMessage, "ty bestie 💚", 20));
|
||||
setTyped(1, teaserMessage);
|
||||
setTyped(2, benefitMessage);
|
||||
setTyped(3, sourceMessage);
|
||||
setTyped(4, workflowMessage);
|
||||
setTyped(5, ownershipMessage);
|
||||
document.querySelector(".cardtitle").textContent = text(
|
||||
vars.cardTitle,
|
||||
"HyperFrames | Write HTML, render pixel-perfect video",
|
||||
@@ -1020,6 +1185,9 @@
|
||||
"12,000+ creators",
|
||||
30,
|
||||
);
|
||||
setTwoLines("mtr-ec-feature-1", text(vars.ecFeature1, "Write|plain HTML", 32));
|
||||
setTwoLines("mtr-ec-feature-2", text(vars.ecFeature2, "Render|pixel-perfect", 32));
|
||||
setTwoLines("mtr-ec-feature-3", text(vars.ecFeature3, "Own|every line", 32));
|
||||
document.getElementById("mtr-ec-cta").textContent = text(
|
||||
vars.ecCta,
|
||||
"Start rendering free",
|
||||
|
||||
@@ -20,6 +20,30 @@
|
||||
"description": "Name pill in the chat header; the avatar shows its first letter.",
|
||||
"default": "Rachel"
|
||||
},
|
||||
{
|
||||
"id": "questionMessage",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Opening question",
|
||||
"description": "First incoming message that establishes what the conversation is about.",
|
||||
"default": "what r u using for the launch video??"
|
||||
},
|
||||
{
|
||||
"id": "teaserMessage",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Teaser reply",
|
||||
"description": "First typed outgoing reply before the shared link card.",
|
||||
"default": "wait look 👀"
|
||||
},
|
||||
{
|
||||
"id": "cardImage",
|
||||
"type": "image",
|
||||
"role": "content",
|
||||
"label": "Link card image",
|
||||
"description": "Preview image on the shared link card.",
|
||||
"default": "assets/card-image.jpg"
|
||||
},
|
||||
{
|
||||
"id": "cardTitle",
|
||||
"type": "string",
|
||||
@@ -36,6 +60,86 @@
|
||||
"description": "Domain line under the card title.",
|
||||
"default": "hyperframes.heygen.com"
|
||||
},
|
||||
{
|
||||
"id": "reactionMessage",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Link reaction",
|
||||
"description": "Incoming reaction immediately after the shared link.",
|
||||
"default": "OMG IT'S HTML"
|
||||
},
|
||||
{
|
||||
"id": "reactionEmoji",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Reaction emoji",
|
||||
"description": "Emoji-only reaction after the shared link.",
|
||||
"default": "🤯🤯🤯"
|
||||
},
|
||||
{
|
||||
"id": "benefitMessage",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Benefit reply",
|
||||
"description": "Typed outgoing reply that names the primary benefit.",
|
||||
"default": "renders in 4K. no editor"
|
||||
},
|
||||
{
|
||||
"id": "discoveryMessage",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Discovery question",
|
||||
"description": "Incoming question asking where the product was found.",
|
||||
"default": "where did u find this"
|
||||
},
|
||||
{
|
||||
"id": "sourceMessage",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Source reply",
|
||||
"description": "Typed outgoing reply naming where to find the product.",
|
||||
"default": "on heygen"
|
||||
},
|
||||
{
|
||||
"id": "workflowMessage",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Workflow reply",
|
||||
"description": "Typed outgoing reply describing how the product works.",
|
||||
"default": "u just write plain html tags"
|
||||
},
|
||||
{
|
||||
"id": "ownershipMessage",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Ownership reply",
|
||||
"description": "Typed outgoing reply that closes the product explanation.",
|
||||
"default": "the code is yours forever"
|
||||
},
|
||||
{
|
||||
"id": "installMessage",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Intent reply",
|
||||
"description": "Incoming message expressing intent to try the product.",
|
||||
"default": "installing rn"
|
||||
},
|
||||
{
|
||||
"id": "thanksMessage",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "Closing reply",
|
||||
"description": "Final incoming message in the conversation.",
|
||||
"default": "ty bestie 💚"
|
||||
},
|
||||
{
|
||||
"id": "brandLogo",
|
||||
"type": "image",
|
||||
"role": "content",
|
||||
"label": "Brand logo",
|
||||
"description": "Transparent horizontal wordmark on the closing card.",
|
||||
"default": "assets/hyperframes-logo-black.svg"
|
||||
},
|
||||
{
|
||||
"id": "ecProof",
|
||||
"type": "string",
|
||||
@@ -44,6 +148,30 @@
|
||||
"description": "Social-proof line under the stars.",
|
||||
"default": "12,000+ creators"
|
||||
},
|
||||
{
|
||||
"id": "ecFeature1",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "End-card feature 1",
|
||||
"description": "First two-line benefit; use | to break the line.",
|
||||
"default": "Write|plain HTML"
|
||||
},
|
||||
{
|
||||
"id": "ecFeature2",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "End-card feature 2",
|
||||
"description": "Second two-line benefit; use | to break the line.",
|
||||
"default": "Render|pixel-perfect"
|
||||
},
|
||||
{
|
||||
"id": "ecFeature3",
|
||||
"type": "string",
|
||||
"role": "content",
|
||||
"label": "End-card feature 3",
|
||||
"description": "Third two-line benefit; use | to break the line.",
|
||||
"default": "Own|every line"
|
||||
},
|
||||
{
|
||||
"id": "ecCta",
|
||||
"type": "string",
|
||||
|
||||
@@ -10,9 +10,10 @@ Only defaults declared in `data-composition-variables` are editable:
|
||||
|
||||
- `notifTitle`, `message1` through `message4`, and `appName`
|
||||
- `headlineTop`, `headlineAccent`, and `footerText`
|
||||
- `brandLogo`, using a transparent mark that remains legible on the dark closing card
|
||||
|
||||
Keep replacement copy within 20% of the original length.
|
||||
|
||||
## Protected
|
||||
|
||||
Do not change CSS, layout, backdrop, notification chrome, logo asset, scene structure, duration, timing, easing, stacking, or reveal behavior. Colors are protected because this template declares no color variables.
|
||||
Do not change CSS, layout, backdrop, notification chrome, scene structure, duration, timing, easing, stacking, or reveal behavior. Do not replace any image outside the declared closing-card logo slot. Colors are protected because this template declares no color variables.
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
{ "id": "appName", "type": "string", "role": "content", "label": "App name", "description": "Small credit in the corner of every banner.", "default": "HyperFrames" },
|
||||
{ "id": "headlineTop", "type": "string", "role": "content", "label": "End-card line 1", "description": "First line of the closing card.", "default": "SHIP VIDEO" },
|
||||
{ "id": "headlineAccent", "type": "string", "role": "content", "label": "End-card line 2", "description": "Accented second line of the closing card.", "default": "FROM HTML" },
|
||||
{ "id": "footerText", "type": "string", "role": "content", "label": "End-card footer", "description": "URL or call to action under the headline.", "default": "hyperframes.heygen.com" }
|
||||
{ "id": "footerText", "type": "string", "role": "content", "label": "End-card footer", "description": "URL or call to action under the headline.", "default": "hyperframes.heygen.com" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent logo centered on the closing card.", "default": "assets/hyperframes-logo-white.svg" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
@@ -358,7 +359,12 @@
|
||||
<div id="nc-endcard-inner">
|
||||
<div id="nc-ec-top">SHIP VIDEO</div>
|
||||
<div id="nc-ec-accent">FROM HTML</div>
|
||||
<img id="nc-ec-mark" src="assets/hyperframes-logo-white.svg" alt="HyperFrames" />
|
||||
<img
|
||||
id="nc-ec-mark"
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-white.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<div id="nc-ec-footer">hyperframes.heygen.com</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -83,6 +83,14 @@
|
||||
"label": "End-card footer",
|
||||
"description": "URL or call to action under the headline.",
|
||||
"default": "hyperframes.heygen.com"
|
||||
},
|
||||
{
|
||||
"id": "brandLogo",
|
||||
"type": "image",
|
||||
"role": "content",
|
||||
"label": "Brand logo",
|
||||
"description": "Transparent logo centered on the closing card.",
|
||||
"default": "assets/hyperframes-logo-white.svg"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
|
||||
@@ -10,9 +10,11 @@ Only defaults declared in `data-composition-variables` are editable:
|
||||
|
||||
- `shareTitle`, `senderName`, `itemLabel`, and `stripText`
|
||||
- `acceptLabel` and `declineLabel`
|
||||
- `slideImage1` through `slideImage4`; each image also drives its matching blurred background
|
||||
- `brandLogo`, using a transparent horizontal wordmark
|
||||
|
||||
Keep replacement copy within 20% of the original length.
|
||||
|
||||
## Protected
|
||||
|
||||
Preserve the share-sheet palette, typography, buttons, geometry, carousel layout, slide assets, logo asset, scene structure, duration, timing, easing, and tap animation. This contract does not declare replaceable image or color slots.
|
||||
Preserve the share-sheet palette, typography, buttons, geometry, carousel layout, scene structure, duration, timing, easing, and tap animation. Do not replace any image outside the declared slide and logo slots, and do not recolor the operating-system interface.
|
||||
|
||||
@@ -59,6 +59,46 @@
|
||||
"label": "Decline label",
|
||||
"description": "Left-hand action button.",
|
||||
"default": "Decline"
|
||||
},
|
||||
{
|
||||
"id": "slideImage1",
|
||||
"type": "image",
|
||||
"role": "content",
|
||||
"label": "Slide image 1",
|
||||
"description": "First carousel image; also fills the blurred background.",
|
||||
"default": "assets/slide-01.jpg"
|
||||
},
|
||||
{
|
||||
"id": "slideImage2",
|
||||
"type": "image",
|
||||
"role": "content",
|
||||
"label": "Slide image 2",
|
||||
"description": "Second carousel image; also fills the blurred background.",
|
||||
"default": "assets/slide-02.jpg"
|
||||
},
|
||||
{
|
||||
"id": "slideImage3",
|
||||
"type": "image",
|
||||
"role": "content",
|
||||
"label": "Slide image 3",
|
||||
"description": "Third carousel image; also fills the blurred background.",
|
||||
"default": "assets/slide-03.jpg"
|
||||
},
|
||||
{
|
||||
"id": "slideImage4",
|
||||
"type": "image",
|
||||
"role": "content",
|
||||
"label": "Slide image 4",
|
||||
"description": "Fourth carousel image; also fills the blurred background.",
|
||||
"default": "assets/slide-04.jpg"
|
||||
},
|
||||
{
|
||||
"id": "brandLogo",
|
||||
"type": "image",
|
||||
"role": "content",
|
||||
"label": "Brand logo",
|
||||
"description": "Transparent horizontal wordmark in the preview strip.",
|
||||
"default": "assets/hyperframes-logo-black.svg"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
|
||||
@@ -7,7 +7,12 @@
|
||||
{ "id": "itemLabel", "type": "string", "role": "content", "label": "Item", "description": "What the sender is offering, completing the sentence \"… would like to share …\".", "default": "a video" },
|
||||
{ "id": "stripText", "type": "string", "role": "content", "label": "Brand strip", "description": "Small-caps line under the preview, beside the logo.", "default": "OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML" },
|
||||
{ "id": "acceptLabel", "type": "string", "role": "content", "label": "Accept label", "description": "Right-hand action button.", "default": "Accept" },
|
||||
{ "id": "declineLabel", "type": "string", "role": "content", "label": "Decline label", "description": "Left-hand action button.", "default": "Decline" }
|
||||
{ "id": "declineLabel", "type": "string", "role": "content", "label": "Decline label", "description": "Left-hand action button.", "default": "Decline" },
|
||||
{ "id": "slideImage1", "type": "image", "role": "content", "label": "Slide image 1", "description": "First carousel image; also fills the blurred background.", "default": "assets/slide-01.jpg" },
|
||||
{ "id": "slideImage2", "type": "image", "role": "content", "label": "Slide image 2", "description": "Second carousel image; also fills the blurred background.", "default": "assets/slide-02.jpg" },
|
||||
{ "id": "slideImage3", "type": "image", "role": "content", "label": "Slide image 3", "description": "Third carousel image; also fills the blurred background.", "default": "assets/slide-03.jpg" },
|
||||
{ "id": "slideImage4", "type": "image", "role": "content", "label": "Slide image 4", "description": "Fourth carousel image; also fills the blurred background.", "default": "assets/slide-04.jpg" },
|
||||
{ "id": "brandLogo", "type": "image", "role": "content", "label": "Brand logo", "description": "Transparent horizontal wordmark in the preview strip.", "default": "assets/hyperframes-logo-black.svg" }
|
||||
]'
|
||||
>
|
||||
<head>
|
||||
@@ -202,10 +207,38 @@
|
||||
data-duration="7.2333"
|
||||
data-track-index="1"
|
||||
>
|
||||
<img class="ssc-bg" id="ssc-bg-1" src="assets/slide-01.jpg" alt="" style="opacity: 1" />
|
||||
<img class="ssc-bg" id="ssc-bg-2" src="assets/slide-02.jpg" alt="" style="opacity: 0" />
|
||||
<img class="ssc-bg" id="ssc-bg-3" src="assets/slide-03.jpg" alt="" style="opacity: 0" />
|
||||
<img class="ssc-bg" id="ssc-bg-4" src="assets/slide-04.jpg" alt="" style="opacity: 0" />
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-1"
|
||||
data-var-src="slideImage1"
|
||||
src="assets/slide-01.jpg"
|
||||
alt=""
|
||||
style="opacity: 1"
|
||||
/>
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-2"
|
||||
data-var-src="slideImage2"
|
||||
src="assets/slide-02.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-3"
|
||||
data-var-src="slideImage3"
|
||||
src="assets/slide-03.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<img
|
||||
class="ssc-bg"
|
||||
id="ssc-bg-4"
|
||||
data-var-src="slideImage4"
|
||||
src="assets/slide-04.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<div id="ssc-card">
|
||||
<div id="ssc-cardclipper">
|
||||
<div id="ssc-title">Share</div>
|
||||
@@ -214,6 +247,7 @@
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-1"
|
||||
data-var-src="slideImage1"
|
||||
src="assets/slide-01.jpg"
|
||||
alt=""
|
||||
style="opacity: 1"
|
||||
@@ -221,6 +255,7 @@
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-2"
|
||||
data-var-src="slideImage2"
|
||||
src="assets/slide-02.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
@@ -228,6 +263,7 @@
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-3"
|
||||
data-var-src="slideImage3"
|
||||
src="assets/slide-03.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
@@ -235,12 +271,17 @@
|
||||
<img
|
||||
class="ssc-slide"
|
||||
id="ssc-slide-4"
|
||||
data-var-src="slideImage4"
|
||||
src="assets/slide-04.jpg"
|
||||
alt=""
|
||||
style="opacity: 0"
|
||||
/>
|
||||
<div id="ssc-strip">
|
||||
<img src="assets/hyperframes-logo-black.svg" alt="HyperFrames" />
|
||||
<img
|
||||
data-var-src="brandLogo"
|
||||
src="assets/hyperframes-logo-black.svg"
|
||||
alt="Brand logo"
|
||||
/>
|
||||
<div id="ssc-strip-text">OPEN-SOURCE VIDEO ENGINE · SHIP FROM HTML</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Binary file not shown.
@@ -2,7 +2,7 @@
|
||||
"model": "bge-small-en-v1.5",
|
||||
"modelRevision": "ea104dacec62c0de699686887e3f920caeb4f3e3",
|
||||
"dimensions": 384,
|
||||
"revision": "fbf1facc93a2cd1dc4507407f21fe4f6097da56670aaab4a0689b12dc0c43d09",
|
||||
"revision": "fb089c68adca459318a6d28b88c09a3ea9ead77d58ef8459bcf90ec79d0b61d9",
|
||||
"names": [
|
||||
"ai-chat-reveal",
|
||||
"animated-bar-chart",
|
||||
|
||||
@@ -1529,6 +1529,6 @@
|
||||
}
|
||||
],
|
||||
"catalogArtifact": {
|
||||
"revision": "fbf1facc93a2cd1dc4507407f21fe4f6097da56670aaab4a0689b12dc0c43d09"
|
||||
"revision": "fb089c68adca459318a6d28b88c09a3ea9ead77d58ef8459bcf90ec79d0b61d9"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user