@mevdragon/vidfarm-devcli 0.17.0 → 0.18.1
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/.agents/skills/vidfarm-media/SKILL.md +43 -6
- package/SKILL.director.md +37 -23
- package/SKILL.platform.md +6 -6
- package/demo/dist/app.js +69 -69
- package/demo/dist/favicon.ico +0 -0
- package/dist/src/app.js +1832 -213
- package/dist/src/cli.js +238 -17
- package/dist/src/devcli/clip-store.js +29 -2
- package/dist/src/devcli/clips.js +116 -73
- package/dist/src/devcli/composition-edit.js +262 -0
- package/dist/src/devcli/timeline-edit.js +283 -0
- package/dist/src/editor-chat.js +29 -6
- package/dist/src/frontend/discover-client.js +130 -0
- package/dist/src/frontend/discover-store.js +23 -0
- package/dist/src/frontend/file-directory.js +744 -0
- package/dist/src/frontend/template-editor-chat.js +22 -19
- package/dist/src/landing-page.js +24 -7
- package/dist/src/page-shell.js +25 -1
- package/dist/src/reskin/agency-page.js +214 -170
- package/dist/src/reskin/calendar-page.js +503 -187
- package/dist/src/reskin/chat-page.js +739 -299
- package/dist/src/reskin/discover-page.js +1450 -279
- package/dist/src/reskin/document.js +1392 -16
- package/dist/src/reskin/help-page.js +139 -100
- package/dist/src/reskin/index-page.js +1 -1
- package/dist/src/reskin/inpaint-page.js +547 -0
- package/dist/src/reskin/job-runs-page.js +355 -127
- package/dist/src/reskin/library-page.js +1188 -317
- package/dist/src/reskin/login-page.js +124 -87
- package/dist/src/reskin/pricing-page.js +197 -166
- package/dist/src/reskin/settings-page.js +566 -187
- package/dist/src/reskin/theme.js +434 -17
- package/dist/src/services/clip-curation/gemini.js +5 -0
- package/dist/src/services/clip-curation/hunt.js +79 -1
- package/dist/src/services/clip-curation/index.js +2 -1
- package/dist/src/services/clip-curation/local-agent.js +4 -3
- package/dist/src/services/clip-curation/media-select.js +85 -0
- package/dist/src/services/clip-curation/query.js +5 -1
- package/dist/src/services/clip-curation/refine.js +50 -20
- package/dist/src/services/clip-curation/scan.js +10 -3
- package/dist/src/services/clip-curation/taxonomy.js +3 -1
- package/dist/src/services/clip-curation/taxonomy.v1.json +13 -1
- package/dist/src/services/clip-records.js +14 -1
- package/dist/src/services/clip-search.js +43 -13
- package/dist/src/services/file-directory.js +114 -0
- package/dist/src/services/storage.js +24 -1
- package/dist/src/services/upstream.js +5 -5
- package/dist/src/template-editor-shell.js +16 -2
- package/package.json +1 -1
- package/public/assets/discover-client-app.js +1 -0
- package/public/assets/file-directory-app.js +2 -0
- package/public/assets/homepage-client-app.js +12 -12
- package/public/assets/page-runtime-client-app.js +24 -24
- package/src/assets/favicon.ico +0 -0
- package/src/assets/logo-vidfarm.png +0 -0
|
@@ -2,6 +2,24 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { memo, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
import { debugError, debugLog, debugWarn } from "./debug.js";
|
|
5
|
+
// Parse the fork id out of the canonical editor path
|
|
6
|
+
// /editor/<template_id>/fork/<fork_id> → "<fork_id>" (else null). The editor
|
|
7
|
+
// URL scheme moved from ?fork= to a path segment; this reads the new form.
|
|
8
|
+
function forkIdFromLocation() {
|
|
9
|
+
if (typeof window === "undefined")
|
|
10
|
+
return null;
|
|
11
|
+
try {
|
|
12
|
+
const match = new URL(window.location.href).pathname.match(/^\/editor\/[^/]+\/fork\/([^/]+)\/?$/);
|
|
13
|
+
if (!match)
|
|
14
|
+
return null;
|
|
15
|
+
const forkId = decodeURIComponent(match[1]);
|
|
16
|
+
// /editor/original/fork/new (blank new project) has no real fork yet.
|
|
17
|
+
return forkId === "new" ? null : forkId;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
5
23
|
const MB = 1024 * 1024;
|
|
6
24
|
const MY_FILES_UPLOAD_LIMIT_BYTES = 50 * MB;
|
|
7
25
|
const CHAT_INLINE_IMAGE_TARGET_BYTES = 2 * MB;
|
|
@@ -2417,25 +2435,10 @@ export function TemplateEditorChat({ boot }) {
|
|
|
2417
2435
|
useEffect(() => {
|
|
2418
2436
|
threadsRef.current = threads;
|
|
2419
2437
|
}, [threads]);
|
|
2420
|
-
const [currentForkId, setCurrentForkId] = useState(() =>
|
|
2421
|
-
if (typeof window === "undefined") {
|
|
2422
|
-
return null;
|
|
2423
|
-
}
|
|
2424
|
-
try {
|
|
2425
|
-
return new URL(window.location.href).searchParams.get("fork");
|
|
2426
|
-
}
|
|
2427
|
-
catch {
|
|
2428
|
-
return null;
|
|
2429
|
-
}
|
|
2430
|
-
});
|
|
2438
|
+
const [currentForkId, setCurrentForkId] = useState(() => forkIdFromLocation());
|
|
2431
2439
|
useEffect(() => {
|
|
2432
2440
|
const syncForkFromLocation = () => {
|
|
2433
|
-
|
|
2434
|
-
setCurrentForkId(new URL(window.location.href).searchParams.get("fork"));
|
|
2435
|
-
}
|
|
2436
|
-
catch {
|
|
2437
|
-
setCurrentForkId(null);
|
|
2438
|
-
}
|
|
2441
|
+
setCurrentForkId(forkIdFromLocation());
|
|
2439
2442
|
};
|
|
2440
2443
|
window.addEventListener("popstate", syncForkFromLocation);
|
|
2441
2444
|
return () => {
|
|
@@ -3704,7 +3707,7 @@ export function TemplateEditorChat({ boot }) {
|
|
|
3704
3707
|
if (!forkRes.ok)
|
|
3705
3708
|
throw new Error(fork?.error || `couldn't create an editable copy (${forkRes.status})`);
|
|
3706
3709
|
const forkId = fork?.fork_id;
|
|
3707
|
-
const editorUrl = `${origin}/editor/${encodeURIComponent(templateId)}${forkId ?
|
|
3710
|
+
const editorUrl = `${origin}/editor/${encodeURIComponent(templateId)}${forkId ? `/fork/${encodeURIComponent(forkId)}` : ""}`;
|
|
3708
3711
|
patch("Your video is ready.", `✅ Your video is ready — [Open it in the editor](${editorUrl}).`);
|
|
3709
3712
|
}
|
|
3710
3713
|
catch (error) {
|
|
@@ -4142,7 +4145,7 @@ export function TemplateEditorChat({ boot }) {
|
|
|
4142
4145
|
left: openThreadMenu.left
|
|
4143
4146
|
}, onClick: (event) => event.stopPropagation(), children: [_jsx("button", { type: "button", onClick: () => copyThreadId(openThreadMenuThread.id), children: "Copy Chat ID" }), _jsx("button", { type: "button", onClick: () => editThreadTracers(openThreadMenuThread.id), children: "Edit tracers" }), _jsx("button", { type: "button", onClick: () => removeThreadFromView(openThreadMenuThread.id), children: "Remove from view" }), _jsx("button", { type: "button", onClick: () => archiveThread(openThreadMenuThread.id), children: "Archive thread" }), _jsx("button", { type: "button", "data-danger": "true", onClick: () => deleteThread(openThreadMenuThread.id), children: "Delete" })] }), document.body) : null] }), _jsx("div", { className: "vf-editor-chat-viewport", ref: viewportRef, children: showHistoryPanel ? (_jsx("div", { className: "vf-editor-chat-history-panel", children: threadListContent })) : showBranchesPanel ? (_jsxs("div", { className: "vf-editor-chat-history-panel vf-editor-chat-branches-panel", children: [_jsxs("div", { className: "vf-editor-chat-branches-header", children: [_jsxs("div", { className: "vf-editor-chat-branches-header-main", children: [_jsx("div", { className: "vf-editor-chat-branches-kicker", children: "Forks" }), _jsxs("div", { className: "vf-editor-chat-branches-title", children: [branches?.length ?? 0, " fork", (branches?.length ?? 0) === 1 ? "" : "s", " of this template"] })] }), _jsx("button", { type: "button", className: "vf-editor-chat-branches-refresh", onClick: () => { void loadBranches({ force: true }); }, disabled: branchesLoading, "aria-label": "Refresh forks", children: branchesLoading ? "Loading…" : "Refresh" })] }), branchesError ? (_jsx("div", { className: "vf-editor-chat-thread-empty", role: "status", children: branchesError })) : branchesLoading && !branches ? (_jsx("div", { className: "vf-editor-chat-thread-empty", children: "Loading forks\u2026" })) : branches && branches.length ? (_jsx("div", { className: "vf-editor-chat-thread-list", children: branches.map((fork) => {
|
|
4144
4147
|
const isCurrent = currentForkId === fork.forkId;
|
|
4145
|
-
const forkUrl = `/editor/${encodeURIComponent(boot.template.templateId)}
|
|
4148
|
+
const forkUrl = `/editor/${encodeURIComponent(boot.template.templateId)}/fork/${encodeURIComponent(fork.forkId)}`;
|
|
4146
4149
|
const label = fork.title && fork.title.trim() ? fork.title : fork.forkId;
|
|
4147
4150
|
const parentSuffix = fork.parentForkId ? ` · forked from ${fork.parentForkId.slice(0, 12)}${fork.parentVersion ? `#v${fork.parentVersion}` : ""}` : "";
|
|
4148
4151
|
const versionSuffix = fork.latestVersion && fork.latestVersion > 0 ? ` · v${fork.latestVersion}` : "";
|
package/dist/src/landing-page.js
CHANGED
|
@@ -33,8 +33,24 @@ export function renderLandingPage(input) {
|
|
|
33
33
|
<head>
|
|
34
34
|
<meta charset="utf-8">
|
|
35
35
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
36
|
-
<title>
|
|
37
|
-
<meta name="description" content="Fork a proven short-form template, remix it on the timeline, and render a share-ready MP4 — all in your browser.
|
|
36
|
+
<title>VidFarm — short-form video that makes itself</title>
|
|
37
|
+
<meta name="description" content="Fork a proven short-form template, remix it on the timeline, and render a share-ready MP4 — all in your browser. VidFarm is the serverless video studio that scales to zero.">
|
|
38
|
+
<meta name="theme-color" content="#171717">
|
|
39
|
+
<meta name="robots" content="index, follow">
|
|
40
|
+
<meta name="application-name" content="VidFarm">
|
|
41
|
+
<link rel="canonical" href="https://vidfarm.cc/">
|
|
42
|
+
<meta property="og:type" content="website">
|
|
43
|
+
<meta property="og:site_name" content="VidFarm">
|
|
44
|
+
<meta property="og:title" content="VidFarm — short-form video that makes itself">
|
|
45
|
+
<meta property="og:description" content="Fork a proven short-form template, remix it on the timeline, and render a share-ready MP4 — all in your browser. VidFarm is the serverless video studio that scales to zero.">
|
|
46
|
+
<meta property="og:url" content="https://vidfarm.cc/">
|
|
47
|
+
<meta property="og:image" content="https://vidfarm.cc/assets/logo-vidfarm.png">
|
|
48
|
+
<meta name="twitter:card" content="summary_large_image">
|
|
49
|
+
<meta name="twitter:title" content="VidFarm — short-form video that makes itself">
|
|
50
|
+
<meta name="twitter:description" content="Fork a proven short-form template, remix it on the timeline, and render a share-ready MP4 — all in your browser. VidFarm is the serverless video studio that scales to zero.">
|
|
51
|
+
<meta name="twitter:image" content="https://vidfarm.cc/assets/logo-vidfarm.png">
|
|
52
|
+
<link rel="icon" href="/assets/favicon.ico" sizes="any">
|
|
53
|
+
<link rel="apple-touch-icon" href="/assets/logo-vidfarm.png">
|
|
38
54
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
39
55
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
40
56
|
<link href="https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;600;700;800&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
@@ -80,7 +96,7 @@ h1,h2,h3,h4{font-family:var(--font-display);font-weight:800;letter-spacing:-.025
|
|
|
80
96
|
.glass{background:rgba(255,255,255,.72);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border:1px solid var(--border);box-shadow:var(--shadow-nav)}
|
|
81
97
|
.nav{width:min(var(--container),100%);display:flex;align-items:center;gap:24px;padding:10px 12px 10px 22px;border-radius:var(--r-full)}
|
|
82
98
|
.brand{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-display);font-weight:800;font-size:22px;color:var(--ink);letter-spacing:-.02em}
|
|
83
|
-
.brand-mark{width:
|
|
99
|
+
.brand-mark{display:inline-block;vertical-align:middle;width:48px;height:48px;border-radius:12px;background:center/contain no-repeat url("/assets/logo-vidfarm.png");font-size:0;color:transparent;text-indent:-9999px;overflow:hidden}
|
|
84
100
|
.nav-links{display:flex;gap:2px;margin:0 auto;list-style:none}
|
|
85
101
|
.nav-links a{display:inline-flex;align-items:center;gap:4px;padding:8px 12px;border-radius:var(--r-lg);font-size:15px;font-weight:500;color:var(--n-700);transition:background var(--dur) var(--ease)}
|
|
86
102
|
.nav-links a:hover{background:#0000000a}
|
|
@@ -186,7 +202,8 @@ h1,h2,h3,h4{font-family:var(--font-display);font-weight:800;letter-spacing:-.025
|
|
|
186
202
|
.footer-inner{width:min(var(--container),100%);margin:0 auto}
|
|
187
203
|
.footer-top{display:grid;grid-template-columns:1.4fr 3fr;gap:40px;margin-bottom:40px}
|
|
188
204
|
@media(max-width:820px){.footer-top{grid-template-columns:1fr}}
|
|
189
|
-
.footer-brand{font-family:var(--font-display);font-weight:800;font-size:28px;color:var(--gold-500);display:inline-flex;align-items:center;gap:
|
|
205
|
+
.footer-brand{font-family:var(--font-display);font-weight:800;font-size:28px;color:var(--gold-500);display:inline-flex;align-items:center;gap:12px}
|
|
206
|
+
.footer-brand .brand-mark{width:60px;height:60px;border-radius:14px}
|
|
190
207
|
.footer-tagline{color:var(--n-500);margin-top:10px;max-width:280px}
|
|
191
208
|
.footer-cols{display:grid;grid-template-columns:repeat(3,1fr);gap:32px}
|
|
192
209
|
@media(max-width:560px){.footer-cols{grid-template-columns:repeat(2,1fr)}}
|
|
@@ -204,7 +221,7 @@ h1,h2,h3,h4{font-family:var(--font-display);font-weight:800;letter-spacing:-.025
|
|
|
204
221
|
<!-- NAV (body-level so it stays sticky across the whole page) -->
|
|
205
222
|
<header class="nav-wrap">
|
|
206
223
|
<nav class="nav glass">
|
|
207
|
-
<a class="brand" href="/"><span class="brand-mark">🎬</span>
|
|
224
|
+
<a class="brand" href="/"><span class="brand-mark">🎬</span>VidFarm</a>
|
|
208
225
|
<ul class="nav-links">
|
|
209
226
|
<li><a href="${HREF.studio}">Templates</a></li>
|
|
210
227
|
<li><a href="${HREF.clips}">Clips</a></li>
|
|
@@ -239,7 +256,7 @@ h1,h2,h3,h4{font-family:var(--font-display);font-weight:800;letter-spacing:-.025
|
|
|
239
256
|
<div class="hero-shot">
|
|
240
257
|
<div class="shot-head">
|
|
241
258
|
<span class="dot dot-r"></span><span class="dot dot-y"></span><span class="dot dot-g"></span>
|
|
242
|
-
<span class="shot-title">
|
|
259
|
+
<span class="shot-title">VidFarm · trackpad editor</span>
|
|
243
260
|
</div>
|
|
244
261
|
<div class="pipeline">
|
|
245
262
|
<div class="node"><span class="tile tile-sky">📼</span><div><div class="node-title">Fork template</div><div class="node-sub">Proven hook</div></div></div>
|
|
@@ -344,7 +361,7 @@ h1,h2,h3,h4{font-family:var(--font-display);font-weight:800;letter-spacing:-.025
|
|
|
344
361
|
<div class="footer-inner">
|
|
345
362
|
<div class="footer-top">
|
|
346
363
|
<div>
|
|
347
|
-
<div class="footer-brand"><span class="brand-mark">🎬</span>
|
|
364
|
+
<div class="footer-brand"><span class="brand-mark">🎬</span>VidFarm</div>
|
|
348
365
|
<div class="footer-tagline">The serverless studio for short-form video.</div>
|
|
349
366
|
</div>
|
|
350
367
|
<div class="footer-cols">
|
package/dist/src/page-shell.js
CHANGED
|
@@ -168,14 +168,38 @@ export function renderBrandLockup(input) {
|
|
|
168
168
|
</a>
|
|
169
169
|
`;
|
|
170
170
|
}
|
|
171
|
+
const BRAND_NAME = "VidFarm";
|
|
172
|
+
const BRAND_ORIGIN = "https://vidfarm.cc";
|
|
173
|
+
const BRAND_OG_IMAGE = `${BRAND_ORIGIN}/assets/logo-vidfarm.png`;
|
|
171
174
|
export function renderPageShell(input) {
|
|
172
175
|
const isEditorTheme = input.bodyClass?.split(/\s+/).includes("is-editor-theme") ?? false;
|
|
176
|
+
// Brand the tab title unless the page already names VidFarm.
|
|
177
|
+
const pageTitle = /vidfarm/i.test(input.title) ? input.title : `${input.title} · ${BRAND_NAME}`;
|
|
178
|
+
const description = input.description ?? `${BRAND_NAME} — serverless short-form video studio. Fork a proven template, remix it, and render a share-ready MP4 in your browser.`;
|
|
179
|
+
const ogImage = input.social?.image ?? BRAND_OG_IMAGE;
|
|
180
|
+
const ogType = input.social?.type ?? "website";
|
|
181
|
+
const ogUrl = input.social?.url ?? BRAND_ORIGIN;
|
|
182
|
+
const metaTags = `
|
|
183
|
+
<meta name="description" content="${escapeHtml(description)}" />
|
|
184
|
+
<meta name="theme-color" content="#f8f4eb" />
|
|
185
|
+
<meta name="robots" content="index, follow" />
|
|
186
|
+
<meta name="application-name" content="${BRAND_NAME}" />
|
|
187
|
+
<meta property="og:type" content="${escapeHtml(ogType)}" />
|
|
188
|
+
<meta property="og:site_name" content="${BRAND_NAME}" />
|
|
189
|
+
<meta property="og:title" content="${escapeHtml(pageTitle)}" />
|
|
190
|
+
<meta property="og:description" content="${escapeHtml(description)}" />
|
|
191
|
+
<meta property="og:url" content="${escapeHtml(ogUrl)}" />
|
|
192
|
+
<meta property="og:image" content="${escapeHtml(ogImage)}" />
|
|
193
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
194
|
+
<meta name="twitter:title" content="${escapeHtml(pageTitle)}" />
|
|
195
|
+
<meta name="twitter:description" content="${escapeHtml(description)}" />
|
|
196
|
+
<meta name="twitter:image" content="${escapeHtml(ogImage)}" />`;
|
|
173
197
|
return `<!doctype html>
|
|
174
198
|
<html lang="en">
|
|
175
199
|
<head>
|
|
176
200
|
<meta charset="utf-8" />
|
|
177
201
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
178
|
-
<title>${escapeHtml(
|
|
202
|
+
<title>${escapeHtml(pageTitle)}</title>${metaTags}
|
|
179
203
|
<link rel="icon" href="/assets/favicon.ico" sizes="any" />
|
|
180
204
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
181
205
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|