hyper-animator-codex 0.8.1 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/bin/hyper-animator-codex.mjs +4 -4
- package/lib/install-skill.mjs +49 -20
- package/lib/minimax-config.mjs +5 -9
- package/package.json +7 -2
- package/skills/hyper-animator-codex/SKILL.md +11 -9
- package/skills/hyper-animator-codex/contracts/shot-plan.schema.json +45 -5
- package/skills/hyper-animator-codex/contracts/workflow-policy.json +8 -2
- package/skills/hyper-animator-codex/references/examples/shot-plan-dual-catalog.json +9 -3
- package/skills/hyper-animator-codex/references/hyperframes-intent-workflow.md +4 -2
- package/skills/hyper-animator-codex/references/minimax-music-workflow.md +5 -7
- package/skills/hyper-animator-codex/references/narration-audio-workflow.md +3 -4
- package/skills/hyper-animator-codex/references/preview-controls-workflow.md +4 -2
- package/skills/hyper-animator-codex/scripts/generate_minimax_music.mjs +11 -6
- package/skills/hyper-animator-codex/scripts/generate_minimax_tts.mjs +20 -8
- package/skills/hyper-animator-codex/scripts/git_checkpoint.mjs +27 -1
- package/skills/hyper-animator-codex/scripts/inject_preview_controls.mjs +37 -1
- package/skills/hyper-animator-codex/scripts/minimax_runtime_config.mjs +5 -9
- package/skills/hyper-animator-codex/scripts/query_shotcraft.mjs +10 -1
- package/skills/hyper-animator-codex/scripts/shot_plan_schema_validator.mjs +3 -0
- package/skills/hyper-animator-codex/scripts/validate_hyperframes_html.py +122 -36
- package/skills/hyper-animator-codex/scripts/validate_shot_plan.mjs +28 -8
package/README.md
CHANGED
|
@@ -77,14 +77,13 @@ generate music and voiceover without asking for credentials later:
|
|
|
77
77
|
```bash
|
|
78
78
|
npx hyper-animator-codex install --force \
|
|
79
79
|
--minimax-api-key "$MINIMAX_API_KEY" \
|
|
80
|
-
--minimax-
|
|
81
|
-
--minimax-model music-2.6-free
|
|
80
|
+
--minimax-model music-3.0-free
|
|
82
81
|
```
|
|
83
82
|
|
|
84
83
|
Environment fallback is also supported:
|
|
85
84
|
|
|
86
85
|
```bash
|
|
87
|
-
MINIMAX_API_KEY=...
|
|
86
|
+
MINIMAX_API_KEY=... npx hyper-animator-codex install --force
|
|
88
87
|
```
|
|
89
88
|
|
|
90
89
|
Or load a JSON config file:
|
|
@@ -107,7 +106,8 @@ Preview HTML can include a bottom page indicator and thin draggable progress bar
|
|
|
107
106
|
|
|
108
107
|
```bash
|
|
109
108
|
node skills/hyper-animator-codex/scripts/inject_preview_controls.mjs composition.html -o composition.preview.html --force
|
|
110
|
-
python3 skills/hyper-animator-codex/scripts/validate_hyperframes_html.py composition.preview.html
|
|
109
|
+
python3 skills/hyper-animator-codex/scripts/validate_hyperframes_html.py composition.preview.html \
|
|
110
|
+
--preview-controls --shot-plan shot-plan.json
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
The injected controls support dragging the progress bar and using ArrowLeft or ArrowRight to move between pages.
|
|
@@ -197,15 +197,17 @@ Validate a dual-catalog plan before authoring:
|
|
|
197
197
|
|
|
198
198
|
```bash
|
|
199
199
|
node skills/hyper-animator-codex/scripts/validate_shot_plan.mjs shot-plan.json
|
|
200
|
+
python3 skills/hyper-animator-codex/scripts/validate_hyperframes_html.py composition.html --shot-plan shot-plan.json
|
|
200
201
|
```
|
|
201
202
|
|
|
202
|
-
When model routing is available, `
|
|
203
|
-
and animation authoring. Planning, discovery, audio
|
|
204
|
-
packaging use
|
|
203
|
+
When model routing is available, the client's `high_quality` tier is reserved
|
|
204
|
+
for page generation and animation authoring. Planning, discovery, audio
|
|
205
|
+
prompting, validation, and packaging use its `fast` tier; the shot plan records
|
|
206
|
+
the actual model names.
|
|
205
207
|
|
|
206
208
|
## Contents
|
|
207
209
|
|
|
208
|
-
- `skills/hyper-animator-codex/SKILL.md`: Codex skill instructions.
|
|
210
|
+
- `skills/hyper-animator-codex/SKILL.md`: Codex and Claude Code skill instructions.
|
|
209
211
|
- `skills/hyper-animator-codex/contracts/`: provider/model policy and shot-plan schema.
|
|
210
212
|
- `skills/hyper-animator-codex/references/`: HyperFrames catalog, ShotCraft knowledge bundle, authoring patterns, workflows, and examples.
|
|
211
213
|
- `skills/hyper-animator-codex/scripts/query_shotcraft.mjs`: ShotCraft intent/reference search.
|
|
@@ -25,12 +25,12 @@ Options:
|
|
|
25
25
|
--quiet Suppress successful install output
|
|
26
26
|
--target <dir> Install into one specific skills directory
|
|
27
27
|
--minimax-api-key <key> Save MiniMax API key into installed skill config
|
|
28
|
-
--minimax-group-id <group_id>
|
|
29
|
-
--minimax-model <model> MiniMax text music model
|
|
30
|
-
--minimax-config <file> Load MiniMax JSON config with api_key
|
|
28
|
+
--minimax-group-id <group_id> Optional legacy account metadata
|
|
29
|
+
--minimax-model <model> MiniMax text music model; default music-3.0
|
|
30
|
+
--minimax-config <file> Load MiniMax JSON config with api_key and optional model
|
|
31
31
|
|
|
32
32
|
Environment fallback:
|
|
33
|
-
MINIMAX_API_KEY, MINIMAX_GROUP_ID
|
|
33
|
+
MINIMAX_API_KEY, MINIMAX_MODEL (MINIMAX_GROUP_ID remains optional)
|
|
34
34
|
`);
|
|
35
35
|
}
|
|
36
36
|
|
package/lib/install-skill.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { chmod, cp, mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
1
|
+
import { chmod, cp, mkdir, mkdtemp, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { basename, dirname, join } from "node:path";
|
|
3
|
+
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
|
|
6
6
|
import {
|
|
@@ -84,46 +84,75 @@ async function restoreExistingMinimaxConfig(installedPath, existingConfig) {
|
|
|
84
84
|
|
|
85
85
|
export async function installSkill(options = {}) {
|
|
86
86
|
const targetRoot = options.targetRoot || resolveCodexSkillsRoot(options.env);
|
|
87
|
-
const sourcePath = options.sourcePath || join(packageRoot, "skills", SKILL_NAME);
|
|
88
|
-
const installedPath =
|
|
87
|
+
const sourcePath = resolve(options.sourcePath || join(packageRoot, "skills", SKILL_NAME));
|
|
88
|
+
const installedPath = resolve(targetRoot, SKILL_NAME);
|
|
89
89
|
const force = Boolean(options.force);
|
|
90
90
|
|
|
91
|
+
if (sourcePath === installedPath
|
|
92
|
+
|| sourcePath.startsWith(`${installedPath}${sep}`)
|
|
93
|
+
|| installedPath.startsWith(`${sourcePath}${sep}`)) {
|
|
94
|
+
throw new Error(`Source and install paths overlap: ${sourcePath} -> ${installedPath}`);
|
|
95
|
+
}
|
|
91
96
|
if (!(await pathExists(sourcePath))) {
|
|
92
97
|
throw new Error(`Packaged skill not found at ${sourcePath}`);
|
|
93
98
|
}
|
|
94
99
|
|
|
95
100
|
await mkdir(targetRoot, { recursive: true });
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (await pathExists(installedPath)) {
|
|
101
|
+
const installExists = await pathExists(installedPath);
|
|
102
|
+
if (installExists) {
|
|
100
103
|
if (!force) {
|
|
101
104
|
throw new Error(`${SKILL_NAME} already exists at ${installedPath}; rerun with --force to replace it`);
|
|
102
105
|
}
|
|
103
|
-
await rm(installedPath, { recursive: true, force: true });
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
await cp(sourcePath, installedPath, {
|
|
107
|
-
recursive: true,
|
|
108
|
-
filter: shouldCopy,
|
|
109
|
-
});
|
|
110
|
-
|
|
111
108
|
const resolvedMinimaxConfig = await resolveInstallMinimaxConfig({
|
|
112
109
|
cliConfig: options.minimaxConfig || {},
|
|
113
110
|
env: options.env || process.env,
|
|
114
111
|
});
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
const existingMinimaxConfig = force ? await readExistingMinimaxConfig(installedPath) : null;
|
|
113
|
+
const stagingRoot = await mkdtemp(join(resolve(targetRoot), `.${SKILL_NAME}-install-`));
|
|
114
|
+
const stagingPath = join(stagingRoot, SKILL_NAME);
|
|
115
|
+
let backupRoot = null;
|
|
116
|
+
let backupPath = null;
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
await cp(sourcePath, stagingPath, {
|
|
120
|
+
recursive: true,
|
|
121
|
+
filter: shouldCopy,
|
|
122
|
+
});
|
|
123
|
+
if (resolvedMinimaxConfig) {
|
|
124
|
+
await writeMinimaxConfig(stagingPath, resolvedMinimaxConfig);
|
|
125
|
+
} else {
|
|
126
|
+
await restoreExistingMinimaxConfig(stagingPath, existingMinimaxConfig);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (installExists) {
|
|
130
|
+
backupRoot = await mkdtemp(join(resolve(targetRoot), `.${SKILL_NAME}-backup-`));
|
|
131
|
+
backupPath = join(backupRoot, SKILL_NAME);
|
|
132
|
+
await rename(installedPath, backupPath);
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
await rename(stagingPath, installedPath);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (backupPath && await pathExists(backupPath)) {
|
|
138
|
+
await rename(backupPath, installedPath);
|
|
139
|
+
}
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
} finally {
|
|
143
|
+
await rm(stagingRoot, { recursive: true, force: true });
|
|
144
|
+
if (backupRoot) await rm(backupRoot, { recursive: true, force: true });
|
|
145
|
+
}
|
|
119
146
|
|
|
120
147
|
return {
|
|
121
148
|
skillName: SKILL_NAME,
|
|
122
149
|
tool: options.tool || "codex",
|
|
123
150
|
sourcePath,
|
|
124
151
|
installedPath,
|
|
125
|
-
minimaxConfigPath:
|
|
126
|
-
|
|
152
|
+
minimaxConfigPath: resolvedMinimaxConfig || existingMinimaxConfig
|
|
153
|
+
? join(installedPath, MINIMAX_CONFIG_RELATIVE_PATH)
|
|
154
|
+
: null,
|
|
155
|
+
minimaxConfig: resolvedMinimaxConfig ? redactMinimaxConfig(resolvedMinimaxConfig) : null,
|
|
127
156
|
};
|
|
128
157
|
}
|
|
129
158
|
|
package/lib/minimax-config.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
|
|
4
|
-
export const DEFAULT_MINIMAX_MODEL = "music-
|
|
5
|
-
export const TEXT_MUSIC_MODELS = new Set(["music-3.0", "music-2.6", "music-2.6-free"]);
|
|
4
|
+
export const DEFAULT_MINIMAX_MODEL = "music-3.0";
|
|
5
|
+
export const TEXT_MUSIC_MODELS = new Set(["music-3.0", "music-3.0-free", "music-2.6", "music-2.6-free"]);
|
|
6
6
|
export const MINIMAX_CONFIG_RELATIVE_PATH = join("config", "minimax.json");
|
|
7
7
|
|
|
8
8
|
async function pathExists(path) {
|
|
@@ -62,19 +62,15 @@ export function validateMinimaxConfig(config = {}) {
|
|
|
62
62
|
throw new Error("MiniMax api_key is required when MiniMax config is provided");
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
if (!normalized.group_id) {
|
|
66
|
-
throw new Error("MiniMax group_id is required when MiniMax config is provided");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
65
|
const model = normalized.model || DEFAULT_MINIMAX_MODEL;
|
|
70
66
|
|
|
71
67
|
if (!TEXT_MUSIC_MODELS.has(model)) {
|
|
72
|
-
throw new Error(`Unsupported MiniMax text music model: ${model}. Use music-3.0, music-2.6, or music-2.6-free.`);
|
|
68
|
+
throw new Error(`Unsupported MiniMax text music model: ${model}. Use music-3.0, music-3.0-free, music-2.6, or music-2.6-free.`);
|
|
73
69
|
}
|
|
74
70
|
|
|
75
71
|
return {
|
|
76
72
|
api_key: normalized.api_key,
|
|
77
|
-
group_id: normalized.group_id,
|
|
73
|
+
...(normalized.group_id ? { group_id: normalized.group_id } : {}),
|
|
78
74
|
model,
|
|
79
75
|
};
|
|
80
76
|
}
|
|
@@ -156,7 +152,7 @@ export function redactMinimaxConfig(config = {}) {
|
|
|
156
152
|
|
|
157
153
|
return {
|
|
158
154
|
api_key: normalized.api_key ? "[redacted]" : undefined,
|
|
159
|
-
group_id: normalized.group_id,
|
|
155
|
+
...(normalized.group_id ? { group_id: normalized.group_id } : {}),
|
|
160
156
|
model: normalized.model || DEFAULT_MINIMAX_MODEL,
|
|
161
157
|
};
|
|
162
158
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hyper-animator-codex",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Install the Hyper Animator skill for Codex and Claude Code.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,11 +8,13 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"postinstall": "node bin/postinstall.mjs",
|
|
11
|
+
"build:contracts": "node tools/build-shot-plan-validator.mjs",
|
|
11
12
|
"preflight": "node tools/verify-governance.mjs",
|
|
12
13
|
"test": "node --test",
|
|
13
14
|
"test:contracts": "node --test test/shot-plan-contract.test.mjs test/workflow-policy.test.mjs test/provider-policy.test.mjs",
|
|
14
15
|
"check": "npm run preflight && npm test && npm run pack:check",
|
|
15
|
-
"pack:check": "npm pack --dry-run"
|
|
16
|
+
"pack:check": "npm pack --dry-run",
|
|
17
|
+
"prepublishOnly": "npm run check"
|
|
16
18
|
},
|
|
17
19
|
"files": [
|
|
18
20
|
"bin/",
|
|
@@ -39,5 +41,8 @@
|
|
|
39
41
|
},
|
|
40
42
|
"publishConfig": {
|
|
41
43
|
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"ajv": "^8.17.1"
|
|
42
47
|
}
|
|
43
48
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hyper-animator-codex
|
|
3
|
-
description: Use when a user asks
|
|
3
|
+
description: Use when a user asks a coding agent to create, plan, author, customize, validate, preview, or render a HyperFrames, HTML, or GSAP animation/video from natural-language requirements, including product demos, code demos, data videos, podcast captions, social shorts, catalog assembly, new HyperFrames HTML, outline/narration detection, voiceover, subtitles, sound effects, background music, rhythm, BPM, final mixing, or beat-synced transitions.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Hyper Animator Codex
|
|
@@ -24,15 +24,15 @@ Turn a natural-language animation or video brief into a validated HyperFrames HT
|
|
|
24
24
|
9. Decide generation mode:
|
|
25
25
|
- `generate_new_hyperframes_html` when the user asks to write HTML, create a new effect, customize style, match a brand, use complex animation, or when component snippets are only paste placeholders.
|
|
26
26
|
- `assemble_existing_catalog_items` only when the user asks to use existing catalog items or quickly compose installed blocks/components.
|
|
27
|
-
10. Apply model routing when model selection is available: use `
|
|
28
|
-
11. Write a visual-first shot plan that follows `contracts/shot-plan.schema.json`, sets workflow_stage: `visual_draft`, `catalog_strategy: "dual_catalog"`, `audio.narration.mode: "deferred"` when narration is requested, explicit start/end timing, both catalog reference lists, and one `motion_contract` per shot including `motion_preset`. Run `scripts/validate_shot_plan.mjs shot-plan.json`; fix every error before HTML authoring.
|
|
27
|
+
10. Apply capability-based model routing when model selection is available: use the client's `high_quality` model for page and animation authoring only, and a `fast` cost-efficient model for requirements, discovery, catalog queries, shot planning, audio prompting, validation, and packaging. On Codex, prefer `gpt-5.6-sol` and `gpt-5.6-terra` respectively; on Claude Code, record the actual Claude models selected. Do not create an extra agent/entity only to implement this routing.
|
|
28
|
+
11. Write a visual-first shot plan that follows `contracts/shot-plan.schema.json`, sets workflow_stage: `visual_draft`, `catalog_strategy: "dual_catalog"`, `audio.narration.mode: "deferred"` when narration is requested, provider-neutral model routing tiers plus actual model names, explicit start/end timing, both catalog reference lists, and one `motion_contract` per shot including `motion_preset`. Run `scripts/validate_shot_plan.mjs shot-plan.json`; fix every error before HTML authoring.
|
|
29
29
|
12. Clarify audio intent only: ask whether the final piece should use narration, subtitles, transition sound effects, and background music. Do not generate narration audio or subtitles before the user confirms the page, transition, and animation. If BGM is the rhythm source, it may be generated or imported before HTML; otherwise defer it with narration.
|
|
30
30
|
13. If generated BGM is needed as the rhythm source, read `references/minimax-music-workflow.md`, run `scripts/validate_provider_policy.mjs --kind bgm --provider minimax_cn --endpoint https://api.minimaxi.com/v1/music_generation`, and use `scripts/generate_minimax_music.mjs`. Then read `references/beat-sync-workflow.md` and run `scripts/analyze_music_beats.py` when dependencies and the file are already available. Do not install beat-analysis dependencies during the run.
|
|
31
31
|
14. Ask the second clarification round with dual-catalog candidate context: visual direction, motion rhythm, selected ShotCraft commitments, generation mode, BGM/beat-sync assumptions when present, and the fact that narration is deferred until visual approval.
|
|
32
32
|
15. Write or assemble the visual HTML using `references/HyperFrames-AI-Generation-Patterns-codex.md`. When beat-sync is enabled, align major reveals, cuts, transitions, camera moves, subtitle placeholders, and visual accents to the beat map instead of arbitrary timestamps.
|
|
33
33
|
16. After each file-writing stage, run `scripts/git_checkpoint.mjs` with the phase-specific allowlist from `references/git-checkpoint-workflow.md`. Do not create, switch, or recommend Git branches or worktrees.
|
|
34
|
-
17.
|
|
35
|
-
18. Read `references/preview-controls-workflow.md`, run `scripts/inject_preview_controls.mjs` to create a preview HTML copy, and run `scripts/validate_hyperframes_html.py preview.html --preview-controls`.
|
|
34
|
+
17. Mark every shot root with `data-shot-id` and `data-motion-preset`, then run `scripts/validate_hyperframes_html.py composition.html --shot-plan shot-plan.json` so planned ShotCraft motion is proven in executable HTML.
|
|
35
|
+
18. Read `references/preview-controls-workflow.md`, run `scripts/inject_preview_controls.mjs` to create a preview HTML copy (with play/pause and interactive autoplay), and run `scripts/validate_hyperframes_html.py preview.html --preview-controls --shot-plan shot-plan.json`.
|
|
36
36
|
19. Show a concise visual plan summary and preview path. Ask the user to confirm or revise the page, transition, and animation before any generated narration or subtitle work.
|
|
37
37
|
20. After visual confirmation, handle narration. If generated narration is used, first run `scripts/validate_provider_policy.mjs --kind narration --provider minimax_cn --endpoint https://api.minimaxi.com/v1/t2a_v2`. Use `scripts/generate_minimax_tts.mjs` for voice listing and TTS; do not construct MiniMax HTTP calls directly. For multi-scene narration, use `--split-scenes` and treat `narration-manifest.json` actual durations as the scene-timing source. Generate subtitles only after this with `scripts/generate_subtitles.mjs --timing-manifest <voice-output>/narration-manifest.json`.
|
|
38
38
|
21. Reconcile shot boundaries with actual narration durations, update the shot plan to `workflow_stage: "audio_integrated"`, re-run `scripts/validate_shot_plan.mjs`, update the HTML/audio preview, and ask for final render confirmation.
|
|
@@ -40,7 +40,7 @@ Turn a natural-language animation or video brief into a validated HyperFrames HT
|
|
|
40
40
|
|
|
41
41
|
## Interactive Questions
|
|
42
42
|
|
|
43
|
-
Prefer
|
|
43
|
+
Prefer the current client's interactive question tool when available. If unavailable, ask the same questions as ordinary concise text and continue after the user answers.
|
|
44
44
|
|
|
45
45
|
Use two rounds:
|
|
46
46
|
|
|
@@ -86,7 +86,7 @@ Hard constraints beat score:
|
|
|
86
86
|
Before render, run:
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
-
python3 scripts/validate_hyperframes_html.py path/to/composition.html
|
|
89
|
+
python3 scripts/validate_hyperframes_html.py path/to/composition.html --shot-plan path/to/shot-plan.json
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
Generated block HTML must include:
|
|
@@ -96,6 +96,8 @@ Generated block HTML must include:
|
|
|
96
96
|
- scoped CSS under `[data-composition-id="..."]` or another unique composition selector;
|
|
97
97
|
- `gsap.timeline({ paused: true })`;
|
|
98
98
|
- `window.__timelines[id]` registration;
|
|
99
|
+
- one `data-shot-id` and matching `data-motion-preset` per planned shot;
|
|
100
|
+
- a real motion-pack helper call for every supported non-`none` preset;
|
|
99
101
|
- no unresolved `<!-- paste from ... -->` placeholders;
|
|
100
102
|
- no wall-clock `Date.now()` or `setInterval()` driving primary timeline progress;
|
|
101
103
|
- no `Math.random()` for visual generation; use a fixed-seed deterministic PRNG;
|
|
@@ -105,7 +107,7 @@ Generated block HTML must include:
|
|
|
105
107
|
Preview HTML must pass:
|
|
106
108
|
|
|
107
109
|
```bash
|
|
108
|
-
python3 scripts/validate_hyperframes_html.py path/to/composition.preview.html --preview-controls
|
|
110
|
+
python3 scripts/validate_hyperframes_html.py path/to/composition.preview.html --preview-controls --shot-plan path/to/shot-plan.json
|
|
109
111
|
```
|
|
110
112
|
|
|
111
113
|
If the validator fails, fix the HTML before asking the user to approve render.
|
|
@@ -140,7 +142,7 @@ Before rendering, summarize:
|
|
|
140
142
|
|
|
141
143
|
- generation mode;
|
|
142
144
|
- shot-plan validator result and selected HyperFrames/ShotCraft references per shot;
|
|
143
|
-
- model routing used, including confirmation that
|
|
145
|
+
- model routing used, including confirmation that the high-quality tier was limited to page/animation authoring;
|
|
144
146
|
- detected outline/narration paths, ambiguity status, and any outline/narration generation assumptions;
|
|
145
147
|
- selected or referenced catalog items;
|
|
146
148
|
- narration usage, selected voice, emotion, voice audio path, subtitle style, subtitle JSON/SRT paths, and voice/BGM/SFX volume values when applicable;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"properties": {
|
|
19
19
|
"schema_version": {
|
|
20
|
-
"const": "1.
|
|
20
|
+
"const": "1.1.0"
|
|
21
21
|
},
|
|
22
22
|
"workflow_stage": {
|
|
23
23
|
"enum": [
|
|
@@ -82,12 +82,32 @@
|
|
|
82
82
|
],
|
|
83
83
|
"properties": {
|
|
84
84
|
"page_animation_authoring": {
|
|
85
|
-
"
|
|
85
|
+
"allOf": [
|
|
86
|
+
{
|
|
87
|
+
"$ref": "#/$defs/modelRoute"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"properties": {
|
|
91
|
+
"tier": {
|
|
92
|
+
"const": "high_quality"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
]
|
|
86
97
|
},
|
|
87
98
|
"planning_and_validation": {
|
|
88
|
-
"
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
"allOf": [
|
|
100
|
+
{
|
|
101
|
+
"$ref": "#/$defs/modelRoute"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"properties": {
|
|
105
|
+
"tier": {
|
|
106
|
+
"const": "fast"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
]
|
|
91
111
|
}
|
|
92
112
|
}
|
|
93
113
|
},
|
|
@@ -106,6 +126,26 @@
|
|
|
106
126
|
}
|
|
107
127
|
},
|
|
108
128
|
"$defs": {
|
|
129
|
+
"modelRoute": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"additionalProperties": false,
|
|
132
|
+
"required": [
|
|
133
|
+
"tier",
|
|
134
|
+
"actual_model"
|
|
135
|
+
],
|
|
136
|
+
"properties": {
|
|
137
|
+
"tier": {
|
|
138
|
+
"enum": [
|
|
139
|
+
"high_quality",
|
|
140
|
+
"fast"
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
"actual_model": {
|
|
144
|
+
"type": "string",
|
|
145
|
+
"minLength": 1
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
},
|
|
109
149
|
"audioTrack": {
|
|
110
150
|
"type": "object",
|
|
111
151
|
"additionalProperties": false,
|
|
@@ -47,14 +47,20 @@
|
|
|
47
47
|
},
|
|
48
48
|
"model_routing": {
|
|
49
49
|
"page_animation_authoring": {
|
|
50
|
-
"
|
|
50
|
+
"tier": "high_quality",
|
|
51
|
+
"preferred_models": {
|
|
52
|
+
"codex": "gpt-5.6-sol"
|
|
53
|
+
},
|
|
51
54
|
"use_for": [
|
|
52
55
|
"page_generation",
|
|
53
56
|
"animation_authoring"
|
|
54
57
|
]
|
|
55
58
|
},
|
|
56
59
|
"planning_and_validation": {
|
|
57
|
-
"
|
|
60
|
+
"tier": "fast",
|
|
61
|
+
"preferred_models": {
|
|
62
|
+
"codex": "gpt-5.6-terra"
|
|
63
|
+
},
|
|
58
64
|
"use_for": [
|
|
59
65
|
"requirements",
|
|
60
66
|
"file_detection",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schema_version": "1.
|
|
2
|
+
"schema_version": "1.1.0",
|
|
3
3
|
"workflow_stage": "visual_draft",
|
|
4
4
|
"generation_mode": "generate_new_hyperframes_html",
|
|
5
5
|
"catalog_strategy": "dual_catalog",
|
|
@@ -18,8 +18,14 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"model_routing": {
|
|
21
|
-
"page_animation_authoring":
|
|
22
|
-
|
|
21
|
+
"page_animation_authoring": {
|
|
22
|
+
"tier": "high_quality",
|
|
23
|
+
"actual_model": "gpt-5.6-sol"
|
|
24
|
+
},
|
|
25
|
+
"planning_and_validation": {
|
|
26
|
+
"tier": "fast",
|
|
27
|
+
"actual_model": "gpt-5.6-terra"
|
|
28
|
+
}
|
|
23
29
|
},
|
|
24
30
|
"shots": [
|
|
25
31
|
{
|
|
@@ -184,9 +184,11 @@ Round 2 不选择 voice/emotion,也不生成字幕。旁白选择放到视觉
|
|
|
184
184
|
|
|
185
185
|
## Model Routing
|
|
186
186
|
|
|
187
|
-
- `
|
|
187
|
+
- 页面生成和动画编写使用当前客户端的 `high_quality` 层级模型;
|
|
188
|
+
Codex 优先 `gpt-5.6-sol`。
|
|
188
189
|
- 需求抽取、文件检测、catalog 查询、镜头计划、音频提示词、校验和打包
|
|
189
|
-
|
|
190
|
+
使用当前客户端的 `fast` 层级模型;Codex 优先 `gpt-5.6-terra`。
|
|
191
|
+
- 在 shot plan 中记录层级和实际模型名;Claude Code 不要伪填 GPT 型号。
|
|
190
192
|
- 不为模型路由自动新增 Agent 或其他实体;在运行环境支持模型选择时才
|
|
191
193
|
应用路由。
|
|
192
194
|
|
|
@@ -26,17 +26,15 @@ The installed config shape is:
|
|
|
26
26
|
```json
|
|
27
27
|
{
|
|
28
28
|
"api_key": "[redacted]",
|
|
29
|
-
"
|
|
30
|
-
"model": "music-2.6-free"
|
|
29
|
+
"model": "music-3.0"
|
|
31
30
|
}
|
|
32
31
|
```
|
|
33
32
|
|
|
34
|
-
Do not print or echo the raw API key. `group_id` is
|
|
33
|
+
Do not print or echo the raw API key. `group_id` is optional legacy account
|
|
34
|
+
metadata and is not required by the current `/v1/music_generation` call.
|
|
35
35
|
|
|
36
|
-
The wrapper accepts `music-3.0`, `music-
|
|
37
|
-
|
|
38
|
-
`music-3.0` explicitly when the account has access and the user wants the
|
|
39
|
-
current model.
|
|
36
|
+
The wrapper accepts `music-3.0`, `music-3.0-free`, `music-2.6`, and
|
|
37
|
+
`music-2.6-free`. The installer default is `music-3.0`.
|
|
40
38
|
|
|
41
39
|
## Clarify Music
|
|
42
40
|
|
|
@@ -19,7 +19,7 @@ Rules:
|
|
|
19
19
|
- if only narration exists, use it as content context but do not generate audio or subtitles yet;
|
|
20
20
|
- if narration is not used, do not generate voice audio or subtitles.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
The coding agent writes or edits outline/narration content. Scripts only validate, convert, call MiniMax, and write artifacts.
|
|
23
23
|
|
|
24
24
|
Narration is a post-visual-confirmation stage. Do not generate MiniMax TTS,
|
|
25
25
|
voice lists, or subtitles until the user has approved the page, transition,
|
|
@@ -31,8 +31,7 @@ and animation direction. A visual draft shot plan should use
|
|
|
31
31
|
Generated narration and BGM use MiniMax mainland China (`minimax_cn`) only.
|
|
32
32
|
Never run `hyperframes auth login` or `hyperframes tts`; never invoke HeyGen,
|
|
33
33
|
Kokoro, or MusicGen; and never install a fallback runtime/model or beat
|
|
34
|
-
analysis dependency during a run.
|
|
35
|
-
but it is outside this product contract and is not needed.
|
|
34
|
+
analysis dependency during a run. Do not add a Kokoro runtime or component.
|
|
36
35
|
|
|
37
36
|
Before a generated-audio call, validate the route:
|
|
38
37
|
|
|
@@ -53,7 +52,7 @@ Use this shape:
|
|
|
53
52
|
|
|
54
53
|
```json
|
|
55
54
|
{
|
|
56
|
-
"voice": "
|
|
55
|
+
"voice": "male-qn-qingse",
|
|
57
56
|
"emotion": "calm",
|
|
58
57
|
"language": "zh",
|
|
59
58
|
"style": "casual",
|
|
@@ -4,7 +4,7 @@ Use this whenever a generated or assembled HyperFrames HTML animation will be sh
|
|
|
4
4
|
|
|
5
5
|
## Required Behavior
|
|
6
6
|
|
|
7
|
-
HTML previews should include a bottom page indicator and thin progress bar.
|
|
7
|
+
HTML previews should include a bottom page indicator, play/pause button, and thin progress bar. The preview copy must start the registered timeline in interactive mode; users can pause/resume, drag the progress bar to seek, or press ArrowLeft and ArrowRight to move between pages. Never show the paused base composition as the interactive preview.
|
|
8
8
|
|
|
9
9
|
Video renders must hide those controls. Use one of these render-hidden signals:
|
|
10
10
|
|
|
@@ -12,6 +12,8 @@ Video renders must hide those controls. Use one of these render-hidden signals:
|
|
|
12
12
|
- `?preview=0`
|
|
13
13
|
- `<html data-render-mode="video">`
|
|
14
14
|
|
|
15
|
+
The main render timeline should remain `paused: true` for deterministic frame capture. Preview controls are responsible for calling `timeline.play()`/`timeline.pause()` and must skip autoplay when any render-hidden signal is active.
|
|
16
|
+
|
|
15
17
|
## Page Model
|
|
16
18
|
|
|
17
19
|
Prefer explicit page starts:
|
|
@@ -34,7 +36,7 @@ After the base HTML passes normal quality gates, create a preview copy:
|
|
|
34
36
|
|
|
35
37
|
```bash
|
|
36
38
|
node scripts/inject_preview_controls.mjs composition.html -o composition.preview.html --force
|
|
37
|
-
python3 scripts/validate_hyperframes_html.py composition.preview.html --preview-controls
|
|
39
|
+
python3 scripts/validate_hyperframes_html.py composition.preview.html --preview-controls --shot-plan shot-plan.json
|
|
38
40
|
```
|
|
39
41
|
|
|
40
42
|
Show the preview copy to the user for validation.
|
|
@@ -108,7 +108,7 @@ Options:
|
|
|
108
108
|
--format <mp3|wav|pcm> Audio encoding format, default mp3
|
|
109
109
|
--sample-rate <rate> 16000, 24000, 32000, or 44100; default 44100
|
|
110
110
|
--bitrate <bits> 32000, 64000, 128000, or 256000; default 256000
|
|
111
|
-
--model <model> music-3.0, music-2.6, or music-2.6-free
|
|
111
|
+
--model <model> music-3.0, music-3.0-free, music-2.6, or music-2.6-free
|
|
112
112
|
--config <file> Explicit MiniMax config JSON
|
|
113
113
|
--request-json <file> Read request options from a JSON file
|
|
114
114
|
--dry-run Print redacted request without contacting MiniMax
|
|
@@ -270,8 +270,12 @@ function safeFileStem(prompt) {
|
|
|
270
270
|
return stem || "minimax-music";
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
-
async function downloadUrl(url) {
|
|
274
|
-
const
|
|
273
|
+
async function downloadUrl(url, timeoutMs) {
|
|
274
|
+
const parsed = URL.canParse(url) ? new URL(url) : null;
|
|
275
|
+
if (!parsed || !["http:", "https:"].includes(parsed.protocol)) {
|
|
276
|
+
throw minimaxError("MiniMax audio URL must use HTTP or HTTPS", { kind: "response" });
|
|
277
|
+
}
|
|
278
|
+
const response = await fetchWithTimeout(url, {}, timeoutMs);
|
|
275
279
|
|
|
276
280
|
if (!response.ok) {
|
|
277
281
|
throw new Error(`MiniMax audio URL download failed with HTTP ${response.status}`);
|
|
@@ -429,7 +433,7 @@ async function callMiniMaxWithRetries(config, request, { endpoint, timeoutMs, ma
|
|
|
429
433
|
throw minimaxError("MiniMax request failed", { kind: "network", retryable: true, attempts });
|
|
430
434
|
}
|
|
431
435
|
|
|
432
|
-
async function writeAudioOutput({ responseJson, request, outputDir, prompt, endpoint }) {
|
|
436
|
+
async function writeAudioOutput({ responseJson, request, outputDir, prompt, endpoint, timeoutMs }) {
|
|
433
437
|
await mkdir(outputDir, { recursive: true });
|
|
434
438
|
|
|
435
439
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
@@ -439,7 +443,7 @@ async function writeAudioOutput({ responseJson, request, outputDir, prompt, endp
|
|
|
439
443
|
const metadataPath = join(outputDir, `${stem}.minimax.json`);
|
|
440
444
|
const audioValue = responseJson.data.audio;
|
|
441
445
|
const audioBuffer = request.output_format === "url"
|
|
442
|
-
? await downloadUrl(audioValue)
|
|
446
|
+
? await downloadUrl(audioValue, timeoutMs)
|
|
443
447
|
: decodeHexAudio(audioValue);
|
|
444
448
|
|
|
445
449
|
await writeFile(audioPath, audioBuffer);
|
|
@@ -496,7 +500,7 @@ async function main() {
|
|
|
496
500
|
}
|
|
497
501
|
|
|
498
502
|
if (!runtime) {
|
|
499
|
-
throw Object.assign(new Error("MiniMax config not found. Run hyper-animator-codex install with --minimax-api-key
|
|
503
|
+
throw Object.assign(new Error("MiniMax config not found. Run hyper-animator-codex install with --minimax-api-key, or set MINIMAX_API_KEY."), {
|
|
500
504
|
kind: "config",
|
|
501
505
|
retryable: false,
|
|
502
506
|
});
|
|
@@ -539,6 +543,7 @@ async function main() {
|
|
|
539
543
|
outputDir: options.output_dir,
|
|
540
544
|
prompt: options.prompt,
|
|
541
545
|
endpoint,
|
|
546
|
+
timeoutMs,
|
|
542
547
|
});
|
|
543
548
|
|
|
544
549
|
printJson({
|