hyperframes 0.7.3 → 0.7.5
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/cli.js +523 -106
- package/dist/skills/hyperframes/SKILL.md +28 -11
- package/dist/studio/assets/{hyperframes-player-Ztwg53-a.js → hyperframes-player-BGW5hpsb.js} +2 -2
- package/dist/studio/assets/{index-C5AdP06R.js → index-BwFzbjZQ.js} +1 -1
- package/dist/studio/assets/{index-C4cVeLOS.js → index-C5NAfiPa.js} +1 -1
- package/dist/studio/assets/{index-hqkzfAEp.js → index-D_JGXmfx.js} +96 -96
- package/dist/studio/index.html +1 -1
- package/dist/studio/index.js +9 -4
- package/dist/studio/index.js.map +1 -1
- package/dist/templates/_shared/AGENTS.md +2 -2
- package/dist/templates/_shared/CLAUDE.md +2 -2
- package/dist/templates/warm-grain/compositions/graphics.html +6 -9
- package/dist/templates/warm-grain/compositions/intro.html +7 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -50,7 +50,7 @@ var VERSION;
|
|
|
50
50
|
var init_version = __esm({
|
|
51
51
|
"src/version.ts"() {
|
|
52
52
|
"use strict";
|
|
53
|
-
VERSION = true ? "0.7.
|
|
53
|
+
VERSION = true ? "0.7.5" : "0.0.0-dev";
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
@@ -25071,8 +25071,16 @@ function findHtmlTag(source) {
|
|
|
25071
25071
|
};
|
|
25072
25072
|
}
|
|
25073
25073
|
function findRootTag(source) {
|
|
25074
|
-
const bodyOpenMatch = /<body\b[^>]
|
|
25074
|
+
const bodyOpenMatch = /<body\b([^>]*)>/i.exec(source);
|
|
25075
25075
|
const bodyCloseMatch = /<\/body>/i.exec(source);
|
|
25076
|
+
if (bodyOpenMatch && (readAttr(bodyOpenMatch[0], "data-composition-id") || readAttr(bodyOpenMatch[0], "data-width") || readAttr(bodyOpenMatch[0], "data-height"))) {
|
|
25077
|
+
return {
|
|
25078
|
+
raw: bodyOpenMatch[0],
|
|
25079
|
+
name: "body",
|
|
25080
|
+
attrs: bodyOpenMatch[1] ?? "",
|
|
25081
|
+
index: bodyOpenMatch.index
|
|
25082
|
+
};
|
|
25083
|
+
}
|
|
25076
25084
|
const bodyStart = bodyOpenMatch ? bodyOpenMatch.index + bodyOpenMatch[0].length : 0;
|
|
25077
25085
|
const bodyEnd = bodyOpenMatch && bodyCloseMatch && bodyCloseMatch.index > bodyStart ? bodyCloseMatch.index : source.length;
|
|
25078
25086
|
const bodyContent = bodyOpenMatch ? source.slice(bodyStart, bodyEnd) : source;
|
|
@@ -26137,6 +26145,30 @@ function isHiddenGsapState(values) {
|
|
|
26137
26145
|
const display = stringValue(values.display)?.toLowerCase();
|
|
26138
26146
|
return zeroValue(values.opacity) || zeroValue(values.autoAlpha) || visibility === "hidden" || display === "none";
|
|
26139
26147
|
}
|
|
26148
|
+
function oneValue(values, keys2) {
|
|
26149
|
+
for (const key2 of keys2) {
|
|
26150
|
+
const value = values[key2];
|
|
26151
|
+
if (value !== void 0) return value;
|
|
26152
|
+
}
|
|
26153
|
+
return void 0;
|
|
26154
|
+
}
|
|
26155
|
+
function isVisibleGsapState(values) {
|
|
26156
|
+
const opacity = oneValue(values, ["opacity", "autoAlpha"]);
|
|
26157
|
+
if (typeof opacity === "number") return opacity > 0;
|
|
26158
|
+
if (typeof opacity === "string" && opacity.trim()) {
|
|
26159
|
+
const numeric = Number(opacity);
|
|
26160
|
+
if (Number.isFinite(numeric)) return numeric > 0;
|
|
26161
|
+
}
|
|
26162
|
+
const visibility = stringValue(values.visibility)?.toLowerCase();
|
|
26163
|
+
if (visibility === "visible" || visibility === "inherit") return true;
|
|
26164
|
+
const display = stringValue(values.display)?.toLowerCase();
|
|
26165
|
+
if (display && display !== "none") return true;
|
|
26166
|
+
return false;
|
|
26167
|
+
}
|
|
26168
|
+
function makesOverlayVisible(win) {
|
|
26169
|
+
if (win.method === "from" && isHiddenGsapState(win.propertyValues)) return true;
|
|
26170
|
+
return isVisibleGsapState(win.propertyValues);
|
|
26171
|
+
}
|
|
26140
26172
|
function isSceneBoundaryExit(win) {
|
|
26141
26173
|
if (win.end <= win.position) return false;
|
|
26142
26174
|
if (win.method !== "to" && win.method !== "fromTo") return false;
|
|
@@ -26225,6 +26257,67 @@ function getSingleClassSelector(selector) {
|
|
|
26225
26257
|
const match = selector.trim().match(/^\.(?<name>[A-Za-z0-9_-]+)$/);
|
|
26226
26258
|
return match?.groups?.name || null;
|
|
26227
26259
|
}
|
|
26260
|
+
function readStyleProperty(style, property) {
|
|
26261
|
+
const escapedProperty = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26262
|
+
const match = style.match(new RegExp(`(?:^|;)\\s*${escapedProperty}\\s*:\\s*([^;]+)`, "i"));
|
|
26263
|
+
return match?.[1]?.trim() || null;
|
|
26264
|
+
}
|
|
26265
|
+
function cssZero(value) {
|
|
26266
|
+
if (!value) return false;
|
|
26267
|
+
return /^0(?:\.0+)?(?:px|%|vw|vh|rem|em)?$/i.test(value.trim());
|
|
26268
|
+
}
|
|
26269
|
+
function styleHasHiddenInitialState(style) {
|
|
26270
|
+
const opacity = readStyleProperty(style, "opacity");
|
|
26271
|
+
if (opacity && Number(opacity) === 0) return true;
|
|
26272
|
+
if (readStyleProperty(style, "visibility")?.toLowerCase() === "hidden") return true;
|
|
26273
|
+
if (readStyleProperty(style, "display")?.toLowerCase() === "none") return true;
|
|
26274
|
+
return false;
|
|
26275
|
+
}
|
|
26276
|
+
function styleHasOpaqueBackground(style) {
|
|
26277
|
+
const background = readStyleProperty(style, "background") || readStyleProperty(style, "background-color");
|
|
26278
|
+
if (!background) return false;
|
|
26279
|
+
const normalized = background.toLowerCase().replace(/\s+/g, "");
|
|
26280
|
+
if (normalized === "transparent" || normalized === "none") return false;
|
|
26281
|
+
if (/rgba?\([^)]*,0(?:\.0+)?\)$/.test(normalized)) return false;
|
|
26282
|
+
if (/hsla?\([^)]*,0(?:\.0+)?\)$/.test(normalized)) return false;
|
|
26283
|
+
return true;
|
|
26284
|
+
}
|
|
26285
|
+
function styleLooksFullFrameOverlay(style) {
|
|
26286
|
+
const position = readStyleProperty(style, "position")?.toLowerCase();
|
|
26287
|
+
if (position !== "fixed" && position !== "absolute") return false;
|
|
26288
|
+
const coversFrame = cssZero(readStyleProperty(style, "inset")) || cssZero(readStyleProperty(style, "top")) && cssZero(readStyleProperty(style, "right")) && cssZero(readStyleProperty(style, "bottom")) && cssZero(readStyleProperty(style, "left"));
|
|
26289
|
+
return coversFrame && styleHasOpaqueBackground(style);
|
|
26290
|
+
}
|
|
26291
|
+
function collectSimpleStyleRules(styles) {
|
|
26292
|
+
const rules = /* @__PURE__ */ new Map();
|
|
26293
|
+
for (const style of styles) {
|
|
26294
|
+
for (const [, selectorList, body] of style.content.matchAll(/([^{}]+)\{([^}]+)\}/g)) {
|
|
26295
|
+
if (!selectorList || !body) continue;
|
|
26296
|
+
for (const selector of selectorList.split(",")) {
|
|
26297
|
+
const token = selector.trim();
|
|
26298
|
+
if (!/^[#.][A-Za-z0-9_-]+$/.test(token)) continue;
|
|
26299
|
+
rules.set(token, `${rules.get(token) || ""};${body}`);
|
|
26300
|
+
}
|
|
26301
|
+
}
|
|
26302
|
+
}
|
|
26303
|
+
return rules;
|
|
26304
|
+
}
|
|
26305
|
+
function tagSimpleSelectors(tag) {
|
|
26306
|
+
const selectors = [];
|
|
26307
|
+
const id = readAttr(tag.raw, "id");
|
|
26308
|
+
if (id) selectors.push(`#${id}`);
|
|
26309
|
+
const classes = readAttr(tag.raw, "class")?.split(/\s+/).filter(Boolean) ?? [];
|
|
26310
|
+
for (const className of classes) selectors.push(`.${className}`);
|
|
26311
|
+
return selectors;
|
|
26312
|
+
}
|
|
26313
|
+
function combinedTagStyle(tag, styleRules) {
|
|
26314
|
+
const styles = [readAttr(tag.raw, "style") || ""];
|
|
26315
|
+
for (const selector of tagSimpleSelectors(tag)) {
|
|
26316
|
+
const ruleStyle = styleRules.get(selector);
|
|
26317
|
+
if (ruleStyle) styles.push(ruleStyle);
|
|
26318
|
+
}
|
|
26319
|
+
return styles.filter(Boolean).join(";");
|
|
26320
|
+
}
|
|
26228
26321
|
function cssTransformToGsapProps(cssTransform) {
|
|
26229
26322
|
const parts = [];
|
|
26230
26323
|
const translateMatch = cssTransform.match(
|
|
@@ -26253,17 +26346,53 @@ function cssTransformToGsapProps(cssTransform) {
|
|
|
26253
26346
|
}
|
|
26254
26347
|
return parts.length > 0 ? parts.join(", ") : null;
|
|
26255
26348
|
}
|
|
26256
|
-
|
|
26349
|
+
function targetedSelectorTokens(selector) {
|
|
26350
|
+
const tokens = /* @__PURE__ */ new Set();
|
|
26351
|
+
for (const group of selector.split(",")) {
|
|
26352
|
+
const compounds = group.trim().split(/[\s>+~]+/).filter(Boolean);
|
|
26353
|
+
const last = compounds[compounds.length - 1];
|
|
26354
|
+
if (!last) continue;
|
|
26355
|
+
const simple2 = last.match(/[#.][A-Za-z0-9_-]+/g);
|
|
26356
|
+
if (simple2) for (const token of simple2) tokens.add(token);
|
|
26357
|
+
}
|
|
26358
|
+
return tokens;
|
|
26359
|
+
}
|
|
26360
|
+
function matchCssTransform(gsapSelector, cssMap) {
|
|
26361
|
+
if (cssMap.size === 0) return void 0;
|
|
26362
|
+
const direct = cssMap.get(gsapSelector);
|
|
26363
|
+
if (direct) return direct;
|
|
26364
|
+
const tokens = targetedSelectorTokens(gsapSelector);
|
|
26365
|
+
for (const [cssSelector, value] of cssMap) {
|
|
26366
|
+
if (tokens.has(cssSelector)) return value;
|
|
26367
|
+
}
|
|
26368
|
+
return void 0;
|
|
26369
|
+
}
|
|
26370
|
+
function extractStandaloneGsapTransformCalls(script) {
|
|
26371
|
+
const calls = [];
|
|
26372
|
+
const pattern = /gsap\.(set|to|from|fromTo)\s*\(\s*(["'])([^"']+)\2\s*,\s*\{([^{}]*)\}/g;
|
|
26373
|
+
let match;
|
|
26374
|
+
while ((match = pattern.exec(script)) !== null) {
|
|
26375
|
+
const method = match[1] ?? "set";
|
|
26376
|
+
const selector = match[3] ?? "";
|
|
26377
|
+
const propsBody = match[4] ?? "";
|
|
26378
|
+
const properties = [...propsBody.matchAll(/([A-Za-z_$][\w$]*)\s*:/g)].map((m2) => m2[1] ?? "");
|
|
26379
|
+
calls.push({ method, selector, properties, raw: truncateSnippet(match[0]) ?? match[0] });
|
|
26380
|
+
}
|
|
26381
|
+
return calls;
|
|
26382
|
+
}
|
|
26383
|
+
var SCENE_BOUNDARY_EPSILON_SECONDS, gsapWindowsCache, CONFLICTING_TRANSLATE_PROPS, CONFLICTING_SCALE_PROPS, gsapRules;
|
|
26257
26384
|
var init_gsap = __esm({
|
|
26258
26385
|
"../core/src/lint/rules/gsap.ts"() {
|
|
26259
26386
|
"use strict";
|
|
26260
26387
|
init_utils2();
|
|
26261
26388
|
SCENE_BOUNDARY_EPSILON_SECONDS = 0.05;
|
|
26262
26389
|
gsapWindowsCache = /* @__PURE__ */ new Map();
|
|
26390
|
+
CONFLICTING_TRANSLATE_PROPS = ["x", "y", "xPercent", "yPercent"];
|
|
26391
|
+
CONFLICTING_SCALE_PROPS = ["scale", "scaleX", "scaleY"];
|
|
26263
26392
|
gsapRules = [
|
|
26264
26393
|
// overlapping_gsap_tweens + gsap_animates_clip_element + unscoped_gsap_selector
|
|
26265
26394
|
// fallow-ignore-next-line complexity
|
|
26266
|
-
async ({ source, tags, scripts, rootCompositionId }) => {
|
|
26395
|
+
async ({ source, tags, scripts, styles, rootCompositionId }) => {
|
|
26267
26396
|
const findings = [];
|
|
26268
26397
|
const clipIds = /* @__PURE__ */ new Map();
|
|
26269
26398
|
const clipClasses = /* @__PURE__ */ new Map();
|
|
@@ -26284,6 +26413,8 @@ var init_gsap = __esm({
|
|
|
26284
26413
|
}
|
|
26285
26414
|
const classUsage = countClassUsage(tags);
|
|
26286
26415
|
const clipStartBoundariesByComposition = collectClipStartBoundariesByComposition(source, tags);
|
|
26416
|
+
const styleRules = collectSimpleStyleRules(styles);
|
|
26417
|
+
const reportedVisibleOverlayKeys = /* @__PURE__ */ new Set();
|
|
26287
26418
|
for (const script of scripts) {
|
|
26288
26419
|
const localTimelineCompId = readRegisteredTimelineCompositionId(script.content);
|
|
26289
26420
|
const gsapWindows = await cachedExtractGsapWindows(script.content);
|
|
@@ -26335,6 +26466,45 @@ ${right.raw}`)
|
|
|
26335
26466
|
});
|
|
26336
26467
|
}
|
|
26337
26468
|
}
|
|
26469
|
+
for (const tag of tags) {
|
|
26470
|
+
const selectors = tagSimpleSelectors(tag);
|
|
26471
|
+
if (selectors.length === 0) continue;
|
|
26472
|
+
const overlayKey = readAttr(tag.raw, "id") || String(tag.index);
|
|
26473
|
+
if (reportedVisibleOverlayKeys.has(overlayKey)) continue;
|
|
26474
|
+
const authoredStyle = combinedTagStyle(tag, styleRules);
|
|
26475
|
+
if (!authoredStyle || !styleLooksFullFrameOverlay(authoredStyle)) continue;
|
|
26476
|
+
if (styleHasHiddenInitialState(authoredStyle)) continue;
|
|
26477
|
+
const visibilityWindows = gsapWindows.filter((win) => {
|
|
26478
|
+
const tokens = targetedSelectorTokens(win.targetSelector);
|
|
26479
|
+
if (!selectors.some((selector2) => tokens.has(selector2))) return false;
|
|
26480
|
+
return win.properties.some(
|
|
26481
|
+
(prop2) => ["opacity", "autoAlpha", "visibility", "display"].includes(prop2)
|
|
26482
|
+
);
|
|
26483
|
+
}).sort((a, b2) => a.position - b2.position);
|
|
26484
|
+
const startsHiddenAtZero = visibilityWindows.some(
|
|
26485
|
+
(win) => win.position <= SCENE_BOUNDARY_EPSILON_SECONDS && isHiddenGsapState(win.propertyValues)
|
|
26486
|
+
);
|
|
26487
|
+
if (startsHiddenAtZero) continue;
|
|
26488
|
+
const firstVisible = visibilityWindows.find((win) => makesOverlayVisible(win));
|
|
26489
|
+
if (!firstVisible) continue;
|
|
26490
|
+
const selector = selectors.find(
|
|
26491
|
+
(candidate) => targetedSelectorTokens(firstVisible.targetSelector).has(candidate)
|
|
26492
|
+
) || selectors[0] || tag.name;
|
|
26493
|
+
const laterHidden = visibilityWindows.some(
|
|
26494
|
+
(win) => win.position >= firstVisible.position && isHiddenGsapState(win.propertyValues)
|
|
26495
|
+
);
|
|
26496
|
+
if (firstVisible.method !== "from" && !laterHidden) continue;
|
|
26497
|
+
reportedVisibleOverlayKeys.add(overlayKey);
|
|
26498
|
+
findings.push({
|
|
26499
|
+
code: "gsap_fullscreen_overlay_starts_visible",
|
|
26500
|
+
severity: "error",
|
|
26501
|
+
message: `Full-frame overlay "${selector}" starts visible before its first GSAP opacity tween at ${firstVisible.position.toFixed(2)}s. It will cover earlier render frames, often as a blank/white video.`,
|
|
26502
|
+
selector,
|
|
26503
|
+
elementId: readAttr(tag.raw, "id") || void 0,
|
|
26504
|
+
fixHint: `Add \`opacity: 0\` to "${selector}" in CSS/inline styles, or add \`tl.set("${selector}", { opacity: 0 }, 0)\` before the reveal tween.`,
|
|
26505
|
+
snippet: truncateSnippet(firstVisible.raw)
|
|
26506
|
+
});
|
|
26507
|
+
}
|
|
26338
26508
|
for (const win of gsapWindows) {
|
|
26339
26509
|
const sel = win.targetSelector;
|
|
26340
26510
|
const clipInfo = clipIds.get(sel) || clipClasses.get(sel);
|
|
@@ -26413,22 +26583,30 @@ ${right.raw}`)
|
|
|
26413
26583
|
for (const script of scripts) {
|
|
26414
26584
|
if (!/gsap\.timeline/.test(script.content)) continue;
|
|
26415
26585
|
const windows = await cachedExtractGsapWindows(script.content);
|
|
26586
|
+
const calls = [
|
|
26587
|
+
...windows.map((win) => ({
|
|
26588
|
+
method: win.method,
|
|
26589
|
+
selector: win.targetSelector,
|
|
26590
|
+
properties: win.properties,
|
|
26591
|
+
raw: win.raw
|
|
26592
|
+
})),
|
|
26593
|
+
...extractStandaloneGsapTransformCalls(stripJsComments(script.content))
|
|
26594
|
+
];
|
|
26416
26595
|
const conflicts = /* @__PURE__ */ new Map();
|
|
26417
|
-
for (const
|
|
26418
|
-
if (
|
|
26419
|
-
const sel =
|
|
26420
|
-
const
|
|
26421
|
-
|
|
26422
|
-
(p2) => ["x", "y", "xPercent", "yPercent"].includes(p2)
|
|
26596
|
+
for (const call of calls) {
|
|
26597
|
+
if (call.method === "fromTo" || call.method === "from") continue;
|
|
26598
|
+
const sel = call.selector;
|
|
26599
|
+
const translateProps = call.properties.filter(
|
|
26600
|
+
(p2) => CONFLICTING_TRANSLATE_PROPS.includes(p2)
|
|
26423
26601
|
);
|
|
26424
|
-
const scaleProps =
|
|
26425
|
-
const cssFromTranslate = translateProps.length > 0 ? cssTranslateSelectors
|
|
26426
|
-
const cssFromScale = scaleProps.length > 0 ? cssScaleSelectors
|
|
26602
|
+
const scaleProps = call.properties.filter((p2) => CONFLICTING_SCALE_PROPS.includes(p2));
|
|
26603
|
+
const cssFromTranslate = translateProps.length > 0 ? matchCssTransform(sel, cssTranslateSelectors) : void 0;
|
|
26604
|
+
const cssFromScale = scaleProps.length > 0 ? matchCssTransform(sel, cssScaleSelectors) : void 0;
|
|
26427
26605
|
if (!cssFromTranslate && !cssFromScale) continue;
|
|
26428
26606
|
const existing = conflicts.get(sel) ?? {
|
|
26429
26607
|
cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(" "),
|
|
26430
26608
|
props: /* @__PURE__ */ new Set(),
|
|
26431
|
-
raw:
|
|
26609
|
+
raw: call.raw
|
|
26432
26610
|
};
|
|
26433
26611
|
for (const p2 of [...translateProps, ...scaleProps]) existing.props.add(p2);
|
|
26434
26612
|
conflicts.set(sel, existing);
|
|
@@ -26925,6 +27103,35 @@ function isCompositionRootOrMount(rawTag) {
|
|
|
26925
27103
|
readAttr(rawTag, "data-composition-id") || readAttr(rawTag, "data-composition-src")
|
|
26926
27104
|
);
|
|
26927
27105
|
}
|
|
27106
|
+
function extractCssSelectors(css) {
|
|
27107
|
+
const out = [];
|
|
27108
|
+
const noComments = css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
27109
|
+
const ruleHeader = /([^{}]+)\{/g;
|
|
27110
|
+
let m2;
|
|
27111
|
+
while ((m2 = ruleHeader.exec(noComments)) !== null) {
|
|
27112
|
+
const header = (m2[1] ?? "").trim();
|
|
27113
|
+
if (!header || header.startsWith("@")) continue;
|
|
27114
|
+
for (const sel of header.split(",")) {
|
|
27115
|
+
const s2 = sel.trim();
|
|
27116
|
+
if (s2) out.push(s2);
|
|
27117
|
+
}
|
|
27118
|
+
}
|
|
27119
|
+
return out;
|
|
27120
|
+
}
|
|
27121
|
+
function leftmostCompoundClasses(selector) {
|
|
27122
|
+
const leftmost = selector.trim().split(/[\s>+~]+/)[0] ?? "";
|
|
27123
|
+
return (leftmost.match(/\.([\w-]+)/g) ?? []).map((c3) => c3.slice(1));
|
|
27124
|
+
}
|
|
27125
|
+
function rootClassStyledSelectors(styles, rootClasses) {
|
|
27126
|
+
const offenders = [];
|
|
27127
|
+
for (const style of styles) {
|
|
27128
|
+
for (const selector of extractCssSelectors(style.content)) {
|
|
27129
|
+
const hitsRoot = leftmostCompoundClasses(selector).some((c3) => rootClasses.includes(c3));
|
|
27130
|
+
if (hitsRoot && !offenders.includes(selector)) offenders.push(selector);
|
|
27131
|
+
}
|
|
27132
|
+
}
|
|
27133
|
+
return offenders;
|
|
27134
|
+
}
|
|
26928
27135
|
var MAX_COMPOSITION_LINES, MAX_TIMED_ELEMENTS_PER_TRACK, TRACK_DENSITY_EXEMPT_TAGS, compositionRules;
|
|
26929
27136
|
var init_composition = __esm({
|
|
26930
27137
|
"../core/src/lint/rules/composition.ts"() {
|
|
@@ -27377,6 +27584,39 @@ var init_composition = __esm({
|
|
|
27377
27584
|
});
|
|
27378
27585
|
}
|
|
27379
27586
|
return findings;
|
|
27587
|
+
},
|
|
27588
|
+
// subcomposition_root_styled_by_class
|
|
27589
|
+
// A sub-composition's <style> is scoped at render time to
|
|
27590
|
+
// `[data-composition-id="<id>"] <selector>` so scenes inlined into one document
|
|
27591
|
+
// can't leak styles into each other. A rule whose LEFTMOST selector is the ROOT
|
|
27592
|
+
// element's own class (e.g. `.frame { ... }` on the same element that carries
|
|
27593
|
+
// data-composition-id) therefore becomes a DESCENDANT selector that can never
|
|
27594
|
+
// match the root — the whole scene renders unstyled (tiny text top-left, images
|
|
27595
|
+
// at natural size). lint/validate/inspect evaluate the file in isolation (no
|
|
27596
|
+
// scoping) and Studio previews each scene in its own iframe (no scoping), so the
|
|
27597
|
+
// break is invisible until the composited MP4 render. Style the root via `#root`
|
|
27598
|
+
// (the scoper special-cases the root id) and descendants via plain selectors,
|
|
27599
|
+
// like the registry blocks — the runtime already scopes each scene by id, so a
|
|
27600
|
+
// class namespace on the root is redundant.
|
|
27601
|
+
({ rootTag, rootCompositionId, styles, options }) => {
|
|
27602
|
+
if (!options.isSubComposition) return [];
|
|
27603
|
+
if (isRegistrySourceFile(options.filePath)) return [];
|
|
27604
|
+
if (!rootTag || !rootCompositionId) return [];
|
|
27605
|
+
const rootClasses = (readAttr(rootTag.raw, "class") || "").split(/\s+/).filter(Boolean);
|
|
27606
|
+
if (rootClasses.length === 0) return [];
|
|
27607
|
+
const offenders = rootClassStyledSelectors(styles, rootClasses);
|
|
27608
|
+
if (offenders.length === 0) return [];
|
|
27609
|
+
const example = offenders.slice(0, 3).join(", ");
|
|
27610
|
+
return [
|
|
27611
|
+
{
|
|
27612
|
+
code: "subcomposition_root_styled_by_class",
|
|
27613
|
+
severity: "error",
|
|
27614
|
+
message: `Root element has class="${rootClasses.join(" ")}" and is styled by ${offenders.length} rule(s) keyed off that class (e.g. ${example}). At render, every sub-composition rule is scoped to [data-composition-id="${rootCompositionId}"] <selector>, so a selector whose leftmost part is the ROOT's own class becomes a descendant selector that cannot match the root \u2014 the scene renders unstyled (tiny text top-left, full-size images). lint/validate/inspect and Studio's per-frame iframe preview do not scope, so this passes every static check and looks correct in preview.`,
|
|
27615
|
+
selector: example,
|
|
27616
|
+
fixHint: `Give the root id="root" and style it with \`#root { ... }\` plus plain descendant selectors (\`.kicker\`, \`#hero\`) \u2014 the runtime already scopes each sub-composition by data-composition-id, so a class namespace on the root is redundant and breaks under scoping.`,
|
|
27617
|
+
snippet: truncateSnippet(rootTag.raw)
|
|
27618
|
+
}
|
|
27619
|
+
];
|
|
27380
27620
|
}
|
|
27381
27621
|
];
|
|
27382
27622
|
}
|
|
@@ -33175,11 +33415,10 @@ async function pageScreenshotCapture(page, options) {
|
|
|
33175
33415
|
format: isPng ? "png" : "jpeg",
|
|
33176
33416
|
quality: isPng ? void 0 : options.quality ?? 80,
|
|
33177
33417
|
fromSurface: true,
|
|
33178
|
-
//
|
|
33179
|
-
//
|
|
33180
|
-
//
|
|
33181
|
-
|
|
33182
|
-
captureBeyondViewport: true,
|
|
33418
|
+
// Use Chrome's faster viewport-bound screenshot path by default. Callers
|
|
33419
|
+
// opt into the beyond-viewport path only for known compositor edge cases,
|
|
33420
|
+
// such as native video surfaces in tall portrait renders.
|
|
33421
|
+
captureBeyondViewport: options.captureBeyondViewport ?? false,
|
|
33183
33422
|
optimizeForSpeed: !isPng,
|
|
33184
33423
|
clip
|
|
33185
33424
|
});
|
|
@@ -33194,8 +33433,8 @@ async function captureScreenshotWithAlpha(page, width, height) {
|
|
|
33194
33433
|
const result = await client.send("Page.captureScreenshot", {
|
|
33195
33434
|
format: "png",
|
|
33196
33435
|
fromSurface: true,
|
|
33436
|
+
// Preserve the #1094 tall-portrait edge-clipping guard on HDR alpha captures.
|
|
33197
33437
|
captureBeyondViewport: true,
|
|
33198
|
-
// see pageScreenshotCapture for rationale
|
|
33199
33438
|
optimizeForSpeed: false,
|
|
33200
33439
|
// `true` uses a zero-alpha-aware fast path that crushes real alpha values — observed empirically, CDP docs don't spell it out
|
|
33201
33440
|
clip: { x: 0, y: 0, width, height, scale: 1 }
|
|
@@ -33224,8 +33463,8 @@ async function captureAlphaPng(page, width, height) {
|
|
|
33224
33463
|
const result = await client.send("Page.captureScreenshot", {
|
|
33225
33464
|
format: "png",
|
|
33226
33465
|
fromSurface: true,
|
|
33466
|
+
// Preserve the #1094 tall-portrait edge-clipping guard on HDR alpha captures.
|
|
33227
33467
|
captureBeyondViewport: true,
|
|
33228
|
-
// see pageScreenshotCapture for rationale
|
|
33229
33468
|
optimizeForSpeed: false,
|
|
33230
33469
|
// must be false to preserve alpha
|
|
33231
33470
|
clip: { x: 0, y: 0, width, height, scale: 1 }
|
|
@@ -34491,7 +34730,11 @@ function getCapturePerfSummary(session) {
|
|
|
34491
34730
|
staticDedupSkipReason: session.staticDedupSkipReason
|
|
34492
34731
|
};
|
|
34493
34732
|
}
|
|
34494
|
-
|
|
34733
|
+
function isTransientBrowserError(error) {
|
|
34734
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
34735
|
+
return TRANSIENT_BROWSER_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
34736
|
+
}
|
|
34737
|
+
var BROWSER_CONSOLE_BUFFER_SIZE, CAPTURE_SESSION_CLOSE_TIMEOUT_MS, LOCKED_WARMUP_TICKS, realSleep, HF_READY_DIAGNOSTIC_EXPR, TRANSIENT_BROWSER_ERROR_PATTERNS;
|
|
34495
34738
|
var init_frameCapture = __esm({
|
|
34496
34739
|
"../engine/src/services/frameCapture.ts"() {
|
|
34497
34740
|
"use strict";
|
|
@@ -34522,6 +34765,17 @@ var init_frameCapture = __esm({
|
|
|
34522
34765
|
declaredDuration: declaredDuration,
|
|
34523
34766
|
};
|
|
34524
34767
|
})()`;
|
|
34768
|
+
TRANSIENT_BROWSER_ERROR_PATTERNS = [
|
|
34769
|
+
/Navigating frame was detached/i,
|
|
34770
|
+
/Target closed/i,
|
|
34771
|
+
/Session closed/i,
|
|
34772
|
+
/browser has disconnected/i,
|
|
34773
|
+
/Page crashed/i,
|
|
34774
|
+
/Execution context was destroyed/i,
|
|
34775
|
+
/Cannot find context with specified id/i,
|
|
34776
|
+
/Failed to launch the browser process/i,
|
|
34777
|
+
/ECONNREFUSED/i
|
|
34778
|
+
];
|
|
34525
34779
|
}
|
|
34526
34780
|
});
|
|
34527
34781
|
|
|
@@ -37049,21 +37303,6 @@ function defaultBuildScopeSelector(compId) {
|
|
|
37049
37303
|
const escaped = compId.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
37050
37304
|
return `[data-composition-id="${escaped}"]`;
|
|
37051
37305
|
}
|
|
37052
|
-
function emptyCompositionHtmlError(src) {
|
|
37053
|
-
return new Error(
|
|
37054
|
-
`Composition HTML is empty or could not be parsed: ${src}. Check that the file referenced by data-composition-src contains valid HTML.`
|
|
37055
|
-
);
|
|
37056
|
-
}
|
|
37057
|
-
function assertNonEmptyCompositionHtml(html, src) {
|
|
37058
|
-
if (!html.trim()) {
|
|
37059
|
-
throw emptyCompositionHtmlError(src);
|
|
37060
|
-
}
|
|
37061
|
-
}
|
|
37062
|
-
function assertParsedCompositionDocument(doc, src) {
|
|
37063
|
-
if (!doc.documentElement) {
|
|
37064
|
-
throw emptyCompositionHtmlError(src);
|
|
37065
|
-
}
|
|
37066
|
-
}
|
|
37067
37306
|
function inlineSubCompositions(document2, hosts, options) {
|
|
37068
37307
|
const {
|
|
37069
37308
|
resolveHtml,
|
|
@@ -37089,15 +37328,15 @@ function inlineSubCompositions(document2, hosts, options) {
|
|
|
37089
37328
|
const src = hostEl.getAttribute("data-composition-src");
|
|
37090
37329
|
if (!src) continue;
|
|
37091
37330
|
const compHtml = resolveHtml(src);
|
|
37092
|
-
if (compHtml == null) {
|
|
37093
|
-
|
|
37094
|
-
onMissingComposition(src);
|
|
37095
|
-
}
|
|
37331
|
+
if (compHtml == null || !compHtml.trim()) {
|
|
37332
|
+
onMissingComposition?.(src);
|
|
37096
37333
|
continue;
|
|
37097
37334
|
}
|
|
37098
|
-
assertNonEmptyCompositionHtml(compHtml, src);
|
|
37099
37335
|
const compDoc = parseHtml2(compHtml);
|
|
37100
|
-
|
|
37336
|
+
if (!compDoc.documentElement) {
|
|
37337
|
+
onMissingComposition?.(src);
|
|
37338
|
+
continue;
|
|
37339
|
+
}
|
|
37101
37340
|
let compId;
|
|
37102
37341
|
let runtimeCompId;
|
|
37103
37342
|
if (hostIdentityMap) {
|
|
@@ -37110,9 +37349,15 @@ function inlineSubCompositions(document2, hosts, options) {
|
|
|
37110
37349
|
}
|
|
37111
37350
|
const contentRoot = compDoc.querySelector("template");
|
|
37112
37351
|
const contentHtml = contentRoot ? contentRoot.innerHTML || "" : compDoc.body?.innerHTML || "";
|
|
37113
|
-
|
|
37352
|
+
if (!contentHtml.trim()) {
|
|
37353
|
+
onMissingComposition?.(src);
|
|
37354
|
+
continue;
|
|
37355
|
+
}
|
|
37114
37356
|
const contentDoc = parseHtml2(contentHtml);
|
|
37115
|
-
|
|
37357
|
+
if (!contentDoc.documentElement) {
|
|
37358
|
+
onMissingComposition?.(src);
|
|
37359
|
+
continue;
|
|
37360
|
+
}
|
|
37116
37361
|
const innerRoot = compId ? queryByAttr(contentDoc, "data-composition-id", compId) : contentDoc.querySelector("[data-composition-id]");
|
|
37117
37362
|
const inferredCompId = innerRoot?.getAttribute("data-composition-id")?.trim() || "";
|
|
37118
37363
|
const authoredRootId = innerRoot?.getAttribute("id")?.trim() || null;
|
|
@@ -41789,6 +42034,7 @@ __export(src_exports2, {
|
|
|
41789
42034
|
isHdrColorSpace: () => isHdrColorSpace,
|
|
41790
42035
|
isHttpUrl: () => isHttpUrl,
|
|
41791
42036
|
isLowMemorySystem: () => isLowMemorySystem,
|
|
42037
|
+
isTransientBrowserError: () => isTransientBrowserError,
|
|
41792
42038
|
isVideoFrameFormat: () => isVideoFrameFormat,
|
|
41793
42039
|
killTrackedProcesses: () => killTrackedProcesses,
|
|
41794
42040
|
launchHdrBrowser: () => launchHdrBrowser,
|
|
@@ -45203,6 +45449,7 @@ __export(manager_exports, {
|
|
|
45203
45449
|
ensureModel: () => ensureModel,
|
|
45204
45450
|
ensureWhisper: () => ensureWhisper,
|
|
45205
45451
|
findWhisper: () => findWhisper,
|
|
45452
|
+
getInstallInstructions: () => getInstallInstructions,
|
|
45206
45453
|
hasFFmpeg: () => hasFFmpeg,
|
|
45207
45454
|
isWhisperUnavailable: () => isWhisperUnavailable
|
|
45208
45455
|
});
|
|
@@ -45309,6 +45556,12 @@ function getInstallInstructions() {
|
|
|
45309
45556
|
if (platform4() === "darwin") {
|
|
45310
45557
|
return "brew install whisper-cpp";
|
|
45311
45558
|
}
|
|
45559
|
+
if (platform4() === "linux") {
|
|
45560
|
+
return "Build from source: https://github.com/ggml-org/whisper.cpp#building (requires cmake and a C compiler)";
|
|
45561
|
+
}
|
|
45562
|
+
if (platform4() === "win32") {
|
|
45563
|
+
return "Build with cmake: https://github.com/ggml-org/whisper.cpp#building";
|
|
45564
|
+
}
|
|
45312
45565
|
return "See https://github.com/ggml-org/whisper.cpp#building";
|
|
45313
45566
|
}
|
|
45314
45567
|
function hasBrew() {
|
|
@@ -45910,7 +46163,8 @@ var init_npxCommand = __esm({
|
|
|
45910
46163
|
// src/commands/skills.ts
|
|
45911
46164
|
var skills_exports = {};
|
|
45912
46165
|
__export(skills_exports, {
|
|
45913
|
-
default: () => skills_default
|
|
46166
|
+
default: () => skills_default,
|
|
46167
|
+
installAllSkills: () => installAllSkills
|
|
45914
46168
|
});
|
|
45915
46169
|
import { execFileSync as execFileSync4, spawn as spawn7 } from "child_process";
|
|
45916
46170
|
function hasNpx() {
|
|
@@ -45922,12 +46176,13 @@ function hasNpx() {
|
|
|
45922
46176
|
return false;
|
|
45923
46177
|
}
|
|
45924
46178
|
}
|
|
45925
|
-
function runSkillsAdd(repo) {
|
|
45926
|
-
const npx = buildNpxCommand(["skills", "add", repo, "--all"]);
|
|
46179
|
+
function runSkillsAdd(repo, opts = {}) {
|
|
46180
|
+
const npx = buildNpxCommand(["skills", "add", repo, ...opts.extraArgs ?? ["--all"]]);
|
|
45927
46181
|
return new Promise((resolve58, reject) => {
|
|
45928
46182
|
const child = spawn7(npx.command, npx.args, {
|
|
45929
46183
|
stdio: "inherit",
|
|
45930
46184
|
timeout: 12e4,
|
|
46185
|
+
cwd: opts.cwd,
|
|
45931
46186
|
// GH #316 — the upstream `skills` CLI shells out to `git clone`.
|
|
45932
46187
|
// When Git's clone-hook protection is active (shipped on by
|
|
45933
46188
|
// default in 2.45.1, reverted in 2.45.2, still present on many
|
|
@@ -45945,6 +46200,22 @@ function runSkillsAdd(repo) {
|
|
|
45945
46200
|
child.on("error", reject);
|
|
45946
46201
|
});
|
|
45947
46202
|
}
|
|
46203
|
+
async function installAllSkills(opts = {}) {
|
|
46204
|
+
if (!hasNpx()) {
|
|
46205
|
+
R2.error(c.error("npx not found. Install Node.js and retry."));
|
|
46206
|
+
return;
|
|
46207
|
+
}
|
|
46208
|
+
for (const source of SOURCES) {
|
|
46209
|
+
console.log();
|
|
46210
|
+
console.log(c.bold(`Installing ${source.name} skills...`));
|
|
46211
|
+
console.log();
|
|
46212
|
+
try {
|
|
46213
|
+
await runSkillsAdd(source.repo, opts);
|
|
46214
|
+
} catch {
|
|
46215
|
+
console.log(c.dim(`${source.name} skills skipped`));
|
|
46216
|
+
}
|
|
46217
|
+
}
|
|
46218
|
+
}
|
|
45948
46219
|
var SOURCES, skills_default;
|
|
45949
46220
|
var init_skills = __esm({
|
|
45950
46221
|
"src/commands/skills.ts"() {
|
|
@@ -45961,20 +46232,7 @@ var init_skills = __esm({
|
|
|
45961
46232
|
},
|
|
45962
46233
|
args: {},
|
|
45963
46234
|
async run() {
|
|
45964
|
-
|
|
45965
|
-
R2.error(c.error("npx not found. Install Node.js and retry."));
|
|
45966
|
-
return;
|
|
45967
|
-
}
|
|
45968
|
-
for (const source of SOURCES) {
|
|
45969
|
-
console.log();
|
|
45970
|
-
console.log(c.bold(`Installing ${source.name} skills...`));
|
|
45971
|
-
console.log();
|
|
45972
|
-
try {
|
|
45973
|
-
await runSkillsAdd(source.repo);
|
|
45974
|
-
} catch {
|
|
45975
|
-
console.log(c.dim(`${source.name} skills skipped`));
|
|
45976
|
-
}
|
|
45977
|
-
}
|
|
46235
|
+
await installAllSkills();
|
|
45978
46236
|
}
|
|
45979
46237
|
});
|
|
45980
46238
|
}
|
|
@@ -46171,7 +46429,16 @@ async function lintProject(project) {
|
|
|
46171
46429
|
const allHtmlSources = [{ html: rootHtml }];
|
|
46172
46430
|
const compositionsDir = resolve12(project.dir, "compositions");
|
|
46173
46431
|
if (existsSync22(compositionsDir)) {
|
|
46174
|
-
const
|
|
46432
|
+
const collectHtmlFiles = (dir, rel) => {
|
|
46433
|
+
const out = [];
|
|
46434
|
+
for (const entry of readdirSync8(dir, { withFileTypes: true })) {
|
|
46435
|
+
const relPath = rel ? `${rel}/${entry.name}` : entry.name;
|
|
46436
|
+
if (entry.isDirectory()) out.push(...collectHtmlFiles(join21(dir, entry.name), relPath));
|
|
46437
|
+
else if (entry.isFile() && entry.name.endsWith(".html")) out.push(relPath);
|
|
46438
|
+
}
|
|
46439
|
+
return out;
|
|
46440
|
+
};
|
|
46441
|
+
const files = collectHtmlFiles(compositionsDir, "").sort();
|
|
46175
46442
|
for (const file of files) {
|
|
46176
46443
|
const filePath = join21(compositionsDir, file);
|
|
46177
46444
|
const html = readFileSync15(filePath, "utf-8");
|
|
@@ -93728,7 +93995,16 @@ var init_fileServer2 = __esm({
|
|
|
93728
93995
|
var root = document.querySelector('[data-composition-id]');
|
|
93729
93996
|
if (!root) return 0;
|
|
93730
93997
|
var d = Number(root.getAttribute('data-duration'));
|
|
93731
|
-
|
|
93998
|
+
if (Number.isFinite(d) && d > 0) return d;
|
|
93999
|
+
var comps = document.querySelectorAll('[data-composition-src]');
|
|
94000
|
+
var maxEnd = 0;
|
|
94001
|
+
for (var i = 0; i < comps.length; i++) {
|
|
94002
|
+
var start = Number(comps[i].getAttribute('data-start')) || 0;
|
|
94003
|
+
var dur = Number(comps[i].getAttribute('data-duration')) || 0;
|
|
94004
|
+
if (dur > 0) maxEnd = Math.max(maxEnd, start + dur);
|
|
94005
|
+
}
|
|
94006
|
+
if (maxEnd > 0) console.warn('[HF Bridge] No root data-duration; derived ' + maxEnd + 's from sub-compositions');
|
|
94007
|
+
return maxEnd;
|
|
93732
94008
|
}
|
|
93733
94009
|
function seekSameOriginChildFrames(frameWindow, nextTimeMs) {
|
|
93734
94010
|
var frames;
|
|
@@ -95272,7 +95548,10 @@ function inlineSubCompositions2(html, subCompositions, projectDir) {
|
|
|
95272
95548
|
},
|
|
95273
95549
|
parseHtml: (htmlStr) => parseHTML(htmlStr).document,
|
|
95274
95550
|
scriptErrorLabel: "[Compiler] Composition script failed",
|
|
95275
|
-
compoundAuthoredRoot: true
|
|
95551
|
+
compoundAuthoredRoot: true,
|
|
95552
|
+
onMissingComposition: (srcPath) => {
|
|
95553
|
+
console.warn(`[Compiler] Composition file missing or empty: ${srcPath}`);
|
|
95554
|
+
}
|
|
95276
95555
|
}
|
|
95277
95556
|
);
|
|
95278
95557
|
for (const hostEl of hosts) {
|
|
@@ -96258,33 +96537,71 @@ async function runProbeStage(input2) {
|
|
|
96258
96537
|
quality: needsAlpha ? void 0 : 80,
|
|
96259
96538
|
deviceScaleFactor
|
|
96260
96539
|
};
|
|
96261
|
-
|
|
96262
|
-
|
|
96263
|
-
|
|
96264
|
-
|
|
96265
|
-
|
|
96266
|
-
|
|
96267
|
-
|
|
96268
|
-
|
|
96269
|
-
|
|
96270
|
-
|
|
96271
|
-
|
|
96272
|
-
|
|
96273
|
-
|
|
96274
|
-
|
|
96275
|
-
|
|
96276
|
-
|
|
96277
|
-
|
|
96278
|
-
|
|
96540
|
+
const PROBE_MAX_ATTEMPTS = 2;
|
|
96541
|
+
for (let attempt = 1; attempt <= PROBE_MAX_ATTEMPTS; attempt++) {
|
|
96542
|
+
const attemptStart = Date.now();
|
|
96543
|
+
try {
|
|
96544
|
+
log2.info("Creating capture session...", { attempt, maxAttempts: PROBE_MAX_ATTEMPTS });
|
|
96545
|
+
probeSession = await createCaptureSession(
|
|
96546
|
+
fileServer.url,
|
|
96547
|
+
join44(workDir, "probe"),
|
|
96548
|
+
captureOpts,
|
|
96549
|
+
null,
|
|
96550
|
+
probeCfg
|
|
96551
|
+
);
|
|
96552
|
+
log2.info("Waiting for composition to initialize...", { attempt });
|
|
96553
|
+
const heartbeat = setInterval(() => {
|
|
96554
|
+
const elapsed = ((Date.now() - attemptStart) / 1e3).toFixed(1);
|
|
96555
|
+
log2.info(`Still waiting for browser initialization... (${elapsed}s elapsed)`);
|
|
96556
|
+
}, 3e4);
|
|
96557
|
+
try {
|
|
96558
|
+
await initializeSession(probeSession);
|
|
96559
|
+
} finally {
|
|
96560
|
+
clearInterval(heartbeat);
|
|
96561
|
+
}
|
|
96562
|
+
} catch (err) {
|
|
96563
|
+
const isTransient = isTransientBrowserError(err);
|
|
96564
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
96565
|
+
log2.warn("Browser probe attempt failed", {
|
|
96566
|
+
attempt,
|
|
96567
|
+
maxAttempts: PROBE_MAX_ATTEMPTS,
|
|
96568
|
+
isTransient,
|
|
96569
|
+
error: errMsg,
|
|
96570
|
+
elapsedMs: Date.now() - attemptStart
|
|
96571
|
+
});
|
|
96572
|
+
if (probeSession) {
|
|
96573
|
+
try {
|
|
96574
|
+
await closeCaptureSession(probeSession);
|
|
96575
|
+
} catch (closeErr) {
|
|
96576
|
+
log2.warn("Failed to close crashed probe session", {
|
|
96577
|
+
error: closeErr instanceof Error ? closeErr.message : String(closeErr)
|
|
96578
|
+
});
|
|
96579
|
+
}
|
|
96580
|
+
probeSession = null;
|
|
96581
|
+
}
|
|
96582
|
+
if (isTransient && attempt < PROBE_MAX_ATTEMPTS) {
|
|
96583
|
+
log2.info("Retrying with a fresh browser session...", {
|
|
96584
|
+
attempt: attempt + 1,
|
|
96585
|
+
maxAttempts: PROBE_MAX_ATTEMPTS
|
|
96586
|
+
});
|
|
96587
|
+
assertNotAborted();
|
|
96588
|
+
continue;
|
|
96589
|
+
}
|
|
96590
|
+
throw err;
|
|
96591
|
+
}
|
|
96592
|
+
log2.info("Composition ready", {
|
|
96593
|
+
attempt,
|
|
96594
|
+
initMs: Date.now() - attemptStart
|
|
96595
|
+
});
|
|
96596
|
+
break;
|
|
96279
96597
|
}
|
|
96280
|
-
log2.info("Composition ready", {
|
|
96281
|
-
initMs: Date.now() - initStart
|
|
96282
|
-
});
|
|
96283
96598
|
assertNotAborted();
|
|
96284
|
-
|
|
96599
|
+
const session = probeSession;
|
|
96600
|
+
probeSession = session;
|
|
96601
|
+
lastBrowserConsole = session.browserConsoleBuffer;
|
|
96285
96602
|
if (composition.duration <= 0) {
|
|
96286
96603
|
log2.info("Discovering composition duration...");
|
|
96287
|
-
const discoveredDuration = await getCompositionDuration(
|
|
96604
|
+
const discoveredDuration = await getCompositionDuration(session);
|
|
96288
96605
|
assertNotAborted();
|
|
96289
96606
|
log2.info("Probed composition duration from browser", {
|
|
96290
96607
|
discoveredDuration,
|
|
@@ -96298,7 +96615,7 @@ async function runProbeStage(input2) {
|
|
|
96298
96615
|
}
|
|
96299
96616
|
if (compiled.unresolvedCompositions.length > 0) {
|
|
96300
96617
|
const resolutions = await resolveCompositionDurations(
|
|
96301
|
-
|
|
96618
|
+
session.page,
|
|
96302
96619
|
compiled.unresolvedCompositions
|
|
96303
96620
|
);
|
|
96304
96621
|
assertNotAborted();
|
|
@@ -96317,7 +96634,7 @@ async function runProbeStage(input2) {
|
|
|
96317
96634
|
}
|
|
96318
96635
|
}
|
|
96319
96636
|
log2.info("Discovering media assets from browser DOM...");
|
|
96320
|
-
const browserMedia = await discoverMediaFromBrowser(
|
|
96637
|
+
const browserMedia = await discoverMediaFromBrowser(session.page);
|
|
96321
96638
|
assertNotAborted();
|
|
96322
96639
|
if (browserMedia.length > 0) {
|
|
96323
96640
|
const existingVideoIds = new Set(composition.videos.map((v2) => v2.id));
|
|
@@ -96408,7 +96725,7 @@ async function runProbeStage(input2) {
|
|
|
96408
96725
|
audioCount: composition.audios.length
|
|
96409
96726
|
});
|
|
96410
96727
|
const automation = await discoverAudioVolumeAutomationFromTimeline(
|
|
96411
|
-
|
|
96728
|
+
session.page,
|
|
96412
96729
|
composition.audios.map((audio) => audio.id),
|
|
96413
96730
|
composition.duration,
|
|
96414
96731
|
fpsToNumber(job.config.fps)
|
|
@@ -96431,7 +96748,7 @@ async function runProbeStage(input2) {
|
|
|
96431
96748
|
videoCount: composition.videos.length
|
|
96432
96749
|
});
|
|
96433
96750
|
const visibilityWindows = await discoverVideoVisibilityFromTimeline(
|
|
96434
|
-
|
|
96751
|
+
session.page,
|
|
96435
96752
|
composition.duration
|
|
96436
96753
|
);
|
|
96437
96754
|
assertNotAborted();
|
|
@@ -99550,6 +99867,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
99550
99867
|
job.startedAt = /* @__PURE__ */ new Date();
|
|
99551
99868
|
assertNotAborted();
|
|
99552
99869
|
assertConfiguredFfmpegBinariesExist();
|
|
99870
|
+
if (!existsSync45(workDir)) mkdirSync26(workDir, { recursive: true });
|
|
99871
|
+
if (job.config.debug) {
|
|
99872
|
+
const logPath = join55(workDir, "render.log");
|
|
99873
|
+
restoreLogger = installDebugLogger(logPath, log2);
|
|
99874
|
+
log2.info("[Render] Debug artifacts enabled", { workDir, logPath });
|
|
99875
|
+
}
|
|
99553
99876
|
log2.info("[Render] Pipeline started", {
|
|
99554
99877
|
platform: process.platform,
|
|
99555
99878
|
arch: process.arch,
|
|
@@ -99574,11 +99897,6 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
99574
99897
|
playerReadyTimeoutMs: cfg.playerReadyTimeout,
|
|
99575
99898
|
requestedWorkers: job.config.workers ?? "auto"
|
|
99576
99899
|
});
|
|
99577
|
-
if (!existsSync45(workDir)) mkdirSync26(workDir, { recursive: true });
|
|
99578
|
-
if (job.config.debug) {
|
|
99579
|
-
const logPath = join55(workDir, "render.log");
|
|
99580
|
-
restoreLogger = installDebugLogger(logPath, log2);
|
|
99581
|
-
}
|
|
99582
99900
|
const entryFile = job.config.entryFile || "index.html";
|
|
99583
99901
|
let htmlPath = join55(projectDir, entryFile);
|
|
99584
99902
|
if (!existsSync45(htmlPath)) {
|
|
@@ -99796,8 +100114,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
99796
100114
|
format: needsAlpha ? "png" : "jpeg",
|
|
99797
100115
|
quality: needsAlpha ? void 0 : job.config.quality === "draft" ? 80 : 95,
|
|
99798
100116
|
variables: job.config.variables,
|
|
99799
|
-
deviceScaleFactor
|
|
100117
|
+
deviceScaleFactor,
|
|
100118
|
+
captureBeyondViewport: composition.videos.length > 0
|
|
99800
100119
|
};
|
|
100120
|
+
updateCaptureObservability({
|
|
100121
|
+
captureBeyondViewport: captureOptions.captureBeyondViewport ?? false
|
|
100122
|
+
});
|
|
99801
100123
|
const buildCaptureOptions = () => ({
|
|
99802
100124
|
...captureOptions,
|
|
99803
100125
|
videoMetadataHints,
|
|
@@ -99926,6 +100248,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
99926
100248
|
observability.checkpoint("capture_strategy", "resolved", {
|
|
99927
100249
|
workerCount,
|
|
99928
100250
|
forceScreenshot: captureForceScreenshot,
|
|
100251
|
+
captureBeyondViewport: captureOptions.captureBeyondViewport ?? false,
|
|
99929
100252
|
useStreamingEncode,
|
|
99930
100253
|
useLayeredComposite,
|
|
99931
100254
|
usePageSideCompositing: usePageSideCompositingForTransitions,
|
|
@@ -102036,6 +102359,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
|
|
|
102036
102359
|
// declare `data-composition-variables` leave this undefined and the
|
|
102037
102360
|
// engine skips the `evaluateOnNewDocument` injection.
|
|
102038
102361
|
variables: encoder.variables,
|
|
102362
|
+
captureBeyondViewport: (planVideos?.videos.length ?? 0) > 0,
|
|
102039
102363
|
// lock the BeginFrame warmup loop to a fixed iteration count so
|
|
102040
102364
|
// `beginFrameTimeTicks` is host-independent. Only chunks ever set this.
|
|
102041
102365
|
lockWarmupTicks: true
|
|
@@ -104527,11 +104851,22 @@ var init_init = __esm({
|
|
|
104527
104851
|
for (const f3 of readdirSync23(destDir2).filter((f4) => !f4.startsWith("."))) {
|
|
104528
104852
|
console.log(` ${c.accent(f3)}`);
|
|
104529
104853
|
}
|
|
104854
|
+
if (!skipSkills) {
|
|
104855
|
+
const { installAllSkills: installAllSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
104856
|
+
const args2 = process.env["CLAUDECODE"] ? ["--agent", "claude-code", "--yes"] : ["--yes"];
|
|
104857
|
+
await installAllSkills2({ cwd: destDir2, extraArgs: args2 });
|
|
104858
|
+
}
|
|
104530
104859
|
console.log();
|
|
104531
104860
|
console.log("Get started:");
|
|
104532
104861
|
console.log();
|
|
104533
|
-
|
|
104534
|
-
|
|
104862
|
+
if (skipSkills) {
|
|
104863
|
+
console.log(` ${c.accent("1.")} Install AI coding skills (one-time):`);
|
|
104864
|
+
console.log(` ${c.accent("npx skills add heygen-com/hyperframes --yes")}`);
|
|
104865
|
+
} else {
|
|
104866
|
+
console.log(
|
|
104867
|
+
` ${c.accent("1.")} Restart your AI agent (new session) so it loads the skills.`
|
|
104868
|
+
);
|
|
104869
|
+
}
|
|
104535
104870
|
console.log();
|
|
104536
104871
|
console.log(` ${c.accent("2.")} Open this project with your AI coding agent:`);
|
|
104537
104872
|
console.log(
|
|
@@ -104718,8 +105053,8 @@ ${c.dim("Use --example blank for offline use.")}`
|
|
|
104718
105053
|
process.exit(0);
|
|
104719
105054
|
}
|
|
104720
105055
|
if (installSkills) {
|
|
104721
|
-
const
|
|
104722
|
-
await
|
|
105056
|
+
const { installAllSkills: installAllSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
105057
|
+
await installAllSkills2({ cwd: destDir });
|
|
104723
105058
|
}
|
|
104724
105059
|
}
|
|
104725
105060
|
R2.info("Opening studio preview...");
|
|
@@ -106649,6 +106984,10 @@ function buildDockerRunArgs(input2) {
|
|
|
106649
106984
|
`${projectDir}:/project:ro`,
|
|
106650
106985
|
"-v",
|
|
106651
106986
|
`${outputDir}:/output`,
|
|
106987
|
+
// Keep debug artifacts on the mounted host output path. The producer roots
|
|
106988
|
+
// `.debug` at dirname(PRODUCER_RENDERS_DIR), so `/output/renders` maps to
|
|
106989
|
+
// `/output/.debug/<job id>` instead of a disposable container path.
|
|
106990
|
+
...options.debug ? ["-e", "PRODUCER_RENDERS_DIR=/output/renders"] : [],
|
|
106652
106991
|
imageTag,
|
|
106653
106992
|
"/project",
|
|
106654
106993
|
"--output",
|
|
@@ -106666,6 +107005,7 @@ function buildDockerRunArgs(input2) {
|
|
|
106666
107005
|
...options.videoBitrate ? ["--video-bitrate", options.videoBitrate] : [],
|
|
106667
107006
|
...options.videoFrameFormat && options.videoFrameFormat !== "auto" ? ["--video-frame-format", options.videoFrameFormat] : [],
|
|
106668
107007
|
...options.quiet ? ["--quiet"] : [],
|
|
107008
|
+
...options.debug ? ["--debug"] : [],
|
|
106669
107009
|
...options.gpu ? ["--gpu"] : [],
|
|
106670
107010
|
...options.browserGpu ? [] : ["--no-browser-gpu"],
|
|
106671
107011
|
...options.hdrMode === "force-hdr" ? ["--hdr"] : [],
|
|
@@ -107413,6 +107753,7 @@ async function renderDocker(projectDir, outputPath, options) {
|
|
|
107413
107753
|
entryFile: options.entryFile,
|
|
107414
107754
|
outputResolution: options.outputResolution,
|
|
107415
107755
|
pageSideCompositing: options.pageSideCompositing,
|
|
107756
|
+
debug: options.debug,
|
|
107416
107757
|
pageNavigationTimeoutMs: options.pageNavigationTimeoutMs
|
|
107417
107758
|
}
|
|
107418
107759
|
});
|
|
@@ -107480,7 +107821,7 @@ async function renderLocal(projectDir, outputPath, options) {
|
|
|
107480
107821
|
const producer = await loadProducer();
|
|
107481
107822
|
const startTime = Date.now();
|
|
107482
107823
|
const logger = createRenderTelemetryLogger(
|
|
107483
|
-
producer.createConsoleLogger?.("info") ?? createNoopProducerLogger()
|
|
107824
|
+
producer.createConsoleLogger?.(options.debug ? "debug" : "info") ?? createNoopProducerLogger()
|
|
107484
107825
|
);
|
|
107485
107826
|
const job = producer.createRenderJob({
|
|
107486
107827
|
fps: options.fps,
|
|
@@ -107503,7 +107844,8 @@ async function renderLocal(projectDir, outputPath, options) {
|
|
|
107503
107844
|
videoFrameFormat: options.videoFrameFormat,
|
|
107504
107845
|
variables: options.variables,
|
|
107505
107846
|
entryFile: options.entryFile,
|
|
107506
|
-
outputResolution: options.outputResolution
|
|
107847
|
+
outputResolution: options.outputResolution,
|
|
107848
|
+
debug: options.debug
|
|
107507
107849
|
});
|
|
107508
107850
|
const onProgress = options.quiet ? void 0 : (progressJob, message) => {
|
|
107509
107851
|
renderProgress(progressJob.progress, message);
|
|
@@ -107882,6 +108224,11 @@ var init_render2 = __esm({
|
|
|
107882
108224
|
description: "Suppress verbose output",
|
|
107883
108225
|
default: false
|
|
107884
108226
|
},
|
|
108227
|
+
debug: {
|
|
108228
|
+
type: "boolean",
|
|
108229
|
+
description: "Write full render diagnostics and keep intermediate artifacts under the producer .debug directory.",
|
|
108230
|
+
default: false
|
|
108231
|
+
},
|
|
107885
108232
|
strict: {
|
|
107886
108233
|
type: "boolean",
|
|
107887
108234
|
description: "Fail render on lint errors",
|
|
@@ -108109,6 +108456,7 @@ var init_render2 = __esm({
|
|
|
108109
108456
|
const browserGpuArg = args["browser-gpu"];
|
|
108110
108457
|
const browserGpuMode = resolveBrowserGpuForCli(useDocker, browserGpuArg);
|
|
108111
108458
|
const quiet = args.quiet ?? false;
|
|
108459
|
+
const debug = args.debug ?? false;
|
|
108112
108460
|
const batchJson = args.json ?? false;
|
|
108113
108461
|
const effectiveQuiet = quiet || batchPath != null && batchJson;
|
|
108114
108462
|
const strictAll = args["strict-all"] ?? false;
|
|
@@ -108280,6 +108628,7 @@ var init_render2 = __esm({
|
|
|
108280
108628
|
pageNavigationTimeoutMs,
|
|
108281
108629
|
protocolTimeout,
|
|
108282
108630
|
playerReadyTimeout,
|
|
108631
|
+
debug,
|
|
108283
108632
|
exitAfterComplete: false,
|
|
108284
108633
|
throwOnError: true,
|
|
108285
108634
|
skipFeedback: true
|
|
@@ -108323,6 +108672,7 @@ var init_render2 = __esm({
|
|
|
108323
108672
|
videoBitrate,
|
|
108324
108673
|
videoFrameFormat,
|
|
108325
108674
|
quiet,
|
|
108675
|
+
debug,
|
|
108326
108676
|
variables,
|
|
108327
108677
|
entryFile,
|
|
108328
108678
|
outputResolution,
|
|
@@ -108348,6 +108698,7 @@ var init_render2 = __esm({
|
|
|
108348
108698
|
videoFrameFormat,
|
|
108349
108699
|
quiet,
|
|
108350
108700
|
browserPath,
|
|
108701
|
+
debug,
|
|
108351
108702
|
variables,
|
|
108352
108703
|
entryFile,
|
|
108353
108704
|
outputResolution,
|
|
@@ -112167,6 +112518,18 @@ function checkEnvironment() {
|
|
|
112167
112518
|
}
|
|
112168
112519
|
return { ok: true, detail: parts.join(" \xB7 ") };
|
|
112169
112520
|
}
|
|
112521
|
+
async function checkWhisper() {
|
|
112522
|
+
const { findWhisper: findWhisper2, getInstallInstructions: getInstallInstructions2 } = await Promise.resolve().then(() => (init_manager(), manager_exports));
|
|
112523
|
+
const result = findWhisper2();
|
|
112524
|
+
if (result) {
|
|
112525
|
+
return { ok: true, detail: result.executablePath };
|
|
112526
|
+
}
|
|
112527
|
+
return {
|
|
112528
|
+
ok: false,
|
|
112529
|
+
detail: "Not found (optional \u2014 needed for transcription)",
|
|
112530
|
+
hint: getInstallInstructions2()
|
|
112531
|
+
};
|
|
112532
|
+
}
|
|
112170
112533
|
function redactHome(s2) {
|
|
112171
112534
|
const home = process.env["HOME"] || process.env["USERPROFILE"];
|
|
112172
112535
|
if (!home) return s2;
|
|
@@ -112221,6 +112584,7 @@ var init_doctor = __esm({
|
|
|
112221
112584
|
checks.push({ name: "/dev/shm", run: checkShm });
|
|
112222
112585
|
}
|
|
112223
112586
|
checks.push({ name: "Environment", run: checkEnvironment });
|
|
112587
|
+
checks.push({ name: "whisper-cpp", run: checkWhisper });
|
|
112224
112588
|
const outcomes = [];
|
|
112225
112589
|
for (const check of checks) {
|
|
112226
112590
|
const result = await check.run();
|
|
@@ -112541,6 +112905,58 @@ Run ${c.accent("hyperframes telemetry --help")} for usage.`
|
|
|
112541
112905
|
}
|
|
112542
112906
|
});
|
|
112543
112907
|
|
|
112908
|
+
// src/commands/events.ts
|
|
112909
|
+
var events_exports2 = {};
|
|
112910
|
+
__export(events_exports2, {
|
|
112911
|
+
default: () => events_default
|
|
112912
|
+
});
|
|
112913
|
+
var ALLOWED_EVENTS, ALLOWED_OUTCOMES, SKILL_SLUG, events_default;
|
|
112914
|
+
var init_events2 = __esm({
|
|
112915
|
+
"src/commands/events.ts"() {
|
|
112916
|
+
"use strict";
|
|
112917
|
+
init_dist();
|
|
112918
|
+
init_client();
|
|
112919
|
+
ALLOWED_EVENTS = ["skill_invoked", "skill_completed"];
|
|
112920
|
+
ALLOWED_OUTCOMES = ["success", "error", "abort"];
|
|
112921
|
+
SKILL_SLUG = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
112922
|
+
events_default = defineCommand({
|
|
112923
|
+
meta: {
|
|
112924
|
+
name: "events",
|
|
112925
|
+
description: "Emit an anonymous skill-usage telemetry event (skills report their own invocation/outcome). Honors DO_NOT_TRACK / telemetry opt-out."
|
|
112926
|
+
},
|
|
112927
|
+
args: {
|
|
112928
|
+
skill: {
|
|
112929
|
+
type: "string",
|
|
112930
|
+
description: "Authoring skill slug, e.g. product-launch-video"
|
|
112931
|
+
},
|
|
112932
|
+
event: {
|
|
112933
|
+
type: "string",
|
|
112934
|
+
description: "Event name: skill_invoked | skill_completed (default: skill_invoked)",
|
|
112935
|
+
default: "skill_invoked"
|
|
112936
|
+
},
|
|
112937
|
+
outcome: {
|
|
112938
|
+
type: "string",
|
|
112939
|
+
description: "Optional outcome for completion events: success | error | abort"
|
|
112940
|
+
}
|
|
112941
|
+
},
|
|
112942
|
+
async run({ args }) {
|
|
112943
|
+
try {
|
|
112944
|
+
const skill = typeof args.skill === "string" ? args.skill.trim() : "";
|
|
112945
|
+
if (!SKILL_SLUG.test(skill)) return;
|
|
112946
|
+
const event = ALLOWED_EVENTS.includes(args.event) ? args.event : "skill_invoked";
|
|
112947
|
+
const props = { authoring_skill: skill };
|
|
112948
|
+
if (args.outcome && ALLOWED_OUTCOMES.includes(args.outcome)) {
|
|
112949
|
+
props["outcome"] = args.outcome;
|
|
112950
|
+
}
|
|
112951
|
+
trackEvent(event, props);
|
|
112952
|
+
await flush();
|
|
112953
|
+
} catch {
|
|
112954
|
+
}
|
|
112955
|
+
}
|
|
112956
|
+
});
|
|
112957
|
+
}
|
|
112958
|
+
});
|
|
112959
|
+
|
|
112544
112960
|
// src/utils/compositionViewport.ts
|
|
112545
112961
|
function parseViewportDimension(value) {
|
|
112546
112962
|
if (!value) return null;
|
|
@@ -162861,6 +163277,7 @@ var commandLoaders = {
|
|
|
162861
163277
|
skills: () => Promise.resolve().then(() => (init_skills(), skills_exports)).then((m2) => m2.default),
|
|
162862
163278
|
feedback: () => Promise.resolve().then(() => (init_feedback2(), feedback_exports)).then((m2) => m2.default),
|
|
162863
163279
|
telemetry: () => Promise.resolve().then(() => (init_telemetry(), telemetry_exports)).then((m2) => m2.default),
|
|
163280
|
+
events: () => Promise.resolve().then(() => (init_events2(), events_exports2)).then((m2) => m2.default),
|
|
162864
163281
|
validate: () => Promise.resolve().then(() => (init_validate(), validate_exports)).then((m2) => m2.default),
|
|
162865
163282
|
snapshot: () => Promise.resolve().then(() => (init_snapshot(), snapshot_exports)).then((m2) => m2.default),
|
|
162866
163283
|
capture: () => Promise.resolve().then(() => (init_capture2(), capture_exports2)).then((m2) => m2.default),
|
|
@@ -162891,7 +163308,7 @@ var _flushSync;
|
|
|
162891
163308
|
var _trackCliError;
|
|
162892
163309
|
var _trackCommandResult;
|
|
162893
163310
|
var _printUpdateNotice;
|
|
162894
|
-
if (!isHelp && command !== "telemetry" && command !== "unknown") {
|
|
163311
|
+
if (!isHelp && command !== "telemetry" && command !== "events" && command !== "unknown") {
|
|
162895
163312
|
Promise.resolve().then(() => (init_telemetry2(), telemetry_exports2)).then((mod) => {
|
|
162896
163313
|
_flush = mod.flush;
|
|
162897
163314
|
_flushSync = mod.flushSync;
|
|
@@ -162902,7 +163319,7 @@ if (!isHelp && command !== "telemetry" && command !== "unknown") {
|
|
|
162902
163319
|
if (mod.shouldTrack()) mod.incrementCommandCount();
|
|
162903
163320
|
});
|
|
162904
163321
|
}
|
|
162905
|
-
if (!isHelp && !hasJsonFlag && command !== "upgrade") {
|
|
163322
|
+
if (!isHelp && !hasJsonFlag && command !== "upgrade" && command !== "events") {
|
|
162906
163323
|
Promise.resolve().then(() => (init_autoUpdate(), autoUpdate_exports)).then((mod) => mod.reportCompletedUpdate()).catch(() => {
|
|
162907
163324
|
});
|
|
162908
163325
|
Promise.resolve().then(() => (init_updateCheck(), updateCheck_exports)).then(async (mod) => {
|