@vibeframe/mcp-server 0.108.0 → 0.108.1
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/dist/index.js +72 -10
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -25267,6 +25267,8 @@ imageProvider: openai
|
|
|
25267
25267
|
|
|
25268
25268
|
Edit these beats before running \`vibe build\`. Each beat starts with
|
|
25269
25269
|
YAML cues that drive narration, backdrop generation, and timing.
|
|
25270
|
+
Pacing: keep beats 6-15 seconds (split longer ones); a 90s video should
|
|
25271
|
+
have 6-8 beats, not 3 long ones.
|
|
25270
25272
|
|
|
25271
25273
|
## Beat hook \u2014 Hook
|
|
25272
25274
|
|
|
@@ -450075,6 +450077,29 @@ function filterSubCompFalsePositives(findings, isSubComposition) {
|
|
|
450075
450077
|
if (!isSubComposition) return noEpsilon;
|
|
450076
450078
|
return noEpsilon.filter((f2) => !SUB_COMP_FALSE_POSITIVES.has(f2.code));
|
|
450077
450079
|
}
|
|
450080
|
+
function findInternalPhaseClipFindings(html) {
|
|
450081
|
+
const findings = [];
|
|
450082
|
+
for (const tagMatch of html.matchAll(/<[a-z][a-z0-9-]*\s[^>]*>/gi)) {
|
|
450083
|
+
const tag = tagMatch[0];
|
|
450084
|
+
if (!/class="[^"]*\bclip\b[^"]*"/i.test(tag)) continue;
|
|
450085
|
+
const startAttr = tag.match(/data-start="([^"]+)"/i);
|
|
450086
|
+
if (!startAttr) continue;
|
|
450087
|
+
const start = Number(startAttr[1]);
|
|
450088
|
+
if (!Number.isFinite(start) || start === 0) continue;
|
|
450089
|
+
findings.push({
|
|
450090
|
+
code: "internal_phase_clip_unsupported",
|
|
450091
|
+
severity: "error",
|
|
450092
|
+
message: `Inner .clip has data-start="${startAttr[1]}". The renderer does not toggle internal clip visibility inside sub-compositions, so phased clips render ALL phases at once (overlapping text).`,
|
|
450093
|
+
fixHint: 'Give every inner .clip data-start="0" spanning the full beat, and drive phase changes with GSAP autoAlpha instead (animate the previous phase out, the next one in).',
|
|
450094
|
+
snippet: tag.slice(0, 120)
|
|
450095
|
+
});
|
|
450096
|
+
}
|
|
450097
|
+
return findings;
|
|
450098
|
+
}
|
|
450099
|
+
function withVibeframeSubCompFindings(findings, html, isSubComposition) {
|
|
450100
|
+
if (!isSubComposition) return findings;
|
|
450101
|
+
return [...findings, ...findInternalPhaseClipFindings(html)];
|
|
450102
|
+
}
|
|
450078
450103
|
function applyMechanicalFixes(html, findings) {
|
|
450079
450104
|
const fixedCodes = /* @__PURE__ */ new Set();
|
|
450080
450105
|
let updated = html;
|
|
@@ -450120,7 +450145,11 @@ async function runProjectLint(opts) {
|
|
|
450120
450145
|
source: "projectDir"
|
|
450121
450146
|
};
|
|
450122
450147
|
const raw2 = runHyperframeLint(prepared);
|
|
450123
|
-
const findings =
|
|
450148
|
+
const findings = withVibeframeSubCompFindings(
|
|
450149
|
+
filterSubCompFalsePositives(raw2.findings, isSub),
|
|
450150
|
+
html,
|
|
450151
|
+
isSub
|
|
450152
|
+
);
|
|
450124
450153
|
if (opts.fix && findings.length > 0) {
|
|
450125
450154
|
const { html: nextHtml, fixedCodes } = applyMechanicalFixes(html, findings);
|
|
450126
450155
|
if (fixedCodes.length > 0) {
|
|
@@ -450130,7 +450159,11 @@ async function runProjectLint(opts) {
|
|
|
450130
450159
|
files.push({
|
|
450131
450160
|
file: rel,
|
|
450132
450161
|
isSubComposition: isSub,
|
|
450133
|
-
findings:
|
|
450162
|
+
findings: withVibeframeSubCompFindings(
|
|
450163
|
+
filterSubCompFalsePositives(reLinted.findings, isSub),
|
|
450164
|
+
nextHtml,
|
|
450165
|
+
isSub
|
|
450166
|
+
)
|
|
450134
450167
|
});
|
|
450135
450168
|
continue;
|
|
450136
450169
|
}
|
|
@@ -469633,8 +469666,14 @@ ${finalDurationBullet}
|
|
|
469633
469666
|
Animate the backdrop/media plane instead; let text enter briefly, then hold
|
|
469634
469667
|
still at its final CSS position. Continuous transforms on text ancestors can
|
|
469635
469668
|
create subpixel shimmer in screenshot-captured renders.
|
|
469636
|
-
-
|
|
469637
|
-
\`data-
|
|
469669
|
+
- Inner \`.clip\` elements carry \`data-start\`, \`data-duration\`,
|
|
469670
|
+
\`data-track-index\` \u2014 but **every inner clip MUST be full-window:
|
|
469671
|
+
\`data-start="0"\` spanning the whole beat.** The renderer does NOT toggle
|
|
469672
|
+
internal clip visibility inside sub-compositions, so "phase clips" with a
|
|
469673
|
+
non-zero \`data-start\` render ALL phases at once and text stacks on top of
|
|
469674
|
+
itself. For multi-phase beats, drive phase changes with GSAP \`autoAlpha\`
|
|
469675
|
+
inside full-window clips: animate phase A out (\`autoAlpha: 0\`), then
|
|
469676
|
+
phase B in, on the same timeline.
|
|
469638
469677
|
- If \`assets/backdrop-${ctx.beat.id}.png\` exists, use that local file as the
|
|
469639
469678
|
full-frame visual backdrop. The exact path string is
|
|
469640
469679
|
\`assets/backdrop-${ctx.beat.id}.png\`; do NOT prefix it with \`../\` or \`./\`
|
|
@@ -469648,7 +469687,9 @@ ${finalDurationBullet}
|
|
|
469648
469687
|
narration.
|
|
469649
469688
|
- Keep a meaningful visual progression across the full beat duration: line
|
|
469650
469689
|
tracing, gentle camera drift, staged labels, value cards, or parallax. Avoid
|
|
469651
|
-
a completed static frame holding silently for most of the beat.
|
|
469690
|
+
a completed static frame holding silently for most of the beat. For longer
|
|
469691
|
+
beats, progress through content phases with GSAP autoAlpha (old phase out,
|
|
469692
|
+
new phase in) \u2014 never with inner clip windows.
|
|
469652
469693
|
- Do not import external font or image URLs. Use the project DESIGN.md font
|
|
469653
469694
|
choice when explicit; otherwise use \`Inter\`, which is available in the
|
|
469654
469695
|
deterministic render font map.
|
|
@@ -469823,7 +469864,11 @@ function lintBeatHtml(html, beatId) {
|
|
|
469823
469864
|
source: "projectDir"
|
|
469824
469865
|
};
|
|
469825
469866
|
const raw2 = runHyperframeLint(prepared);
|
|
469826
|
-
const findings =
|
|
469867
|
+
const findings = withVibeframeSubCompFindings(
|
|
469868
|
+
filterSubCompFalsePositives(raw2.findings, true),
|
|
469869
|
+
html,
|
|
469870
|
+
true
|
|
469871
|
+
);
|
|
469827
469872
|
return {
|
|
469828
469873
|
errorCount: findings.filter((f2) => f2.severity === "error").length,
|
|
469829
469874
|
warningCount: findings.filter((f2) => f2.severity === "warning").length,
|
|
@@ -470262,7 +470307,8 @@ function buildInstructions(args) {
|
|
|
470262
470307
|
lines.push(`2. Read \`DESIGN.md\` for project-specific palette, typography, motion signature.`);
|
|
470263
470308
|
lines.push(`3. For each beat in the \`beats\` array below, author HTML at \`outputPath\` matching the \`userPrompt\`. The beat \`body\` carries the narrative + visual + animation intent; \`cues\` carries machine-readable per-beat overrides (narration, duration, backdrop, voice).`);
|
|
470264
470309
|
lines.push(`3b. Use each beat's \`finalDurationSec\` (narration-synced) for \`data-duration\` and timeline anchors when present \u2014 NOT the storyboard \`duration\`, which is only the minimum. Scenes composed at the storyboard duration end early and render black tails.`);
|
|
470265
|
-
lines.push(`3c.
|
|
470310
|
+
lines.push(`3c. Never give inner \`.clip\` elements a non-zero \`data-start\` \u2014 the renderer does not toggle internal clip visibility inside sub-compositions, so phased clips render all phases at once (overlapping text). Use full-window clips and GSAP autoAlpha phase transitions instead. Also keep beats 6-15s; split anything longer in the storyboard first.`);
|
|
470311
|
+
lines.push(`3d. If your environment cannot write files (e.g. Claude Desktop / MCP-only hosts), author each beat's HTML and submit it with the \`scene_submit\` tool (beat id + html). It validates with the same Hyperframes lint and writes the file for you; on lint errors it returns the findings without writing \u2014 fix and resubmit.`);
|
|
470266
470312
|
if (args.beatCount > 1) {
|
|
470267
470313
|
lines.push(`4. After authoring all ${args.beatCount} beat(s), run \`vibe scene lint --fix\` to validate. Fix any remaining errors by editing the HTML directly.`);
|
|
470268
470314
|
} else if (args.filtered) {
|
|
@@ -470584,7 +470630,11 @@ function lintHtml(html, rel, isSub) {
|
|
|
470584
470630
|
source: "projectDir"
|
|
470585
470631
|
};
|
|
470586
470632
|
const raw2 = runHyperframeLint(prepared);
|
|
470587
|
-
return
|
|
470633
|
+
return withVibeframeSubCompFindings(
|
|
470634
|
+
filterSubCompFalsePositives(raw2.findings, isSub),
|
|
470635
|
+
html,
|
|
470636
|
+
isSub
|
|
470637
|
+
);
|
|
470588
470638
|
}
|
|
470589
470639
|
function lintFilesToIssues(files) {
|
|
470590
470640
|
const issues = [];
|
|
@@ -471655,6 +471705,16 @@ function validateStoryboardMarkdown(markdown) {
|
|
|
471655
471705
|
}
|
|
471656
471706
|
}
|
|
471657
471707
|
}
|
|
471708
|
+
for (const beat of parsed.beats) {
|
|
471709
|
+
if (beat.duration !== void 0 && beat.duration > MAX_RECOMMENDED_BEAT_SEC) {
|
|
471710
|
+
issues.push({
|
|
471711
|
+
severity: "warning",
|
|
471712
|
+
code: "BEAT_DURATION_TOO_LONG",
|
|
471713
|
+
beatId: beat.id,
|
|
471714
|
+
message: `Beat "${beat.id}" is ${beat.duration}s \u2014 beats longer than ${MAX_RECOMMENDED_BEAT_SEC}s render static and overstuffed. Split it into 6-15s beats (a 90s video should have 6-8 beats).`
|
|
471715
|
+
});
|
|
471716
|
+
}
|
|
471717
|
+
}
|
|
471658
471718
|
return {
|
|
471659
471719
|
ok: !issues.some((i2) => i2.severity === "error"),
|
|
471660
471720
|
beats: parsed.beats,
|
|
@@ -471753,7 +471813,7 @@ function readLeadingCueBlock(body) {
|
|
|
471753
471813
|
return { full: match2[0], error: error instanceof Error ? error.message : String(error) };
|
|
471754
471814
|
}
|
|
471755
471815
|
}
|
|
471756
|
-
var import_yaml5, STORYBOARD_CUE_KEYS, HEADING_RE2, LEADING_CUE_RE, ALLOWED_CUE_KEYS, STRING_CUE_KEYS;
|
|
471816
|
+
var import_yaml5, STORYBOARD_CUE_KEYS, HEADING_RE2, LEADING_CUE_RE, ALLOWED_CUE_KEYS, STRING_CUE_KEYS, MAX_RECOMMENDED_BEAT_SEC;
|
|
471757
471817
|
var init_storyboard_edit = __esm({
|
|
471758
471818
|
"../cli/src/commands/_shared/storyboard-edit.ts"() {
|
|
471759
471819
|
"use strict";
|
|
@@ -471773,6 +471833,7 @@ var init_storyboard_edit = __esm({
|
|
|
471773
471833
|
LEADING_CUE_RE = /^(\s*)```ya?ml\s*\n([\s\S]*?)\n```\s*(?:\n|$)/;
|
|
471774
471834
|
ALLOWED_CUE_KEYS = new Set(STORYBOARD_CUE_KEYS);
|
|
471775
471835
|
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "motion", "voice", "music", "asset"]);
|
|
471836
|
+
MAX_RECOMMENDED_BEAT_SEC = 15;
|
|
471776
471837
|
}
|
|
471777
471838
|
});
|
|
471778
471839
|
|
|
@@ -491942,7 +492003,8 @@ function revisionMessages(opts) {
|
|
|
491942
492003
|
"The JSON object must have: storyboardMd string, summary string, changedBeats string[], warnings string[].",
|
|
491943
492004
|
"Preserve existing frontmatter, beat ids, cue YAML keys, and useful prose unless the user asks to change structure.",
|
|
491944
492005
|
"Keep cue YAML valid. Allowed cue keys are duration, narration, backdrop, video, motion, voice, music, asset.",
|
|
491945
|
-
"If a target duration is supplied, every beat must have a positive duration cue and durations must sum to that target."
|
|
492006
|
+
"If a target duration is supplied, every beat must have a positive duration cue and durations must sum to that target.",
|
|
492007
|
+
"Aim for 6-15 seconds per beat and never exceed ~15s \u2014 long beats render as static, overstuffed scenes. A 90-second video should have 6-8 beats."
|
|
491946
492008
|
].join("\n");
|
|
491947
492009
|
const repairBlock = opts.invalidStoryboard ? [
|
|
491948
492010
|
"The previous revision failed validation. Repair it.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/mcp-server",
|
|
3
|
-
"version": "0.108.
|
|
3
|
+
"version": "0.108.1",
|
|
4
4
|
"description": "VibeFrame MCP Server - AI-native video editing via Model Context Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"tsx": "^4.21.0",
|
|
61
61
|
"typescript": "^5.3.3",
|
|
62
62
|
"vitest": "^1.2.2",
|
|
63
|
-
"@vibeframe/
|
|
64
|
-
"@vibeframe/
|
|
63
|
+
"@vibeframe/core": "0.108.1",
|
|
64
|
+
"@vibeframe/cli": "0.108.1"
|
|
65
65
|
},
|
|
66
66
|
"engines": {
|
|
67
67
|
"node": ">=20"
|