mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-05 00:56:23 +00:00
Merge pull request #1672 from heygen-com/fix/skill-authoring-fixes
fix(skills): harden music-to-video Step 3 gate, align product-launch-video with pr-to-video
This commit is contained in:
@@ -63,7 +63,7 @@ python3 <SKILL_DIR>/scripts/analyze-beatgrid.py "$PROJECT_DIR/assets/bgm.mp3" \
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Frame skeleton
|
||||
## Step 2: Frame skeleton (structure only)
|
||||
|
||||
Goal: Read the music and lay out the frames — the skeleton of `STORYBOARD.md`.
|
||||
|
||||
@@ -73,7 +73,7 @@ Read [`references/frame-skeleton.md`](references/frame-skeleton.md). Turn `audio
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Plan (user-gated)
|
||||
## Step 3: Fill the plan (user-gated)
|
||||
|
||||
Goal: Turn the skeleton into an approved, complete `STORYBOARD.md`.
|
||||
|
||||
@@ -93,7 +93,7 @@ Fix every `✗` (hard errors: duration mismatch, frames not tiling the track, a
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Build frames
|
||||
## Step 4: Build frames from the plan
|
||||
|
||||
Goal: Build every frame as a self-contained composition file.
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
// not exist yet), so it checks fields, not on-disk html.
|
||||
//
|
||||
// HARD (exit 1): frontmatter duration_s == audiomap duration; >=1 frame; each frame
|
||||
// has src + positive duration; frames tile the track gap-free (sum == duration_s).
|
||||
// has src + positive duration; frames tile the track gap-free (sum == duration_s);
|
||||
// every frame has >=1 filled group (a frame whose `### Groups` is still
|
||||
// `TBD (Step 3)`/empty is a Step-2 skeleton, not an approved plan — fail it so a
|
||||
// skipped Step 3 can never reach the build step).
|
||||
// WARN (exit 0): best-effort group checks — each group exactly one of
|
||||
// template/free_design/asset; a template id exists under the --templates dir;
|
||||
// phrase_flow frame has no beat_cut asset treatment.
|
||||
@@ -114,12 +117,18 @@ for (const ln of raw.split(/\r?\n/)) {
|
||||
if (cur) cur.lines.push(ln);
|
||||
}
|
||||
|
||||
// HARD: every frame needs >=1 filled group. A frame with no parseable group head
|
||||
// is still a Step-2 skeleton (`### Groups` = `TBD (Step 3)`/empty) — erroring here
|
||||
// is what stops a skipped Step 3 from reaching the build step.
|
||||
const framesWithGroups = new Set(blocks.map((b) => b.frameLabel));
|
||||
for (const f of frames) {
|
||||
const title = String(f.title ?? "").trim();
|
||||
const lbl = `Frame ${f.number ?? ""} — ${f.title ?? f.index}`.replace(/\s+—\s+$/, "");
|
||||
if (![...framesWithGroups].some((s) => s.includes(String(f.title ?? "")))) {
|
||||
warns.push(
|
||||
`${lbl}: no parseable groups (expected \`- **gN** — template|free_design|asset …\`)`,
|
||||
const hasGroup = title !== "" && [...framesWithGroups].some((s) => s.includes(title));
|
||||
if (!hasGroup) {
|
||||
errors.push(
|
||||
`${lbl}: no filled groups — still a Step-2 skeleton (\`### Groups\` is TBD/empty). ` +
|
||||
`Run Step 3: fill its groups (\`- **gN** — template|free_design|asset …\`) before building.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ If your dispatch carries lint / validate feedback from a prior pass, address eac
|
||||
|
||||
## What comes fixed — realize it as given
|
||||
|
||||
- **No plan = stop.** If your `### Groups` is `TBD`/empty (Step 3 was skipped), report back and write nothing — never invent groups, templates, or copy.
|
||||
- **The plan** is set in your `## Frame` block: the groups, templates / primitives, copy, brand,
|
||||
and anchors. Build it as written. If a plan is genuinely wrong (wrong template or copy), stop
|
||||
and report — the orchestrator re-plans at Step 3.
|
||||
|
||||
Reference in New Issue
Block a user