hyperframes 0.4.39 → 0.4.40
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 +58 -9
- package/dist/skills/gsap/SKILL.md +30 -1
- package/dist/templates/_shared/CLAUDE.md +5 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -54,7 +54,7 @@ var VERSION;
|
|
|
54
54
|
var init_version = __esm({
|
|
55
55
|
"src/version.ts"() {
|
|
56
56
|
"use strict";
|
|
57
|
-
VERSION = true ? "0.4.
|
|
57
|
+
VERSION = true ? "0.4.40" : "0.0.0-dev";
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
60
|
|
|
@@ -26182,6 +26182,27 @@ async function pollPageExpression(page, expression, timeoutMs, intervalMs = 100)
|
|
|
26182
26182
|
}
|
|
26183
26183
|
return Boolean(await page.evaluate(expression));
|
|
26184
26184
|
}
|
|
26185
|
+
async function applyVideoMetadataHints(page, hints) {
|
|
26186
|
+
if (!hints || hints.length === 0) return;
|
|
26187
|
+
await page.evaluate(
|
|
26188
|
+
(metadataHints) => {
|
|
26189
|
+
for (const hint of metadataHints) {
|
|
26190
|
+
if (!hint.id || !Number.isFinite(hint.width) || !Number.isFinite(hint.height) || hint.width <= 0 || hint.height <= 0) {
|
|
26191
|
+
continue;
|
|
26192
|
+
}
|
|
26193
|
+
const video = document.getElementById(hint.id);
|
|
26194
|
+
if (!video) continue;
|
|
26195
|
+
if (!video.hasAttribute("width")) video.setAttribute("width", String(hint.width));
|
|
26196
|
+
if (!video.hasAttribute("height")) video.setAttribute("height", String(hint.height));
|
|
26197
|
+
const computed = window.getComputedStyle(video);
|
|
26198
|
+
if (!video.style.aspectRatio && (!computed.aspectRatio || computed.aspectRatio === "auto")) {
|
|
26199
|
+
video.style.aspectRatio = `${hint.width} / ${hint.height}`;
|
|
26200
|
+
}
|
|
26201
|
+
}
|
|
26202
|
+
},
|
|
26203
|
+
[...hints]
|
|
26204
|
+
);
|
|
26205
|
+
}
|
|
26185
26206
|
async function initializeSession(session) {
|
|
26186
26207
|
const { page, serverUrl } = session;
|
|
26187
26208
|
page.on("console", (msg) => {
|
|
@@ -26225,6 +26246,7 @@ async function initializeSession(session) {
|
|
|
26225
26246
|
`[FrameCapture] window.__hf not ready after ${pageReadyTimeout2}ms. Page must expose window.__hf = { duration, seek }.`
|
|
26226
26247
|
);
|
|
26227
26248
|
}
|
|
26249
|
+
await applyVideoMetadataHints(page, session.options.videoMetadataHints);
|
|
26228
26250
|
const skipIdsLiteral = JSON.stringify(session.options.skipReadinessVideoIds ?? []);
|
|
26229
26251
|
const videosReady = await pollPageExpression(
|
|
26230
26252
|
page,
|
|
@@ -26291,6 +26313,7 @@ async function initializeSession(session) {
|
|
|
26291
26313
|
`[FrameCapture] window.__hf not ready after ${pageReadyTimeout}ms. Page must expose window.__hf = { duration, seek }.`
|
|
26292
26314
|
);
|
|
26293
26315
|
}
|
|
26316
|
+
await applyVideoMetadataHints(page, session.options.videoMetadataHints);
|
|
26294
26317
|
const beginframeSkipIdsLiteral = JSON.stringify(session.options.skipReadinessVideoIds ?? []);
|
|
26295
26318
|
const videoDeadline = Date.now() + (session.config?.playerReadyTimeout ?? DEFAULT_CONFIG2.playerReadyTimeout);
|
|
26296
26319
|
while (Date.now() < videoDeadline) {
|
|
@@ -34108,6 +34131,24 @@ function applyRenderModeHints(cfg, compiled, log2 = defaultLogger) {
|
|
|
34108
34131
|
reasons: compiled.renderModeHints.reasons.map((reason) => reason.message)
|
|
34109
34132
|
});
|
|
34110
34133
|
}
|
|
34134
|
+
function collectVideoReadinessSkipIds(nativeHdrVideoIds, extractedVideos) {
|
|
34135
|
+
return Array.from(
|
|
34136
|
+
/* @__PURE__ */ new Set([
|
|
34137
|
+
...nativeHdrVideoIds,
|
|
34138
|
+
...extractedVideos.filter((video) => hasUsableVideoDimensions(video.metadata)).map((video) => video.videoId)
|
|
34139
|
+
])
|
|
34140
|
+
).sort();
|
|
34141
|
+
}
|
|
34142
|
+
function hasUsableVideoDimensions(metadata) {
|
|
34143
|
+
return Number.isFinite(metadata.width) && Number.isFinite(metadata.height) && metadata.width > 0 && metadata.height > 0;
|
|
34144
|
+
}
|
|
34145
|
+
function collectVideoMetadataHints(extractedVideos) {
|
|
34146
|
+
return extractedVideos.filter((video) => hasUsableVideoDimensions(video.metadata)).map((video) => ({
|
|
34147
|
+
id: video.videoId,
|
|
34148
|
+
width: video.metadata.width,
|
|
34149
|
+
height: video.metadata.height
|
|
34150
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
34151
|
+
}
|
|
34111
34152
|
function resolveRenderWorkerCount(totalFrames, requestedWorkers, cfg, compiled, composition, log2 = defaultLogger, measuredCaptureCost) {
|
|
34112
34153
|
const captureCost = combineCaptureCostEstimates(
|
|
34113
34154
|
estimateCaptureCostMultiplier(compiled, composition),
|
|
@@ -35119,6 +35160,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35119
35160
|
let frameLookup = null;
|
|
35120
35161
|
const compiledDir = join35(workDir, "compiled");
|
|
35121
35162
|
let extractionResult = null;
|
|
35163
|
+
let videoReadinessSkipIds = [];
|
|
35164
|
+
let videoMetadataHints = [];
|
|
35122
35165
|
const nativeHdrVideoIds = /* @__PURE__ */ new Set();
|
|
35123
35166
|
const videoTransfers = /* @__PURE__ */ new Map();
|
|
35124
35167
|
if (job.config.hdrMode !== "force-sdr" && composition.videos.length > 0) {
|
|
@@ -35175,6 +35218,11 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35175
35218
|
if (extractionResult.extracted.length > 0) {
|
|
35176
35219
|
frameLookup = createFrameLookupTable(composition.videos, extractionResult.extracted);
|
|
35177
35220
|
}
|
|
35221
|
+
videoReadinessSkipIds = collectVideoReadinessSkipIds(
|
|
35222
|
+
nativeHdrVideoIds,
|
|
35223
|
+
extractionResult.extracted
|
|
35224
|
+
);
|
|
35225
|
+
videoMetadataHints = collectVideoMetadataHints(extractionResult.extracted);
|
|
35178
35226
|
perfStages.videoExtractMs = Date.now() - stage2Start;
|
|
35179
35227
|
const existingAudioSrcs = new Set(composition.audios.map((a) => a.src));
|
|
35180
35228
|
for (const ext of extractionResult.extracted) {
|
|
@@ -35288,9 +35336,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35288
35336
|
format: needsAlpha ? "png" : "jpeg",
|
|
35289
35337
|
quality: needsAlpha ? void 0 : job.config.quality === "draft" ? 80 : 95
|
|
35290
35338
|
};
|
|
35291
|
-
const
|
|
35339
|
+
const buildCaptureOptions = () => ({
|
|
35292
35340
|
...captureOptions,
|
|
35293
|
-
|
|
35341
|
+
videoMetadataHints,
|
|
35342
|
+
skipReadinessVideoIds: videoReadinessSkipIds
|
|
35294
35343
|
});
|
|
35295
35344
|
let captureCalibration;
|
|
35296
35345
|
let switchedToScreenshotAfterCalibration = false;
|
|
@@ -35303,7 +35352,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35303
35352
|
calibrationSession = await createCaptureSession(
|
|
35304
35353
|
fileServer.url,
|
|
35305
35354
|
calibrationDir,
|
|
35306
|
-
|
|
35355
|
+
buildCaptureOptions(),
|
|
35307
35356
|
videoInjector,
|
|
35308
35357
|
calibrationCfg
|
|
35309
35358
|
);
|
|
@@ -35427,7 +35476,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35427
35476
|
const domSession = await createCaptureSession(
|
|
35428
35477
|
fileServer.url,
|
|
35429
35478
|
framesDir,
|
|
35430
|
-
|
|
35479
|
+
buildCaptureOptions(),
|
|
35431
35480
|
createVideoFrameInjector(frameLookup),
|
|
35432
35481
|
cfg
|
|
35433
35482
|
);
|
|
@@ -35960,7 +36009,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35960
36009
|
fileServer.url,
|
|
35961
36010
|
workDir,
|
|
35962
36011
|
tasks,
|
|
35963
|
-
|
|
36012
|
+
buildCaptureOptions(),
|
|
35964
36013
|
() => createVideoFrameInjector(frameLookup),
|
|
35965
36014
|
abortSignal,
|
|
35966
36015
|
(progress) => {
|
|
@@ -35990,7 +36039,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35990
36039
|
const session = probeSession ?? await createCaptureSession(
|
|
35991
36040
|
fileServer.url,
|
|
35992
36041
|
framesDir,
|
|
35993
|
-
|
|
36042
|
+
buildCaptureOptions(),
|
|
35994
36043
|
videoInjector,
|
|
35995
36044
|
cfg
|
|
35996
36045
|
);
|
|
@@ -36045,7 +36094,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
36045
36094
|
initialWorkerCount: workerCount,
|
|
36046
36095
|
allowRetry: job.config.workers === void 0,
|
|
36047
36096
|
frameExt: needsAlpha ? "png" : "jpg",
|
|
36048
|
-
captureOptions:
|
|
36097
|
+
captureOptions: buildCaptureOptions(),
|
|
36049
36098
|
createBeforeCaptureHook: () => createVideoFrameInjector(frameLookup),
|
|
36050
36099
|
abortSignal,
|
|
36051
36100
|
onProgress: (progress) => {
|
|
@@ -36080,7 +36129,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
36080
36129
|
const session = probeSession ?? await createCaptureSession(
|
|
36081
36130
|
fileServer.url,
|
|
36082
36131
|
framesDir,
|
|
36083
|
-
|
|
36132
|
+
buildCaptureOptions(),
|
|
36084
36133
|
videoInjector,
|
|
36085
36134
|
cfg
|
|
36086
36135
|
);
|
|
@@ -5,6 +5,28 @@ description: GSAP animation reference for HyperFrames. Covers gsap.to(), from(),
|
|
|
5
5
|
|
|
6
6
|
# GSAP
|
|
7
7
|
|
|
8
|
+
## HyperFrames Contract
|
|
9
|
+
|
|
10
|
+
HyperFrames controls GSAP through its `gsap` runtime adapter. Create a paused timeline synchronously, register it on `window.__timelines` with the exact `data-composition-id`, and let HyperFrames seek it.
|
|
11
|
+
|
|
12
|
+
```html
|
|
13
|
+
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
|
14
|
+
<script>
|
|
15
|
+
window.__timelines = window.__timelines || {};
|
|
16
|
+
const tl = gsap.timeline({ paused: true });
|
|
17
|
+
|
|
18
|
+
tl.from(".title", { y: 48, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
|
|
19
|
+
tl.to(".accent", { scaleX: 1, duration: 0.5, ease: "power2.out" }, 0.25);
|
|
20
|
+
|
|
21
|
+
window.__timelines["main"] = tl; // key must equal data-composition-id on the composition root
|
|
22
|
+
</script>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- The registry key must match the composition root's `data-composition-id`.
|
|
26
|
+
- Do not call `tl.play()` for render-critical motion.
|
|
27
|
+
- Do not build timelines inside async code, timers, or event handlers.
|
|
28
|
+
- Keep loops finite. HyperFrames renders finite video durations.
|
|
29
|
+
|
|
8
30
|
## Core Tween Methods
|
|
9
31
|
|
|
10
32
|
- **gsap.to(targets, vars)** — animate from current state to `vars`. Most common.
|
|
@@ -21,7 +43,7 @@ Always use **camelCase** property names (e.g. `backgroundColor`, `rotationX`).
|
|
|
21
43
|
- **ease** — `"power1.out"` (default), `"power3.inOut"`, `"back.out(1.7)"`, `"elastic.out(1, 0.3)"`, `"none"`.
|
|
22
44
|
- **stagger** — number `0.1` or object: `{ amount: 0.3, from: "center" }`, `{ each: 0.1, from: "random" }`.
|
|
23
45
|
- **overwrite** — `false` (default), `true`, or `"auto"`.
|
|
24
|
-
- **repeat** — number
|
|
46
|
+
- **repeat** — finite number; never `-1` in HyperFrames. Compute repeats from the visible duration. **yoyo** — alternates direction with repeat.
|
|
25
47
|
- **onComplete**, **onStart**, **onUpdate** — callbacks.
|
|
26
48
|
- **immediateRender** — default `true` for from()/fromTo(). Set `false` on later tweens targeting the same property+element to avoid overwrite.
|
|
27
49
|
|
|
@@ -209,3 +231,10 @@ Pause or kill off-screen animations.
|
|
|
209
231
|
- Chain animations with delay when a timeline can sequence them.
|
|
210
232
|
- Create tweens before the DOM exists.
|
|
211
233
|
- Skip cleanup — always kill tweens when no longer needed.
|
|
234
|
+
- Use infinite repeat values in HyperFrames compositions. Use finite repeat counts computed from the visible duration.
|
|
235
|
+
|
|
236
|
+
## Credits And References
|
|
237
|
+
|
|
238
|
+
- HyperFrames adapter source: `packages/core/src/runtime/adapters/gsap.ts`.
|
|
239
|
+
- GSAP documentation: https://gsap.com/docs/v3/
|
|
240
|
+
- GSAP timeline pause and seek behavior: https://gsap.com/docs/v3/GSAP/Timeline/pause%28%29/
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
| **hyperframes-registry** | `/hyperframes-registry` | Installing blocks and components via `hyperframes add` |
|
|
12
12
|
| **website-to-hyperframes** | `/website-to-hyperframes` | Capturing a URL and turning it into a video — full website-to-video pipeline |
|
|
13
13
|
| **gsap** | `/gsap` | GSAP animations for HyperFrames — tweens, timelines, easing, performance |
|
|
14
|
+
| **animejs** | `/animejs` | Anime.js animations registered on `window.__hfAnime` |
|
|
15
|
+
| **css-animations** | `/css-animations` | CSS keyframes that HyperFrames can pause and seek |
|
|
16
|
+
| **lottie** | `/lottie` | `lottie-web` and dotLottie players registered on `window.__hfLottie` |
|
|
17
|
+
| **three** | `/three` | Three.js scenes rendered from HyperFrames `hf-seek` events |
|
|
18
|
+
| **waapi** | `/waapi` | Web Animations API motion driven through `document.getAnimations()` |
|
|
14
19
|
|
|
15
20
|
> **Skills not available?** Ask the user to run `npx hyperframes skills` and restart their
|
|
16
21
|
> agent session, or install manually: `npx skills add heygen-com/hyperframes`.
|