Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/guides/color-grading.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ When grading a video, animate opacity on a wrapper element instead of directly o
| Build a terminal/editorial character treatment | `effects.ascii` + `effects.asciiSize` + an optional two-color `palette` |
| Build a restrained multi-color pixel treatment | `effects.dither` + `effects.ditherSize` + a two-to-six-color `palette` |
| Add an organic light leak | Install the finite `organic-light-leak-overlay` Registry block |
| Build a freeze-frame cutout | Existing background removal + the `freeze-frame-cutout` Registry overlay block + host GSAP |
| Build a freeze-frame cutout | Existing background removal + the `freeze-frame-dressing` Registry overlay block + host GSAP |
| Make a presenter float over graphics | Existing [Remove Background](/guides/remove-background) workflow |
| Put text behind a presenter | Existing `remove-background --background-output` workflow |
| Render HDR delivery files | Existing [HDR Rendering](/guides/hdr) workflow |
Expand Down
18 changes: 17 additions & 1 deletion packages/cli/src/registry/registryBlocks.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { readFileSync, readdirSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { bundleToSingleHtml } from "@hyperframes/core/compiler";
import { parseHTML } from "linkedom";
import { describe, expect, it } from "vitest";

const blocksDir = resolve(dirname(fileURLToPath(import.meta.url)), "../../../../registry/blocks");
Expand Down Expand Up @@ -29,7 +31,7 @@ function findMissingLocalScripts(itemDir: string, manifest: RegistryManifest): s
return missing;
}

describe("registry block manifests", () => {
describe("registry blocks", () => {
it("installs every local script referenced by a block composition", () => {
const missing: string[] = [];

Expand All @@ -48,4 +50,18 @@ describe("registry block manifests", () => {

expect(missing).toEqual([]);
});

it("keeps the Camcorder HUD seekable inside a differently named host composition", async () => {
const bundled = await bundleToSingleHtml(resolve(blocksDir, "camcorder-hud"), {
entryFile: "demo.html",
});
const { document } = parseHTML(bundled);
const demo = document.getElementById("camcorder-hud-demo");
const hud = document.getElementById("ch-demo-overlay");

expect(demo?.getAttribute("data-composition-id")).toBe("camcorder-hud-demo");
expect(hud?.getAttribute("data-composition-id")).toBe("camcorder-hud");
expect(hud?.hasAttribute("data-composition-src")).toBe(false);
expect(bundled).toContain('var __hfTimelineCompId = "camcorder-hud";');
});
});
163 changes: 163 additions & 0 deletions registry/blocks/camcorder-hud/camcorder-hud.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
*::before,
*::after {
box-sizing: border-box;
}

html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: transparent;
}

#ch-hud {
--hf-camcorder-color: #fff;
--hf-camcorder-accent: #f12c2c;
--hf-camcorder-inset: 5vmin;
--hf-camcorder-font-size: 3.7vmin;
position: absolute;
inset: 0;
color: var(--hf-camcorder-color);
font-family: monospace;
font-size: var(--hf-camcorder-font-size);
font-weight: 700;
line-height: 1.25;
pointer-events: none;
-webkit-text-stroke: 0.12vmin rgb(0 0 0 / 92%);
text-shadow: 0 0.2vmin 0.6vmin rgb(0 0 0 / 90%);
}

#ch-hud .ch-corner {
position: absolute;
}

#ch-hud .ch-record {
top: var(--hf-camcorder-inset);
left: var(--hf-camcorder-inset);
display: flex;
align-items: center;
gap: 1.8vmin;
}

#ch-hud .ch-record-dot {
width: 2.2vmin;
height: 2.2vmin;
border-radius: 50%;
background: var(--hf-camcorder-accent);
box-shadow: 0 0 0.9vmin color-mix(in srgb, var(--hf-camcorder-accent) 55%, transparent);
}

#ch-hud .ch-battery {
top: var(--hf-camcorder-inset);
right: var(--hf-camcorder-inset);
width: 7vmin;
height: 3.5vmin;
border: 0.35vmin solid currentcolor;
}

#ch-hud .ch-battery::before {
position: absolute;
top: 0.7vmin;
left: 0.7vmin;
width: 4.7vmin;
height: 1.4vmin;
background: currentcolor;
content: "";
}

#ch-hud .ch-battery::after {
position: absolute;
top: 0.7vmin;
right: -1vmin;
width: 0.7vmin;
height: 1.4vmin;
background: currentcolor;
content: "";
}

#ch-hud .ch-date {
bottom: var(--hf-camcorder-inset);
left: var(--hf-camcorder-inset);
}

#ch-hud .ch-counter {
right: var(--hf-camcorder-inset);
bottom: var(--hf-camcorder-inset);
text-align: right;
}

