hyperframes 0.8.22 → 0.8.23
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 +112 -23
- package/dist/fontLocalizeCli.js +43 -2
- package/dist/hyperframes-player.global.js +1 -1
- package/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +1 -1
- package/dist/studio/assets/{hyperframes-player-DmtkkaPN.js → hyperframes-player-oZ6g4tHJ.js} +1 -1
- package/dist/studio/assets/{index-DXR3nsh2.js → index-DW-H7Y2b.js} +1 -1
- package/dist/studio/assets/{index-BIf0zQNt.js → index-Tiu74FPg.js} +3 -3
- package/dist/studio/assets/{index-DivnGS5G.js → index-UyvIa_cE.js} +1 -1
- package/dist/studio/index.html +1 -1
- 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.8.
|
|
53
|
+
VERSION = true ? "0.8.23" : "0.0.0-dev";
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
@@ -84035,6 +84035,47 @@ ${other.raw}`)
|
|
|
84035
84035
|
}
|
|
84036
84036
|
return findings;
|
|
84037
84037
|
},
|
|
84038
|
+
// gsap_timeline_return_used_as_tween — `tl.to()` returns the TIMELINE, not the tween it just
|
|
84039
|
+
// created. `gsap.to()` returns a Tween, so the two read identically and behave nothing alike.
|
|
84040
|
+
// Capturing the timeline's return and later treating it as an individual animation aims a
|
|
84041
|
+
// tween-scoped call at the whole composition: `.kill()` on it interrupts the master timeline
|
|
84042
|
+
// and detaches it from its parent, which stops a parent-driven seek dead while leaving an
|
|
84043
|
+
// explicit `tl.progress()` still working -- so a render of the packaged defaults looks fine
|
|
84044
|
+
// and only live playback breaks. A rebuild that collected these to discard them also leaves
|
|
84045
|
+
// every previous keyframe in place and stacks the new ones on top.
|
|
84046
|
+
({ scripts }) => {
|
|
84047
|
+
const findings = [];
|
|
84048
|
+
for (const script of scripts) {
|
|
84049
|
+
const source = stripJsComments(script.content);
|
|
84050
|
+
const timelineVars = collectTimelineVarNames(source);
|
|
84051
|
+
if (timelineVars.length === 0) continue;
|
|
84052
|
+
const receivers = timelineVars.map(escapeRegExp22).join("|");
|
|
84053
|
+
const pattern = new RegExp(
|
|
84054
|
+
String.raw`(?:\.push\s*\(\s*|(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*)(?:${receivers})\s*\.\s*(to|from|fromTo|set|call|add)\s*\(`,
|
|
84055
|
+
"g"
|
|
84056
|
+
);
|
|
84057
|
+
let match;
|
|
84058
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
84059
|
+
const boundName = match[1];
|
|
84060
|
+
const method = match[2];
|
|
84061
|
+
if (boundName) {
|
|
84062
|
+
const treatedAsTween = new RegExp(
|
|
84063
|
+
String.raw`\b${escapeRegExp22(boundName)}\s*\.\s*(?:kill|revert|invalidate|pause|resume|restart|seek|progress|timeScale)\s*\(`
|
|
84064
|
+
);
|
|
84065
|
+
if (!treatedAsTween.test(source)) continue;
|
|
84066
|
+
}
|
|
84067
|
+
const contextStart = Math.max(0, match.index - 40);
|
|
84068
|
+
findings.push({
|
|
84069
|
+
code: "gsap_timeline_return_used_as_tween",
|
|
84070
|
+
severity: "error",
|
|
84071
|
+
message: `\`${match[0].includes(".push") ? "push" : boundName}\` captures the return of \`.${method}()\` on timeline \`${timelineVars[0]}\`, but a timeline's \`.to()\`/\`.from()\`/\`.set()\` returns THE TIMELINE ITSELF, not the tween it created. Every captured value is the same master timeline, so a tween-scoped call on it \u2014 \`.kill()\` above all \u2014 hits the whole composition: it interrupts the timeline and detaches it from its parent, which freezes a parent-driven seek while an explicit \`tl.progress()\` keeps working. Only \`gsap.to()\` returns a tween.`,
|
|
84072
|
+
fixHint: "To build a group of keyframes you can later discard, put them in a nested timeline: `const nested = gsap.timeline(); nested.to(...); tl.add(nested, 0);` \u2014 then `nested.kill()` replaces exactly those keyframes and cannot reach `tl`. Children keep their absolute times when the nest is added at 0. To hold a single real tween, create it with `gsap.to(...)` and place it with `tl.add(tween, at)`.",
|
|
84073
|
+
snippet: truncateSnippet(source.slice(contextStart, match.index + match[0].length + 60))
|
|
84074
|
+
});
|
|
84075
|
+
}
|
|
84076
|
+
}
|
|
84077
|
+
return findings;
|
|
84078
|
+
},
|
|
84038
84079
|
// gsap_group_selector_keyframes
|
|
84039
84080
|
({ scripts }) => {
|
|
84040
84081
|
const findings = [];
|
|
@@ -149583,18 +149624,22 @@ function geometryIssueAnchor(candidate, time) {
|
|
|
149583
149624
|
rect: candidate.rect
|
|
149584
149625
|
};
|
|
149585
149626
|
}
|
|
149586
|
-
function
|
|
149587
|
-
const
|
|
149588
|
-
const
|
|
149589
|
-
const
|
|
149590
|
-
|
|
149627
|
+
function captionBoxOverlapsZone(box, zone, canvas) {
|
|
149628
|
+
const zx0 = zone.x0 * canvas.width;
|
|
149629
|
+
const zy0 = zone.y0 * canvas.height;
|
|
149630
|
+
const zx1 = zone.x1 * canvas.width;
|
|
149631
|
+
const zy1 = zone.y1 * canvas.height;
|
|
149632
|
+
const bx1 = box.left + box.width;
|
|
149633
|
+
const by1 = box.top + box.height;
|
|
149634
|
+
const overlaps = box.left < zx1 && bx1 > zx0 && box.top < zy1 && by1 > zy0;
|
|
149635
|
+
return { overlaps, cy: box.top + box.height / 2 };
|
|
149591
149636
|
}
|
|
149592
149637
|
function captionFinding(candidate, options, canvas, time) {
|
|
149593
149638
|
const zone = options.captionZone;
|
|
149594
149639
|
if (!zone || candidate.kind !== "text" || !candidateIsSized(candidate, canvas)) return null;
|
|
149595
149640
|
if ("data-layout-allow-caption-zone" in candidate.dataAttributes) return null;
|
|
149596
|
-
const {
|
|
149597
|
-
if (!
|
|
149641
|
+
const { overlaps, cy } = captionBoxOverlapsZone(candidate.elementRect, zone, canvas);
|
|
149642
|
+
if (!overlaps) return null;
|
|
149598
149643
|
const text2 = candidate.text.slice(0, 48);
|
|
149599
149644
|
const pctFromBottom = Math.round((canvas.height - cy) / canvas.height * 100);
|
|
149600
149645
|
return {
|
|
@@ -149604,7 +149649,7 @@ function captionFinding(candidate, options, canvas, time) {
|
|
|
149604
149649
|
code: "caption_zone_collision",
|
|
149605
149650
|
severity: zone.severity === "error" ? "error" : "warning",
|
|
149606
149651
|
text: text2,
|
|
149607
|
-
message: `<${candidate.tag}> "${text2}"
|
|
149652
|
+
message: `<${candidate.tag}> "${text2}" overlaps the reserved caption band (~${pctFromBottom}% up from the bottom).`,
|
|
149608
149653
|
fixHint: "Keep main content outside the configured caption band, or mark intentional lower-third copy with data-layout-allow-caption-zone."
|
|
149609
149654
|
}
|
|
149610
149655
|
};
|
|
@@ -203174,18 +203219,25 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
|
|
|
203174
203219
|
}
|
|
203175
203220
|
const openRouterKey = process.env.OPENROUTER_API_KEY;
|
|
203176
203221
|
const geminiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
|
|
203177
|
-
|
|
203222
|
+
const vertexProject = process.env.HYPERFRAMES_VERTEX_PROJECT_ID;
|
|
203223
|
+
const vertexServiceAccount = process.env.HYPERFRAMES_VERTEX_SERVICE_ACCOUNT;
|
|
203224
|
+
const useVertex = Boolean(vertexProject && vertexServiceAccount);
|
|
203225
|
+
if (!openRouterKey && !useVertex && !geminiKey) {
|
|
203178
203226
|
reportOutcome();
|
|
203179
203227
|
return geminiCaptions;
|
|
203180
203228
|
}
|
|
203181
|
-
const
|
|
203182
|
-
const providerName =
|
|
203183
|
-
const model =
|
|
203229
|
+
const provider = openRouterKey ? "openrouter" : useVertex ? "vertex" : "gemini";
|
|
203230
|
+
const providerName = { openrouter: "OpenRouter", vertex: "Vertex AI", gemini: "Gemini" }[provider];
|
|
203231
|
+
const model = {
|
|
203232
|
+
openrouter: process.env.HYPERFRAMES_OPENROUTER_MODEL || "google/gemini-3.1-flash-lite",
|
|
203233
|
+
vertex: process.env.HYPERFRAMES_VERTEX_MODEL || "gemini-2.5-flash",
|
|
203234
|
+
gemini: process.env.HYPERFRAMES_GEMINI_MODEL || "gemini-3.1-flash-lite-preview"
|
|
203235
|
+
}[provider];
|
|
203184
203236
|
const requestTimeoutMs = resolveVisionRequestTimeoutMs();
|
|
203185
203237
|
progress("design", `Captioning images with ${providerName} vision...`);
|
|
203186
203238
|
try {
|
|
203187
203239
|
let captionOne;
|
|
203188
|
-
if (
|
|
203240
|
+
if (provider === "openrouter") {
|
|
203189
203241
|
captionOne = async ({ mimeType, base64, prompt, maxTokens, timeoutMs }) => {
|
|
203190
203242
|
return runBoundedVisionRequest(async (signal) => {
|
|
203191
203243
|
const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
|
|
@@ -203221,9 +203273,31 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
|
|
|
203221
203273
|
}, timeoutMs);
|
|
203222
203274
|
};
|
|
203223
203275
|
} else {
|
|
203224
|
-
if (!geminiKey) return geminiCaptions;
|
|
203225
203276
|
const { GoogleGenAI: GoogleGenAI2 } = await Promise.resolve().then(() => (init_node4(), node_exports));
|
|
203226
|
-
|
|
203277
|
+
let ai;
|
|
203278
|
+
if (provider === "vertex") {
|
|
203279
|
+
if (!vertexProject || !vertexServiceAccount) return geminiCaptions;
|
|
203280
|
+
let credentials;
|
|
203281
|
+
try {
|
|
203282
|
+
credentials = JSON.parse(vertexServiceAccount);
|
|
203283
|
+
} catch {
|
|
203284
|
+
warnings.push(
|
|
203285
|
+
"HYPERFRAMES_VERTEX_SERVICE_ACCOUNT is not valid JSON; skipped vision captioning."
|
|
203286
|
+
);
|
|
203287
|
+
internalError = true;
|
|
203288
|
+
reportOutcome();
|
|
203289
|
+
return geminiCaptions;
|
|
203290
|
+
}
|
|
203291
|
+
ai = new GoogleGenAI2({
|
|
203292
|
+
vertexai: true,
|
|
203293
|
+
project: vertexProject,
|
|
203294
|
+
location: process.env.HYPERFRAMES_VERTEX_LOCATION || "us-central1",
|
|
203295
|
+
googleAuthOptions: { credentials }
|
|
203296
|
+
});
|
|
203297
|
+
} else {
|
|
203298
|
+
if (!geminiKey) return geminiCaptions;
|
|
203299
|
+
ai = new GoogleGenAI2({ apiKey: geminiKey });
|
|
203300
|
+
}
|
|
203227
203301
|
captionOne = async ({ mimeType, base64, prompt, maxTokens, timeoutMs }) => {
|
|
203228
203302
|
const response = await runBoundedVisionRequest(
|
|
203229
203303
|
(signal) => ai.models.generateContent({
|
|
@@ -203236,6 +203310,12 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
|
|
|
203236
203310
|
],
|
|
203237
203311
|
config: {
|
|
203238
203312
|
maxOutputTokens: maxTokens,
|
|
203313
|
+
// A one-line factual caption needs no reasoning, and leaving thinking on is
|
|
203314
|
+
// not merely wasteful: thinking tokens are drawn from maxOutputTokens, so the
|
|
203315
|
+
// model can spend the whole budget and return empty text. That surfaces as a
|
|
203316
|
+
// successful request with no caption — the capture then logs "Captioned N/N
|
|
203317
|
+
// images" followed by "0 images captioned", which is what production shows.
|
|
203318
|
+
thinkingConfig: { thinkingBudget: 0 },
|
|
203239
203319
|
abortSignal: signal,
|
|
203240
203320
|
httpOptions: { timeout: timeoutMs }
|
|
203241
203321
|
}
|
|
@@ -203327,6 +203407,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
|
|
|
203327
203407
|
reportOutcome();
|
|
203328
203408
|
return geminiCaptions;
|
|
203329
203409
|
}
|
|
203410
|
+
const hostConcurrency = sharp3.concurrency();
|
|
203330
203411
|
progress("design", `Rasterizing + captioning ${svgFiles.length} SVGs via vision API...`);
|
|
203331
203412
|
const SVG_BATCH = 20;
|
|
203332
203413
|
const SVG_RENDER_SIZE = 256;
|
|
@@ -203339,10 +203420,11 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
|
|
|
203339
203420
|
}
|
|
203340
203421
|
const timeoutMs = Math.max(1, Math.min(requestTimeoutMs, remainingMs));
|
|
203341
203422
|
const batch = svgFiles.slice(i2, i2 + SVG_BATCH);
|
|
203342
|
-
const
|
|
203343
|
-
|
|
203423
|
+
const rasterized = [];
|
|
203424
|
+
sharp3.concurrency(1);
|
|
203425
|
+
try {
|
|
203426
|
+
for (const { relPath } of batch) {
|
|
203344
203427
|
const filePath = join121(assetsDir, relPath);
|
|
203345
|
-
let pngBase64;
|
|
203346
203428
|
try {
|
|
203347
203429
|
const svgSource = readFileSync84(filePath, "utf-8");
|
|
203348
203430
|
const lightFillHits = (svgSource.match(/fill\s*=\s*["'](#fff(fff)?|white|#[ef][ef][ef]|#[ef]{6})["']/gi) || []).length;
|
|
@@ -203354,11 +203436,18 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
|
|
|
203354
203436
|
fit: "inside",
|
|
203355
203437
|
withoutEnlargement: false
|
|
203356
203438
|
}).flatten({ background: bg }).png().toBuffer();
|
|
203357
|
-
pngBase64
|
|
203439
|
+
rasterized.push({ relPath, pngBase64: pngBuffer.toString("base64") });
|
|
203358
203440
|
} catch {
|
|
203359
203441
|
svgsSkipped++;
|
|
203360
|
-
|
|
203442
|
+
rasterized.push({ relPath, pngBase64: null });
|
|
203361
203443
|
}
|
|
203444
|
+
}
|
|
203445
|
+
} finally {
|
|
203446
|
+
sharp3.concurrency(hostConcurrency);
|
|
203447
|
+
}
|
|
203448
|
+
const results = await Promise.allSettled(
|
|
203449
|
+
rasterized.map(async ({ relPath, pngBase64 }) => {
|
|
203450
|
+
if (pngBase64 === null) return { file: relPath, caption: "" };
|
|
203362
203451
|
const caption = await captionOne({
|
|
203363
203452
|
mimeType: "image/png",
|
|
203364
203453
|
base64: pngBase64,
|
|
@@ -204810,8 +204899,8 @@ ${extracted.bodyHtml}
|
|
|
204810
204899
|
try {
|
|
204811
204900
|
const lines = generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCaptions);
|
|
204812
204901
|
if (lines.length > 0) {
|
|
204813
|
-
const hasVisionKey = !!(!skipVision && (process.env.OPENROUTER_API_KEY || process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY));
|
|
204814
|
-
const header = hasVisionKey ? "# Asset Descriptions\n\nOne line per file. Read this instead of opening every image individually.\n\nTo find a specific brand or icon, **grep this file for the brand name in the description text** (e.g. `grep -i 'autodesk' asset-descriptions.md`). The Gemini Vision captions identify what's actually in each file \u2014 that's the agent's selector.\n\nThe `logo-<hash>.svg` filename prefix is a cheap structural hint (DOM said this SVG was inside a `<header>`, home-link `<a>`, or had an aria-label matching the page brand). It is NOT a content claim \u2014 many `logo-*` files are nav icons or decorative shapes. Trust the captions, not the filename prefix.\n\n" : "# Asset Descriptions\n\n\u26A0\uFE0F
|
|
204902
|
+
const hasVisionKey = !!(!skipVision && (process.env.OPENROUTER_API_KEY || process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || process.env.HYPERFRAMES_VERTEX_PROJECT_ID && process.env.HYPERFRAMES_VERTEX_SERVICE_ACCOUNT));
|
|
204903
|
+
const header = hasVisionKey ? "# Asset Descriptions\n\nOne line per file. Read this instead of opening every image individually.\n\nTo find a specific brand or icon, **grep this file for the brand name in the description text** (e.g. `grep -i 'autodesk' asset-descriptions.md`). The Gemini Vision captions identify what's actually in each file \u2014 that's the agent's selector.\n\nThe `logo-<hash>.svg` filename prefix is a cheap structural hint (DOM said this SVG was inside a `<header>`, home-link `<a>`, or had an aria-label matching the page brand). It is NOT a content claim \u2014 many `logo-*` files are nav icons or decorative shapes. Trust the captions, not the filename prefix.\n\n" : "# Asset Descriptions\n\n\u26A0\uFE0F No vision credentials \u2014 descriptions below are catalog-derived (alt text, headings, section context, filename) instead of Vision-generated. To get richer Vision descriptions on the next capture, set GEMINI_API_KEY (or GOOGLE_API_KEY), or HYPERFRAMES_VERTEX_PROJECT_ID plus HYPERFRAMES_VERTEX_SERVICE_ACCOUNT for Vertex service-account auth, and re-run.\n\nThe `logo-<hash>.svg` filename prefix is a structural hint (DOM said this SVG was inside a `<header>`, home-link `<a>`, or had an aria-label matching the page brand). To pick the actual brand logo without Vision, open the `logo-*` candidates in a previewer or rasterize them with `sharp` before referencing \u2014 composing a fake logo ships off-brand in the final video.\n\n";
|
|
204815
204904
|
writeFileSync56(
|
|
204816
204905
|
join126(outputDir, "extracted", "asset-descriptions.md"),
|
|
204817
204906
|
header + lines.map((l) => "- " + l).join("\n") + "\n",
|
package/dist/fontLocalizeCli.js
CHANGED
|
@@ -72753,6 +72753,47 @@ ${other.raw}`)
|
|
|
72753
72753
|
}
|
|
72754
72754
|
return findings;
|
|
72755
72755
|
},
|
|
72756
|
+
// gsap_timeline_return_used_as_tween — `tl.to()` returns the TIMELINE, not the tween it just
|
|
72757
|
+
// created. `gsap.to()` returns a Tween, so the two read identically and behave nothing alike.
|
|
72758
|
+
// Capturing the timeline's return and later treating it as an individual animation aims a
|
|
72759
|
+
// tween-scoped call at the whole composition: `.kill()` on it interrupts the master timeline
|
|
72760
|
+
// and detaches it from its parent, which stops a parent-driven seek dead while leaving an
|
|
72761
|
+
// explicit `tl.progress()` still working -- so a render of the packaged defaults looks fine
|
|
72762
|
+
// and only live playback breaks. A rebuild that collected these to discard them also leaves
|
|
72763
|
+
// every previous keyframe in place and stacks the new ones on top.
|
|
72764
|
+
({ scripts }) => {
|
|
72765
|
+
const findings = [];
|
|
72766
|
+
for (const script of scripts) {
|
|
72767
|
+
const source = stripJsComments(script.content);
|
|
72768
|
+
const timelineVars = collectTimelineVarNames(source);
|
|
72769
|
+
if (timelineVars.length === 0) continue;
|
|
72770
|
+
const receivers = timelineVars.map(escapeRegExp22).join("|");
|
|
72771
|
+
const pattern = new RegExp(
|
|
72772
|
+
String.raw`(?:\.push\s*\(\s*|(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*)(?:${receivers})\s*\.\s*(to|from|fromTo|set|call|add)\s*\(`,
|
|
72773
|
+
"g"
|
|
72774
|
+
);
|
|
72775
|
+
let match;
|
|
72776
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
72777
|
+
const boundName = match[1];
|
|
72778
|
+
const method = match[2];
|
|
72779
|
+
if (boundName) {
|
|
72780
|
+
const treatedAsTween = new RegExp(
|
|
72781
|
+
String.raw`\b${escapeRegExp22(boundName)}\s*\.\s*(?:kill|revert|invalidate|pause|resume|restart|seek|progress|timeScale)\s*\(`
|
|
72782
|
+
);
|
|
72783
|
+
if (!treatedAsTween.test(source)) continue;
|
|
72784
|
+
}
|
|
72785
|
+
const contextStart = Math.max(0, match.index - 40);
|
|
72786
|
+
findings.push({
|
|
72787
|
+
code: "gsap_timeline_return_used_as_tween",
|
|
72788
|
+
severity: "error",
|
|
72789
|
+
message: `\`${match[0].includes(".push") ? "push" : boundName}\` captures the return of \`.${method}()\` on timeline \`${timelineVars[0]}\`, but a timeline's \`.to()\`/\`.from()\`/\`.set()\` returns THE TIMELINE ITSELF, not the tween it created. Every captured value is the same master timeline, so a tween-scoped call on it \u2014 \`.kill()\` above all \u2014 hits the whole composition: it interrupts the timeline and detaches it from its parent, which freezes a parent-driven seek while an explicit \`tl.progress()\` keeps working. Only \`gsap.to()\` returns a tween.`,
|
|
72790
|
+
fixHint: "To build a group of keyframes you can later discard, put them in a nested timeline: `const nested = gsap.timeline(); nested.to(...); tl.add(nested, 0);` \u2014 then `nested.kill()` replaces exactly those keyframes and cannot reach `tl`. Children keep their absolute times when the nest is added at 0. To hold a single real tween, create it with `gsap.to(...)` and place it with `tl.add(tween, at)`.",
|
|
72791
|
+
snippet: truncateSnippet(source.slice(contextStart, match.index + match[0].length + 60))
|
|
72792
|
+
});
|
|
72793
|
+
}
|
|
72794
|
+
}
|
|
72795
|
+
return findings;
|
|
72796
|
+
},
|
|
72756
72797
|
// gsap_group_selector_keyframes
|
|
72757
72798
|
({ scripts }) => {
|
|
72758
72799
|
const findings = [];
|
|
@@ -97707,8 +97748,8 @@ async function runFontLocalize(io, localize) {
|
|
|
97707
97748
|
}
|
|
97708
97749
|
|
|
97709
97750
|
// src/version.ts
|
|
97710
|
-
var VERSION = true ? "0.8.
|
|
97711
|
-
var PRODUCER_VERSION = true ? "0.8.
|
|
97751
|
+
var VERSION = true ? "0.8.23" : "0.0.0-dev";
|
|
97752
|
+
var PRODUCER_VERSION = true ? "0.8.23" : "0.0.0-dev";
|
|
97712
97753
|
|
|
97713
97754
|
// src/fontLocalizeCli.ts
|
|
97714
97755
|
async function readStdin() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var HyperframesPlayer=(()=>{var ee=Object.defineProperty;var et=Object.getOwnPropertyDescriptor;var tt=Object.getOwnPropertyNames;var it=Object.prototype.hasOwnProperty;var rt=(r,e)=>{for(var t in e)ee(r,t,{get:e[t],enumerable:!0})},nt=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of tt(e))!it.call(r,n)&&n!==t&&ee(r,n,{get:()=>e[n],enumerable:!(i=et(e,n))||i.enumerable});return r};var ot=r=>nt(ee({},"__esModule",{value:!0}),r);var Ht={};rt(Ht,{HyperframesPlayer:()=>K,SPEED_PRESETS:()=>re,formatSpeed:()=>O,formatTime:()=>q});function we(r){return r.hasRuntime||r.runtimeInjected?!1:!!(r.hasNestedCompositions||r.hasTimelines&&r.attempts>=5)}function P(r){return typeof r=="object"&&r!==null}function Ae(r){return P(r)&&typeof r.getDuration=="function"}function Ce(r){return P(r)&&typeof r.duration=="function"&&typeof r.time=="function"&&typeof r.seek=="function"&&typeof r.play=="function"&&typeof r.pause=="function"}var k="https://cdn.jsdelivr.net/npm/@hyperframes/core@0.8.
|
|
1
|
+
"use strict";var HyperframesPlayer=(()=>{var ee=Object.defineProperty;var et=Object.getOwnPropertyDescriptor;var tt=Object.getOwnPropertyNames;var it=Object.prototype.hasOwnProperty;var rt=(r,e)=>{for(var t in e)ee(r,t,{get:e[t],enumerable:!0})},nt=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of tt(e))!it.call(r,n)&&n!==t&&ee(r,n,{get:()=>e[n],enumerable:!(i=et(e,n))||i.enumerable});return r};var ot=r=>nt(ee({},"__esModule",{value:!0}),r);var Ht={};rt(Ht,{HyperframesPlayer:()=>K,SPEED_PRESETS:()=>re,formatSpeed:()=>O,formatTime:()=>q});function we(r){return r.hasRuntime||r.runtimeInjected?!1:!!(r.hasNestedCompositions||r.hasTimelines&&r.attempts>=5)}function P(r){return typeof r=="object"&&r!==null}function Ae(r){return P(r)&&typeof r.getDuration=="function"}function Ce(r){return P(r)&&typeof r.duration=="function"&&typeof r.time=="function"&&typeof r.seek=="function"&&typeof r.play=="function"&&typeof r.pause=="function"}var k="https://cdn.jsdelivr.net/npm/@hyperframes/core@0.8.23/dist/hyperframe.runtime.iife.js";function N(r){if(r===null)return null;let e=Number.parseInt(r,10);return Number.isFinite(e)&&e>0?e:null}function at(r){let e=r?.querySelector("[data-composition-id][data-width][data-height]")??r?.querySelector("[data-width][data-height]");if(!e)return null;let t=N(e.getAttribute("data-width")),i=N(e.getAttribute("data-height"));return t!==null&&i!==null?{width:t,height:i}:null}var W=class{constructor(e,t){this._iframe=e;this._callbacks=t}_iframe;_callbacks;_interval=null;_runtimeInjected=!1;get runtimeInjected(){return this._runtimeInjected}start(){this.stop(),this._runtimeInjected=!1;let e=0;this._interval=setInterval(()=>{e++;try{let t=this._iframe.contentWindow;if(!t)return;let i=!!(t.__hf||t.__player),n=!!(t.__timelines&&Object.keys(t.__timelines).length>0),o=!!this._iframe.contentDocument?.querySelector("[data-composition-src]");if(we({hasRuntime:i,hasTimelines:n,hasNestedCompositions:o,runtimeInjected:this._runtimeInjected,attempts:e})){this._injectRuntime();return}if(this._runtimeInjected&&!i)return;let d=this._resolvePlaybackDurationAdapter(t);if(d&&d.getDuration()>0){this.stop();let s=at(this._iframe.contentDocument);this._callbacks.onReady({duration:d.getDuration(),adapter:d,compositionSize:s});return}}catch{}e>=40&&(this.stop(),this._callbacks.onError("Composition timeline not found after 8s"))},200)}stop(){this._interval!==null&&(clearInterval(this._interval),this._interval=null)}resolveDirectTimelineAdapter(){try{let e=this._iframe.contentWindow;return e?this._resolveDirectTimelineAdapterFromWindow(e):null}catch{return null}}resolveDirectTimelineAdapterFromWindow(e){return this._resolveDirectTimelineAdapterFromWindow(e)}hasRuntimeBridge(e){return Reflect.get(e,"__hf")!==void 0||P(Reflect.get(e,"__player"))}_injectRuntime(){this._runtimeInjected=!0;try{let e=this._iframe.contentDocument;if(!e)return;let t=e.createElement("script");t.src=k,(e.head||e.documentElement).appendChild(t),this._callbacks.onRuntimeInjected?.()}catch{}}_resolveDirectTimelineAdapterFromWindow(e){if(this.hasRuntimeBridge(e))return null;let t=Reflect.get(e,"__timelines");if(!P(t))return null;let i=Object.keys(t);if(i.length===0)return null;let n=this._iframe.contentDocument?.querySelector("[data-composition-id]")?.getAttribute("data-composition-id"),o=n&&n in t?n:i[i.length-1],d=t[o];return Ce(d)?d:null}_resolvePlaybackDurationAdapter(e){let t=Reflect.get(e,"__player");if(Ae(t))return{kind:"runtime",getDuration:()=>t.getDuration()};let i=this._resolveDirectTimelineAdapterFromWindow(e);return i?{kind:"direct-timeline",timeline:i,getDuration:()=>i.duration()}:null}};var Re=`
|
|
2
2
|
:host {
|
|
3
3
|
display: block;
|
|
4
4
|
position: relative;
|
|
@@ -67,7 +67,7 @@ npx hyperframes check --caption-zone "x0=0;y0=.82;x1=1;y1=1;severity=error;seek=
|
|
|
67
67
|
npx hyperframes check --frame-check # media (img/svg/video/canvas) out-of-frame detection
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
`--caption-zone` takes fractional band geometry (`x0/y0/x1/y1` required, 0-1 fractions of the composition's own canvas, portrait included) with optional `severity` and comma-separated `seek` fractions; it flags
|
|
70
|
+
`--caption-zone` takes fractional band geometry (`x0/y0/x1/y1` required, 0-1 fractions of the composition's own canvas, portrait included) with optional `severity` and comma-separated `seek` fractions; it flags a text element's DOM box (`getBoundingClientRect`) that overlaps the band. Waive intentional lower-third copy with `data-layout-allow-caption-zone` on the element or its nearest wrapper (see Escape hatches). `--frame-check` reports media elements breaching the canvas beyond `max(120px, 6% of the min canvas dimension)`.
|
|
71
71
|
|
|
72
72
|
**Fixing contrast errors** — thresholds are 4.5:1 for normal text, 3:1 for large text (24px+, or 19px+ bold). The finding's `suggestedColor` already picks the nearest compliant color in the right direction (brighten on dark backgrounds, darken on light); apply it or adjust within the palette family, then re-run `check`.
|
|
73
73
|
|
package/dist/studio/assets/{hyperframes-player-DmtkkaPN.js → hyperframes-player-oZ6g4tHJ.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var ve=Object.defineProperty;var be=(n,i,e)=>i in n?ve(n,i,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[i]=e;var u=(n,i,e)=>be(n,typeof i!="symbol"?i+"":i,e);import{r as le,i as we,a as Ae}from"./index-
|
|
1
|
+
var ve=Object.defineProperty;var be=(n,i,e)=>i in n?ve(n,i,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[i]=e;var u=(n,i,e)=>be(n,typeof i!="symbol"?i+"":i,e);import{r as le,i as we,a as Ae}from"./index-Tiu74FPg.js";function Ee(n){return n.hasRuntime||n.runtimeInjected?!1:!!(n.hasNestedCompositions||n.hasTimelines&&n.attempts>=5)}function V(n){return typeof n=="object"&&n!==null}function Ce(n){return V(n)&&typeof n.getDuration=="function"}function Te(n){return V(n)&&typeof n.duration=="function"&&typeof n.time=="function"&&typeof n.seek=="function"&&typeof n.play=="function"&&typeof n.pause=="function"}function Se(n){if(!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(n))throw new Error(`Invalid HyperFrames runtime version: ${n}`);return`https://cdn.jsdelivr.net/npm/@hyperframes/core@${n}/dist/hyperframe.runtime.iife.js`}const H=typeof __HYPERFRAMES_RUNTIME_CDN_URL__=="string"?__HYPERFRAMES_RUNTIME_CDN_URL__:Se("0.0.0-dev");function $(n){if(n===null)return null;const i=Number.parseInt(n,10);return Number.isFinite(i)&&i>0?i:null}function Re(n){const i=(n==null?void 0:n.querySelector("[data-composition-id][data-width][data-height]"))??(n==null?void 0:n.querySelector("[data-width][data-height]"));if(!i)return null;const e=$(i.getAttribute("data-width")),t=$(i.getAttribute("data-height"));return e!==null&&t!==null?{width:e,height:t}:null}class xe{constructor(i,e){u(this,"_interval",null);u(this,"_runtimeInjected",!1);this._iframe=i,this._callbacks=e}get runtimeInjected(){return this._runtimeInjected}start(){this.stop(),this._runtimeInjected=!1;let i=0;this._interval=setInterval(()=>{var e;i++;try{const t=this._iframe.contentWindow;if(!t)return;const r=!!(t.__hf||t.__player),s=!!(t.__timelines&&Object.keys(t.__timelines).length>0),o=!!((e=this._iframe.contentDocument)!=null&&e.querySelector("[data-composition-src]"));if(Ee({hasRuntime:r,hasTimelines:s,hasNestedCompositions:o,runtimeInjected:this._runtimeInjected,attempts:i})){this._injectRuntime();return}if(this._runtimeInjected&&!r)return;const d=this._resolvePlaybackDurationAdapter(t);if(d&&d.getDuration()>0){this.stop();const p=Re(this._iframe.contentDocument);this._callbacks.onReady({duration:d.getDuration(),adapter:d,compositionSize:p});return}}catch{}i>=40&&(this.stop(),this._callbacks.onError("Composition timeline not found after 8s"))},200)}stop(){this._interval!==null&&(clearInterval(this._interval),this._interval=null)}resolveDirectTimelineAdapter(){try{const i=this._iframe.contentWindow;return i?this._resolveDirectTimelineAdapterFromWindow(i):null}catch{return null}}resolveDirectTimelineAdapterFromWindow(i){return this._resolveDirectTimelineAdapterFromWindow(i)}hasRuntimeBridge(i){return Reflect.get(i,"__hf")!==void 0||V(Reflect.get(i,"__player"))}_injectRuntime(){var i,e;this._runtimeInjected=!0;try{const t=this._iframe.contentDocument;if(!t)return;const r=t.createElement("script");r.src=H,(t.head||t.documentElement).appendChild(r),(e=(i=this._callbacks).onRuntimeInjected)==null||e.call(i)}catch{}}_resolveDirectTimelineAdapterFromWindow(i){var d,p;if(this.hasRuntimeBridge(i))return null;const e=Reflect.get(i,"__timelines");if(!V(e))return null;const t=Object.keys(e);if(t.length===0)return null;const r=(p=(d=this._iframe.contentDocument)==null?void 0:d.querySelector("[data-composition-id]"))==null?void 0:p.getAttribute("data-composition-id"),s=r&&r in e?r:t[t.length-1],o=e[s];return Te(o)?o:null}_resolvePlaybackDurationAdapter(i){const e=Reflect.get(i,"__player");if(Ce(e))return{kind:"runtime",getDuration:()=>e.getDuration()};const t=this._resolveDirectTimelineAdapterFromWindow(i);return t?{kind:"direct-timeline",timeline:t,getDuration:()=>t.duration()}:null}}const Me=`
|
|
2
2
|
:host {
|
|
3
3
|
display: block;
|
|
4
4
|
position: relative;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as P}from"./index-
|
|
1
|
+
import{g as P}from"./index-Tiu74FPg.js";function j(c,d){for(var s=0;s<d.length;s++){const a=d[s];if(typeof a!="string"&&!Array.isArray(a)){for(const i in a)if(i!=="default"&&!(i in c)){const l=Object.getOwnPropertyDescriptor(a,i);l&&Object.defineProperty(c,i,l.get?l:{enumerable:!0,get:()=>a[i]})}}}return Object.freeze(Object.defineProperty(c,Symbol.toStringTag,{value:"Module"}))}var v={},w;function k(){if(w)return v;w=1,Object.defineProperty(v,"__esModule",{value:!0}),v.default=d;var c=window.OfflineAudioContext||window.webkitOfflineAudioContext;function d(e){var r=a(e);return r.start(0),[i,y,O(e.sampleRate),s].reduce(function(t,o){return o(t)},r.buffer.getChannelData(0))}function s(e){return e.sort(function(r,t){return t.count-r.count}).splice(0,5)[0].tempo}function a(e){var r=e.length,t=e.numberOfChannels,o=e.sampleRate,n=new c(t,r,o),u=n.createBufferSource();u.buffer=e;var f=n.createBiquadFilter();return f.type="lowpass",u.connect(f),f.connect(n.destination),u}function i(e){for(var r=[],t=.9,o=.3,n=15;r.length<n&&t>=o;)r=l(e,t),t-=.05;if(r.length<n)throw new Error("Could not find enough samples for a reliable detection.");return r}function l(e,r){for(var t=[],o=0,n=e.length;o<n;o+=1)e[o]>r&&(t.push(o),o+=1e4);return t}function y(e){var r=[];return e.forEach(function(t,o){for(var n=function(x){var g=e[o+x]-t,_=r.some(function(h){if(h.interval===g)return h.count+=1});_||r.push({interval:g,count:1})},u=0;u<10;u+=1)n(u)}),r}function O(e){return function(r){var t=[];return r.forEach(function(o){if(o.interval!==0){for(var n=60/(o.interval/e);n<90;)n*=2;for(;n>180;)n/=2;n=Math.round(n);var u=t.some(function(f){if(f.tempo===n)return f.count+=o.count});u||t.push({tempo:n,count:o.count})}}),t}}return v}var p,b;function q(){return b||(b=1,p=k().default),p}var m=q();const A=P(m),D=j({__proto__:null,default:A},[m]);export{D as i};
|