mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-13 15:49:53 +00:00
initial code (#2)
* feat: initial code port from hyperframes-internal Port all OSS-ready packages from the internal monorepo: - @hyperframes/core — shared types, HTML generation, GSAP utilities, runtime - @hyperframes/cli — CLI for creating, previewing, and rendering compositions - @hyperframes/engine — framework-agnostic rendering engine (BeginFrame + FFmpeg) - @hyperframes/producer — video rendering pipeline (Puppeteer + FFmpeg) - @hyperframes/ui-player — browser-based video player component - @hyperframes/studio — composition editor (React frontend + Hono backend) Includes regression test suite with Docker-based test harness. All HeyGen-internal references, deployment infrastructure, and proprietary assets have been removed. Package names migrated from @app/* to @hyperframes/*. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: scrub internal codenames and stale references from OSS port - Replace static.heygen.ai runtime URLs in test fixtures - Remove internal CDN publish script (publish-hyperframe-runtime.ts) - Replace sandbox-studio, sandbox-interceptor, __magicEditRuntime with neutral names (studio, hyperframe-runtime, __hyperframeRuntime) - Fix stale Vault API / localhost references in docs - Remove broken deprecated_studio link Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove remaining internal codenames and stale references - Delete stale producer README.md and PIPELINE.md (referenced nonexistent files) - Replace "Cerberus" codename with "HyperFrames" in test design reviews - Replace magic-edit postMessage identifiers with hf-preview/hf-parent - Rename debug-magic-edit-timeline.ts to debug-timeline.ts - Replace "Motion Cut" with "HyperFrames" in Timeline comments - Fix studio/CLI references to nonexistent archive package (use local data/projects/ dir, stub render proxy) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
10621e7903
commit
9f8e5ba5a1
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "style-7-prod",
|
||||
"description": "Regression fixture imported from normalized style pack style-7-prod",
|
||||
"tags": [
|
||||
"style-regression",
|
||||
"prod-style",
|
||||
"slow",
|
||||
"landscape"
|
||||
],
|
||||
"minPsnr": 30,
|
||||
"maxFrameFailures": 0,
|
||||
"minAudioCorrelation": 0.9,
|
||||
"maxAudioLagWindows": 120,
|
||||
"renderConfig": {
|
||||
"fps": 30
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
# HyperFrame Schema Compliance Review
|
||||
|
||||
## Executive Summary
|
||||
- Total files reviewed: 4
|
||||
- Critical issues: 0
|
||||
- Overall compliance status: PASS
|
||||
|
||||
## Critical Issues
|
||||
None found. All compositions follow the deterministic and finite timeline requirements.
|
||||
|
||||
## Compliance Checklist
|
||||
- [x] All compositions have `data-width` and `data-height` attributes
|
||||
- [x] All timelines are finite with duration > 0
|
||||
- [x] All compositions registered in `window.__timelines`
|
||||
- [x] No use of `Math.random()`, `Date.now()`, or non-deterministic code
|
||||
- [x] Primitive clips have required data attributes (`id`, `data-start`, `data-track`)
|
||||
- [x] `data-duration` specified for all `<img>` clips (N/A - no images used)
|
||||
- [x] No manual media playback control (`video.play()`, `audio.pause()`, etc.)
|
||||
- [x] No manual clip mounting/unmounting in scripts
|
||||
- [x] Relative timing references are valid (N/A - no relative timing used)
|
||||
- [x] Clips on same track don't overlap in time
|
||||
- [x] Reusable compositions in separate HTML files
|
||||
- [x] Composition files use `<template>` tags
|
||||
- [x] External compositions loaded via `data-composition-src`
|
||||
- [x] All script-animated content wrapped in compositions
|
||||
- [x] No infinite or zero-duration timelines
|
||||
|
||||
## File-by-File Analysis
|
||||
|
||||
### index.html
|
||||
**Status**: COMPLIANT
|
||||
|
||||
**Observations**:
|
||||
- Correctly defines the root composition with `data-composition-id="root"`.
|
||||
- Properly loads sub-compositions using `data-composition-src`.
|
||||
- Registers the root timeline in `window.__timelines`.
|
||||
- Audio clip has all required attributes (`id`, `data-start`, `data-duration`, `data-track`).
|
||||
|
||||
### compositions/intro.html
|
||||
**Status**: COMPLIANT
|
||||
|
||||
**Observations**:
|
||||
- Uses `<template>` tag correctly.
|
||||
- Composition root has `data-width`, `data-height`, and `data-duration`.
|
||||
- Script is deterministic (uses string splitting and fixed durations).
|
||||
- Timeline is correctly registered.
|
||||
|
||||
### compositions/captions.html
|
||||
**Status**: COMPLIANT
|
||||
|
||||
**Observations**:
|
||||
- Uses `<template>` tag correctly.
|
||||
- Composition root has `data-width`, `data-height`, and `data-duration`.
|
||||
- Script is deterministic, iterating over a fixed array of caption data.
|
||||
- Timeline is correctly registered.
|
||||
|
||||
### compositions/main.html
|
||||
**Status**: COMPLIANT
|
||||
|
||||
**Observations**:
|
||||
- Uses `<template>` tag correctly.
|
||||
- Composition root has `data-width`, `data-height`, and `data-duration`.
|
||||
- Video clip has all required attributes (`id`, `data-start`, `data-duration`, `data-track`).
|
||||
- Script-animated content (`.stats-container`) is correctly wrapped inside the `main` composition.
|
||||
- Timeline is correctly registered.
|
||||
|
||||
## Actionable Fixes
|
||||
No fixes required. The project structure and implementation are in full accordance with the HyperFrame schema.
|
||||
@@ -0,0 +1,112 @@
|
||||
<template id="captions-template">
|
||||
<div data-composition-id="captions" data-width="1920" data-height="1080" data-duration="16.7">
|
||||
<div class="bg-gradient"></div>
|
||||
<div class="caption-wrapper">
|
||||
<div id="caption-container">
|
||||
<div id="caption-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
[data-composition-id="captions"] {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[data-composition-id="captions"] .bg-gradient {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 25%; /* Reduced height to focus on bottom */
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.6) 50%, rgba(0, 0, 0, 0) 100%);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
[data-composition-id="captions"] .caption-wrapper {
|
||||
position: absolute;
|
||||
bottom: 54px; /* 5% of 1080px */
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
[data-composition-id="captions"] #caption-container {
|
||||
min-width: 400px;
|
||||
max-width: 1600px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10px 60px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
[data-composition-id="captions"] #caption-text {
|
||||
color: #FFFFFF;
|
||||
font-family: 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 42px;
|
||||
font-weight: 300; /* Light */
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.4em; /* Wide letter-spacing, but readable */
|
||||
text-align: center;
|
||||
line-height: 1.4;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
const container = document.querySelector('[data-composition-id="captions"] #caption-container');
|
||||
const textElement = document.querySelector('[data-composition-id="captions"] #caption-text');
|
||||
const bgGradient = document.querySelector('[data-composition-id="captions"] .bg-gradient');
|
||||
|
||||
const OFFSET = 0; // Adjusted to 0 as per standard unless specified otherwise by Lyra's context, but keeping logic flexible.
|
||||
|
||||
const captions = [
|
||||
{ start: 0.1, end: 1.8, text: "WE ASKED WHAT YOU NEEDED" },
|
||||
{ start: 1.8, end: 4.6, text: "47 PERCENT SAID MOTION GRAPHICS" },
|
||||
{ start: 4.6, end: 6.9, text: "62 PERCENT SAID STATIC CONTENT" },
|
||||
{ start: 6.9, end: 8.6, text: "WAS COSTING YOU ATTENTION" },
|
||||
{ start: 8.6, end: 10.0, text: "THREE OUT OF FOUR SAID" },
|
||||
{ start: 10.0, end: 11.3, text: "KNOW THE LOOK YOU WANT" },
|
||||
{ start: 11.3, end: 12.8, text: "BUT NO EDITING SKILLS" },
|
||||
{ start: 12.8, end: 14.2, text: "TO GET THERE" },
|
||||
{ start: 14.2, end: 16.2, text: "SO WE BUILT EDITOR AGENT" }
|
||||
];
|
||||
|
||||
if (captions.length > 0) {
|
||||
const firstStart = captions[0].start + OFFSET;
|
||||
const lastEnd = captions[captions.length - 1].end + OFFSET;
|
||||
|
||||
// Fade in gradient and container
|
||||
tl.to([bgGradient, container], { opacity: 1, duration: 0.5, ease: "power2.out" }, firstStart);
|
||||
|
||||
captions.forEach((cap, index) => {
|
||||
const startTime = cap.start + OFFSET;
|
||||
|
||||
// Update text
|
||||
tl.set(textElement, { innerText: cap.text }, startTime);
|
||||
|
||||
// Subtle scale/fade effect for each new line to make it feel modern
|
||||
tl.fromTo(textElement,
|
||||
{ opacity: 0.7, scale: 0.98 },
|
||||
{ opacity: 1, scale: 1, duration: 0.3, ease: "power1.out" },
|
||||
startTime
|
||||
);
|
||||
});
|
||||
|
||||
// Fade out at the very end
|
||||
tl.to([bgGradient, container], { opacity: 0, duration: 0.5, ease: "power2.in" }, lastEnd);
|
||||
}
|
||||
|
||||
window.__timelines["captions"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,107 @@
|
||||
<template id="intro-template">
|
||||
<div data-composition-id="intro" data-width="1920" data-height="1080" data-duration="3">
|
||||
<div class="container">
|
||||
<div class="title">EDITOR AGENT</div>
|
||||
<div class="rule"></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
[data-composition-id="intro"] {
|
||||
background-color: #000000;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: "Helvetica", "Arial", sans-serif;
|
||||
color: #FFFFFF;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[data-composition-id="intro"] .container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
/* Vignelli style: precise, clean spacing */
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
[data-composition-id="intro"] .title {
|
||||
font-size: 120px;
|
||||
font-weight: 700; /* Vignelli often used bold Helvetica */
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1em;
|
||||
/* Offset the last letter's spacing to keep it centered */
|
||||
margin-right: -1em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
[data-composition-id="intro"] .char {
|
||||
display: inline-block;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
[data-composition-id="intro"] .rule {
|
||||
width: 800px;
|
||||
height: 4px;
|
||||
background-color: #FFFFFF;
|
||||
transform: scaleX(0);
|
||||
transform-origin: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const compId = "intro";
|
||||
const root = document.querySelector(`[data-composition-id="${compId}"]`);
|
||||
const titleEl = root.querySelector('.title');
|
||||
const ruleEl = root.querySelector('.rule');
|
||||
|
||||
// Split text into spans for staggered animation
|
||||
const text = titleEl.textContent;
|
||||
titleEl.innerHTML = '';
|
||||
[...text].forEach(char => {
|
||||
const span = document.createElement('span');
|
||||
span.textContent = char === ' ' ? '\u00A0' : char;
|
||||
span.className = 'char';
|
||||
titleEl.appendChild(span);
|
||||
});
|
||||
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
// 1. Horizontal rule expands from center
|
||||
tl.to(ruleEl, {
|
||||
scaleX: 1,
|
||||
duration: 1.5,
|
||||
ease: "power4.inOut"
|
||||
}, 0);
|
||||
|
||||
// 2. Tracking animation (letter-spacing: 1em to 0.5em)
|
||||
tl.to(titleEl, {
|
||||
letterSpacing: "0.5em",
|
||||
marginRight: "-0.5em",
|
||||
duration: 3,
|
||||
ease: "power2.out"
|
||||
}, 0);
|
||||
|
||||
// 3. Staggered letter fade-in
|
||||
tl.to(root.querySelectorAll('.char'), {
|
||||
opacity: 1,
|
||||
duration: 0.8,
|
||||
stagger: 0.1,
|
||||
ease: "power1.out"
|
||||
}, 0.2);
|
||||
|
||||
// Ambient motion: subtle scale pulse for the whole container
|
||||
tl.to(root.querySelector('.container'), {
|
||||
scale: 1.05,
|
||||
duration: 3,
|
||||
ease: "none"
|
||||
}, 0);
|
||||
|
||||
window.__timelines[compId] = tl;
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,190 @@
|
||||
<template id="main-template">
|
||||
<div data-composition-id="main" data-width="1920" data-height="1080" data-duration="16.7">
|
||||
<!-- A-roll Video -->
|
||||
<video id="aroll"
|
||||
src="https://gen-os-static.s3.us-east-2.amazonaws.com/astral_assets/uploaded_assets/70648f53_abe84fb9991841ae8ba82ee21ba6d37e.mp4"
|
||||
data-start="0"
|
||||
data-duration="16.7"
|
||||
data-track-index="1"
|
||||
muted
|
||||
crossorigin="anonymous">
|
||||
</video>
|
||||
|
||||
<!-- Statistics Overlay -->
|
||||
<div class="stats-container">
|
||||
<div class="stat-item" id="stat-1">
|
||||
<div class="stat-bg"></div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value">47%</div>
|
||||
<div class="stat-subtext">MOTION GRAPHICS</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item" id="stat-2">
|
||||
<div class="stat-bg"></div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value">62%</div>
|
||||
<div class="stat-subtext">STATIC CONTENT</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item" id="stat-3">
|
||||
<div class="stat-bg"></div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value">75%</div>
|
||||
<div class="stat-subtext">LACK SKILLS</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
[data-composition-id="main"] {
|
||||
background-color: #000000;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
overflow: hidden;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[data-composition-id="main"] #aroll {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 6px;
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
[data-composition-id="main"] .stats-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[data-composition-id="main"] .stat-item {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
bottom: 15%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
[data-composition-id="main"] .stat-bg {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 110%;
|
||||
height: 110%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 20px;
|
||||
z-index: -1;
|
||||
filter: blur(20px);
|
||||
}
|
||||
|
||||
[data-composition-id="main"] .stat-content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 40px 80px;
|
||||
}
|
||||
|
||||
[data-composition-id="main"] .stat-value {
|
||||
font-size: 180px; /* Large, centered, and precise */
|
||||
font-weight: 900;
|
||||
color: #6B0F1A; /* Deep Burgundy for emphasis */
|
||||
line-height: 0.9;
|
||||
letter-spacing: -5px;
|
||||
text-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
[data-composition-id="main"] .stat-subtext {
|
||||
font-size: 60px;
|
||||
font-weight: 700;
|
||||
color: #FFFFFF;
|
||||
letter-spacing: 4px;
|
||||
margin-top: 10px;
|
||||
text-transform: uppercase;
|
||||
text-shadow: 0 5px 15px rgba(0,0,0,0.5);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
const aroll = '#aroll';
|
||||
|
||||
// 1. At 3.0s: A-roll fades in smoothly (500ms) at 100% scale, centered.
|
||||
tl.to(aroll, {
|
||||
opacity: 1,
|
||||
duration: 0.5,
|
||||
ease: 'power2.inOut'
|
||||
}, 3.0);
|
||||
|
||||
// 2. Stat 1 (1.8s - 4.6s)
|
||||
tl.to('#stat-1', {
|
||||
opacity: 1,
|
||||
y: -20,
|
||||
duration: 0.8,
|
||||
ease: 'expo.out'
|
||||
}, 1.8);
|
||||
|
||||
// 3. At 4.6s (Stat 2): Cross-dissolve Stat 1 to Stat 2
|
||||
tl.to('#stat-1', {
|
||||
opacity: 0,
|
||||
y: -40,
|
||||
duration: 0.5,
|
||||
ease: 'power2.inOut'
|
||||
}, 4.6);
|
||||
|
||||
tl.to('#stat-2', {
|
||||
opacity: 1,
|
||||
y: -20,
|
||||
duration: 0.8,
|
||||
ease: 'expo.out'
|
||||
}, 4.6);
|
||||
|
||||
// 4. At 8.6s (Stat 3): Cross-dissolve Stat 2 to Stat 3
|
||||
tl.to('#stat-2', {
|
||||
opacity: 0,
|
||||
y: -40,
|
||||
duration: 0.5,
|
||||
ease: 'power2.inOut'
|
||||
}, 8.6);
|
||||
|
||||
tl.to('#stat-3', {
|
||||
opacity: 1,
|
||||
y: -20,
|
||||
duration: 0.8,
|
||||
ease: 'expo.out'
|
||||
}, 8.6);
|
||||
|
||||
// 5. At 14.2s: Stat 3 fades out.
|
||||
tl.to('#stat-3', {
|
||||
opacity: 0,
|
||||
y: -40,
|
||||
duration: 0.5,
|
||||
ease: 'power2.inOut'
|
||||
}, 14.2);
|
||||
|
||||
window.__timelines["main"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,61 @@
|
||||
# HyperFrames Design Review
|
||||
|
||||
## First Impression
|
||||
This looks like a "minimalist" template designed by someone who thinks Helvetica and a black background are a substitute for actual creative direction. It's safe, it's sterile, and it's dangerously close to being completely forgettable.
|
||||
|
||||
---
|
||||
|
||||
## CRITICAL Design Failures
|
||||
|
||||
Issues that make this look unprofessional or straight-up ugly. These MUST be fixed.
|
||||
|
||||
### The "Giant Stat" Obstruction
|
||||
**Where:** `compositions/main.html` - `.stat-value` (240px)
|
||||
**What's wrong:** You've slapped a 240px font size statistic right in the middle of the screen. It's not "bold," it's obnoxious. It's going to cover the subject's face or the primary action of the A-roll video.
|
||||
**Why it matters:** If I can't see the video because a giant "47%" is screaming in my face, the video is useless. You're sacrificing the primary content for a secondary metric.
|
||||
**Fix it:** Reduce the `stat-value` to 120px-140px and move the `.stat-item` to a corner (e.g., bottom-left or top-right) with proper padding. Let the video breathe.
|
||||
|
||||
### Caption Letter-Spacing Overkill
|
||||
**Where:** `compositions/captions.html` - `#caption-text` (`letter-spacing: 0.6em`)
|
||||
**What's wrong:** 0.6em letter spacing on a 42px font is absurd. It makes the words fall apart. The human eye shouldn't have to work this hard to reassemble "MOTION GRAPHICS" into a coherent thought.
|
||||
**Why it matters:** Captions are for readability. This is "aesthetic" at the expense of function. It looks like a broken typewriter.
|
||||
**Fix it:** Bring that `letter-spacing` down to 0.1em or 0.2em max. If you want "wide," do it subtly, not like you're trying to fill the entire 1920px width with one word.
|
||||
|
||||
### The "Vignelli" Identity Crisis
|
||||
**Where:** `compositions/intro.html`
|
||||
**What's wrong:** You claim "Vignelli style" in the comments but then use a 1em letter-spacing on the title. Vignelli was about tight, intentional kerning and powerful grids, not "let's see how far apart I can push these letters before they fall off the screen."
|
||||
**Why it matters:** It feels like a parody of modernism rather than an execution of it.
|
||||
**Fix it:** Tighten the `letter-spacing` to 0.05em or even slightly negative for that true high-end Swiss feel. Use a heavier weight and let the white space around the text do the work, not the gaps between the letters.
|
||||
|
||||
---
|
||||
|
||||
## Design Improvements
|
||||
|
||||
Things that aren't broken but are boring, lazy, or could be significantly better.
|
||||
|
||||
### Robotic Stat Transitions
|
||||
**Where:** `compositions/main.html` - GSAP Timeline
|
||||
**The problem:** The stats just fade and move 'y: -20'. It's the most basic "PowerPoint" transition imaginable.
|
||||
**Make it better:** Use a "counter" animation for the numbers. Have the percentage roll up from 0 to 47. It adds dynamic energy and makes the data feel "live" rather than static.
|
||||
|
||||
### Generic Background Gradient
|
||||
**Where:** `compositions/captions.html` - `.bg-gradient`
|
||||
**The problem:** A simple black-to-transparent linear gradient is the "I don't know what else to do" of video design.
|
||||
**Make it better:** Add a subtle blur or a frosted glass (backdrop-filter) effect to the caption container instead. It feels more premium and less like a 2010 YouTube tutorial.
|
||||
|
||||
---
|
||||
|
||||
## What Actually Works
|
||||
|
||||
The **Intro Rule Animation** (`.rule` scaleX) is actually decent. It provides a clean, architectural anchor for the text. It’s the only thing in this entire project that feels like it had a moment of genuine thought behind its motion.
|
||||
|
||||
---
|
||||
|
||||
## Design Verdict
|
||||
|
||||
**Visual Impact:** 4/10 - It’s "clean" only because there’s nothing there.
|
||||
**Color & Typography:** 3/10 - Black and white is a cop-out when the typography is this poorly spaced.
|
||||
**Motion & Animation Feel:** 5/10 - Standard GSAP eases. Nothing offensive, nothing inspiring.
|
||||
**Overall Aesthetic:** 4/10 - Corporate minimalism that forgot the "design" part.
|
||||
|
||||
**Bottom Line:** This looks like a wireframe that someone forgot to skin. It’s functional, but it has zero soul. If you want this to look professional, stop spacing your letters like they’re social distancing and stop blocking your video with giant numbers.
|
||||
@@ -0,0 +1,82 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Editor Agent - Velvet Standard</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
}
|
||||
#viewport {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="viewport"
|
||||
data-composition-id="root"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
data-duration="16.7">
|
||||
|
||||
<!-- Intro Sequence (0-3s) -->
|
||||
<div id="intro-layer"
|
||||
data-composition-src="compositions/intro.html"
|
||||
data-composition-id="intro"
|
||||
data-start="0"
|
||||
data-duration="3"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
data-track-index="10"
|
||||
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10;">
|
||||
</div>
|
||||
|
||||
<!-- Main A-roll and Stats (3s - End) -->
|
||||
<div id="main-layer"
|
||||
data-composition-src="compositions/main.html"
|
||||
data-composition-id="main"
|
||||
data-start="0"
|
||||
data-duration="16.7"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
data-track-index="5"
|
||||
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 5;">
|
||||
</div>
|
||||
|
||||
<!-- Captions (3s - End) -->
|
||||
<div id="captions-layer"
|
||||
data-composition-src="compositions/captions.html"
|
||||
data-composition-id="captions"
|
||||
data-start="0"
|
||||
data-duration="16.7"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
data-track-index="20"
|
||||
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 20;">
|
||||
</div>
|
||||
|
||||
<!-- Background Audio (A-roll Audio) -->
|
||||
<audio id="aroll-audio"
|
||||
src="https://gen-os-static.s3.us-east-2.amazonaws.com/astral_assets/uploaded_assets/70648f53_abe84fb9991841ae8ba82ee21ba6d37e.mp4"
|
||||
data-start="0"
|
||||
data-duration="16.7"
|
||||
data-track-index="1">
|
||||
</audio>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.__timelines = {};
|
||||
const mainTimeline = gsap.timeline({ paused: true });
|
||||
window.__timelines["root"] = mainTimeline;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user