#ch-hud .ch-mode {
display: block;
margin-bottom: 0.7vmin;
font-size: 2.6vmin;
}
</style>
</head>
<body>
<div
id="camcorder-hud"
data-composition-id="camcorder-hud"
data-start="0"
data-duration="4"
data-width="1920"
data-height="1080"
>
<div id="ch-hud" data-hf-counter-start="0" aria-hidden="true">
<div class="ch-corner ch-record"><span class="ch-record-dot"></span><span>REC</span></div>
<div class="ch-corner ch-battery"></div>
<div class="ch-corner ch-date">JAN 01 2000<br />12:00 AM</div>
<div class="ch-corner ch-counter">
<span class="ch-mode">SP · 16:9</span><span class="ch-counter-value">00:00:00</span>
</div>
</div>
</div>

<script>
window.__timelines = window.__timelines || {};

var hud = document.getElementById("ch-hud");
var counter = hud && hud.querySelector(".ch-counter-value");
var recordDot = hud && hud.querySelector(".ch-record-dot");
var host = hud && hud.closest("[data-composition-id]");
if (!hud || !counter || !recordDot || !host) {
throw new Error("Camcorder HUD could not find its composition host");
}

var compositionId = host.getAttribute("data-composition-id");
var duration = Number(host.getAttribute("data-duration")) || 4;
var counterStart = Number(hud.getAttribute("data-hf-counter-start")) || 0;
var state = { seconds: 0 };

function formatCounter(value) {
var seconds = Math.max(0, Math.floor(value));
var hours = Math.floor(seconds / 3600);
var minutes = Math.floor((seconds % 3600) / 60);
var remainder = seconds % 60;
return [hours, minutes, remainder]
.map(function (part) {
return String(part).padStart(2, "0");
})
.join(":");
}

function updateHud() {
counter.textContent = formatCounter(counterStart + state.seconds);
recordDot.style.opacity = Math.floor(state.seconds / 0.55) % 2 === 0 ? "1" : "0.25";
}

var tl = gsap.timeline({ paused: true });
tl.to(state, { seconds: duration, duration: duration, ease: "none", onUpdate: updateHud }, 0);
updateHud();
window.__timelines[compositionId] = tl;
</script>
</body>
</html>
Binary file added registry/blocks/camcorder-hud/demo-backdrop.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions registry/blocks/camcorder-hud/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Camcorder HUD - Demo</title>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
* {
box-sizing: border-box;
}

html,
body,
#camcorder-hud-demo {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #050505;
}

#ch-demo-backdrop,
#ch-demo-overlay {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}

#ch-demo-backdrop {
object-fit: cover;
}
</style>
</head>
<body>
<div
id="camcorder-hud-demo"
data-composition-id="camcorder-hud-demo"
data-start="0"
data-duration="4"
data-width="1920"
data-height="1080"
>
<img
id="ch-demo-backdrop"
class="clip"
src="demo-backdrop.jpg"
data-start="0"
data-duration="4"
data-track-index="0"
alt="Creator recording a video"
/>
<div
id="ch-demo-overlay"
data-composition-id="camcorder-hud"
data-composition-src="camcorder-hud.html"
data-start="0"
data-duration="4"
data-track-index="1"
data-width="1920"
data-height="1080"
></div>
</div>

<script>
const tl = gsap.timeline({ paused: true });
tl.to("#ch-demo-backdrop", { scale: 1.02, duration: 4, ease: "none" }, 0);
window.__timelines = window.__timelines || {};
window.__timelines["camcorder-hud-demo"] = tl;
</script>
</body>
</html>
32 changes: 32 additions & 0 deletions registry/blocks/camcorder-hud/registry-item.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "camcorder-hud",
"type": "hyperframes:block",
"title": "Camcorder HUD",
"description": "Responsive REC, battery, editable date placeholder, and timeline-driven counter overlay for creator-camera and camcorder treatments",
"tags": [
"camcorder",
"camera",
"recording",
"hud",
"overlay",
"creator",
"media-treatment-overlay"
],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 4,
"files": [
{
"path": "camcorder-hud.html",
"target": "compositions/camcorder-hud.html",
"type": "hyperframes:composition"
}
],
"preview": {
"poster": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/camcorder-hud.png",
"video": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/camcorder-hud.mp4"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions registry/blocks/editorial-flash-overlay/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
*::before,
*::after {
box-sizing: border-box;
}

html,
body,
#editorial-flash-demo {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #080808;
}

#ef-demo-backdrop,
#ef-demo-overlay {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}

#ef-demo-backdrop {
object-fit: cover;
}
</style>
</head>
<body>
<div
id="editorial-flash-demo"
data-composition-id="editorial-flash-demo"
data-start="0"
data-duration="4"
data-width="1920"
data-height="1080"
>
<img
id="ef-demo-backdrop"
class="clip"
src="./demo-backdrop.jpg"
alt=""
data-start="0"
data-duration="4"
data-track-index="0"
/>
<div
id="ef-demo-overlay"
data-composition-id="editorial-flash-overlay"
data-composition-src="editorial-flash-overlay.html"
data-start="0"
data-duration="4"
data-track-index="1"
data-width="1920"
data-height="1080"
></div>
</div>

<script>
var tl = gsap.timeline({ paused: true });
tl.to("#ef-demo-backdrop", { scale: 1.035, duration: 4, ease: "none" }, 0);
window.__timelines = window.__timelines || {};
window.__timelines["editorial-flash-demo"] = tl;
</script>
</body>
</html>
Loading
Loading