mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 16:42:27 +00:00
* docs(skills): make captions non-optional in changelog-video The Jul 13-20 build shipped without captions because the pipeline had two soft failure modes: - Empty vo-words.json from the TTS provider was silently accepted, so align-captions.mjs had nothing to align. captions.json was never produced. - Step 5 tolerated the master-skeleton's LINES array staying empty. The build lint-checked and validated clean, but the caption rail rendered no text. This adds three hard gates on top of the existing scaffold: - Step 4 adds a whisper forced-alignment fallback so a missing TTS timestamp payload no longer breaks the caption pipeline. Whisper only supplies timings; captions still use the DISPLAY layer from script-tokens.json. - Step 5 flags an empty LINES array as a shipped bug and shows the exact IIFE-input shape it expects. - Step 6 adds gate 5: sample 3-4 frames across the VO window and confirm visible caption text on each. If any spoken window renders no caption, the build is red. Anti-patterns table gets two rows covering the empty-LINES and missing-word-timings failure modes. .claude and .agents mirrors stay byte-identical. Follow-up to #2669 (pre-build gate); paired with the v5 rebuild that retrofitted captions onto the shipped Jul 13-20 video. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(skills): bump changelog caption size to 32px for phone-screen legibility 25px reads too small at 1080² when the video is viewed on a phone without zoom. Bumped to 32px (font-size 25→32, top 1002→990, height 40→52, alpha .92→.94) so captions carry across small-screen playback. Change is CSS-only on the master-skeleton; existing per-scene chrome and layouts are untouched. Retrofitted the Jul 13-20 v6 build with the same values (identical CSS block) so the shipped video and the future default match. .claude and .agents mirrors stay byte-identical. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(skills): sync caption position refs to top: 990 across SKILL.md + build-spec Miga caught: the master-skeleton bump to top: 990 / 32px / height: 52 was not reflected in the SKILL.md prose or build-spec.md. All three files now name the same values so the doc, gate, and code stay consistent. Also clarifies build-spec.md's caption-rail line to point at SKILL.md step 5 as the source of the LINES-populated requirement. .claude and .agents mirrors byte-identical. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(skills): sync script-voice.md caption rail to top: 990 / 32px Third and final stale reference to top: 1002 / 25px — script-voice.md was still stating the pre-bump values. Now matches master-skeleton.html, build-spec.md, and SKILL.md. Also bumps the 'keep critical small text out' guidance from ~80px to ~100px to reflect the slightly taller caption rail. Full-directory sweep confirms zero remaining occurrences of 1002 or 25px across .claude/ and .agents/ skill mirrors. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
119 lines
6.9 KiB
HTML
119 lines
6.9 KiB
HTML
<!DOCTYPE html>
|
||
<!-- master-skeleton — the verbatim scaffold for a changelog master. Mirrors the
|
||
proven build. Replace <RANGE>, <TOTAL>, scene bodies; keep the mechanics. -->
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=1080, height=1080">
|
||
<title>HyperFrames Weekly — <RANGE></title>
|
||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||
<style>
|
||
@font-face { font-family:'ABC Solar Display'; src:url('assets/fonts/ABCSolarDisplay-Bold.woff2') format('woff2'); font-weight:700; font-display:block; }
|
||
@font-face { font-family:'TT Norms Pro'; src:url('assets/fonts/TT_Norms_Pro_Normal.woff2') format('woff2'); font-weight:400; font-display:block; }
|
||
@font-face { font-family:'TT Norms Pro'; src:url('assets/fonts/TT_Norms_Pro_Medium.woff2') format('woff2'); font-weight:500; font-display:block; }
|
||
@font-face { font-family:'TT Norms Mono'; src:url('assets/fonts/tt_norms_pro_mono_regular-webfont.woff2') format('woff2'); font-weight:400; font-display:block; }
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
html, body { width: 1080px; height: 1080px; background: #0a0c0b; overflow: hidden;
|
||
font-family: 'TT Norms Pro', sans-serif; color: #f5f6f4; }
|
||
#bg-video { position: absolute; inset: 0; width: 1080px; height: 1080px; object-fit: cover; }
|
||
#bg-scrim { position: absolute; inset: 0; background: rgba(8,10,9,.25); }
|
||
.chrome { position: absolute; z-index: 6; }
|
||
#kicker-chip { top: 44px; left: 76px; font-family: 'TT Norms Mono', monospace; font-size: 20px;
|
||
letter-spacing: .06em; color: rgba(245,246,244,.72); background: rgba(255,255,255,.05);
|
||
border: 1px solid rgba(255,255,255,.14); border-radius: 12px; padding: 10px 18px; }
|
||
#progress { top: 58px; right: 76px; display: flex; gap: 10px; }
|
||
#progress .dot { width: 8px; height: 8px; border-radius: 50%; background: rgba(245,246,244,.18); }
|
||
.slide { position: absolute; inset: 0; opacity: 0; }
|
||
.sec-chip { position: absolute; top: 128px; left: 76px; font-family: 'TT Norms Mono', monospace;
|
||
font-size: 22px; letter-spacing: .05em; color: rgba(245,246,244,.72);
|
||
background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.14);
|
||
border-radius: 12px; padding: 10px 16px; }
|
||
.sec-head { position: absolute; top: 186px; left: 76px; font-family: 'ABC Solar Display', sans-serif;
|
||
font-weight: 700; font-size: 54px; letter-spacing: -.01em; color: #f5f6f4; }
|
||
.glass { background: rgba(10,12,11,.78); border: 1px solid rgba(190,255,205,.32);
|
||
border-radius: 22px; box-shadow: 0 24px 60px rgba(0,0,0,.5); }
|
||
/* caption rail — overlay on top of the film, never a reserved band */
|
||
#cap-line { position: absolute; left: 0; right: 0; top: 990px; height: 52px; text-align: center;
|
||
z-index: 7; font-family: 'TT Norms Pro', sans-serif; font-weight: 500; font-size: 32px;
|
||
letter-spacing: .01em; color: rgba(245,246,244,.94);
|
||
text-shadow: 0 2px 14px rgba(0,0,0,.85), 0 0 3px rgba(0,0,0,.6);
|
||
white-space: nowrap; pointer-events: none; }
|
||
.cap-phrase { position: absolute; left: 0; right: 0; }
|
||
.cap-w { display: inline-block; margin: 0 4px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="root" data-composition-id="main" data-start="0" data-duration="<TOTAL>" data-width="1080" data-height="1080">
|
||
<video id="bg-video" class="clip" src="assets/bg-pattern-<TOTAL>s.mp4" muted data-start="0" data-duration="<TOTAL>" data-track-index="0"></video>
|
||
<div id="bg-scrim"></div>
|
||
<div id="kicker-chip" class="chrome">HYPERFRAMES WEEKLY <span style="color:rgba(245,246,244,.66)">· <RANGE></span></div>
|
||
<div id="progress" class="chrome"><span class="dot" id="dot1"></span><!-- one per theme --></div>
|
||
<div id="cap-line" class="chrome" data-layout-allow-overlap></div>
|
||
|
||
<!-- Title (film open — authors its OWN entry; exit is stamped) -->
|
||
<div id="s-title" class="slide clip" data-start="0" data-duration="<CUT1>" data-track-index="1">
|
||
<!-- mono kicker date · ABC Solar h1 · green rule -->
|
||
</div>
|
||
|
||
<!-- One slide per theme. data-start = EXACTLY the ledger cut time.
|
||
Shell composed at local t=0; internal beats ≥0.4s after the cut,
|
||
done ≥0.45s before the next. data-layout-allow-overlap on mock slides. -->
|
||
<div id="s-t1" class="slide clip" data-start="<CUT1>" data-duration="<DUR1>" data-track-index="1" data-layout-allow-overlap>
|
||
<div class="sec-chip">01 · <THEME></div>
|
||
<div class="sec-head"><HEADLINE></div>
|
||
<!-- the mock, from references/visualization-registry.md, y ∈ [288, 944] -->
|
||
</div>
|
||
|
||
<!-- s-t2..tN, then outro (kicker · "See what shipped." · green rule · URL chip) -->
|
||
|
||
<audio id="bgm" src="bgm.mp3" data-start="0" data-duration="<TOTAL>" data-track-index="2" data-volume="0.14" data-media-start="0"></audio>
|
||
<audio id="vo" src="voiceover.mp3" data-start="0" data-duration="<TOTAL>" data-track-index="3" data-volume="1.0"></audio>
|
||
</div>
|
||
|
||
<script>
|
||
gsap.defaults({ overwrite: 'auto' });
|
||
const tl = gsap.timeline({ paused: true });
|
||
tl.to({}, { duration: /*<TOTAL>*/ 47 }, 0);
|
||
|
||
// chrome in; progress dots via tl.set at each cut (never tl.call)
|
||
gsap.set('#kicker-chip', { autoAlpha: 0, y: -10 });
|
||
tl.to('#kicker-chip', { autoAlpha: 1, y: 0, duration: 0.5, ease: 'power3.out' }, 0.1);
|
||
// tl.set('#dot1', { backgroundColor: '#f5f6f4' }, <CUT1>); …
|
||
|
||
// ══ per-scene internal beats ══
|
||
// init states: gsap.set(...) at build time; motion: sequential tl.to(...) only.
|
||
// Every beat lands on a vo-words.json timestamp (local = master − scene start).
|
||
// One green (#5ef17c) moment per scene.
|
||
|
||
// ══ CAPTION RAIL — paste captions.json "lines" from align-captions.mjs ══
|
||
(function () {
|
||
const LINES = /* paste captions.json lines — [{id, end, w:[[display, start],…]},…] */ [];
|
||
const host = document.getElementById('cap-line');
|
||
LINES.forEach((line, li) => {
|
||
const ph = document.createElement('div');
|
||
ph.className = 'cap-phrase'; ph.id = 'cap-p' + li;
|
||
line.w.forEach(([txt], wi) => {
|
||
const s = document.createElement('span');
|
||
s.className = 'cap-w'; s.id = 'cap-p' + li + '-w' + wi; s.textContent = txt;
|
||
ph.appendChild(s);
|
||
});
|
||
host.appendChild(ph);
|
||
});
|
||
gsap.set('.cap-phrase', { autoAlpha: 0 });
|
||
gsap.set('.cap-w', { autoAlpha: 0 });
|
||
LINES.forEach((line, li) => {
|
||
tl.set('#cap-p' + li, { autoAlpha: 1 }, line.w[0][1]);
|
||
tl.set('#cap-p' + li, { autoAlpha: 0 }, line.end);
|
||
line.w.forEach(([txt, at], wi) => {
|
||
tl.to('#cap-p' + li + '-w' + wi, { autoAlpha: 1, duration: 0.12, ease: 'power1.out' }, at);
|
||
});
|
||
});
|
||
})();
|
||
|
||
window.__timelines = window.__timelines || {};
|
||
window.__timelines["main"] = tl;
|
||
// seam-stamp.mjs inserts the <seams:auto> block after the registration above.
|
||
</script>
|
||
</body>
|
||
</html>
|