hyperframes 0.6.64 → 0.6.65
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 +189 -48
- package/dist/skills/hyperframes/references/techniques.md +15 -30
- 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.6.
|
|
53
|
+
VERSION = true ? "0.6.65" : "0.0.0-dev";
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
@@ -71433,7 +71433,7 @@ var init_urlDownloader2 = __esm({
|
|
|
71433
71433
|
|
|
71434
71434
|
// ../producer/src/services/htmlCompiler.ts
|
|
71435
71435
|
import { readFileSync as readFileSync27, existsSync as existsSync35, mkdirSync as mkdirSync20 } from "fs";
|
|
71436
|
-
import { join as join39, dirname as dirname13, resolve as resolve19 } from "path";
|
|
71436
|
+
import { join as join39, dirname as dirname13, resolve as resolve19, basename as basename5 } from "path";
|
|
71437
71437
|
function dedupeElementsById(elements) {
|
|
71438
71438
|
const deduped = /* @__PURE__ */ new Map();
|
|
71439
71439
|
for (const element of elements) {
|
|
@@ -71566,6 +71566,7 @@ async function compileHtmlFile(html, baseDir, downloadDir) {
|
|
|
71566
71566
|
}
|
|
71567
71567
|
compiledHtml = compiledHtml.replace(/(<video\b[^>]*)\s+crossorigin(?:=["'][^"']*["'])?/gi, "$1");
|
|
71568
71568
|
compiledHtml = compiledHtml.replace(/(<img\b[^>]*)\s+crossorigin(?:=["'][^"']*["'])?/gi, "$1");
|
|
71569
|
+
compiledHtml = compiledHtml.replace(/(<audio\b[^>]*)\s+crossorigin(?:=["'][^"']*["'])?/gi, "$1");
|
|
71569
71570
|
return { html: compiledHtml, unresolvedCompositions };
|
|
71570
71571
|
}
|
|
71571
71572
|
async function parseSubCompositions(html, projectDir, downloadDir, parentOffset = 0, parentEnd = Infinity, visited = /* @__PURE__ */ new Set()) {
|
|
@@ -71978,6 +71979,46 @@ function collectExternalAssets(html, projectDir) {
|
|
|
71978
71979
|
externalAssets
|
|
71979
71980
|
};
|
|
71980
71981
|
}
|
|
71982
|
+
async function localizeRemoteMediaSources(html, downloadDir) {
|
|
71983
|
+
const remoteDir = join39(downloadDir, REMOTE_MEDIA_SUBDIR);
|
|
71984
|
+
const urlSet = /* @__PURE__ */ new Set();
|
|
71985
|
+
const re2 = new RegExp(REMOTE_MEDIA_TAG_RE.source, REMOTE_MEDIA_TAG_RE.flags);
|
|
71986
|
+
let m2;
|
|
71987
|
+
while ((m2 = re2.exec(html)) !== null) {
|
|
71988
|
+
if (m2[1]) urlSet.add(m2[1]);
|
|
71989
|
+
}
|
|
71990
|
+
if (urlSet.size === 0) return { html, remoteMediaAssets: /* @__PURE__ */ new Map() };
|
|
71991
|
+
if (!existsSync35(remoteDir)) mkdirSync20(remoteDir, { recursive: true });
|
|
71992
|
+
const urlToLocal = /* @__PURE__ */ new Map();
|
|
71993
|
+
await Promise.all(
|
|
71994
|
+
[...urlSet].map(async (url) => {
|
|
71995
|
+
try {
|
|
71996
|
+
const localPath = await downloadToTemp(url, remoteDir);
|
|
71997
|
+
urlToLocal.set(url, localPath);
|
|
71998
|
+
} catch (err) {
|
|
71999
|
+
console.warn(
|
|
72000
|
+
`[Compiler] Remote media download failed for ${url} \u2014 using original URL as fallback. ${err instanceof Error ? err.message : String(err)}`
|
|
72001
|
+
);
|
|
72002
|
+
}
|
|
72003
|
+
})
|
|
72004
|
+
);
|
|
72005
|
+
if (urlToLocal.size === 0) return { html, remoteMediaAssets: /* @__PURE__ */ new Map() };
|
|
72006
|
+
const remoteMediaAssets = /* @__PURE__ */ new Map();
|
|
72007
|
+
const urlToRelPath = /* @__PURE__ */ new Map();
|
|
72008
|
+
for (const [url, absPath] of urlToLocal) {
|
|
72009
|
+
const relPath = `${REMOTE_MEDIA_SUBDIR}/${basename5(absPath)}`;
|
|
72010
|
+
remoteMediaAssets.set(relPath, absPath);
|
|
72011
|
+
urlToRelPath.set(url, relPath);
|
|
72012
|
+
}
|
|
72013
|
+
let result = html;
|
|
72014
|
+
for (const [url, relPath] of urlToRelPath) {
|
|
72015
|
+
result = result.replaceAll(`"${url}"`, `"${relPath}"`).replaceAll(`'${url}'`, `'${relPath}'`);
|
|
72016
|
+
}
|
|
72017
|
+
console.log(
|
|
72018
|
+
`[Compiler] Localized ${urlToLocal.size} remote media source(s) to ${REMOTE_MEDIA_SUBDIR}/`
|
|
72019
|
+
);
|
|
72020
|
+
return { html: result, remoteMediaAssets };
|
|
72021
|
+
}
|
|
71981
72022
|
function rewriteUnresolvableGsapToCdn(html, projectDir) {
|
|
71982
72023
|
return html.replace(
|
|
71983
72024
|
/(<script\b[^>]*\bsrc=["'])([^"']*gsap[^"']*\/dist\/([^"']+))(["'][^>]*>)/gi,
|
|
@@ -72028,10 +72069,17 @@ async function compileForRender(projectDir, htmlPath, downloadDir, options = {})
|
|
|
72028
72069
|
'data-hf-studio-motion="'
|
|
72029
72070
|
];
|
|
72030
72071
|
const hasPositionEdits = HF_POSITION_ATTRS.some((attr) => htmlWithAssets.includes(attr));
|
|
72031
|
-
const
|
|
72072
|
+
const htmlWithPositionScript = hasPositionEdits ? htmlWithAssets.replace(
|
|
72032
72073
|
/<\/body>/i,
|
|
72033
72074
|
`<script>${createStudioPositionSeekReapplyScript()}</script></body>`
|
|
72034
72075
|
) : htmlWithAssets;
|
|
72076
|
+
const { html, remoteMediaAssets } = await localizeRemoteMediaSources(
|
|
72077
|
+
htmlWithPositionScript,
|
|
72078
|
+
downloadDir
|
|
72079
|
+
);
|
|
72080
|
+
for (const [relPath, absPath] of remoteMediaAssets) {
|
|
72081
|
+
externalAssets.set(relPath, absPath);
|
|
72082
|
+
}
|
|
72035
72083
|
const mainVideos = parseVideoElements(html);
|
|
72036
72084
|
const mainAudios = parseAudioElements(html);
|
|
72037
72085
|
const mainImages = parseImageElements(html);
|
|
@@ -72312,7 +72360,7 @@ async function recompileWithResolutions(compiled, resolutions, projectDir, downl
|
|
|
72312
72360
|
hasShaderTransitions: compiled.hasShaderTransitions
|
|
72313
72361
|
};
|
|
72314
72362
|
}
|
|
72315
|
-
var INLINE_SCRIPT_PATTERN, COMPILER_MOUNT_BLOCK_START, COMPILER_MOUNT_BLOCK_END, SHADER_TRANSITION_USAGE_PATTERN, GSAP_CDN_BASE;
|
|
72363
|
+
var INLINE_SCRIPT_PATTERN, COMPILER_MOUNT_BLOCK_START, COMPILER_MOUNT_BLOCK_END, SHADER_TRANSITION_USAGE_PATTERN, REMOTE_MEDIA_SUBDIR, REMOTE_MEDIA_TAG_RE, GSAP_CDN_BASE;
|
|
72316
72364
|
var init_htmlCompiler2 = __esm({
|
|
72317
72365
|
"../producer/src/services/htmlCompiler.ts"() {
|
|
72318
72366
|
"use strict";
|
|
@@ -72329,6 +72377,8 @@ var init_htmlCompiler2 = __esm({
|
|
|
72329
72377
|
COMPILER_MOUNT_BLOCK_START = "/* __HF_COMPILER_MOUNT_START__ */";
|
|
72330
72378
|
COMPILER_MOUNT_BLOCK_END = "/* __HF_COMPILER_MOUNT_END__ */";
|
|
72331
72379
|
SHADER_TRANSITION_USAGE_PATTERN = /\b(?:(?:window|globalThis)\s*\.\s*)?HyperShader\s*\.\s*init\s*\(|\b__hf\s*\.\s*transitions\s*=/;
|
|
72380
|
+
REMOTE_MEDIA_SUBDIR = "_remote_media";
|
|
72381
|
+
REMOTE_MEDIA_TAG_RE = /<(?:video|audio)\b[^>]*?\bsrc\s*=\s*["'](https?:\/\/[^"']+)["'][^>]*>/gi;
|
|
72332
72382
|
GSAP_CDN_BASE = "https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/";
|
|
72333
72383
|
}
|
|
72334
72384
|
});
|
|
@@ -78343,7 +78393,7 @@ __export(studioServer_exports, {
|
|
|
78343
78393
|
import { Hono as Hono5 } from "hono";
|
|
78344
78394
|
import { streamSSE as streamSSE3 } from "hono/streaming";
|
|
78345
78395
|
import { existsSync as existsSync48, readFileSync as readFileSync35, writeFileSync as writeFileSync25, statSync as statSync17 } from "fs";
|
|
78346
|
-
import { resolve as resolve24, join as join58, basename as
|
|
78396
|
+
import { resolve as resolve24, join as join58, basename as basename6 } from "path";
|
|
78347
78397
|
function resolveDistDir() {
|
|
78348
78398
|
return resolveStudioBundle().dir;
|
|
78349
78399
|
}
|
|
@@ -78470,7 +78520,7 @@ async function loadPreviewServerBuildSignature() {
|
|
|
78470
78520
|
}
|
|
78471
78521
|
function createStudioServer(options) {
|
|
78472
78522
|
const { projectDir, projectName } = options;
|
|
78473
|
-
const projectId = projectName ||
|
|
78523
|
+
const projectId = projectName || basename6(projectDir);
|
|
78474
78524
|
const studioDir = resolveDistDir();
|
|
78475
78525
|
const runtimePath = resolveRuntimePath();
|
|
78476
78526
|
const watcher = createProjectWatcher(projectDir);
|
|
@@ -78646,19 +78696,19 @@ function createStudioServer(options) {
|
|
|
78646
78696
|
async installRegistryBlock(opts) {
|
|
78647
78697
|
const { resolveItem: resolveItem2 } = await Promise.resolve().then(() => (init_resolver(), resolver_exports));
|
|
78648
78698
|
const { installItem: installItem2 } = await Promise.resolve().then(() => (init_installer(), installer_exports));
|
|
78649
|
-
const { readFileSync:
|
|
78699
|
+
const { readFileSync: readFileSync59, writeFileSync: writeFileSync40, existsSync: existsSync81 } = await import("fs");
|
|
78650
78700
|
const { join: join92 } = await import("path");
|
|
78651
78701
|
const item = await resolveItem2(opts.blockName);
|
|
78652
78702
|
const { written } = await installItem2(item, { destDir: opts.project.dir });
|
|
78653
78703
|
const indexPath = join92(opts.project.dir, "index.html");
|
|
78654
78704
|
if (existsSync81(indexPath)) {
|
|
78655
|
-
const indexHtml =
|
|
78705
|
+
const indexHtml = readFileSync59(indexPath, "utf-8");
|
|
78656
78706
|
const hostW = indexHtml.match(/data-width="(\d+)"/)?.[1];
|
|
78657
78707
|
const hostH = indexHtml.match(/data-height="(\d+)"/)?.[1];
|
|
78658
78708
|
if (hostW && hostH) {
|
|
78659
78709
|
for (const absPath of written) {
|
|
78660
78710
|
if (!absPath.endsWith(".html")) continue;
|
|
78661
|
-
let content =
|
|
78711
|
+
let content = readFileSync59(absPath, "utf-8");
|
|
78662
78712
|
content = content.replace(
|
|
78663
78713
|
/(<meta\s+name="viewport"\s+content="width=)\d+(,\s*height=)\d+/i,
|
|
78664
78714
|
`$1${hostW}$2${hostH}`
|
|
@@ -78856,14 +78906,14 @@ __export(preview_exports, {
|
|
|
78856
78906
|
});
|
|
78857
78907
|
import { spawn as spawn11 } from "child_process";
|
|
78858
78908
|
import { existsSync as existsSync49, lstatSync as lstatSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync5, readlinkSync, mkdirSync as mkdirSync30 } from "fs";
|
|
78859
|
-
import { resolve as resolve25, dirname as dirname19, basename as
|
|
78909
|
+
import { resolve as resolve25, dirname as dirname19, basename as basename7, join as join59 } from "path";
|
|
78860
78910
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
78861
78911
|
import { createRequire as createRequire2 } from "module";
|
|
78862
78912
|
async function runDevMode(dir, options) {
|
|
78863
78913
|
const thisFile = fileURLToPath6(import.meta.url);
|
|
78864
78914
|
const repoRoot2 = resolve25(dirname19(thisFile), "..", "..", "..", "..");
|
|
78865
78915
|
const projectsDir = join59(repoRoot2, "packages", "studio", "data", "projects");
|
|
78866
|
-
const pName = options?.projectName ??
|
|
78916
|
+
const pName = options?.projectName ?? basename7(dir);
|
|
78867
78917
|
const symlinkPath = join59(projectsDir, pName);
|
|
78868
78918
|
mkdirSync30(projectsDir, { recursive: true });
|
|
78869
78919
|
let createdSymlink = false;
|
|
@@ -78953,7 +79003,7 @@ function hasLocalStudio(dir) {
|
|
|
78953
79003
|
async function runLocalStudioMode(dir, options) {
|
|
78954
79004
|
const req = createRequire2(join59(dir, "package.json"));
|
|
78955
79005
|
const studioPkgPath = dirname19(req.resolve("@hyperframes/studio/package.json"));
|
|
78956
|
-
const pName = options?.projectName ??
|
|
79006
|
+
const pName = options?.projectName ?? basename7(dir);
|
|
78957
79007
|
const projectsDir = join59(studioPkgPath, "data", "projects");
|
|
78958
79008
|
const symlinkPath = join59(projectsDir, pName);
|
|
78959
79009
|
mkdirSync30(projectsDir, { recursive: true });
|
|
@@ -79024,7 +79074,7 @@ async function runLocalStudioMode(dir, options) {
|
|
|
79024
79074
|
}
|
|
79025
79075
|
async function runEmbeddedMode(dir, startPort, options) {
|
|
79026
79076
|
const { createStudioServer: createStudioServer2, loadPreviewServerBuildSignature: loadPreviewServerBuildSignature2, resolveStudioBundle: resolveStudioBundle2 } = await Promise.resolve().then(() => (init_studioServer(), studioServer_exports));
|
|
79027
|
-
const pName = options?.projectName ??
|
|
79077
|
+
const pName = options?.projectName ?? basename7(dir);
|
|
79028
79078
|
const studioBundle = resolveStudioBundle2();
|
|
79029
79079
|
ge(c2.bold("hyperframes preview"));
|
|
79030
79080
|
const s2 = ft();
|
|
@@ -79254,7 +79304,7 @@ var init_preview2 = __esm({
|
|
|
79254
79304
|
const rawArg = args.dir;
|
|
79255
79305
|
const dir = resolve25(rawArg ?? ".");
|
|
79256
79306
|
const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
|
|
79257
|
-
const projectName = isImplicitCwd ?
|
|
79307
|
+
const projectName = isImplicitCwd ? basename7(process.env.PWD ?? dir) : basename7(dir);
|
|
79258
79308
|
const indexPath = join59(dir, "index.html");
|
|
79259
79309
|
if (existsSync49(indexPath)) {
|
|
79260
79310
|
const project = { dir, name: projectName, indexPath };
|
|
@@ -79342,7 +79392,7 @@ import {
|
|
|
79342
79392
|
readFileSync as readFileSync36,
|
|
79343
79393
|
readdirSync as readdirSync21
|
|
79344
79394
|
} from "fs";
|
|
79345
|
-
import { resolve as resolve26, basename as
|
|
79395
|
+
import { resolve as resolve26, basename as basename8, join as join60, dirname as dirname20 } from "path";
|
|
79346
79396
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
79347
79397
|
import { execFileSync as execFileSync5, spawn as spawn12 } from "child_process";
|
|
79348
79398
|
function probeVideo(filePath) {
|
|
@@ -79423,7 +79473,7 @@ function getSharedTemplateDir() {
|
|
|
79423
79473
|
return resolveAssetDir(["..", "templates", "_shared"], ["templates", "_shared"]);
|
|
79424
79474
|
}
|
|
79425
79475
|
function toPackageName(projectName) {
|
|
79426
|
-
const normalized =
|
|
79476
|
+
const normalized = basename8(projectName).trim().toLowerCase().replace(/^[._]+/, "").replace(/[^a-z0-9._~-]+/g, "-").replace(/-+/g, "-").replace(/^[-.]+|[-.]+$/g, "");
|
|
79427
79477
|
return normalized || "hyperframes-project";
|
|
79428
79478
|
}
|
|
79429
79479
|
function getHyperframesPackageSpecifier() {
|
|
@@ -79534,7 +79584,7 @@ async function patchTranscript(dir, transcriptPath) {
|
|
|
79534
79584
|
async function handleVideoFile(videoPath, destDir, interactive) {
|
|
79535
79585
|
const probed = probeVideo(videoPath);
|
|
79536
79586
|
let meta = { ...DEFAULT_META };
|
|
79537
|
-
let localVideoName =
|
|
79587
|
+
let localVideoName = basename8(videoPath);
|
|
79538
79588
|
if (probed) {
|
|
79539
79589
|
meta = probed;
|
|
79540
79590
|
if (interactive) {
|
|
@@ -79884,8 +79934,8 @@ var init_init = __esm({
|
|
|
79884
79934
|
process.exit(1);
|
|
79885
79935
|
}
|
|
79886
79936
|
sourceFilePath2 = audioPath;
|
|
79887
|
-
copyFileSync5(audioPath, resolve26(destDir2,
|
|
79888
|
-
console.log(`Audio: ${
|
|
79937
|
+
copyFileSync5(audioPath, resolve26(destDir2, basename8(audioPath)));
|
|
79938
|
+
console.log(`Audio: ${basename8(audioPath)}`);
|
|
79889
79939
|
}
|
|
79890
79940
|
if (sourceFilePath2 && !skipTranscribe) {
|
|
79891
79941
|
try {
|
|
@@ -79909,7 +79959,7 @@ var init_init = __esm({
|
|
|
79909
79959
|
try {
|
|
79910
79960
|
await scaffoldProject(
|
|
79911
79961
|
destDir2,
|
|
79912
|
-
|
|
79962
|
+
basename8(destDir2),
|
|
79913
79963
|
templateId2,
|
|
79914
79964
|
localVideoName2,
|
|
79915
79965
|
videoDuration2,
|
|
@@ -80016,8 +80066,8 @@ var init_init = __esm({
|
|
|
80016
80066
|
}
|
|
80017
80067
|
mkdirSync31(destDir, { recursive: true });
|
|
80018
80068
|
sourceFilePath = audioPath;
|
|
80019
|
-
copyFileSync5(audioPath, resolve26(destDir,
|
|
80020
|
-
R2.info(`Audio copied to ${c2.accent(
|
|
80069
|
+
copyFileSync5(audioPath, resolve26(destDir, basename8(audioPath)));
|
|
80070
|
+
R2.info(`Audio copied to ${c2.accent(basename8(audioPath))}`);
|
|
80021
80071
|
}
|
|
80022
80072
|
if (sourceFilePath) {
|
|
80023
80073
|
const transcribeChoice = await ue({
|
|
@@ -80579,10 +80629,10 @@ var init_format = __esm({
|
|
|
80579
80629
|
|
|
80580
80630
|
// src/utils/project.ts
|
|
80581
80631
|
import { existsSync as existsSync52, statSync as statSync18 } from "fs";
|
|
80582
|
-
import { resolve as resolve29, basename as
|
|
80632
|
+
import { resolve as resolve29, basename as basename9 } from "path";
|
|
80583
80633
|
function resolveProject(dirArg) {
|
|
80584
80634
|
const dir = resolve29(dirArg ?? ".");
|
|
80585
|
-
const name =
|
|
80635
|
+
const name = basename9(dir);
|
|
80586
80636
|
const indexPath = resolve29(dir, "index.html");
|
|
80587
80637
|
if (!existsSync52(dir) || !statSync18(dir).isDirectory()) {
|
|
80588
80638
|
errorBox("Not a directory: " + dir);
|
|
@@ -80874,7 +80924,7 @@ var init_play = __esm({
|
|
|
80874
80924
|
});
|
|
80875
80925
|
|
|
80876
80926
|
// src/utils/publishProject.ts
|
|
80877
|
-
import { basename as
|
|
80927
|
+
import { basename as basename10, join as join61, relative as relative9 } from "path";
|
|
80878
80928
|
import { readdirSync as readdirSync22, readFileSync as readFileSync38, statSync as statSync19 } from "fs";
|
|
80879
80929
|
import AdmZip from "adm-zip";
|
|
80880
80930
|
function isRecord2(value) {
|
|
@@ -81088,7 +81138,7 @@ async function publishProjectArchiveStaged(apiBaseUrl2, title, archive) {
|
|
|
81088
81138
|
return publishedProject;
|
|
81089
81139
|
}
|
|
81090
81140
|
async function publishProjectArchive(projectDir) {
|
|
81091
|
-
const title =
|
|
81141
|
+
const title = basename10(projectDir);
|
|
81092
81142
|
const archive = createPublishArchive(projectDir);
|
|
81093
81143
|
const apiBaseUrl2 = getPublishApiBaseUrl();
|
|
81094
81144
|
const stagedResult = await publishProjectArchiveStaged(apiBaseUrl2, title, archive);
|
|
@@ -81114,7 +81164,7 @@ __export(publish_exports, {
|
|
|
81114
81164
|
default: () => publish_default,
|
|
81115
81165
|
examples: () => examples6
|
|
81116
81166
|
});
|
|
81117
|
-
import { basename as
|
|
81167
|
+
import { basename as basename11, resolve as resolve31 } from "path";
|
|
81118
81168
|
import { existsSync as existsSync54 } from "fs";
|
|
81119
81169
|
import { join as join62 } from "path";
|
|
81120
81170
|
var examples6, publish_default;
|
|
@@ -81150,7 +81200,7 @@ var init_publish = __esm({
|
|
|
81150
81200
|
const rawArg = args.dir;
|
|
81151
81201
|
const dir = resolve31(rawArg ?? ".");
|
|
81152
81202
|
const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
|
|
81153
|
-
const projectName = isImplicitCwd ?
|
|
81203
|
+
const projectName = isImplicitCwd ? basename11(process.env["PWD"] ?? dir) : basename11(dir);
|
|
81154
81204
|
const indexPath = join62(dir, "index.html");
|
|
81155
81205
|
if (existsSync54(indexPath)) {
|
|
81156
81206
|
const lintResult = await lintProject({ dir, name: projectName, indexPath });
|
|
@@ -81573,7 +81623,7 @@ __export(render_exports, {
|
|
|
81573
81623
|
});
|
|
81574
81624
|
import { mkdirSync as mkdirSync32, readdirSync as readdirSync23, readFileSync as readFileSync40, statSync as statSync20, writeFileSync as writeFileSync27, rmSync as rmSync14 } from "fs";
|
|
81575
81625
|
import { cpus as cpus4, freemem as freemem4, tmpdir as tmpdir5 } from "os";
|
|
81576
|
-
import { resolve as resolve33, dirname as dirname22, join as join63, basename as
|
|
81626
|
+
import { resolve as resolve33, dirname as dirname22, join as join63, basename as basename12 } from "path";
|
|
81577
81627
|
import { execFileSync as execFileSync6, spawn as spawn13 } from "child_process";
|
|
81578
81628
|
function formatFpsParseError(input2, reason) {
|
|
81579
81629
|
switch (reason) {
|
|
@@ -81677,7 +81727,7 @@ async function renderDocker(projectDir, outputPath, options) {
|
|
|
81677
81727
|
process.exit(1);
|
|
81678
81728
|
}
|
|
81679
81729
|
const outputDir = dirname22(outputPath);
|
|
81680
|
-
const outputFilename =
|
|
81730
|
+
const outputFilename = basename12(outputPath);
|
|
81681
81731
|
const dockerArgs = buildDockerRunArgs({
|
|
81682
81732
|
imageTag,
|
|
81683
81733
|
projectDir: resolve33(projectDir),
|
|
@@ -84666,7 +84716,7 @@ __export(synthesize_exports, {
|
|
|
84666
84716
|
});
|
|
84667
84717
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
84668
84718
|
import { existsSync as existsSync63, writeFileSync as writeFileSync29, mkdirSync as mkdirSync35, readdirSync as readdirSync25, unlinkSync as unlinkSync6 } from "fs";
|
|
84669
|
-
import { join as join70, dirname as dirname26, basename as
|
|
84719
|
+
import { join as join70, dirname as dirname26, basename as basename13 } from "path";
|
|
84670
84720
|
import { homedir as homedir11 } from "os";
|
|
84671
84721
|
function findPython() {
|
|
84672
84722
|
for (const name of ["python3", "python"]) {
|
|
@@ -84705,7 +84755,7 @@ function ensureSynthScript() {
|
|
|
84705
84755
|
if (!existsSync63(SCRIPT_PATH)) {
|
|
84706
84756
|
mkdirSync35(SCRIPT_DIR, { recursive: true });
|
|
84707
84757
|
writeFileSync29(SCRIPT_PATH, SYNTH_SCRIPT);
|
|
84708
|
-
const currentName =
|
|
84758
|
+
const currentName = basename13(SCRIPT_PATH);
|
|
84709
84759
|
try {
|
|
84710
84760
|
for (const entry of readdirSync25(SCRIPT_DIR)) {
|
|
84711
84761
|
if (entry !== currentName && /^synth(-v\d+)?\.py$/.test(entry)) {
|
|
@@ -85977,7 +86027,7 @@ __export(contactSheet_exports, {
|
|
|
85977
86027
|
});
|
|
85978
86028
|
import sharp from "sharp";
|
|
85979
86029
|
import { readdirSync as readdirSync26, readFileSync as readFileSync48, writeFileSync as writeFileSync30, unlinkSync as unlinkSync7, existsSync as existsSync67 } from "fs";
|
|
85980
|
-
import { join as join73, extname as extname13, basename as
|
|
86030
|
+
import { join as join73, extname as extname13, basename as basename14, dirname as dirname29 } from "path";
|
|
85981
86031
|
async function createContactSheet(imagePaths, outputPath, opts = {}) {
|
|
85982
86032
|
const {
|
|
85983
86033
|
cols = 3,
|
|
@@ -86010,7 +86060,7 @@ async function createContactSheet(imagePaths, outputPath, opts = {}) {
|
|
|
86010
86060
|
overlays.push({ input: resized, left: x3, top: y + labelH });
|
|
86011
86061
|
let labelText = `${i2 + 1}`;
|
|
86012
86062
|
if (labelMode === "filename") {
|
|
86013
|
-
labelText = `${i2 + 1}. ${
|
|
86063
|
+
labelText = `${i2 + 1}. ${basename14(files[i2]).replace(extname13(files[i2]), "")}`;
|
|
86014
86064
|
} else if (labelMode === "custom" && labels?.[i2]) {
|
|
86015
86065
|
labelText = `${i2 + 1}. ${labels[i2]}`;
|
|
86016
86066
|
}
|
|
@@ -93108,7 +93158,7 @@ var require_node_domexception = __commonJS({
|
|
|
93108
93158
|
|
|
93109
93159
|
// ../../node_modules/.bun/fetch-blob@3.2.0/node_modules/fetch-blob/from.js
|
|
93110
93160
|
import { statSync as statSync23, createReadStream as createReadStream2, promises as fs2 } from "fs";
|
|
93111
|
-
import { basename as
|
|
93161
|
+
import { basename as basename15 } from "path";
|
|
93112
93162
|
var import_node_domexception, stat, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
|
|
93113
93163
|
var init_from = __esm({
|
|
93114
93164
|
"../../node_modules/.bun/fetch-blob@3.2.0/node_modules/fetch-blob/from.js"() {
|
|
@@ -93132,7 +93182,7 @@ var init_from = __esm({
|
|
|
93132
93182
|
size: stat3.size,
|
|
93133
93183
|
lastModified: stat3.mtimeMs,
|
|
93134
93184
|
start: 0
|
|
93135
|
-
})],
|
|
93185
|
+
})], basename15(path2), { type, lastModified: stat3.mtimeMs });
|
|
93136
93186
|
BlobDataItem = class _BlobDataItem {
|
|
93137
93187
|
#path;
|
|
93138
93188
|
#start;
|
|
@@ -131866,6 +131916,57 @@ ${HELP}`);
|
|
|
131866
131916
|
}
|
|
131867
131917
|
});
|
|
131868
131918
|
|
|
131919
|
+
// src/cloud/detectAspectRatio.ts
|
|
131920
|
+
import { readFileSync as readFileSync58 } from "fs";
|
|
131921
|
+
function extractAttributeNumber(tag, re2) {
|
|
131922
|
+
const match = tag.match(re2);
|
|
131923
|
+
if (!match) return null;
|
|
131924
|
+
const raw = match[1] ?? match[2] ?? match[3];
|
|
131925
|
+
if (raw === void 0) return null;
|
|
131926
|
+
const value = Number(raw);
|
|
131927
|
+
return Number.isFinite(value) ? value : null;
|
|
131928
|
+
}
|
|
131929
|
+
function detectAspectRatioFromHtml(entryHtmlPath) {
|
|
131930
|
+
let html;
|
|
131931
|
+
try {
|
|
131932
|
+
html = readFileSync58(entryHtmlPath, "utf-8");
|
|
131933
|
+
} catch (err) {
|
|
131934
|
+
return { kind: "read-error", error: err instanceof Error ? err.message : String(err) };
|
|
131935
|
+
}
|
|
131936
|
+
return detectAspectRatioFromHtmlString(html);
|
|
131937
|
+
}
|
|
131938
|
+
function detectAspectRatioFromHtmlString(html) {
|
|
131939
|
+
const tagMatch = html.match(ROOT_COMPOSITION_DIV_RE);
|
|
131940
|
+
if (!tagMatch) return { kind: "no-root-div" };
|
|
131941
|
+
const openTag = tagMatch[0];
|
|
131942
|
+
const width = extractAttributeNumber(openTag, DATA_WIDTH_RE);
|
|
131943
|
+
const height = extractAttributeNumber(openTag, DATA_HEIGHT_RE);
|
|
131944
|
+
if (width === null || height === null) return { kind: "no-dims" };
|
|
131945
|
+
if (width <= 0 || height <= 0) return { kind: "invalid-dims", width, height };
|
|
131946
|
+
const ratio = width / height;
|
|
131947
|
+
for (const candidate of SUPPORTED_RATIOS) {
|
|
131948
|
+
if (Math.abs(ratio - candidate.ratio) <= RATIO_TOLERANCE) {
|
|
131949
|
+
return { kind: "matched", aspectRatio: candidate.value, width, height };
|
|
131950
|
+
}
|
|
131951
|
+
}
|
|
131952
|
+
return { kind: "no-match", width, height, ratio };
|
|
131953
|
+
}
|
|
131954
|
+
var RATIO_TOLERANCE, SUPPORTED_RATIOS, ROOT_COMPOSITION_DIV_RE, DATA_WIDTH_RE, DATA_HEIGHT_RE;
|
|
131955
|
+
var init_detectAspectRatio = __esm({
|
|
131956
|
+
"src/cloud/detectAspectRatio.ts"() {
|
|
131957
|
+
"use strict";
|
|
131958
|
+
RATIO_TOLERANCE = 0.05;
|
|
131959
|
+
SUPPORTED_RATIOS = [
|
|
131960
|
+
{ value: "16:9", ratio: 16 / 9 },
|
|
131961
|
+
{ value: "9:16", ratio: 9 / 16 },
|
|
131962
|
+
{ value: "1:1", ratio: 1 }
|
|
131963
|
+
];
|
|
131964
|
+
ROOT_COMPOSITION_DIV_RE = /<div\b[^>]*?\bdata-composition-id\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)[^>]*>/i;
|
|
131965
|
+
DATA_WIDTH_RE = /\bdata-width\s*=\s*(?:"(\d+(?:\.\d+)?)"|'(\d+(?:\.\d+)?)'|(\d+(?:\.\d+)?))(?=\s|>|\/)/i;
|
|
131966
|
+
DATA_HEIGHT_RE = /\bdata-height\s*=\s*(?:"(\d+(?:\.\d+)?)"|'(\d+(?:\.\d+)?)'|(\d+(?:\.\d+)?))(?=\s|>|\/)/i;
|
|
131967
|
+
}
|
|
131968
|
+
});
|
|
131969
|
+
|
|
131869
131970
|
// src/cloud/poll.ts
|
|
131870
131971
|
function isTerminal(status) {
|
|
131871
131972
|
return TERMINAL_STATUSES.has(status);
|
|
@@ -133321,6 +133422,40 @@ function resolveProjectInput(opts) {
|
|
|
133321
133422
|
if (explicit.url) return { kind: "url", url: opts.url };
|
|
133322
133423
|
return { kind: "dir", dir: opts.dir ?? "." };
|
|
133323
133424
|
}
|
|
133425
|
+
function maybeAutoDetectAspectRatio(project, compositionArg, asJson) {
|
|
133426
|
+
if (project.kind !== "dir") {
|
|
133427
|
+
const reason = project.kind === "asset_id" ? "--asset-id" : "--url";
|
|
133428
|
+
logDetection(asJson, `Auto-detect skipped (project is ${reason})`);
|
|
133429
|
+
return void 0;
|
|
133430
|
+
}
|
|
133431
|
+
const dir = project.dir ?? ".";
|
|
133432
|
+
const entryRelative = compositionArg ?? "index.html";
|
|
133433
|
+
const entryPath = resolvePath4(dir, entryRelative);
|
|
133434
|
+
const detection = detectAspectRatioFromHtml(entryPath);
|
|
133435
|
+
logDetection(asJson, summarizeDetection(detection, entryRelative));
|
|
133436
|
+
return detection.kind === "matched" ? detection.aspectRatio : void 0;
|
|
133437
|
+
}
|
|
133438
|
+
function logDetection(asJson, message) {
|
|
133439
|
+
if (asJson) return;
|
|
133440
|
+
const suffix = message.startsWith("Detected aspect ratio") ? "" : `; ${ASPECT_FALLBACK_HINT}`;
|
|
133441
|
+
console.log(c2.dim(` ${message}${suffix}`));
|
|
133442
|
+
}
|
|
133443
|
+
function summarizeDetection(detection, entryRelative) {
|
|
133444
|
+
switch (detection.kind) {
|
|
133445
|
+
case "matched":
|
|
133446
|
+
return `Detected aspect ratio: ${detection.aspectRatio} (from ${entryRelative} dims ${detection.width}\xD7${detection.height})`;
|
|
133447
|
+
case "no-root-div":
|
|
133448
|
+
return `No <div data-composition-id> found in ${entryRelative}`;
|
|
133449
|
+
case "no-dims":
|
|
133450
|
+
return `${entryRelative} root composition has no data-width / data-height`;
|
|
133451
|
+
case "invalid-dims":
|
|
133452
|
+
return `${entryRelative} root has invalid dims (${detection.width}\xD7${detection.height})`;
|
|
133453
|
+
case "no-match":
|
|
133454
|
+
return `${entryRelative} dims ${detection.width}\xD7${detection.height} (ratio ${detection.ratio.toFixed(2)}) don't match 16:9, 9:16, or 1:1`;
|
|
133455
|
+
case "read-error":
|
|
133456
|
+
return `Couldn't read ${entryRelative} for aspect-ratio detection (${detection.error})`;
|
|
133457
|
+
}
|
|
133458
|
+
}
|
|
133324
133459
|
function resolveVariablesAndValidateIfLocal(inline, filePath, strict, source) {
|
|
133325
133460
|
const variables = resolveVariablesArg(inline, filePath);
|
|
133326
133461
|
if (!variables || Object.keys(variables).length === 0) return variables;
|
|
@@ -133398,6 +133533,7 @@ function buildRenderBody(opts) {
|
|
|
133398
133533
|
if (opts.quality !== void 0) body.quality = opts.quality;
|
|
133399
133534
|
if (opts.format !== void 0) body.format = opts.format;
|
|
133400
133535
|
if (opts.resolution !== void 0) body.resolution = opts.resolution;
|
|
133536
|
+
if (opts.aspectRatio !== void 0) body.aspect_ratio = opts.aspectRatio;
|
|
133401
133537
|
if (opts.composition !== void 0) body.composition = opts.composition;
|
|
133402
133538
|
if (opts.variables !== void 0) body.variables = opts.variables;
|
|
133403
133539
|
if (opts.title !== void 0) body.title = opts.title;
|
|
@@ -133490,11 +133626,12 @@ async function streamVideo(url, destPath, asJson) {
|
|
|
133490
133626
|
process.exit(1);
|
|
133491
133627
|
}
|
|
133492
133628
|
}
|
|
133493
|
-
var VALID_QUALITY2, VALID_FORMAT2, VALID_RESOLUTION, FORMAT_EXT2, examples26, render_default2, IDEMPOTENCY_KEY_RE;
|
|
133629
|
+
var VALID_QUALITY2, VALID_FORMAT2, VALID_RESOLUTION, VALID_ASPECT_RATIO, FORMAT_EXT2, examples26, render_default2, IDEMPOTENCY_KEY_RE, ASPECT_FALLBACK_HINT;
|
|
133494
133630
|
var init_render4 = __esm({
|
|
133495
133631
|
"src/commands/cloud/render.ts"() {
|
|
133496
133632
|
"use strict";
|
|
133497
133633
|
init_dist();
|
|
133634
|
+
init_detectAspectRatio();
|
|
133498
133635
|
init_colors();
|
|
133499
133636
|
init_format();
|
|
133500
133637
|
init_project();
|
|
@@ -133507,14 +133644,8 @@ var init_render4 = __esm({
|
|
|
133507
133644
|
init_statusColor();
|
|
133508
133645
|
VALID_QUALITY2 = ["draft", "standard", "high"];
|
|
133509
133646
|
VALID_FORMAT2 = ["mp4", "webm", "mov"];
|
|
133510
|
-
VALID_RESOLUTION = [
|
|
133511
|
-
|
|
133512
|
-
"portrait",
|
|
133513
|
-
"landscape-4k",
|
|
133514
|
-
"portrait-4k",
|
|
133515
|
-
"square",
|
|
133516
|
-
"square-4k"
|
|
133517
|
-
];
|
|
133647
|
+
VALID_RESOLUTION = ["1080p", "4k"];
|
|
133648
|
+
VALID_ASPECT_RATIO = ["16:9", "9:16", "1:1"];
|
|
133518
133649
|
FORMAT_EXT2 = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
133519
133650
|
examples26 = [
|
|
133520
133651
|
["Render the current directory in the cloud", "hyperframes cloud render"],
|
|
@@ -133542,7 +133673,11 @@ var init_render4 = __esm({
|
|
|
133542
133673
|
format: { type: "string", description: "mp4 | webm | mov (default: mp4)" },
|
|
133543
133674
|
resolution: {
|
|
133544
133675
|
type: "string",
|
|
133545
|
-
description: "Resolution
|
|
133676
|
+
description: "Resolution tier: 1080p | 4k (default: 1080p; 4k is billed at 1.5x)"
|
|
133677
|
+
},
|
|
133678
|
+
"aspect-ratio": {
|
|
133679
|
+
type: "string",
|
|
133680
|
+
description: "Aspect ratio: 16:9 | 9:16 | 1:1 (default: 16:9)"
|
|
133546
133681
|
},
|
|
133547
133682
|
composition: {
|
|
133548
133683
|
type: "string",
|
|
@@ -133625,6 +133760,9 @@ var init_render4 = __esm({
|
|
|
133625
133760
|
const resolution = parseEnumFlag(args.resolution, VALID_RESOLUTION, {
|
|
133626
133761
|
flag: "--resolution"
|
|
133627
133762
|
});
|
|
133763
|
+
const explicitAspectRatio = parseEnumFlag(args["aspect-ratio"], VALID_ASPECT_RATIO, {
|
|
133764
|
+
flag: "--aspect-ratio"
|
|
133765
|
+
});
|
|
133628
133766
|
const pollIntervalMs = parsePollIntervalMs(args["poll-interval"]);
|
|
133629
133767
|
const maxWaitMs = parseMaxWaitMs(args["max-wait"]);
|
|
133630
133768
|
validateIdempotencyKey(args["idempotency-key"]);
|
|
@@ -133633,6 +133771,7 @@ var init_render4 = __esm({
|
|
|
133633
133771
|
assetId: args["asset-id"],
|
|
133634
133772
|
url: args.url
|
|
133635
133773
|
});
|
|
133774
|
+
const aspectRatio = explicitAspectRatio ?? maybeAutoDetectAspectRatio(project, args.composition, asJson);
|
|
133636
133775
|
const variables = resolveVariablesAndValidateIfLocal(
|
|
133637
133776
|
args.variables,
|
|
133638
133777
|
args["variables-file"],
|
|
@@ -133647,6 +133786,7 @@ var init_render4 = __esm({
|
|
|
133647
133786
|
quality,
|
|
133648
133787
|
format,
|
|
133649
133788
|
resolution,
|
|
133789
|
+
aspectRatio,
|
|
133650
133790
|
composition: args.composition,
|
|
133651
133791
|
variables,
|
|
133652
133792
|
title: args.title,
|
|
@@ -133707,6 +133847,7 @@ var init_render4 = __esm({
|
|
|
133707
133847
|
}
|
|
133708
133848
|
});
|
|
133709
133849
|
IDEMPOTENCY_KEY_RE = /^[A-Za-z0-9_:.-]{1,255}$/;
|
|
133850
|
+
ASPECT_FALLBACK_HINT = "server will default aspect_ratio to 16:9. Pass --aspect-ratio to override.";
|
|
133710
133851
|
}
|
|
133711
133852
|
});
|
|
133712
133853
|
|
|
@@ -135091,10 +135232,10 @@ if (rootVersionRequested) {
|
|
|
135091
135232
|
process.exit(0);
|
|
135092
135233
|
}
|
|
135093
135234
|
try {
|
|
135094
|
-
const { readFileSync:
|
|
135235
|
+
const { readFileSync: readFileSync59 } = await import("fs");
|
|
135095
135236
|
const { resolve: resolve46 } = await import("path");
|
|
135096
135237
|
const envPath = resolve46(process.cwd(), ".env");
|
|
135097
|
-
const envContent =
|
|
135238
|
+
const envContent = readFileSync59(envPath, "utf-8");
|
|
135098
135239
|
for (const rawLine of envContent.split("\n")) {
|
|
135099
135240
|
let line = rawLine.trim();
|
|
135100
135241
|
if (!line || line.startsWith("#")) continue;
|
|
@@ -181,38 +181,23 @@ The slide distance DECAYS per word (80→12px) — mimics a camera settling.
|
|
|
181
181
|
Vector animations that play inside a composition. Use for logos, character animations, icons.
|
|
182
182
|
|
|
183
183
|
```html
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
The element tag is <dotlottie-wc>. -->
|
|
187
|
-
<script
|
|
188
|
-
src="https://cdn.jsdelivr.net/npm/@lottiefiles/dotlottie-wc/dist/dotlottie-wc.js"
|
|
189
|
-
type="module"
|
|
190
|
-
></script>
|
|
191
|
-
<dotlottie-wc
|
|
192
|
-
class="lottie"
|
|
193
|
-
src="capture/assets/lottie/animation-0.json"
|
|
194
|
-
autoplay
|
|
195
|
-
loop
|
|
196
|
-
speed="1.5"
|
|
197
|
-
style="width:500px;height:500px;"
|
|
198
|
-
>
|
|
199
|
-
</dotlottie-wc>
|
|
184
|
+
<div id="anim" class="lottie"></div>
|
|
185
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.12.2/lottie.min.js"></script>
|
|
200
186
|
<script>
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
187
|
+
window.__hfLottie = window.__hfLottie || [];
|
|
188
|
+
|
|
189
|
+
const anim = lottie.loadAnimation({
|
|
190
|
+
container: document.getElementById("anim"),
|
|
191
|
+
renderer: "svg",
|
|
192
|
+
loop: false,
|
|
193
|
+
autoplay: false,
|
|
194
|
+
path: "capture/assets/lottie/animation-0.json",
|
|
195
|
+
});
|
|
196
|
+
window.__hfLottie.push(anim);
|
|
207
197
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
renderer: "svg",
|
|
212
|
-
loop: false,
|
|
213
|
-
autoplay: false,
|
|
214
|
-
path: "capture/assets/lottie/animation-0.json",
|
|
215
|
-
});
|
|
198
|
+
gsap.set("#anim", { scale: 0.3, opacity: 0 });
|
|
199
|
+
tl.to("#anim", { scale: 1, opacity: 1, duration: 0.35, ease: "back.out(1.6)" }, 0.2);
|
|
200
|
+
</script>
|
|
216
201
|
```
|
|
217
202
|
|
|
218
203
|
---
|