mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
refactor(skills): rebuild faceless-explainer + pr-to-video on the shot-sequence architecture (#1778)
* refactor(skills): rebuild faceless-explainer + pr-to-video on the shot-sequence architecture Move both skills onto the current shot-sequence authoring architecture and the latest shared engine, then re-narrate to each domain. The engine fixes (pre-assembly frame guards + BGM loop-extend in assemble-index, dark-ground caption contrast, brand-accent selection + mono role in tokens, dark-mode polarity invert / weight-clamp / icon-font filter in build-frame) had only landed in one copy; both skills were a generation behind. - Authoring model: visual-design now writes a time-coded shot sequence (Scene windows paced to the voiceover) instead of the older effects-id phased note; motion-language carries the move vocabulary + the tightened motion doctrine (smooth over bouncy) + the seek-safe core (fromTo entrances, no CSS-transition motion); add cut-catalog (within-frame velocity-matched seams); frame-worker and SKILL Step 4/5 move to blueprint instantiation + shot-sequence fidelity. - faceless-explainer: fold the standalone composition.md into visual-design (inventing-the-visual / portrait / caption geometry); keep the explainer story doctrine; graft cue-segmented VO + candidate-blueprint-from-Step-3. - pr-to-video: keep the ingest pipeline (fetch-pr / ingest / fetch-people-avatars) and code-vocabulary; preserve the code-beat (code-* block as focal, Scenes choreograph the surround) and mechanism-beat treatments under the new model. - Drop stage-assets from both (no captured assets to stage); remove derivation references so each skill reads standalone. bun run scripts/lint-skills.ts passes; all scripts node --check clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(skills): resync skills-manifest after format pass The pre-commit skills-manifest hook hashed the skills before the format hook reformatted cut-catalog.md, so the committed manifest lagged the on-disk content and CI's "Skills: manifest in sync" check failed. Regenerated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c811a2750a
commit
7cb8386539
@@ -36,7 +36,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { parseStoryboard } from "./lib/storyboard.mjs";
|
||||
import { captionBand, parseFormat } from "./lib/dimensions.mjs";
|
||||
import { parseColors, parseFonts, semanticColors } from "./lib/tokens.mjs";
|
||||
import { parseColors, parseFonts, semanticColors, lum } from "./lib/tokens.mjs";
|
||||
|
||||
const flag = (argv, name, def) => {
|
||||
const i = argv.indexOf(`--${name}`);
|
||||
@@ -276,6 +276,20 @@ function buildFromSkin(skin, groups, total, W, H, tokens, die, faces = "", fonts
|
||||
// overflow:hidden — nothing is clipped); zeroing it would need an airy line-height that
|
||||
// balloons the pill, which is worse. Override only if a brand font genuinely clips.
|
||||
out += "\n<style>\n .caption-line { line-height: 1.1 !important; }\n</style>";
|
||||
// dark-ground caption contrast (auto). The preset caption skins are tuned for a LIGHT
|
||||
// pill (cream); on a dark brand ground the pill goes near-black, so the skin's faint
|
||||
// upcoming-word mix and light highlight block turn unreadable. When the resolved caption
|
||||
// canvas is dark, override the three word states: a brighter muted upcoming color + an
|
||||
// on-brand ACCENT highlight block with light text. Light grounds are left untouched.
|
||||
const capCanvas = (tokens.match(/--cap-canvas:\s*(#[0-9a-fA-F]{6})/) || [])[1];
|
||||
if (capCanvas && (lum(capCanvas) ?? 255) < 90) {
|
||||
out +=
|
||||
"\n<style>\n" +
|
||||
" .caption-word { color: color-mix(in srgb, var(--cap-ink) 64%, var(--cap-canvas)); }\n" +
|
||||
" .caption-word.is-active { color: var(--cap-ink); background: var(--cap-accent); box-shadow: 0 0 0 0.06em var(--cap-accent); }\n" +
|
||||
" .caption-word.is-spoken { color: var(--cap-ink); background: transparent; box-shadow: none; }\n" +
|
||||
"</style>";
|
||||
}
|
||||
return `<template id="captions-template" data-composition-id="captions" data-width="${W}" data-height="${H}">\n${out.trim()}\n</template>\n`;
|
||||
}
|
||||
|
||||
@@ -291,8 +305,11 @@ function brandFontFaces(framePath, hyperframesDir) {
|
||||
];
|
||||
if (!families.length) return "";
|
||||
const dirs = [
|
||||
{ abs: join(hyperframesDir, "assets/fonts"), rel: "../assets/fonts" },
|
||||
{ abs: join(hyperframesDir, "capture/assets/fonts"), rel: "../capture/assets/fonts" },
|
||||
// ROOT-RELATIVE — compositions are served with the project root as their base URL, so a
|
||||
// "../" prefix escapes the root (lint: invalid_parent_traversal_in_asset_path) and 404s in
|
||||
// Studio/preview. Mirror what the frame workers use for images.
|
||||
{ abs: join(hyperframesDir, "assets/fonts"), rel: "assets/fonts" },
|
||||
{ abs: join(hyperframesDir, "capture/assets/fonts"), rel: "capture/assets/fonts" },
|
||||
].filter((d) => existsSync(d.abs));
|
||||
const weightOf = (n) => {
|
||||
const s = n.toLowerCase();
|
||||
|
||||
Reference in New Issue
Block a user