hyperframes 0.8.150 → 0.8.152
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/{add-3ZIFEN2U.js → add-SA33REHW.js} +14 -14
- package/dist/{animatedGifPrep-77LPFLKJ.js → animatedGifPrep-3YXJQZ7L.js} +9 -9
- package/dist/api.js +19 -19
- package/dist/{asset-EYSZEHM6.js → asset-PUVPTWPD.js} +2 -2
- package/dist/{assetCataloger-KX3HD7ZI.js → assetCataloger-VWE2PLBX.js} +4 -4
- package/dist/{auth-L6IWNRXY.js → auth-PS3M6AI7.js} +1 -1
- package/dist/{autoUpdate-2O3HZB65.js → autoUpdate-CMO4SHWU.js} +2 -2
- package/dist/{backgroundChecks-BH2LMJYE.js → backgroundChecks-EDZ2A55J.js} +3 -3
- package/dist/backgroundChecksWorker.js +3 -3
- package/dist/{batchRender-ZBKAYLWU.js → batchRender-7PLJISCN.js} +5 -5
- package/dist/{beats-IVLF2566.js → beats-2MDSIOE7.js} +15 -15
- package/dist/{benchmark-SYZFW2G7.js → benchmark-KBBXAPI4.js} +10 -10
- package/dist/{browser-OSW3L25S.js → browser-OMWKZRSW.js} +5 -5
- package/dist/{bundleWithLocalizedFonts-I4CWOXLK.js → bundleWithLocalizedFonts-76DMCRIW.js} +2 -2
- package/dist/{capture-AZOQ57TM.js → capture-LRUUXH5Q.js} +2 -2
- package/dist/{capture-V5ICGSVJ.js → capture-YGDC7GN3.js} +13 -13
- package/dist/{catalog-VBJOA2Y5.js → catalog-SMEBKEVO.js} +14 -14
- package/dist/{catch-up-TKSEDNJK.js → catch-up-OMILX3WE.js} +4 -4
- package/dist/{check-3HFISKDB.js → check-NUZ62LIW.js} +288 -64
- package/dist/{checkBrowser-MXBDNZJB.js → checkBrowser-MSTVEL4V.js} +181 -38
- package/dist/{chunk-73RBX2E7.js → chunk-3DZBQ7MH.js} +3 -3
- package/dist/{chunk-6QB7F2II.js → chunk-3E4OCOC5.js} +1 -1
- package/dist/{chunk-OQ7XMM3S.js → chunk-3HPJM5IQ.js} +1 -1
- package/dist/{chunk-UJB7356Y.js → chunk-3LO7BBJX.js} +3 -3
- package/dist/{chunk-APDLWWFG.js → chunk-3VGU2SH7.js} +1 -1
- package/dist/{chunk-DUUFDLC4.js → chunk-4MLYMDQ4.js} +1 -1
- package/dist/{chunk-AXPNVC3N.js → chunk-4UMKAUZI.js} +1 -1
- package/dist/{chunk-XPQSL5VS.js → chunk-54DMWFQZ.js} +8 -1
- package/dist/chunk-57GN6KWT.js +179 -0
- package/dist/{chunk-374QQGBQ.js → chunk-5CS4T6C6.js} +63 -12
- package/dist/{chunk-PCWOSS7G.js → chunk-5ERVRJMV.js} +3 -3
- package/dist/{chunk-TZPZE5PS.js → chunk-5VMSUW4Z.js} +6 -3
- package/dist/{chunk-M6UDJ2E7.js → chunk-6Z4YJ5Q3.js} +3 -3
- package/dist/{chunk-FJWEYVEM.js → chunk-7FYFEXD2.js} +658 -198
- package/dist/{chunk-UQYQ7TBA.js → chunk-7NPSXBIN.js} +2 -2
- package/dist/chunk-7TASSBN2.js +215 -0
- package/dist/{chunk-F2RLIE7P.js → chunk-ANS56TPS.js} +11 -11
- package/dist/{chunk-DOVJRUFM.js → chunk-BQK3J7XO.js} +1 -1
- package/dist/{chunk-FPAT5HTI.js → chunk-BYJYQWEX.js} +10 -10
- package/dist/{chunk-XXPYZBZ3.js → chunk-C6TPGUWD.js} +2 -2
- package/dist/{chunk-XQMEGSHG.js → chunk-D6RJXQLD.js} +1 -1
- package/dist/{chunk-RW7NLGPD.js → chunk-DFXK7KUO.js} +25 -17
- package/dist/{chunk-6SFPQ2RZ.js → chunk-E6EYZ33P.js} +2 -2
- package/dist/{chunk-AKYQGZLU.js → chunk-EVTHG34H.js} +2 -2
- package/dist/{chunk-5NAYNDBT.js → chunk-EXH6L2XZ.js} +6 -2
- package/dist/{chunk-AIJS74LG.js → chunk-FFDC5OWV.js} +8 -2
- package/dist/{chunk-4WFNTWKZ.js → chunk-FNN5QINS.js} +2 -2
- package/dist/{chunk-DMKI64EZ.js → chunk-FSZAFCU7.js} +1 -1
- package/dist/{chunk-S5F26DUL.js → chunk-GQETH4PE.js} +3 -3
- package/dist/{chunk-3UAIVF4L.js → chunk-H2SGM2V2.js} +1 -1
- package/dist/{chunk-O4DC5CHF.js → chunk-H7FXBK3Q.js} +1 -1
- package/dist/{chunk-UVVI2NJQ.js → chunk-HBCRRCTX.js} +109 -31
- package/dist/{chunk-NFQY7EIC.js → chunk-IBYC3VUA.js} +1 -1
- package/dist/{chunk-2KAL22B5.js → chunk-IEDT4EXE.js} +1 -1
- package/dist/{chunk-I6DATIHC.js → chunk-IZIRIDJH.js} +2 -2
- package/dist/{chunk-Z6WZDGCS.js → chunk-IZKXUYZE.js} +2 -2
- package/dist/chunk-KCFF4ENE.js +24 -0
- package/dist/{chunk-6KWA3XPS.js → chunk-KZ3L3W4Q.js} +1 -1
- package/dist/{chunk-7IEGPJ4P.js → chunk-LBT4AMSF.js} +1 -1
- package/dist/{chunk-7JTFPUMA.js → chunk-LECTCGGS.js} +1 -1
- package/dist/{chunk-7E4VHPKJ.js → chunk-LVPSWUS6.js} +5 -5
- package/dist/{chunk-6NPFJ255.js → chunk-MNHPG2UO.js} +1 -1
- package/dist/{chunk-FN6KAS7A.js → chunk-NHAG2KCE.js} +7 -7
- package/dist/{chunk-423DJVX2.js → chunk-PKO2EWO7.js} +1 -1
- package/dist/{chunk-ZNHAJCEA.js → chunk-PRXAOZWZ.js} +28 -13
- package/dist/{chunk-VQ7YIURZ.js → chunk-PTXZDSW5.js} +5 -5
- package/dist/{chunk-XANZ4R4P.js → chunk-QECEOV6W.js} +3 -3
- package/dist/{chunk-BLRJKBKP.js → chunk-QESSGUKX.js} +1 -1
- package/dist/{chunk-WLIUULZQ.js → chunk-RN5I2DP5.js} +29 -15
- package/dist/chunk-S3RCK56N.js +3795 -0
- package/dist/{chunk-UAIUVPZE.js → chunk-SWCSL6WS.js} +6 -6
- package/dist/{chunk-2PSPARWP.js → chunk-TYXH3EKP.js} +4 -0
- package/dist/{chunk-FMNVTKX2.js → chunk-U3BCDVZO.js} +1 -1
- package/dist/{chunk-LW5VFBSY.js → chunk-VS732BUG.js} +1 -1
- package/dist/{chunk-LFNQDTSH.js → chunk-VYKPBRCB.js} +63 -12
- package/dist/{chunk-M5B42RL5.js → chunk-WUUOFMHU.js} +3 -3
- package/dist/{chunk-A6ZO4BX7.js → chunk-XEFFJRYX.js} +2 -2
- package/dist/{chunk-EL5QVJEG.js → chunk-XINGD6MS.js} +4 -4
- package/dist/chunk-XSEGMQYA.js +30 -0
- package/dist/{chunk-CZQLCBWY.js → chunk-YG2Y55KF.js} +1 -1
- package/dist/{chunk-B3XLIBFL.js → chunk-YIJMVFEJ.js} +1 -1
- package/dist/{chunk-JDB65PPT.js → chunk-YOEGUBBY.js} +13 -12
- package/dist/{chunk-AFRXL75S.js → chunk-YYEYOFHW.js} +1 -1
- package/dist/{chunk-R5A7454P.js → chunk-ZTM3RMAD.js} +2 -2
- package/dist/{clean-7HU7S7DT.js → clean-F75G45BI.js} +56 -35
- package/dist/cli.js +53 -53
- package/dist/{cloud-HAXHBO25.js → cloud-KVJAOUWH.js} +4 -4
- package/dist/{cloudrun-A3PIJ6DX.js → cloudrun-Q7Q7O4GY.js} +6 -6
- package/dist/{compare-6IPSQMSM.js → compare-DGUJ4QWU.js} +30 -30
- package/dist/{compiler-UQP2VXN6.js → compiler-NCN6PTVH.js} +6 -6
- package/dist/{component-FF3AU24M.js → component-PSYGT3JV.js} +3 -3
- package/dist/{compositions-JSH4MZXB.js → compositions-J3GAETIC.js} +13 -13
- package/dist/{delete-G763SW64.js → delete-MR7LRGRP.js} +2 -2
- package/dist/{deterministicFonts-C5JQLCTS.js → deterministicFonts-EOMDR6ZF.js} +3 -3
- package/dist/{dist-HUMFCJ6T.js → dist-2YYJYYPY.js} +3 -3
- package/dist/{dist-Z7Q3JS7K.js → dist-3MHXG6EJ.js} +4 -4
- package/dist/{doctor-WZB6WMBY.js → doctor-JOUGR5UK.js} +15 -15
- package/dist/{events-T4YFQC5G.js → events-63BKDWVO.js} +3 -3
- package/dist/{events-MUWJJCC7.js → events-FZFBJCIH.js} +2 -2
- package/dist/{feedback-AUTHQNN2.js → feedback-QLKWUDXR.js} +8 -8
- package/dist/{ffmpeg-TZB5WAYE.js → ffmpeg-MJFMBBSF.js} +2 -2
- package/dist/{figma-NBG6WBI7.js → figma-YJ7HGVQC.js} +3 -3
- package/dist/fontLocalizeCli.js +12 -12
- package/dist/{get-OXBJLKLV.js → get-54MUUXMR.js} +2 -2
- package/dist/{gpuPolicy-HBCCEQUS.js → gpuPolicy-5OVNR75D.js} +9 -9
- package/dist/{grade-compare-2LX4FDH7.js → grade-compare-7IDUF673.js} +32 -32
- package/dist/{gsapParserAcorn-VXZ3ZIF2.js → gsapParserAcorn-7NCK2LVT.js} +2 -2
- package/dist/{help-LJI46EDO.js → help-GQFYO5LU.js} +1 -1
- package/dist/{history-MFKAQEHU.js → history-UI3O7CSO.js} +77 -205
- package/dist/hyperframe-runtime.js +54 -54
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +54 -54
- package/dist/hyperframes-player.global.js +3 -3
- package/dist/{info-D6Y5O2QE.js → info-VQV3APEX.js} +9 -9
- package/dist/{init-47NZPEBI.js → init-2UBFV5D7.js} +31 -31
- package/dist/{inspect-U5UXJK5D.js → inspect-36ACJ3CO.js} +31 -31
- package/dist/{installer-AW7VFVTQ.js → installer-GDUZDJG4.js} +7 -7
- package/dist/{keyframes-5G334NWB.js → keyframes-GPBU34BG.js} +227 -82
- package/dist/{lambda-GASGXN3A.js → lambda-CBJVLTHY.js} +7 -7
- package/dist/{layout-OXAQFLJS.js → layout-2IHFV6EI.js} +31 -31
- package/dist/{lint-F36QFSNF.js → lint-IR6IYCEO.js} +9 -9
- package/dist/{lintProject-SSEXWCH6.js → lintProject-XQWXJYSC.js} +3 -3
- package/dist/{list-TR6QCI53.js → list-UAGKWARH.js} +2 -2
- package/dist/{login-6LA2RWTC.js → login-2GYCNCZF.js} +4 -4
- package/dist/{manager-ES2UFT4X.js → manager-X44GKUEL.js} +3 -3
- package/dist/{manager-GWU5J6RJ.js → manager-ZLJD3EAY.js} +2 -2
- package/dist/{media-treatment-BOHYDWVY.js → media-treatment-Z553F7XI.js} +14 -14
- package/dist/{models-6GW5Q3IW.js → models-6AZTNNSO.js} +15 -15
- package/dist/{motionShot-O7AOMPUN.js → motionShot-ARRL7WXT.js} +29 -16
- package/dist/{normalize-audio-UO5B4O76.js → normalize-audio-CME4NUB6.js} +6 -6
- package/dist/{open-JV2EHVKM.js → open-HU2VXUFD.js} +4 -4
- package/dist/{parakeetRunner-23DZUF6G.js → parakeetRunner-X5MKFMCB.js} +16 -16
- package/dist/{pipeline-KTICSIK7.js → pipeline-MNFTEBJU.js} +11 -11
- package/dist/{play-CMUYPXBC.js → play-2BBJDDAZ.js} +24 -24
- package/dist/{preflight-JOD4OXGC.js → preflight-JYOX64YP.js} +4 -4
- package/dist/{present-ZDT5FM2H.js → present-OE2WL2NY.js} +20 -20
- package/dist/{preview-ASHLGKDD.js → preview-RYSCCAWJ.js} +21 -21
- package/dist/{producer-FFH2KUAZ.js → producer-SQWNRO66.js} +1 -1
- package/dist/{projectConfig-FHIAOPKW.js → projectConfig-B55Z7YKQ.js} +9 -9
- package/dist/{publication-WO5ZXURT.js → publication-MDZCOBJP.js} +4 -4
- package/dist/{publish-QWO2W7FB.js → publish-AILV36BO.js} +12 -12
- package/dist/{remove-background-BO5MQR25.js → remove-background-6F72LKHG.js} +12 -12
- package/dist/{render-XTJKGT3G.js → render-2MZKU3L5.js} +10 -10
- package/dist/{render-SDHFXL3Y.js → render-5EREH6YD.js} +95 -37
- package/dist/{render-HS3YOLSD.js → render-6GH5FSXU.js} +5 -5
- package/dist/{render-batch-J64AJHQY.js → render-batch-UMBUQWWS.js} +5 -5
- package/dist/renderSetupWorker.js +6 -6
- package/dist/{resolver-IHNWMDJA.js → resolver-KO6WWO5P.js} +6 -6
- package/dist/{sherpa-FXBBYMDR.js → sherpa-DADGYWNR.js} +15 -15
- package/dist/skills/hyperframes/references/frame-worker-core.md +11 -9
- package/dist/skills/hyperframes/references/subagent-dispatch.md +1 -1
- package/dist/skills/hyperframes-cli/SKILL.md +3 -0
- package/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +5 -1
- package/dist/skills/media-use/audio/scripts/lib/tts.cleanup.test.mjs +175 -0
- package/dist/skills/media-use/audio/scripts/lib/tts.mjs +24 -19
- package/dist/skills/media-use/references/grading.md +1 -2
- package/dist/skills/media-use/references/meta.md +17 -17
- package/dist/skills/media-use/references/operations.md +6 -6
- package/dist/skills/media-use/references/setup-providers.md +3 -4
- package/dist/skills/media-use/scripts/lib/cutlist.mjs +9 -2
- package/dist/skills/media-use/scripts/lib/cutlist.test.mjs +12 -0
- package/dist/skills/media-use/scripts/lib/telemetry.mjs +4 -1
- package/dist/skills/media-use/scripts/lib/telemetry.test.mjs +20 -0
- package/dist/skills/media-use/scripts/transcript-cut.mjs +23 -4
- package/dist/skills/media-use/scripts/transcript-cut.test.mjs +224 -0
- package/dist/{skills-ALLSN7TB.js → skills-QLKSNU4Y.js} +5 -5
- package/dist/{skillsUpdateCheck-EIT5NWM6.js → skillsUpdateCheck-Z2QQGF2W.js} +3 -3
- package/dist/{snapshot-Y3I76OIZ.js → snapshot-D5BBFXOS.js} +342 -154
- package/dist/{src-7V6LBC56.js → src-AVQBAECC.js} +10 -8
- package/dist/{src-S5IZVJUX.js → src-V7263E47.js} +11 -11
- package/dist/{staticProjectServer-QLWWGHZE.js → staticProjectServer-HNWSVEWN.js} +20 -20
- package/dist/studio/assets/{hyperframes-player-kup62bDR.js → hyperframes-player-0BY7-PK7.js} +1 -1
- package/dist/studio/assets/{index-B8BBYY8L.js → index-COrWdzlj.js} +1 -1
- package/dist/studio/assets/{index-CS_m0TkX.js → index-p-VXwuJ2.js} +132 -132
- package/dist/studio/assets/{index-DQ5jGodF.js → index-rmD5k_ES.js} +1 -1
- package/dist/studio/index.html +1 -1
- package/dist/{studio-api-UBFLZ3DA.js → studio-api-UXKTDWLT.js} +30 -16
- package/dist/{studioServer-REOVCIFP.js → studioServer-JOVR24O3.js} +51 -51
- package/dist/{synthesize-22B7L5GX.js → synthesize-MBDVUSH3.js} +2 -1
- package/dist/{telemetry-C3GDIXHO.js → telemetry-UW7XAM5W.js} +3 -3
- package/dist/{timeline-H42EGLMT.js → timeline-JSGTZ3AN.js} +73 -20
- package/dist/{tokens-2K7ISTKV.js → tokens-ADDBGTQ7.js} +2 -2
- package/dist/{transcribe-NUPASAUP.js → transcribe-FEHOK626.js} +14 -14
- package/dist/{transcribe-DVM7UFZZ.js → transcribe-P6MJGSZJ.js} +20 -20
- package/dist/{tts-QSAQZVEZ.js → tts-POI553RG.js} +1 -1
- package/dist/{updateCheck-3RWFSEZD.js → updateCheck-IBWMLXQ4.js} +2 -2
- package/dist/{upgrade-YKKL36N7.js → upgrade-NHZ7AYPO.js} +2 -2
- package/dist/{urlDownloader-6JNJYLPN.js → urlDownloader-ULDRBWS5.js} +8 -8
- package/dist/{validate-Z7KQT7GO.js → validate-NVWNXNBV.js} +25 -25
- package/dist/{video-EXL2JDSL.js → video-74DRD2DN.js} +9 -9
- package/package.json +1 -1
- package/dist/chunk-CEND6BLF.js +0 -3795
- package/dist/chunk-WBLXWOYK.js +0 -15
|
@@ -7,11 +7,20 @@ var __dirname = __hf_dirname(__filename);
|
|
|
7
7
|
import {
|
|
8
8
|
parseAngle
|
|
9
9
|
} from "./chunk-KZI44OPA.js";
|
|
10
|
+
import {
|
|
11
|
+
pngDimensions,
|
|
12
|
+
reportArtifacts,
|
|
13
|
+
withProjectLock
|
|
14
|
+
} from "./chunk-57GN6KWT.js";
|
|
15
|
+
import {
|
|
16
|
+
captureArtifactRevision
|
|
17
|
+
} from "./chunk-KCFF4ENE.js";
|
|
18
|
+
import "./chunk-7TASSBN2.js";
|
|
10
19
|
import {
|
|
11
20
|
serveStaticProjectHtml
|
|
12
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-GQETH4PE.js";
|
|
13
22
|
import "./chunk-XUHOIDKG.js";
|
|
14
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-XEFFJRYX.js";
|
|
15
24
|
import "./chunk-X7MTZ4T2.js";
|
|
16
25
|
import {
|
|
17
26
|
DEFAULT_ZOOM_SCALE,
|
|
@@ -21,41 +30,46 @@ import {
|
|
|
21
30
|
resolveCropRegion,
|
|
22
31
|
runFfmpegOnce,
|
|
23
32
|
seekCompositionTimeline
|
|
24
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-SWCSL6WS.js";
|
|
25
34
|
import "./chunk-FH7WODJH.js";
|
|
26
|
-
import "./chunk-
|
|
27
|
-
import "./chunk-
|
|
35
|
+
import "./chunk-4UMKAUZI.js";
|
|
36
|
+
import "./chunk-PKO2EWO7.js";
|
|
28
37
|
import "./chunk-WPNE5NEP.js";
|
|
29
|
-
import "./chunk-
|
|
30
|
-
import "./chunk-
|
|
31
|
-
import "./chunk-
|
|
32
|
-
import
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
import "./chunk-HBCRRCTX.js";
|
|
39
|
+
import "./chunk-PRXAOZWZ.js";
|
|
40
|
+
import "./chunk-C6TPGUWD.js";
|
|
41
|
+
import {
|
|
42
|
+
artifactDirectory,
|
|
43
|
+
forgetRecordedArtifacts,
|
|
44
|
+
recordArtifacts
|
|
45
|
+
} from "./chunk-7FYFEXD2.js";
|
|
46
|
+
import "./chunk-XINGD6MS.js";
|
|
47
|
+
import "./chunk-FFDC5OWV.js";
|
|
35
48
|
import {
|
|
36
49
|
resolveProject
|
|
37
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-IBYC3VUA.js";
|
|
38
51
|
import {
|
|
39
52
|
formatLintFindings
|
|
40
53
|
} from "./chunk-6CSYCFQV.js";
|
|
41
54
|
import "./chunk-K2FLNJVB.js";
|
|
55
|
+
import "./chunk-DQBY7FRR.js";
|
|
42
56
|
import {
|
|
43
57
|
resolveLocalBrowserGpuMode
|
|
44
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-EVTHG34H.js";
|
|
45
59
|
import "./chunk-442JNXRM.js";
|
|
46
|
-
import "./chunk-
|
|
60
|
+
import "./chunk-D6RJXQLD.js";
|
|
47
61
|
import "./chunk-XT7X6QCP.js";
|
|
48
62
|
import "./chunk-4YYJOFKS.js";
|
|
49
63
|
import "./chunk-HVW7ABXD.js";
|
|
50
|
-
import "./chunk-
|
|
51
|
-
import "./chunk-
|
|
52
|
-
import "./chunk-
|
|
64
|
+
import "./chunk-QESSGUKX.js";
|
|
65
|
+
import "./chunk-6Z4YJ5Q3.js";
|
|
66
|
+
import "./chunk-3HPJM5IQ.js";
|
|
53
67
|
import "./chunk-AWDFDFI3.js";
|
|
54
68
|
import "./chunk-P6LJ4Y32.js";
|
|
55
69
|
import "./chunk-GMECXFAN.js";
|
|
56
|
-
import "./chunk-
|
|
57
|
-
import "./chunk-
|
|
58
|
-
import "./chunk-
|
|
70
|
+
import "./chunk-5CS4T6C6.js";
|
|
71
|
+
import "./chunk-H2SGM2V2.js";
|
|
72
|
+
import "./chunk-KZ3L3W4Q.js";
|
|
59
73
|
import "./chunk-VWG7OQKU.js";
|
|
60
74
|
import "./chunk-XBSPQ52S.js";
|
|
61
75
|
import {
|
|
@@ -78,7 +92,7 @@ import "./chunk-K4WIOZFP.js";
|
|
|
78
92
|
import "./chunk-XUXGIA7H.js";
|
|
79
93
|
import "./chunk-WERLJGIC.js";
|
|
80
94
|
import "./chunk-ISN5GRYI.js";
|
|
81
|
-
import "./chunk-
|
|
95
|
+
import "./chunk-IZIRIDJH.js";
|
|
82
96
|
import {
|
|
83
97
|
loadOptionalPackage
|
|
84
98
|
} from "./chunk-3DKN5WKL.js";
|
|
@@ -88,24 +102,25 @@ import {
|
|
|
88
102
|
findFFmpeg,
|
|
89
103
|
findFFprobe,
|
|
90
104
|
getFFmpegInstallHint
|
|
91
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-4MLYMDQ4.js";
|
|
92
106
|
import "./chunk-AMKC3AXA.js";
|
|
93
|
-
import "./chunk-
|
|
94
|
-
import "./chunk-
|
|
107
|
+
import "./chunk-EXH6L2XZ.js";
|
|
108
|
+
import "./chunk-RN5I2DP5.js";
|
|
95
109
|
import "./chunk-NE55C6S5.js";
|
|
96
110
|
import "./chunk-JYVGYKXG.js";
|
|
97
111
|
import {
|
|
112
|
+
createRuntimeStartTimeResolver,
|
|
98
113
|
isClipVisibleAt,
|
|
99
114
|
isInClipWindow
|
|
100
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-5ERVRJMV.js";
|
|
101
116
|
import {
|
|
102
117
|
readElementRateSpec,
|
|
103
118
|
sourceTimeAt,
|
|
104
119
|
timeAtSourceTime
|
|
105
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-S3RCK56N.js";
|
|
106
121
|
import "./chunk-VC76R6W2.js";
|
|
107
122
|
import "./chunk-UJKQWGFF.js";
|
|
108
|
-
import "./chunk-
|
|
123
|
+
import "./chunk-VYKPBRCB.js";
|
|
109
124
|
import "./chunk-OFQWTKPW.js";
|
|
110
125
|
import "./chunk-DPVXBVLL.js";
|
|
111
126
|
import "./chunk-T76PLPD6.js";
|
|
@@ -113,18 +128,20 @@ import "./chunk-FXMKHHPO.js";
|
|
|
113
128
|
import "./chunk-RQVDTPGD.js";
|
|
114
129
|
import {
|
|
115
130
|
runCancellableProcess
|
|
116
|
-
} from "./chunk-
|
|
131
|
+
} from "./chunk-54DMWFQZ.js";
|
|
117
132
|
import "./chunk-TWWSYAKJ.js";
|
|
118
133
|
import {
|
|
119
134
|
lintProject
|
|
120
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-YOEGUBBY.js";
|
|
121
136
|
import "./chunk-IWFLMU2N.js";
|
|
122
|
-
import "./chunk-
|
|
137
|
+
import "./chunk-3VGU2SH7.js";
|
|
123
138
|
import "./chunk-VAS6HQX3.js";
|
|
124
139
|
import "./chunk-3RM2ETQT.js";
|
|
125
140
|
import "./chunk-BSQ7XANM.js";
|
|
126
|
-
import
|
|
127
|
-
|
|
141
|
+
import {
|
|
142
|
+
parseHTML
|
|
143
|
+
} from "./chunk-SDYDNHEE.js";
|
|
144
|
+
import "./chunk-TYXH3EKP.js";
|
|
128
145
|
import "./chunk-IXLUTE6N.js";
|
|
129
146
|
import {
|
|
130
147
|
normalizeErrorMessage
|
|
@@ -133,7 +150,57 @@ import "./chunk-KGPLIH7B.js";
|
|
|
133
150
|
import "./chunk-3GXQPCJC.js";
|
|
134
151
|
import "./chunk-M2WBOQ2Q.js";
|
|
135
152
|
|
|
153
|
+
// src/commands/snapshotSampling.ts
|
|
154
|
+
function parseSnapshotRange(value) {
|
|
155
|
+
const parts = value.split(/[,:]/);
|
|
156
|
+
const range = parts.map((part) => part.trim() === "" ? NaN : Number(part));
|
|
157
|
+
if (parts.length !== 2 || !range.every(Number.isFinite) || range[0] < 0 || range[1] <= range[0])
|
|
158
|
+
throw new Error("--range must be START,END in seconds, with 0 <= START < END");
|
|
159
|
+
return [range[0], range[1]];
|
|
160
|
+
}
|
|
161
|
+
function sampleSnapshotRange([start, end], frames, duration, exclusiveEnd = false) {
|
|
162
|
+
if (!Number.isInteger(frames) || frames < 1)
|
|
163
|
+
throw new Error("--frames must be a positive integer");
|
|
164
|
+
if (!Number.isFinite(duration) || duration <= 0 || !Number.isFinite(start) || !Number.isFinite(end) || start < 0 || end <= start || end > duration)
|
|
165
|
+
throw new Error(`Snapshot range must satisfy 0 <= START < END <= ${duration}s`);
|
|
166
|
+
if (frames === 1) return [(start + end) / 2];
|
|
167
|
+
const last = exclusiveEnd || end === duration ? end - Math.min(1e-3, (end - start) / (frames * 2)) : end;
|
|
168
|
+
return Array.from({ length: frames }, (_, i) => start + (last - start) * i / (frames - 1));
|
|
169
|
+
}
|
|
170
|
+
function resolveSnapshotCompositionRange(html, durations, id, duration) {
|
|
171
|
+
const { document: document2 } = parseHTML(html);
|
|
172
|
+
const matches = Array.from(document2.querySelectorAll("[data-composition-id]")).filter(
|
|
173
|
+
(el) => el.getAttribute("data-composition-id") === id
|
|
174
|
+
);
|
|
175
|
+
if (matches.length !== 1)
|
|
176
|
+
throw new Error(
|
|
177
|
+
`Composition ID ${JSON.stringify(id)} matched ${matches.length} elements; expected exactly one`
|
|
178
|
+
);
|
|
179
|
+
const registry = Object.fromEntries(
|
|
180
|
+
Object.entries(durations).map(([key, value]) => [key, { duration: () => value }])
|
|
181
|
+
);
|
|
182
|
+
const resolver = createRuntimeStartTimeResolver({
|
|
183
|
+
documentRef: document2,
|
|
184
|
+
timelineRegistry: registry,
|
|
185
|
+
includeAuthoredTimingAttrs: true
|
|
186
|
+
});
|
|
187
|
+
let start = 0, end = duration;
|
|
188
|
+
for (let el = matches[0]; el; el = el.parentElement) {
|
|
189
|
+
if (!el.hasAttribute("data-composition-id") && !el.hasAttribute("data-start")) continue;
|
|
190
|
+
const localStart = resolver.resolveStartForElement(el, 0);
|
|
191
|
+
const length = resolver.resolveDurationForElement(el);
|
|
192
|
+
if (!Number.isFinite(localStart))
|
|
193
|
+
throw new Error(`Cannot resolve start of composition ${JSON.stringify(id)}`);
|
|
194
|
+
start = Math.max(start, localStart);
|
|
195
|
+
if (length != null) end = Math.min(end, localStart + length);
|
|
196
|
+
}
|
|
197
|
+
if (end <= start)
|
|
198
|
+
throw new Error(`Composition ${JSON.stringify(id)} has no visible time interval`);
|
|
199
|
+
return [start, end];
|
|
200
|
+
}
|
|
201
|
+
|
|
136
202
|
// src/commands/snapshot.ts
|
|
203
|
+
import { randomUUID } from "crypto";
|
|
137
204
|
import { existsSync, mkdtempSync, readFileSync, mkdirSync, rmSync, writeFileSync } from "fs";
|
|
138
205
|
import { tmpdir } from "os";
|
|
139
206
|
import { resolve, join, relative, isAbsolute, basename, posix } from "path";
|
|
@@ -373,18 +440,29 @@ function computeSnapshotTimes(duration, opts) {
|
|
|
373
440
|
return { times: times.map(round), appendedTail: false };
|
|
374
441
|
}
|
|
375
442
|
async function captureSnapshots(projectDir, opts) {
|
|
376
|
-
const { bundleWithLocalizedFonts } = await import("./bundleWithLocalizedFonts-
|
|
443
|
+
const { bundleWithLocalizedFonts } = await import("./bundleWithLocalizedFonts-76DMCRIW.js");
|
|
444
|
+
const capture = await captureArtifactRevision(projectDir).catch(warnSnapshotsNotRecorded);
|
|
445
|
+
const invocation = randomUUID();
|
|
446
|
+
const artifacts = [];
|
|
447
|
+
const replaced = [];
|
|
448
|
+
const warnings = [];
|
|
449
|
+
let completed = false;
|
|
377
450
|
const numFrames = opts.frames ?? 5;
|
|
378
451
|
const html = await bundleWithLocalizedFonts(projectDir);
|
|
379
452
|
const server = await serveStaticProjectHtml(projectDir, html, void 0, [], opts.autoProxy);
|
|
380
453
|
const savedPaths = [];
|
|
381
454
|
try {
|
|
382
|
-
const {
|
|
455
|
+
const {
|
|
456
|
+
browser: chromeBrowser,
|
|
457
|
+
page,
|
|
458
|
+
renderReadyTimedOut
|
|
459
|
+
} = await openSettledCompositionPage(html, server.url, {
|
|
383
460
|
renderReadyTimeoutMs: opts.timeout ?? 5e3,
|
|
384
461
|
renderReadyWarningSuffix: "snapshots may be inaccurate",
|
|
385
462
|
browserGpuMode: opts.browserGpuMode
|
|
386
463
|
});
|
|
387
464
|
try {
|
|
465
|
+
if (renderReadyTimedOut) warnings.push("Render readiness timed out");
|
|
388
466
|
const fontReport = await page.evaluate(() => {
|
|
389
467
|
const loaded = [];
|
|
390
468
|
const errored = [];
|
|
@@ -407,6 +485,8 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
407
485
|
console.log(` ${c.error("Fonts FAILED:")} ${fontReport.errored.join(", ")}`);
|
|
408
486
|
}
|
|
409
487
|
}
|
|
488
|
+
if (fontReport.errored.length)
|
|
489
|
+
warnings.push(`Fonts failed: ${fontReport.errored.join(", ")}`);
|
|
410
490
|
const duration = await page.evaluate(() => {
|
|
411
491
|
const win = window;
|
|
412
492
|
if (typeof win.__player?.getDuration === "function") {
|
|
@@ -420,24 +500,51 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
420
500
|
if (duration <= 0 && !opts.at?.length) {
|
|
421
501
|
return [];
|
|
422
502
|
}
|
|
423
|
-
|
|
503
|
+
let range = opts.range;
|
|
504
|
+
if (opts.composition) {
|
|
505
|
+
const timing = await page.evaluate(() => ({
|
|
506
|
+
html: document.documentElement.outerHTML,
|
|
507
|
+
durations: Object.fromEntries(
|
|
508
|
+
Object.entries(window.__timelines ?? {}).map(([id, timeline]) => [
|
|
509
|
+
id,
|
|
510
|
+
Number(timeline.duration?.())
|
|
511
|
+
])
|
|
512
|
+
)
|
|
513
|
+
}));
|
|
514
|
+
range = resolveSnapshotCompositionRange(
|
|
515
|
+
timing.html,
|
|
516
|
+
timing.durations,
|
|
517
|
+
opts.composition,
|
|
518
|
+
duration
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
const { times: positions, appendedTail } = range ? {
|
|
522
|
+
times: sampleSnapshotRange(range, numFrames, duration, !!opts.composition),
|
|
523
|
+
appendedTail: false
|
|
524
|
+
} : computeSnapshotTimes(duration, {
|
|
424
525
|
frames: numFrames,
|
|
425
526
|
at: opts.at,
|
|
426
527
|
includeEnd: opts.includeEnd
|
|
427
528
|
});
|
|
529
|
+
if (range)
|
|
530
|
+
console.log(
|
|
531
|
+
` Sampling ${positions.length} frames within ${range[0]}\u2013${range[1]}s${opts.composition ? ` (composition ${opts.composition})` : ""}`
|
|
532
|
+
);
|
|
428
533
|
if (appendedTail) {
|
|
429
534
|
console.log(
|
|
430
535
|
` ${c.dim(`Note: added an end-of-timeline frame at ${positions[positions.length - 1].toFixed(2)}s. Short beats between your --at times may still be skipped \u2014 pass them explicitly.`)}`
|
|
431
536
|
);
|
|
432
537
|
}
|
|
433
538
|
const cameraExpr = opts.angle && (opts.angle.yaw !== 0 || opts.angle.pitch !== 0) ? `(${orbitStageSource()})(${JSON.stringify(opts.angle)})` : null;
|
|
434
|
-
const snapshotDir = opts.outputDir ??
|
|
539
|
+
const snapshotDir = opts.outputDir ?? artifactDirectory(projectDir, "snapshots");
|
|
435
540
|
mkdirSync(snapshotDir, { recursive: true });
|
|
436
541
|
try {
|
|
437
542
|
const { readdirSync } = await import("fs");
|
|
438
543
|
for (const file of readdirSync(snapshotDir)) {
|
|
439
544
|
if (/\.(png|jpg|jpeg)$/i.test(file)) {
|
|
440
|
-
|
|
545
|
+
const path = resolve(snapshotDir, file);
|
|
546
|
+
replaced.push(path);
|
|
547
|
+
rmSync(path, { force: true });
|
|
441
548
|
}
|
|
442
549
|
}
|
|
443
550
|
} catch {
|
|
@@ -446,11 +553,12 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
446
553
|
let syncVideoFrameVisibility = null;
|
|
447
554
|
let extractMediaMetadata = null;
|
|
448
555
|
try {
|
|
449
|
-
const engine = await import("./src-
|
|
556
|
+
const engine = await import("./src-AVQBAECC.js");
|
|
450
557
|
injectVideoFramesBatch = engine.injectVideoFramesBatch;
|
|
451
558
|
syncVideoFrameVisibility = engine.syncVideoFrameVisibility;
|
|
452
559
|
extractMediaMetadata = engine.extractMediaMetadata;
|
|
453
560
|
} catch {
|
|
561
|
+
warnings.push("Video frame extraction engine unavailable");
|
|
454
562
|
console.warn(
|
|
455
563
|
` ${c.warn("\u26A0")} @hyperframes/engine unavailable \u2014 <video> elements will appear black in snapshots. Verify media via a draft render's extracted frames instead.`
|
|
456
564
|
);
|
|
@@ -553,6 +661,7 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
553
661
|
}
|
|
554
662
|
if (active.length > 0 && updates.length < active.length) {
|
|
555
663
|
const missed = active.length - updates.length;
|
|
664
|
+
warnings.push(`${missed} video frames missing at ${time}s`);
|
|
556
665
|
console.warn(
|
|
557
666
|
` ${c.warn("\u26A0")} ${missed}/${active.length} active <video> frame(s) could not be extracted at ${time.toFixed(1)}s \u2014 those videos will appear black/stale in this snapshot`
|
|
558
667
|
);
|
|
@@ -566,6 +675,7 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
566
675
|
active.map((a) => a.id)
|
|
567
676
|
);
|
|
568
677
|
} catch {
|
|
678
|
+
warnings.push(`Video injection failed at ${time}s`);
|
|
569
679
|
console.warn(
|
|
570
680
|
` ${c.warn("\u26A0")} video frame injection failed at ${time.toFixed(1)}s \u2014 <video> elements will appear black/stale in this snapshot`
|
|
571
681
|
);
|
|
@@ -576,6 +686,7 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
576
686
|
const index = String(i).padStart(2, "0");
|
|
577
687
|
const filename = `frame-${index}-at-${timeLabel}.png`;
|
|
578
688
|
const framePath = join(snapshotDir, filename);
|
|
689
|
+
let crop;
|
|
579
690
|
if (opts.zoom) {
|
|
580
691
|
const canvas = await page.evaluate(() => ({
|
|
581
692
|
width: window.innerWidth,
|
|
@@ -583,11 +694,13 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
583
694
|
}));
|
|
584
695
|
const region = await resolveCropRegion(page, opts.zoom, canvas);
|
|
585
696
|
if (!region) {
|
|
697
|
+
warnings.push(`Crop target unavailable at ${time}s`);
|
|
586
698
|
console.error(
|
|
587
699
|
` ${c.warn("\u26A0")} --zoom target has no visible box at ${time.toFixed(1)}s \u2014 frame skipped`
|
|
588
700
|
);
|
|
589
701
|
continue;
|
|
590
702
|
}
|
|
703
|
+
crop = region;
|
|
591
704
|
const buffer = await captureRegionCrop(
|
|
592
705
|
page,
|
|
593
706
|
region,
|
|
@@ -597,6 +710,19 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
597
710
|
} else {
|
|
598
711
|
await page.screenshot({ path: framePath, type: "png", omitBackground: true });
|
|
599
712
|
}
|
|
713
|
+
artifacts.push({
|
|
714
|
+
id: `${invocation}-${i}`,
|
|
715
|
+
image: resolve(framePath),
|
|
716
|
+
time,
|
|
717
|
+
metadata: {
|
|
718
|
+
...pngDimensions(framePath),
|
|
719
|
+
crop,
|
|
720
|
+
zoom: opts.zoom,
|
|
721
|
+
zoomScale: opts.zoom ? opts.zoomScale ?? DEFAULT_ZOOM_SCALE : 1,
|
|
722
|
+
angle: opts.angle,
|
|
723
|
+
browserGpuMode: opts.browserGpuMode
|
|
724
|
+
}
|
|
725
|
+
});
|
|
600
726
|
if (opts.against) {
|
|
601
727
|
const refPng = await extractVideoFrameToBuffer(opts.against, time);
|
|
602
728
|
if (!refPng) {
|
|
@@ -620,14 +746,48 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
620
746
|
const rel = relative(projectDir, framePath);
|
|
621
747
|
savedPaths.push(rel.startsWith("..") || isAbsolute(rel) ? framePath : rel);
|
|
622
748
|
}
|
|
749
|
+
completed = true;
|
|
623
750
|
} finally {
|
|
624
751
|
await chromeBrowser.close();
|
|
625
752
|
}
|
|
626
753
|
} finally {
|
|
627
754
|
await server.close();
|
|
755
|
+
const recorded = capture ? await recordSnapshotArtifacts(
|
|
756
|
+
projectDir,
|
|
757
|
+
capture,
|
|
758
|
+
artifacts,
|
|
759
|
+
opts.zoom,
|
|
760
|
+
warnings,
|
|
761
|
+
completed
|
|
762
|
+
) : false;
|
|
763
|
+
if (!recorded) {
|
|
764
|
+
const paths = [...replaced, ...artifacts.map((artifact) => artifact.image)];
|
|
765
|
+
if (paths.length > 0) await forgetRecordedArtifacts(projectDir, paths).catch(() => void 0);
|
|
766
|
+
}
|
|
628
767
|
}
|
|
629
768
|
return savedPaths;
|
|
630
769
|
}
|
|
770
|
+
function warnSnapshotsNotRecorded(error) {
|
|
771
|
+
console.warn(` ${c.warn("\u26A0")} Snapshots were not recorded: ${normalizeErrorMessage(error)}`);
|
|
772
|
+
return void 0;
|
|
773
|
+
}
|
|
774
|
+
async function recordSnapshotArtifacts(projectDir, capture, artifacts, zoom, warnings, completed) {
|
|
775
|
+
const records = await recordArtifacts(
|
|
776
|
+
projectDir,
|
|
777
|
+
capture,
|
|
778
|
+
artifacts.map((artifact) => ({
|
|
779
|
+
kind: "snapshot",
|
|
780
|
+
scope: zoom ? "crop" : "full",
|
|
781
|
+
...artifact,
|
|
782
|
+
metadata: { ...artifact.metadata, warnings, partial: !completed || warnings.length > 0 }
|
|
783
|
+
}))
|
|
784
|
+
).catch(warnSnapshotsNotRecorded);
|
|
785
|
+
const record = records?.[0];
|
|
786
|
+
if (!record) return false;
|
|
787
|
+
console.log(` Revision: ${record.revision ?? "none"} (${record.attribution})`);
|
|
788
|
+
console.log(` State: ${join(projectDir, ".hyperframes", "video-state.json")}`);
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
631
791
|
var snapshot_default = defineCommand({
|
|
632
792
|
meta: {
|
|
633
793
|
name: "snapshot",
|
|
@@ -642,7 +802,7 @@ var snapshot_default = defineCommand({
|
|
|
642
802
|
output: {
|
|
643
803
|
type: "string",
|
|
644
804
|
alias: "o",
|
|
645
|
-
description: "Directory to write snapshots into (default: <project
|
|
805
|
+
description: "Directory to write snapshots into (default: unique directory under <project>/.hyperframes/artifacts/snapshots)"
|
|
646
806
|
},
|
|
647
807
|
frames: {
|
|
648
808
|
type: "string",
|
|
@@ -653,6 +813,14 @@ var snapshot_default = defineCommand({
|
|
|
653
813
|
type: "string",
|
|
654
814
|
description: "Comma-separated timestamps in seconds (e.g., --at 3.0,10.5,18.0). Each is captured at that exact instant, not snapped to a frame."
|
|
655
815
|
},
|
|
816
|
+
range: {
|
|
817
|
+
type: "string",
|
|
818
|
+
description: "Root-timeline range START,END in seconds; sample --frames evenly within it, without adding the full-video tail"
|
|
819
|
+
},
|
|
820
|
+
composition: {
|
|
821
|
+
type: "string",
|
|
822
|
+
description: "data-composition-id to sample; take --frames within its effective root-timeline interval, without adding the full-video tail"
|
|
823
|
+
},
|
|
656
824
|
timeout: {
|
|
657
825
|
type: "string",
|
|
658
826
|
description: "Ms to wait for runtime to initialize (default: 5000)",
|
|
@@ -696,6 +864,12 @@ var snapshot_default = defineCommand({
|
|
|
696
864
|
}
|
|
697
865
|
},
|
|
698
866
|
async run({ args }) {
|
|
867
|
+
if ([args.at, args.range, args.composition].filter((value) => value !== void 0).length > 1)
|
|
868
|
+
throw new Error("Use only one of --at, --range, or --composition");
|
|
869
|
+
const frames = parseInt(args.frames, 10) || 5;
|
|
870
|
+
const range = args.range === void 0 ? void 0 : parseSnapshotRange(String(args.range));
|
|
871
|
+
const composition = args.composition === void 0 ? void 0 : String(args.composition).trim();
|
|
872
|
+
if (composition === "") throw new Error("--composition requires a composition ID");
|
|
699
873
|
const project = resolveProject(args.dir);
|
|
700
874
|
const lintResult = await lintProject(project.dir);
|
|
701
875
|
if (hasDefinitiveEntryMismatch(lintResult)) {
|
|
@@ -724,7 +898,6 @@ var snapshot_default = defineCommand({
|
|
|
724
898
|
console.log("");
|
|
725
899
|
failCommand();
|
|
726
900
|
}
|
|
727
|
-
const frames = parseInt(args.frames, 10) || 5;
|
|
728
901
|
const timeout = parseInt(args.timeout, 10) || 5e3;
|
|
729
902
|
const atTimestamps = args.at ? String(args.at).split(",").map((s) => parseFloat(s.trim())).filter((n) => !isNaN(n)) : void 0;
|
|
730
903
|
const describeArg = args.describe === void 0 ? "true" : String(args.describe) === "false" ? null : String(args.describe);
|
|
@@ -740,129 +913,144 @@ var snapshot_default = defineCommand({
|
|
|
740
913
|
const angleLabel = camera && (camera.yaw !== 0 || camera.pitch !== 0) ? ` ${c.dim(`(angle yaw ${camera.yaw}\xB0 pitch ${camera.pitch}\xB0)`)}` : "";
|
|
741
914
|
console.log(`${c.accent("\u25C6")} Capturing ${label} from ${c.accent(project.name)}${angleLabel}`);
|
|
742
915
|
try {
|
|
743
|
-
const snapshotDir = args.output ? resolve(String(args.output)) :
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
console.log(
|
|
765
|
-
`
|
|
766
|
-
${c.success("\u25C7")} ${paths.length} snapshots saved to ${args.output ? snapshotDir : "snapshots/"}`
|
|
767
|
-
);
|
|
768
|
-
for (const p of paths) {
|
|
769
|
-
console.log(` ${p}`);
|
|
770
|
-
}
|
|
771
|
-
if (against) {
|
|
772
|
-
console.log(
|
|
773
|
-
` ${c.dim("ref-*.png + pair-*.jpg")} beside each frame (reference frame, render | reference sheet)`
|
|
774
|
-
);
|
|
775
|
-
}
|
|
776
|
-
try {
|
|
777
|
-
const { createSnapshotContactSheet } = await import("./contactSheet-27SRU7A4.js");
|
|
778
|
-
const sheets = await createSnapshotContactSheet(
|
|
779
|
-
snapshotDir,
|
|
780
|
-
join(snapshotDir, "contact-sheet.jpg")
|
|
916
|
+
const snapshotDir = args.output ? resolve(String(args.output)) : artifactDirectory(project.dir, "snapshots");
|
|
917
|
+
await withProjectLock(project.dir, "snapshot", async () => {
|
|
918
|
+
const paths = await captureSnapshots(project.dir, {
|
|
919
|
+
frames,
|
|
920
|
+
range,
|
|
921
|
+
composition,
|
|
922
|
+
timeout,
|
|
923
|
+
at: atTimestamps,
|
|
924
|
+
outputDir: snapshotDir,
|
|
925
|
+
angle: camera,
|
|
926
|
+
includeEnd: args.end !== false,
|
|
927
|
+
zoom: zoomTarget,
|
|
928
|
+
zoomScale,
|
|
929
|
+
autoProxy: args.proxy,
|
|
930
|
+
browserGpuMode: resolveLocalBrowserGpuMode(args["browser-gpu"]),
|
|
931
|
+
against
|
|
932
|
+
});
|
|
933
|
+
reportArtifacts(
|
|
934
|
+
"snapshot",
|
|
935
|
+
"frame",
|
|
936
|
+
paths.map((path) => resolve(project.dir, path))
|
|
781
937
|
);
|
|
782
|
-
if (
|
|
783
|
-
|
|
784
|
-
|
|
938
|
+
if (paths.length === 0) {
|
|
939
|
+
console.log(
|
|
940
|
+
`
|
|
941
|
+
${c.error("\u2717")} Could not determine composition duration \u2014 no frames captured`
|
|
942
|
+
);
|
|
943
|
+
failCommand();
|
|
944
|
+
}
|
|
945
|
+
console.log(`
|
|
946
|
+
${c.success("\u25C7")} ${paths.length} snapshots saved to ${snapshotDir}`);
|
|
947
|
+
for (const p of paths) {
|
|
948
|
+
console.log(` ${p}`);
|
|
949
|
+
}
|
|
950
|
+
if (against) {
|
|
951
|
+
console.log(
|
|
952
|
+
` ${c.dim("ref-*.png + pair-*.jpg")} beside each frame (reference frame, render | reference sheet)`
|
|
953
|
+
);
|
|
785
954
|
}
|
|
786
|
-
} catch (err) {
|
|
787
|
-
console.warn(
|
|
788
|
-
` ${c.warn("\u26A0")} Contact sheet skipped: ${normalizeErrorMessage(err)}. Individual snapshot PNGs are still available.`
|
|
789
|
-
);
|
|
790
|
-
}
|
|
791
|
-
if (describeArg !== null) {
|
|
792
955
|
try {
|
|
793
|
-
const
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
956
|
+
const { createSnapshotContactSheet } = await import("./contactSheet-27SRU7A4.js");
|
|
957
|
+
const sheets = await createSnapshotContactSheet(
|
|
958
|
+
snapshotDir,
|
|
959
|
+
join(snapshotDir, "contact-sheet.jpg")
|
|
960
|
+
);
|
|
961
|
+
reportArtifacts("snapshot", "contact-sheet", sheets);
|
|
962
|
+
for (const sheet of sheets) {
|
|
963
|
+
console.log(` ${resolve(sheet)} (grid view for AI review)`);
|
|
964
|
+
}
|
|
965
|
+
} catch (err) {
|
|
966
|
+
console.warn(
|
|
967
|
+
` ${c.warn("\u26A0")} Contact sheet skipped: ${normalizeErrorMessage(err)}. Individual snapshot PNGs are still available.`
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
if (describeArg !== null) {
|
|
971
|
+
try {
|
|
972
|
+
const geminiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
|
|
973
|
+
if (!geminiKey) {
|
|
974
|
+
if (args.describe !== void 0)
|
|
975
|
+
console.log(` ${c.dim("--describe: GEMINI_API_KEY not set, skipping")}`);
|
|
976
|
+
} else if (paths.length > 0) {
|
|
977
|
+
console.log(` ${c.dim("Describing frames with Gemini vision...")}`);
|
|
978
|
+
const { GoogleGenAI } = await loadOptionalPackage("@google/genai", "--describe");
|
|
979
|
+
const ai = new GoogleGenAI({ apiKey: geminiKey });
|
|
980
|
+
const model = process.env.HYPERFRAMES_GEMINI_MODEL || "gemini-3.1-flash-lite-preview";
|
|
981
|
+
const customQuestion = describeArg === "true" ? "Describe this video composition frame in 1-2 sentences. Be specific and factual: what elements are visible, what text appears, is the frame blank/black/loading, what is the composition. Flag any obvious problems." : describeArg;
|
|
982
|
+
const descriptions = [
|
|
983
|
+
`# Snapshot Frame Descriptions`,
|
|
984
|
+
``,
|
|
985
|
+
`**Question asked:** ${customQuestion}`,
|
|
986
|
+
``,
|
|
987
|
+
`Compare each description against your storyboard spec. A "black frame" or "loading screen" for a content beat is a bug.`,
|
|
988
|
+
``
|
|
989
|
+
];
|
|
990
|
+
let sharpFn = null;
|
|
991
|
+
try {
|
|
992
|
+
const s = await import("sharp");
|
|
993
|
+
sharpFn = s.default ?? s;
|
|
994
|
+
} catch {
|
|
995
|
+
}
|
|
996
|
+
const results = await Promise.allSettled(
|
|
997
|
+
paths.map(async (p) => {
|
|
998
|
+
const filename = basename(p);
|
|
999
|
+
const filePath = join(snapshotDir, filename);
|
|
1000
|
+
if (!existsSync(filePath)) return { filename, desc: "file not found" };
|
|
1001
|
+
const raw = readFileSync(filePath);
|
|
1002
|
+
let imageData;
|
|
1003
|
+
let mimeType = "image/png";
|
|
1004
|
+
if (sharpFn) {
|
|
1005
|
+
imageData = await sharpFn(raw).resize(960).jpeg().toBuffer();
|
|
1006
|
+
mimeType = "image/jpeg";
|
|
1007
|
+
} else {
|
|
1008
|
+
if (raw.length > 38e5)
|
|
1009
|
+
return {
|
|
1010
|
+
filename,
|
|
1011
|
+
desc: "file too large for Gemini \u2014 install sharp to enable auto-resize"
|
|
1012
|
+
};
|
|
1013
|
+
imageData = raw;
|
|
1014
|
+
}
|
|
1015
|
+
const base64 = imageData.toString("base64");
|
|
1016
|
+
const response = await ai.models.generateContent({
|
|
1017
|
+
model,
|
|
1018
|
+
contents: [
|
|
1019
|
+
{
|
|
1020
|
+
role: "user",
|
|
1021
|
+
parts: [
|
|
1022
|
+
{ inlineData: { mimeType, data: base64 } },
|
|
1023
|
+
{ text: customQuestion }
|
|
1024
|
+
]
|
|
1025
|
+
}
|
|
1026
|
+
],
|
|
1027
|
+
config: { maxOutputTokens: 250 }
|
|
1028
|
+
});
|
|
1029
|
+
return { filename, desc: response.text?.trim() || "no description" };
|
|
1030
|
+
})
|
|
1031
|
+
);
|
|
1032
|
+
for (const result of results) {
|
|
1033
|
+
if (result.status === "fulfilled") {
|
|
1034
|
+
descriptions.push(`## ${result.value.filename}`, `${result.value.desc}`, ``);
|
|
827
1035
|
} else {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
1036
|
+
const errMsg = normalizeErrorMessage(result.reason);
|
|
1037
|
+
descriptions.push(
|
|
1038
|
+
`## (error)`,
|
|
1039
|
+
`Gemini call failed: ${errMsg.slice(0, 120)}`,
|
|
1040
|
+
``
|
|
1041
|
+
);
|
|
834
1042
|
}
|
|
835
|
-
const base64 = imageData.toString("base64");
|
|
836
|
-
const response = await ai.models.generateContent({
|
|
837
|
-
model,
|
|
838
|
-
contents: [
|
|
839
|
-
{
|
|
840
|
-
role: "user",
|
|
841
|
-
parts: [{ inlineData: { mimeType, data: base64 } }, { text: customQuestion }]
|
|
842
|
-
}
|
|
843
|
-
],
|
|
844
|
-
config: { maxOutputTokens: 250 }
|
|
845
|
-
});
|
|
846
|
-
return { filename, desc: response.text?.trim() || "no description" };
|
|
847
|
-
})
|
|
848
|
-
);
|
|
849
|
-
for (const result of results) {
|
|
850
|
-
if (result.status === "fulfilled") {
|
|
851
|
-
descriptions.push(`## ${result.value.filename}`, `${result.value.desc}`, ``);
|
|
852
|
-
} else {
|
|
853
|
-
const errMsg = normalizeErrorMessage(result.reason);
|
|
854
|
-
descriptions.push(`## (error)`, `Gemini call failed: ${errMsg.slice(0, 120)}`, ``);
|
|
855
1043
|
}
|
|
1044
|
+
const descPath = join(snapshotDir, "descriptions.md");
|
|
1045
|
+
writeFileSync(descPath, descriptions.join("\n"));
|
|
1046
|
+
console.log(` ${c.dim("descriptions.md")} (Gemini frame analysis)`);
|
|
856
1047
|
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
console.log(` ${c.dim(
|
|
1048
|
+
} catch (descErr) {
|
|
1049
|
+
const msg = normalizeErrorMessage(descErr);
|
|
1050
|
+
console.log(` ${c.dim(`--describe failed: ${msg}`)}`);
|
|
860
1051
|
}
|
|
861
|
-
} catch (descErr) {
|
|
862
|
-
const msg = normalizeErrorMessage(descErr);
|
|
863
|
-
console.log(` ${c.dim(`--describe failed: ${msg}`)}`);
|
|
864
1052
|
}
|
|
865
|
-
}
|
|
1053
|
+
});
|
|
866
1054
|
} catch (err) {
|
|
867
1055
|
const msg = normalizeErrorMessage(err);
|
|
868
1056
|
console.error(`
|