@mevdragon/vidfarm-devcli 0.16.0 → 0.17.0
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/farmville-saas-ux/SKILL.md +156 -0
- package/.agents/skills/farmville-saas-ux/assets/starter.html +294 -0
- package/.agents/skills/farmville-saas-ux/references/components.md +340 -0
- package/.agents/skills/farmville-saas-ux/references/porting-guide.md +121 -0
- package/.agents/skills/farmville-saas-ux/references/tokens.md +271 -0
- package/.agents/skills/vidfarm-media/SKILL.md +2 -1
- package/.agents/skills/vidfarm-media/references/tts.md +20 -1
- package/dist/src/account-pages-legacy.js +2 -2
- package/dist/src/app.js +441 -77
- package/dist/src/editor-chat.js +2 -2
- package/dist/src/frontend/homepage-client.js +162 -2
- package/dist/src/frontend/homepage-store.js +30 -1
- package/dist/src/frontend/homepage-view.js +111 -4
- package/dist/src/homepage.js +184 -1
- package/dist/src/landing-page.js +367 -0
- package/dist/src/primitive-registry.js +278 -2
- package/dist/src/reskin/agency-page.js +255 -0
- package/dist/src/reskin/calendar-page.js +252 -0
- package/dist/src/reskin/chat-page.js +414 -0
- package/dist/src/reskin/discover-page.js +380 -0
- package/dist/src/reskin/document.js +74 -0
- package/dist/src/reskin/help-page.js +318 -0
- package/dist/src/reskin/index-page.js +62 -0
- package/dist/src/reskin/job-runs-page.js +249 -0
- package/dist/src/reskin/library-page.js +515 -0
- package/dist/src/reskin/login-page.js +225 -0
- package/dist/src/reskin/pricing-page.js +359 -0
- package/dist/src/reskin/settings-page.js +353 -0
- package/dist/src/reskin/theme.js +265 -0
- package/dist/src/services/serverless-records.js +54 -0
- package/dist/src/services/swipe-customize.js +434 -0
- package/package.json +1 -1
- package/public/assets/homepage-client-app.js +22 -22
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Farmville SaaS — Design Tokens
|
|
2
|
+
|
|
3
|
+
The complete design system as CSS custom properties. Paste the `:root` block below into your global
|
|
4
|
+
stylesheet and reference the variables everywhere — never hand-pick ad-hoc hex/px values, or the system
|
|
5
|
+
drifts. Values are the real ones distilled from Fillout.com (a Tailwind-v4 default scale + a custom
|
|
6
|
+
honey-gold brand palette + rounded display type).
|
|
7
|
+
|
|
8
|
+
## Table of contents
|
|
9
|
+
1. Fonts (loading + stacks)
|
|
10
|
+
2. The `:root` token block (copy-paste)
|
|
11
|
+
3. Color rationale
|
|
12
|
+
4. Typography scale & usage
|
|
13
|
+
5. Radius, shadow, spacing rationale
|
|
14
|
+
6. Glass / blur
|
|
15
|
+
7. Motion
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. Fonts
|
|
20
|
+
|
|
21
|
+
**Display / headings — `Hanken Grotesk`.** Fillout uses a proprietary rounded grotesque called
|
|
22
|
+
*blMelody*. Hanken Grotesk is the closest free, warm, rounded grotesque with an excellent bold. Good
|
|
23
|
+
alternates, all free on Google Fonts, in order of similarity: **Figtree**, **Gantari**, **Onest**,
|
|
24
|
+
**Plus Jakarta Sans**. If you have a license for blMelody, use it and keep Hanken as the fallback.
|
|
25
|
+
|
|
26
|
+
**Body / UI — `Inter`.** Exact match to Fillout. Free.
|
|
27
|
+
|
|
28
|
+
```html
|
|
29
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
30
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
31
|
+
<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">
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Rules of thumb:
|
|
35
|
+
- Headlines, section titles, big numbers, the logo → **Hanken Grotesk** (or blMelody).
|
|
36
|
+
- Body copy, labels, buttons, nav items, form fields → **Inter**.
|
|
37
|
+
- Never set body copy in the display font, and never set a huge headline in Inter — the mix is the point.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. The `:root` token block
|
|
42
|
+
|
|
43
|
+
```css
|
|
44
|
+
:root {
|
|
45
|
+
/* ---- Fonts ---- */
|
|
46
|
+
--font-display: "Hanken Grotesk", "blMelody", ui-sans-serif, system-ui, sans-serif;
|
|
47
|
+
--font-body: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
48
|
+
--font-mono: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, monospace;
|
|
49
|
+
|
|
50
|
+
/* ---- Signature accent: HONEY GOLD (the one "joy" color) ---- */
|
|
51
|
+
--gold-500: #ffc738; /* primary accent */
|
|
52
|
+
--gold-400: #ffd66f; /* lighter */
|
|
53
|
+
--gold-300: #f8d884; /* soft */
|
|
54
|
+
--gold-600: #f6c744; /* focus-ring gold */
|
|
55
|
+
--gold-700: #fcb900; /* deep / hover */
|
|
56
|
+
--gold-tint: #fff5e4; /* pale wash bg */
|
|
57
|
+
--gold-tint2:#ffe9cc; /* warm cream */
|
|
58
|
+
|
|
59
|
+
/* ---- Ink & neutral scale (Tailwind neutral) ---- */
|
|
60
|
+
--ink: #171717; /* primary text, dark buttons, footer */
|
|
61
|
+
--ink-950: #0a0a0a; /* deepest */
|
|
62
|
+
--n-900: #171717;
|
|
63
|
+
--n-800: #262626;
|
|
64
|
+
--n-700: #404040; /* heading text on light */
|
|
65
|
+
--n-600: #525252;
|
|
66
|
+
--n-500: #737373; /* secondary / body text */
|
|
67
|
+
--n-400: #a3a3a3; /* muted, placeholders, disabled */
|
|
68
|
+
--n-300: #d4d4d4; /* strong border */
|
|
69
|
+
--n-200: #ededed; /* hairline border (default) */
|
|
70
|
+
--n-150: #f0f0f0;
|
|
71
|
+
--n-100: #f5f5f5; /* section tint background */
|
|
72
|
+
--n-50: #fbfbfb; /* page background */
|
|
73
|
+
--white: #ffffff; /* card surface */
|
|
74
|
+
|
|
75
|
+
/* ---- Support pastels (icon tiles, nodes, illustration accents) ---- */
|
|
76
|
+
--sky: #3f9fe0; --sky-tint: #e2effd; /* hero sky / info */
|
|
77
|
+
--violet: #9f5bde; --violet-tint: #e4ddfd; /* AI / smart */
|
|
78
|
+
--green: #22c55e; --green-tint: #dcfce7; /* branch / success / nature */
|
|
79
|
+
--coral: #f97316; --coral-tint: #ffe9cc; /* energy / warm */
|
|
80
|
+
--red: #ef4444; --red-tint: #fee2e2; /* destructive */
|
|
81
|
+
|
|
82
|
+
/* ---- Semantic roles ---- */
|
|
83
|
+
--bg: var(--n-50);
|
|
84
|
+
--bg-section: var(--n-100);
|
|
85
|
+
--surface: var(--white);
|
|
86
|
+
--border: var(--n-200);
|
|
87
|
+
--border-strong: var(--n-300);
|
|
88
|
+
--text: var(--n-700);
|
|
89
|
+
--text-muted: var(--n-500);
|
|
90
|
+
--text-faint: var(--n-400);
|
|
91
|
+
--accent: var(--gold-500);
|
|
92
|
+
|
|
93
|
+
/* ---- Radius (curves are signature — nothing sharp) ---- */
|
|
94
|
+
--r-sm: 4px;
|
|
95
|
+
--r-md: 6px; /* inputs, small chips */
|
|
96
|
+
--r-lg: 8px; /* small buttons */
|
|
97
|
+
--r-xl: 12px; /* buttons, icon tiles */
|
|
98
|
+
--r-2xl: 16px; /* cards, nodes */
|
|
99
|
+
--r-3xl: 24px; /* big feature cards, image frames, nav pill */
|
|
100
|
+
--r-full: 9999px; /* nav bar, pill buttons, badges, avatars */
|
|
101
|
+
|
|
102
|
+
/* ---- Shadows (diffuse, low-opacity = soft sunlight, never harsh) ---- */
|
|
103
|
+
--shadow-xs: 0 1px 2px 0 #0000000d;
|
|
104
|
+
--shadow-sm: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a;
|
|
105
|
+
--shadow-md: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;
|
|
106
|
+
--shadow-lg: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;
|
|
107
|
+
--shadow-xl: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;
|
|
108
|
+
--shadow-2xl:0 25px 50px -12px #00000040;
|
|
109
|
+
--shadow-card: 0 1px 2px #0000000d, 0 8px 24px -12px #00000014; /* lifted-card ambient */
|
|
110
|
+
--shadow-nav: 0 4px 24px -8px #00000026, 0 1px 2px #0000000d; /* floating glass nav */
|
|
111
|
+
--ring-gold: 0 0 0 3px var(--gold-600), 0 0 14px rgba(246,199,68,.4); /* focus */
|
|
112
|
+
|
|
113
|
+
/* ---- Type scale (rem) ---- */
|
|
114
|
+
--text-xs: 0.75rem; --lh-xs: 1rem;
|
|
115
|
+
--text-sm: 0.875rem; --lh-sm: 1.25rem;
|
|
116
|
+
--text-base:1rem; --lh-base:1.5rem;
|
|
117
|
+
--text-lg: 1.125rem; --lh-lg: 1.75rem;
|
|
118
|
+
--text-xl: 1.25rem; --lh-xl: 1.75rem;
|
|
119
|
+
--text-2xl: 1.5rem; --lh-2xl: 2rem;
|
|
120
|
+
--text-3xl: 1.875rem; --lh-3xl: 2.25rem;
|
|
121
|
+
--text-4xl: 2.25rem; --lh-4xl: 2.5rem;
|
|
122
|
+
--text-5xl: 3rem; --lh-5xl: 1.05;
|
|
123
|
+
--text-6xl: 3.75rem; --lh-6xl: 1.0;
|
|
124
|
+
--text-7xl: 4.5rem; --lh-7xl: 1.0;
|
|
125
|
+
--display: clamp(3rem, 7vw, 6rem); /* hero headline, fluid */
|
|
126
|
+
|
|
127
|
+
/* ---- Font weights ---- */
|
|
128
|
+
--fw-normal: 400; --fw-medium: 500; --fw-semibold: 600;
|
|
129
|
+
--fw-bold: 700; --fw-extrabold: 800;
|
|
130
|
+
|
|
131
|
+
/* ---- Tracking / leading ---- */
|
|
132
|
+
--track-tighter: -0.05em;
|
|
133
|
+
--track-tight: -0.025em; /* headings default */
|
|
134
|
+
--track-normal: 0em;
|
|
135
|
+
--lh-tight: 1.1; --lh-snug: 1.25; --lh-normal: 1.5; --lh-relaxed: 1.6;
|
|
136
|
+
|
|
137
|
+
/* ---- Spacing (4px base) ---- */
|
|
138
|
+
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px;
|
|
139
|
+
--sp-6: 24px; --sp-8: 32px; --sp-10:40px; --sp-12:48px; --sp-16:64px;
|
|
140
|
+
--sp-20:80px; --sp-24:96px; --sp-32:128px;
|
|
141
|
+
--section-y: clamp(4rem, 9vw, 7rem); /* vertical rhythm between sections */
|
|
142
|
+
--container: 75rem; /* 1200px, max content width */
|
|
143
|
+
--gutter: clamp(1rem, 4vw, 2rem);
|
|
144
|
+
|
|
145
|
+
/* ---- Glass / blur ---- */
|
|
146
|
+
--glass-bg: rgba(251,251,251,0.8);
|
|
147
|
+
--glass-blur: 16px;
|
|
148
|
+
|
|
149
|
+
/* ---- Motion ---- */
|
|
150
|
+
--ease: cubic-bezier(0.22, 1, 0.36, 1); /* gentle ease-out */
|
|
151
|
+
--dur-fast: 150ms; --dur: 220ms; --dur-slow: 320ms;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* Baseline application */
|
|
155
|
+
html { font-size: 16px; }
|
|
156
|
+
body {
|
|
157
|
+
font-family: var(--font-body);
|
|
158
|
+
color: var(--text);
|
|
159
|
+
background: var(--bg);
|
|
160
|
+
-webkit-font-smoothing: antialiased;
|
|
161
|
+
text-rendering: optimizeLegibility;
|
|
162
|
+
}
|
|
163
|
+
h1,h2,h3,h4 {
|
|
164
|
+
font-family: var(--font-display);
|
|
165
|
+
font-weight: var(--fw-extrabold);
|
|
166
|
+
letter-spacing: var(--track-tight);
|
|
167
|
+
line-height: var(--lh-tight);
|
|
168
|
+
color: var(--ink);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 3. Color rationale
|
|
175
|
+
|
|
176
|
+
- **Honey-gold `#ffc738` is the whole personality.** It is the *only* saturated brand color. Use it
|
|
177
|
+
where you want a smile: the footer's primary CTA, star ratings, a "Publish" chip, the logo, a small
|
|
178
|
+
underline/highlight, a hover glow. If you find yourself using gold on more than ~5–10% of a screen,
|
|
179
|
+
pull back — its power is scarcity. Never pair it with a second competing bright brand color.
|
|
180
|
+
- **Charcoal `#171717` is the workhorse.** Primary buttons on light backgrounds, primary text, the
|
|
181
|
+
footer surface. It reads premium and calm and lets the gold pop.
|
|
182
|
+
- **Everything else is the neutral gray scale.** Backgrounds alternate `#fbfbfb` (page) ↔ `#f5f5f5`
|
|
183
|
+
(tinted section) ↔ `#ffffff` (cards). Borders are the near-invisible `#ededed` hairline. Text steps
|
|
184
|
+
down `#171717` → `#404040` → `#737373` → `#a3a3a3`.
|
|
185
|
+
- **Support pastels are for tiny surfaces only** — icon tiles, workflow nodes, illustration accents,
|
|
186
|
+
chart dots. Each has a saturated glyph color + a pale tint background (violet on `#e4ddfd`, green on
|
|
187
|
+
`#dcfce7`, etc.). They add life without stealing the gold's job.
|
|
188
|
+
- **The illustrated hero introduces sky-blue and green** as *painted* colors, not UI colors. That's
|
|
189
|
+
intentional — the warmth lives in the artwork, the UI stays disciplined.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 4. Typography scale & usage
|
|
194
|
+
|
|
195
|
+
| Element | Font | Size | Weight | Tracking | Line-height |
|
|
196
|
+
|---|---|---|---|---|---|
|
|
197
|
+
| Hero headline | display | `--display` (clamp 3→6rem) | 800 | -0.03em | 1.0 |
|
|
198
|
+
| Section title | display | `--text-5xl`/`4xl` | 800 | -0.025em | 1.05 |
|
|
199
|
+
| Card / feature title | display | `--text-xl`/`2xl` | 700 | -0.02em | 1.2 |
|
|
200
|
+
| Subhead / lede | body | `--text-lg`/`xl` | 400 | 0 | 1.5 |
|
|
201
|
+
| Body copy | body | `--text-base` | 400 | 0 | 1.6 |
|
|
202
|
+
| Small / caption | body | `--text-sm` | 400/500 | 0 | 1.4 |
|
|
203
|
+
| Button label | body | `--text-sm`/`base` | 600 | 0 | 1 |
|
|
204
|
+
| Badge / eyebrow | body | `--text-sm` | 500 | 0 | 1 |
|
|
205
|
+
| Big stat number | display | `--text-5xl`+ | 700 | -0.02em | 1 |
|
|
206
|
+
|
|
207
|
+
**Two-tone hero trick:** split the headline across two lines and set the first line to a translucent
|
|
208
|
+
white and the second to solid white for a soft-to-strong reveal:
|
|
209
|
+
|
|
210
|
+
```css
|
|
211
|
+
.hero-h1 { font: 800 var(--display)/1.0 var(--font-display); letter-spacing:-0.03em; color:#fff; }
|
|
212
|
+
.hero-h1 .soft { color: rgba(255,255,255,0.55); }
|
|
213
|
+
```
|
|
214
|
+
```html
|
|
215
|
+
<h1 class="hero-h1"><span class="soft">Forms that</span><br>do it all</h1>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
On light backgrounds, headings are ink `#171717`; subheads are `#737373`.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 5. Radius, shadow, spacing rationale
|
|
223
|
+
|
|
224
|
+
- **Radius is a personality dial and it's turned way up.** Interactive elements are *fully* rounded
|
|
225
|
+
(nav, buttons, badges → `--r-full`). Containers are generously rounded (cards `16px`, big cards &
|
|
226
|
+
image frames `24px`). Only truly small utility elements go as low as `4–6px`. When in doubt, round
|
|
227
|
+
more. A single sharp corner breaks the whole cozy feeling.
|
|
228
|
+
- **Shadows imitate soft ambient sunlight**, not hard drop-shadows. They're always large-radius and
|
|
229
|
+
low-opacity (`#0000001a` ≈ 10% black; the biggest is 25%). Use `--shadow-card` on resting cards and
|
|
230
|
+
`--shadow-nav` on the floating nav. On hover, step a card from `--shadow-card` to `--shadow-lg` and
|
|
231
|
+
nudge it up 2px.
|
|
232
|
+
- **Spacing is generous and rhythmic.** Sections get `--section-y` (≈ 6rem) of vertical padding.
|
|
233
|
+
Content maxes at `--container` (1200px) and stays centered with `--gutter` side padding. Inside
|
|
234
|
+
cards, pad `24–40px`. Whitespace *is* the premium signal — don't crowd.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 6. Glass / blur
|
|
239
|
+
|
|
240
|
+
The floating nav and any sticky "feature tab" bar use frosted glass:
|
|
241
|
+
|
|
242
|
+
```css
|
|
243
|
+
.glass {
|
|
244
|
+
background: var(--glass-bg); /* rgba(251,251,251,0.8) */
|
|
245
|
+
backdrop-filter: blur(var(--glass-blur)); /* 16px */
|
|
246
|
+
-webkit-backdrop-filter: blur(var(--glass-blur));
|
|
247
|
+
border: 1px solid var(--border);
|
|
248
|
+
box-shadow: var(--shadow-nav);
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
Over the illustrated hero, use a whiter translucent fill (`rgba(255,255,255,0.7)`) so nav text stays legible.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## 7. Motion
|
|
256
|
+
|
|
257
|
+
Gentle and springy, never bouncy-cartoonish. One easing curve (`--ease`, a soft ease-out) and short
|
|
258
|
+
durations (150–320ms). The canonical interactions:
|
|
259
|
+
|
|
260
|
+
- **Card hover:** `transform: translateY(-2px)` + shadow `--shadow-card` → `--shadow-lg`.
|
|
261
|
+
- **Button hover:** slight brightness/darken + `--shadow-md`; the trailing `→` arrow nudges right ~3px.
|
|
262
|
+
- **Focus:** `box-shadow: var(--ring-gold)` — the gold glow ring.
|
|
263
|
+
- **Section reveal (optional):** fade-up 12px over 320ms as it enters the viewport.
|
|
264
|
+
|
|
265
|
+
```css
|
|
266
|
+
.card { transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
|
|
267
|
+
.card:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); }
|
|
268
|
+
.btn .arrow { transition: transform var(--dur) var(--ease); }
|
|
269
|
+
.btn:hover .arrow { transform: translateX(3px); }
|
|
270
|
+
:where(a,button,input,textarea):focus-visible { outline: none; box-shadow: var(--ring-gold); }
|
|
271
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vidfarm-media
|
|
3
|
-
description: Media resolution for video workflows — narration TTS, word-level timings, BGM, SFX, and image/clip sourcing through vidfarm. Use when a video needs audio (voiceover/narration, music, sound effects), caption word timings, or media assets. Ships the shared audio engine scripts/audio.mjs (audio_request.json → audio_meta.json) used by faceless-explainer, product-launch-video, and general-video; documents vidfarm tts/stt BYOK primitives, the keyless local Kokoro + whisper.cpp engines, and My Files / clip-library / generation sourcing. No third-party media accounts — everything is user-owned or generated on the user's keys.
|
|
3
|
+
description: Media resolution for video workflows — narration TTS, voice-matched speech regeneration ("same speaker, new words"), word-level timings, BGM, SFX, and image/clip sourcing through vidfarm. Use when a video needs audio (voiceover/narration, music, sound effects), rewording of existing narration in the original speaker's voice, caption word timings, or media assets. Ships the shared audio engine scripts/audio.mjs (audio_request.json → audio_meta.json) used by faceless-explainer, product-launch-video, and general-video; documents vidfarm tts/stt BYOK primitives, the keyless local Kokoro + whisper.cpp engines, and My Files / clip-library / generation sourcing. No third-party media accounts — everything is user-owned or generated on the user's keys.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# vidfarm-media
|
|
@@ -63,6 +63,7 @@ Contract points:
|
|
|
63
63
|
| Narration, promptable voice (BYOK) | `vidfarm tts "…" --style "calm, warm narrator"` | Local-first on your env key; `--voice alloy`/`Kore`…; `--cloud` = saved-key platform job → `POST /api/v1/primitives/audio/speech` |
|
|
64
64
|
| Narration, zero keys | `npx hyperframes tts "…" -v af_heart --json` | Kokoro-82M, local, WAV + duration in JSON |
|
|
65
65
|
| Transcript + SRT (BYOK) | `vidfarm stt <file\|url>` | Gemini key labels speakers; OpenAI whisper-1 gives real word timestamps |
|
|
66
|
+
| Reword existing narration in the (approximate) original voice | `POST /api/v1/primitives/audio/regenerate-speech` (platform job on saved keys; no devcli command yet) | One job: listens to a video/audio source, profiles the speaker (needs a Gemini key), rewords the transcript per `rewrite_instruction` (or takes exact `text`), regenerates with the closest preset voice + matched style. Always an approximation — OpenAI/Gemini cannot clone voices. Details: `references/tts.md` |
|
|
66
67
|
| Word timings, zero keys | `npx hyperframes transcribe <audio> --json` | whisper.cpp; writes word-level `transcript.json` |
|
|
67
68
|
| Captions straight into a composition | `vidfarm captions generate <dir>` | whisper-1 real timings when an OpenAI key exists; estimates otherwise |
|
|
68
69
|
|
|
@@ -21,7 +21,26 @@ vidfarm tts "Welcome back to the channel" --style "calm, warm bedtime narrator"
|
|
|
21
21
|
- Gemini (`gemini-*-tts`, TitleCase, also the default family for OpenRouter TTS): `Kore, Puck, Charon, Aoede, Fenrir, Leda, Orus, Zephyr, Achernar, Achird, Algenib, Algieba, Alnilam, Autonoe, Callirrhoe, Despina, Enceladus, Erinome, Gacrux, Iapetus, Laomedeia, Pulcherrima, Rasalgethi, Sadachbia, Sadaltager, Schedar, Sulafat, Umbriel, Vindemiatrix, Zubenelgenubi`
|
|
22
22
|
- **Formats**: `--format mp3|wav` (default mp3). `--json` prints `{ ok, provider, model, out, … }`.
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## Voice-matched regeneration — "same speaker, new words"
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Platform job on saved keys (no devcli command yet); poll the returned job_id.
|
|
28
|
+
POST /api/v1/primitives/audio/regenerate-speech # alias: /api/v1/primitives/regenerate-speech
|
|
29
|
+
{ "tracer": "…", "payload": {
|
|
30
|
+
"source_url": "…", # video or audio; video audio is demuxed automatically
|
|
31
|
+
"rewrite_instruction": "mention the summer sale instead of the discount code",
|
|
32
|
+
"text": "…", # OR: the exact new script (one of the two is required)
|
|
33
|
+
"voice": "…", "instructions": "…", # optional preset override / extra style guidance
|
|
34
|
+
"provider": "…", "model": "…", "language": "…", "output_format": "mp3|wav"
|
|
35
|
+
} }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
One job: listens to the source, profiles the dominant speaker with an audio-native Gemini call (verbatim transcript + gender/age/accent/pace/pitch/energy profile + a dense style direction + the closest preset in both voice families), rewords the transcript per `rewrite_instruction` (keeping length and rhythm) or takes the exact `text`, then regenerates via TTS with the matched preset + profiled style instructions. Result: durable `audioUrl`, `script`, `original_transcript`, `voice_profile`, `voice_match`, plus a `regenerate-speech.json` artifact.
|
|
39
|
+
|
|
40
|
+
- **Honesty rule (non-negotiable): this is an approximation, never a clone.** Neither OpenAI nor Gemini exposes voice cloning through their public APIs — both offer preset voices with style steering only (actual cloning is sales-allowlisted at both, e.g. OpenAI "Custom Voices", Google Chirp 3 Instant Custom Voice). `voice_match` says `"approximate"` or `"none"`; always present it that way to the user. True self-serve cloning would need an ElevenLabs/Cartesia-class provider or a local OSS model (F5-TTS, CosyVoice, XTTS-v2, Chatterbox) — none are wired into vidfarm today.
|
|
41
|
+
- **Voice profiling needs a saved Gemini key** (it is the audio-native LLM). With only openai/openrouter keys the job degrades gracefully: STT transcript + reword still work, but the voice is a default or explicitly passed preset and `voice_match` is `"none"`.
|
|
42
|
+
- Sources over ~40 minutes of speech must be trimmed first (same cap as `/audio/transcribe`).
|
|
43
|
+
- To swap the result into a composition: mute the original span (`/videos/mute` or the layer's volume), then place `audioUrl` as a new audio layer.
|
|
25
44
|
|
|
26
45
|
```bash
|
|
27
46
|
npx hyperframes tts "Welcome back" -v af_heart -o line.wav --json # {"ok":true,"durationSeconds":…,"outputPath":…}
|
|
@@ -880,10 +880,10 @@ export function renderSettingsPage(input) {
|
|
|
880
880
|
</div>
|
|
881
881
|
<div class="profile-field">
|
|
882
882
|
<div class="profile-field-head">
|
|
883
|
-
<label for="about">
|
|
883
|
+
<label for="about">Product / offer description</label>
|
|
884
884
|
<button type="submit" data-profile-about-save disabled>Save</button>
|
|
885
885
|
</div>
|
|
886
|
-
<textarea id="about" name="about" placeholder="
|
|
886
|
+
<textarea id="about" name="about" placeholder="Describe your product or offer — what it is, who it's for, and the promise. Swipe mode uses this to auto-recut templates into ads for you." data-profile-about data-initial-value="${escapeAttribute(input.about ?? "")}">${escapeHtml(input.about ?? "")}</textarea>
|
|
887
887
|
</div>
|
|
888
888
|
</form>
|
|
889
889
|
<section class="files-card" data-files-card>
|