@docyrus/animaguru 0.35.0 → 0.36.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/README.md
CHANGED
|
@@ -61,7 +61,9 @@ CLI 0.33.0 adds **Cartoon Host Explainer** (`cartoon-host-explainer`): the talki
|
|
|
61
61
|
|
|
62
62
|
CLI 0.34.0 adds `"thumbnail"` to `film.config.json` for a designed cover. It names a PNG, JPEG or WebP in the film's folder, such as generated key art at `production/thumbnail.png`. `npm run export:mp4` saves that image as `FILM.jpg` instead of the `"poster"` frame, cropped to the film's shape, so every re-export keeps the cover and `youtube upload` sets it. A wrong path or an unreadable image stops the export before it renders. `submit --file FILM.mp4` now uses the `FILM.jpg` beside it as the AnimaGuru cover; `--poster FILE` chooses another and `--poster none` skips it. `videos poster VIDEO_ID --file IMAGE --yes` replaces the poster of a video already uploaded, and MCP's `set_video_poster` does the same from a saved project image, a public URL or base64.
|
|
63
63
|
|
|
64
|
-
CLI 0.35.0 adds photoreal Gaussian splats: `assets generate --type model --model idol --reference SHA` turns the object in a saved image into splats with Sperid Labs' Idol on fal (`--photo` for a camera photo, `--splats` 32,768–1,048,576, `--seed`), saved as `.spz`, upright and facing +Z. New video workspaces include Spark, and the kit's `stage.splat()` draws splats in a three.js shot, sorted for each frame's camera, with `photoView()` to open on the reference image's exact view and `softShadow()` to ground them. See the `animaguru-3d-models` skill.
|
|
64
|
+
CLI 0.35.0 adds photoreal Gaussian splats: `assets generate --type model --model idol --reference SHA` turns the object in a saved image into splats with Sperid Labs' Idol on fal (`--photo` for a camera photo, `--splats` 32,768–1,048,576, `--seed`), saved as `.spz`, upright and facing +Z. New video workspaces include Spark, and the kit's `stage.splat()` draws splats in a three.js shot, sorted for each frame's camera, with `photoView()` to open on the reference image's exact view and `softShadow()` to ground them. See the `animaguru-3d-models` skill. CLI 0.35.1 fixes `photoView()` for product images Idol reads as near-orthographic (a field of view under 0.1°): it widens the view to 6° and moves the camera in, so the shot still opens on the product.
|
|
65
|
+
|
|
66
|
+
CLI 0.36.0 adds Mureka 9.5 music on fal, HeyGen Voice speech and Seedance video on BytePlus (`--model byteplus/seedance-2.5`, `-2.0`, `-2.0-fast` or `-2.0-mini`). `--type music --model fal/mureka-9.5-song` sings `--lyrics` with `--vocals female|male` or writes a song from the prompt in `--styles`, for `--seconds` 120–300 or a length of its own; `fal/mureka-9.5-instrumental` writes from the prompt; `fal/mureka-9.5-soundtrack --source SHA` scores a saved video, image or sprite art. `--type speech --model heygen-voice-1` or `heygen-voice-1-turbo` speaks a HeyGen public voice ID given as `--voice` (Nadine by default). `catalog` lists `musicOptions` and `heygenVoices`. See [image, video, music and speech generation](#image-video-music-and-speech-generation).
|
|
65
67
|
|
|
66
68
|
CLI 0.16.2 also installs `animaguru-art-motion` for Codex and Claude Code: one skill with 36 English art-treatment references and nine explainer motion grammars, plus AnimaGuru generation, timing, camera and review guidance. Request it explicitly for a custom film treatment; its references are separate from the gallery presets. Source coverage and the upstream MIT notice are included in the skill.
|
|
67
69
|
|
|
@@ -248,6 +250,22 @@ animaguru assets generate PROJECT_ID --type sfx --name "Magic spell" \
|
|
|
248
250
|
--prompt-influence 0.6 --dry-run
|
|
249
251
|
```
|
|
250
252
|
|
|
253
|
+
CLI 0.36.0 adds Mureka 9.5 music on fal and HeyGen Voice speech. A Mureka song sings `--lyrics` (with `--vocals female` or `male`, the prompt setting the style) or writes its own from the prompt in optional `--styles`; `--seconds` asks for 120–300 seconds. A soundtrack scores a saved video, image or sprite art given as `--source`, and runs as long as the video. HeyGen Voice speaks a public voice ID (Nadine is the default; `catalog --type speech` lists `heygenVoices`) and reads the transcript as written, so it takes no `--delivery`:
|
|
254
|
+
|
|
255
|
+
```sh
|
|
256
|
+
animaguru assets generate PROJECT_ID --type music --model fal/mureka-9.5-song \
|
|
257
|
+
--name "Studio song" --prompt "Upbeat synth-pop" --vocals female \
|
|
258
|
+
--lyrics $'[Verse]\nTiny robots in the studio light\n[Chorus]\nAnimate, animate' --dry-run
|
|
259
|
+
animaguru assets generate PROJECT_ID --type music --model fal/mureka-9.5-song \
|
|
260
|
+
--name "Summer song" --prompt "A bright summer love song" --styles pop,r&b --dry-run
|
|
261
|
+
animaguru assets generate PROJECT_ID --type music --model fal/mureka-9.5-instrumental \
|
|
262
|
+
--name "Menu loop" --prompt "Calm lo-fi piano for a cozy game menu" --dry-run
|
|
263
|
+
animaguru assets generate PROJECT_ID --type music --model fal/mureka-9.5-soundtrack \
|
|
264
|
+
--name "Trailer score" --source VIDEO_BLOB_SHA --prompt "Tense, then hopeful" --dry-run
|
|
265
|
+
animaguru assets generate PROJECT_ID --type speech --model heygen-voice-1-turbo \
|
|
266
|
+
--name "Host" --prompt "Welcome to AnimaGuru." --dry-run
|
|
267
|
+
```
|
|
268
|
+
|
|
251
269
|
Replace `--dry-run` with `--yes` to generate within your authorized credit budget. ElevenLabs accepts a voice ID in `--voice` and defaults to George when omitted. Use audio tags in the transcript; `--delivery` is only for Gemini and is rejected for ElevenLabs. SFX has a single model, `eleven_text_to_sound_v2`; `--seconds` accepts 0.5–30 (default 5), `--loop` requests a seamless loop, and `--prompt-influence` accepts 0–1 (default 0.3). Both return MP3. `catalog` includes `sfxModels` and `elevenLabsVoices`. The server needs `AI_PROVIDER_KEY_ELEVENLABS`; provider keys never belong in CLI credentials.
|
|
252
270
|
|
|
253
271
|
CLI 0.8.0 adds MiniMax H3 Max Turbo and the H3 workflows. MiniMax H3 Max and H3 Max Turbo on fal.ai (`fal/minimax-h3-max`, `fal/minimax-h3-max-turbo`) also write videos from text and extend saved videos. Choose with `--workflow`:
|
|
@@ -334,6 +352,19 @@ animaguru assets generate PROJECT_ID --type video --model heygen/heygen-video-1
|
|
|
334
352
|
|
|
335
353
|
From an image or text, HeyGen's clips run to 30 seconds while it rewrites the prompt: `--prompt-expansion balanced` asks for its fastest rewriting and `quality` its fuller one. Every second of a clip over 15 seconds costs its long-clip rate. At 1080p and 2K, text-to-video and reference-to-video are 16:9 or 9:16; from an image, the clip keeps the image's shape. `reference-to-video` takes up to nine `--references` images, three `--reference-videos` (HeyGen reads the first 5 seconds of each) and three `--audio-references`, twelve files in all, named Image 1, Video 1, Audio 1 in the prompt. It takes no `--reference`, `--end-reference` or `--middle-reference`, and `--aspect-ratio auto` (default) follows the first image or clip. HeyGen takes images of up to 5 MB, and clips and audio of up to 16 MB. Up to 5 seconds of each reference clip, and each reference image after the second, add to the cost; audio references are free.
|
|
336
354
|
|
|
355
|
+
CLI 0.36.0 adds ByteDance's Seedance on BytePlus: `byteplus/seedance-2.5`, `byteplus/seedance-2.0`, `byteplus/seedance-2.0-fast` and `byteplus/seedance-2.0-mini`. Each films from an image (`--reference`, optionally ending on `--end-reference`; the clip keeps the image's shape), from text (`--workflow text-to-video`, with `--aspect-ratio`), or from saved images and audio (`--workflow reference-to-video`: up to nine `--references` and three `--audio-references`, named Image 1 and Audio 1 in the prompt; 2.0, fast and mini need an image beside audio). Clips are 4–15 whole seconds (2.5 up to 30), at 480p or 720p (2.0 also 1080p), with sound of their own and no `--soundtrack`, `--seed` or `--prompt-expansion`. Seedance takes no reference videos or extensions here, and refuses images of real people's faces. A clip is charged the tokens BytePlus counts, at most the estimate: a 5-second 720p clip is about 118 credits on 2.5, 77 on 2.0, 62 on fast and 39 on mini.
|
|
356
|
+
|
|
357
|
+
```sh
|
|
358
|
+
# A sprite's wave, from its art to its art.
|
|
359
|
+
animaguru assets generate PROJECT_ID --type video --model byteplus/seedance-2.0-mini \
|
|
360
|
+
--name "Wave" --reference ART_SHA --end-reference ART_SHA \
|
|
361
|
+
--prompt "The robot waves its right hand, then stands still again" --seconds 5 --resolution 720p --dry-run
|
|
362
|
+
# A 20-second scene from text on Seedance 2.5.
|
|
363
|
+
animaguru assets generate PROJECT_ID --type video --model byteplus/seedance-2.5 \
|
|
364
|
+
--workflow text-to-video --name "Harbor" --aspect-ratio 21:9 \
|
|
365
|
+
--prompt "Fishing boats leave a foggy harbor at dawn, gulls calling, one slow continuous shot" --seconds 20 --dry-run
|
|
366
|
+
```
|
|
367
|
+
|
|
337
368
|
### Vectors
|
|
338
369
|
|
|
339
370
|
CLI 0.27.0 adds vectors: editable SVG files drawn by Ideogram on fal.ai (`fal/ideogram-vector`), for logos, icons, mascots and flat illustrations that stay sharp at any size and can be animated shape by shape.
|
package/dist/animaguru.js
CHANGED
|
@@ -19761,7 +19761,7 @@ var require_ignore2 = __commonJS({
|
|
|
19761
19761
|
// cli/package.json
|
|
19762
19762
|
var package_default = {
|
|
19763
19763
|
name: "@docyrus/animaguru",
|
|
19764
|
-
version: "0.
|
|
19764
|
+
version: "0.36.0",
|
|
19765
19765
|
description: "Agent-friendly AnimaGuru CLI built with CrustJS",
|
|
19766
19766
|
type: "module",
|
|
19767
19767
|
bin: {
|
|
@@ -45013,7 +45013,11 @@ var SPRITE_IMAGE_MODELS = [
|
|
|
45013
45013
|
{ id: "bytedance/seedream-5-pro", label: "Seedream 5 Pro", provider: "workers-ai", edit: true, maxImages: 10, relCost: 1.5 },
|
|
45014
45014
|
{ id: "xai/grok-imagine-image-2.0", label: "Grok Imagine Image 2.0", provider: "workers-ai", edit: true, maxImages: 5, relCost: 1 },
|
|
45015
45015
|
{ id: "alibaba/qwen-image-3.0-pro", label: "Qwen Image 3.0 Pro", provider: "workers-ai", edit: false, maxImages: 0, relCost: 0.5 },
|
|
45016
|
-
{ id: "krea/krea-2-medium-turbo", label: "Krea 2 Medium Turbo", provider: "workers-ai", edit: false, maxImages: 0, relCost: 0.25 }
|
|
45016
|
+
{ id: "krea/krea-2-medium-turbo", label: "Krea 2 Medium Turbo", provider: "workers-ai", edit: false, maxImages: 0, relCost: 0.25 },
|
|
45017
|
+
// Seedream on AnimaGuru's own BytePlus account: $0.045 an image (Pro, up to 2.61 MP), $0.018 (Flash), $0.035 (Lite).
|
|
45018
|
+
{ id: "byteplus/seedream-5.0-pro", label: "Seedream 5.0 Pro (BytePlus)", provider: "byteplus", providerModel: "dola-seedream-5-0-pro-260628", edit: true, spriteBackupCutout: true, maxImages: 10, relCost: 0.35 },
|
|
45019
|
+
{ id: "byteplus/seedream-5.0-flash", label: "Seedream 5.0 Flash (BytePlus)", provider: "byteplus", providerModel: "dola-seedream-5-0-flash-260915", edit: true, spriteBackupCutout: true, maxImages: 10, relCost: 0.15 },
|
|
45020
|
+
{ id: "byteplus/seedream-5.0-lite", label: "Seedream 5.0 Lite (BytePlus)", provider: "byteplus", providerModel: "seedream-5-0-260128", edit: true, spriteBackupCutout: true, maxImages: 14, relCost: 0.3 }
|
|
45017
45021
|
];
|
|
45018
45022
|
var SPRITE_IMAGE_MODEL_IDS = SPRITE_IMAGE_MODELS.map((m) => m.id);
|
|
45019
45023
|
function spriteImageModel(id2) {
|
|
@@ -45048,6 +45052,8 @@ var HEYGEN_LONG = { max: 30, creditsPerSecond: { "480p": 4.5, "768p": 7.5, "1080
|
|
|
45048
45052
|
var H3_MAX = "minimax/h3-max";
|
|
45049
45053
|
var FLUX_3_MAX = "blackforestlabs/flux-3-max";
|
|
45050
45054
|
var h3Endpoints = (route) => ({ "image-to-video": `${route}/image-to-video`, "text-to-video": `${route}/text-to-video`, "extend-video": `${route}/extend-video` });
|
|
45055
|
+
var SEEDANCE_WORKFLOWS = ["image-to-video", "text-to-video", "reference-to-video"];
|
|
45056
|
+
var SEEDANCE_REFERENCES = { referencesOnly: true, mediaReferences: ["images", "audio"] };
|
|
45051
45057
|
var SPRITE_VIDEO_MODELS = [
|
|
45052
45058
|
{
|
|
45053
45059
|
id: "pruna/p-video-2-pro",
|
|
@@ -45145,6 +45151,59 @@ var SPRITE_VIDEO_MODELS = [
|
|
|
45145
45151
|
promptExpansion: ["balanced", "quality"],
|
|
45146
45152
|
estimatedCreditsPerSecond: { "720p": { quality: 17 }, "1080p": { quality: 29 } },
|
|
45147
45153
|
seconds: { min: 5, max: 20 }
|
|
45154
|
+
},
|
|
45155
|
+
// BytePlus bills a clip's tokens (width × height × frames / 1024, at 24 fps plus a frame); credits take each resolution's largest shape.
|
|
45156
|
+
{
|
|
45157
|
+
id: "byteplus/seedance-2.5",
|
|
45158
|
+
label: "Seedance 2.5 (BytePlus)",
|
|
45159
|
+
provider: "byteplus",
|
|
45160
|
+
providerModel: "dreamina-seedance-2-5-260628",
|
|
45161
|
+
workflows: SEEDANCE_WORKFLOWS,
|
|
45162
|
+
resolutions: ["480p", "720p"],
|
|
45163
|
+
workflowOptions: { "reference-to-video": { ...SEEDANCE_REFERENCES, mediaSeconds: 30 } },
|
|
45164
|
+
modes: ["quality"],
|
|
45165
|
+
lastFrame: true,
|
|
45166
|
+
estimatedCreditsPerSecond: { "480p": { quality: 10.86 }, "720p": { quality: 23.51 } },
|
|
45167
|
+
seconds: { min: 4, max: 30 }
|
|
45168
|
+
},
|
|
45169
|
+
{
|
|
45170
|
+
id: "byteplus/seedance-2.0",
|
|
45171
|
+
label: "Seedance 2.0 (BytePlus)",
|
|
45172
|
+
provider: "byteplus",
|
|
45173
|
+
providerModel: "dreamina-seedance-2-0-260128",
|
|
45174
|
+
workflows: SEEDANCE_WORKFLOWS,
|
|
45175
|
+
resolutions: ["480p", "720p", "1080p"],
|
|
45176
|
+
workflowOptions: { "reference-to-video": { ...SEEDANCE_REFERENCES, audioNeedsImages: true } },
|
|
45177
|
+
modes: ["quality"],
|
|
45178
|
+
lastFrame: true,
|
|
45179
|
+
estimatedCreditsPerSecond: { "480p": { quality: 7.11 }, "720p": { quality: 15.38 }, "1080p": { quality: 38.06 } },
|
|
45180
|
+
seconds: { min: 4, max: 15 }
|
|
45181
|
+
},
|
|
45182
|
+
{
|
|
45183
|
+
id: "byteplus/seedance-2.0-fast",
|
|
45184
|
+
label: "Seedance 2.0 Fast (BytePlus)",
|
|
45185
|
+
provider: "byteplus",
|
|
45186
|
+
providerModel: "dreamina-seedance-2-0-fast-260128",
|
|
45187
|
+
workflows: SEEDANCE_WORKFLOWS,
|
|
45188
|
+
resolutions: ["480p", "720p"],
|
|
45189
|
+
workflowOptions: { "reference-to-video": { ...SEEDANCE_REFERENCES, audioNeedsImages: true } },
|
|
45190
|
+
modes: ["speed"],
|
|
45191
|
+
lastFrame: true,
|
|
45192
|
+
estimatedCreditsPerSecond: { "480p": { speed: 5.69 }, "720p": { speed: 12.3 } },
|
|
45193
|
+
seconds: { min: 4, max: 15 }
|
|
45194
|
+
},
|
|
45195
|
+
{
|
|
45196
|
+
id: "byteplus/seedance-2.0-mini",
|
|
45197
|
+
label: "Seedance 2.0 Mini (BytePlus)",
|
|
45198
|
+
provider: "byteplus",
|
|
45199
|
+
providerModel: "dreamina-seedance-2-0-mini-260615",
|
|
45200
|
+
workflows: SEEDANCE_WORKFLOWS,
|
|
45201
|
+
resolutions: ["480p", "720p"],
|
|
45202
|
+
workflowOptions: { "reference-to-video": { ...SEEDANCE_REFERENCES, audioNeedsImages: true } },
|
|
45203
|
+
modes: ["cost"],
|
|
45204
|
+
lastFrame: true,
|
|
45205
|
+
estimatedCreditsPerSecond: { "480p": { cost: 3.56 }, "720p": { cost: 7.69 } },
|
|
45206
|
+
seconds: { min: 4, max: 15 }
|
|
45148
45207
|
}
|
|
45149
45208
|
];
|
|
45150
45209
|
var SPRITE_VIDEO_MODEL_IDS = SPRITE_VIDEO_MODELS.map((m) => m.id);
|
|
@@ -46985,18 +47044,48 @@ var modelCostUsd = (p) => generationCostUsd(p) + (p.rig ? rigCostUsd(p.animation
|
|
|
46985
47044
|
// shared/assets.ts
|
|
46986
47045
|
var ASSET_TYPES = ["image", "vector", "video", "music", "speech", "sfx", "model"];
|
|
46987
47046
|
var SPEECH_MODELS = [
|
|
46988
|
-
{ id: "gemini-3.8-flash-tts", label: "Gemini 3.8 Flash TTS" },
|
|
46989
|
-
{ id: "gemini-3.8-flash-lite-tts", label: "Gemini 3.8 Flash-Lite TTS" },
|
|
46990
|
-
{ id: "eleven_v4", label: "ElevenLabs v4" },
|
|
46991
|
-
{ id: "eleven_v4_turbo", label: "ElevenLabs v4 Turbo" }
|
|
47047
|
+
{ id: "gemini-3.8-flash-tts", label: "Gemini 3.8 Flash TTS", provider: "google" },
|
|
47048
|
+
{ id: "gemini-3.8-flash-lite-tts", label: "Gemini 3.8 Flash-Lite TTS", provider: "google" },
|
|
47049
|
+
{ id: "eleven_v4", label: "ElevenLabs v4", provider: "elevenlabs" },
|
|
47050
|
+
{ id: "eleven_v4_turbo", label: "ElevenLabs v4 Turbo", provider: "elevenlabs" },
|
|
47051
|
+
{ id: "heygen-voice-1", label: "HeyGen Voice 1", provider: "heygen" },
|
|
47052
|
+
{ id: "heygen-voice-1-turbo", label: "HeyGen Voice 1 Turbo", provider: "heygen" }
|
|
46992
47053
|
];
|
|
46993
47054
|
var ELEVENLABS_SPEECH_MODEL_IDS = ["eleven_v4", "eleven_v4_turbo"];
|
|
47055
|
+
var HEYGEN_SPEECH_MODEL_IDS = ["heygen-voice-1", "heygen-voice-1-turbo"];
|
|
46994
47056
|
var SFX_MODELS = [{ id: "eleven_text_to_sound_v2", label: "ElevenLabs Sound Effects v2" }];
|
|
46995
47057
|
var DEFAULT_ELEVENLABS_VOICE = "JBFqnCBsd6RMkjVDRZzb";
|
|
46996
47058
|
var ELEVENLABS_VOICES = [{ id: DEFAULT_ELEVENLABS_VOICE, label: "George" }];
|
|
46997
47059
|
var isElevenLabsSpeech = (model) => ELEVENLABS_SPEECH_MODEL_IDS.includes(model);
|
|
46998
|
-
var
|
|
47060
|
+
var isHeyGenSpeech = (model) => HEYGEN_SPEECH_MODEL_IDS.includes(model);
|
|
47061
|
+
var DEFAULT_HEYGEN_VOICE = "83548de556df48ba8c09c42a57c51d85";
|
|
47062
|
+
var HEYGEN_VOICES = [
|
|
47063
|
+
{ id: DEFAULT_HEYGEN_VOICE, label: "Nadine \xB7 Calm & Gentle" },
|
|
47064
|
+
{ id: "75300849b571414c8d62693289cb6509", label: "Sabrina \xB7 Upbeat & Lively" },
|
|
47065
|
+
{ id: "aa9746e325ff46d482a54fe5bc87890f", label: "Meredith \xB7 Serious & Composed" },
|
|
47066
|
+
{ id: "fe333747c7d04a7188d20a8ea2a222d9", label: "Claire \xB7 Rich & Expressive" },
|
|
47067
|
+
{ id: "7e48c8d406b04a8089c5eb3cd057cb2e", label: "Jonah \xB7 Clear & Professional" },
|
|
47068
|
+
{ id: "826be797681d4b1a92042b54b3c75c64", label: "Gareth \xB7 Conversational & Easygoing" },
|
|
47069
|
+
{ id: "9b71011176ac49ee8d0936c36566d665", label: "Hugh \xB7 Firm & Measured" },
|
|
47070
|
+
{ id: "7bb4df56d7714d33bb88ed1dde8128f6", label: "Rory \xB7 Upbeat & Lively" }
|
|
47071
|
+
];
|
|
46999
47072
|
var SPEECH_VOICES = ["Kore", "Puck", "Charon", "Fenrir", "Aoede", "Leda", "Orus", "Zephyr"];
|
|
47073
|
+
var defaultSpeechVoice = (model) => isElevenLabsSpeech(model) ? DEFAULT_ELEVENLABS_VOICE : isHeyGenSpeech(model) ? DEFAULT_HEYGEN_VOICE : "Kore";
|
|
47074
|
+
var speechVoiceValid = (model, voice) => isElevenLabsSpeech(model) ? /^[a-zA-Z0-9]{20}$/.test(voice) : isHeyGenSpeech(model) ? /^[A-Za-z0-9_]{8,64}$/.test(voice) : SPEECH_VOICES.includes(voice);
|
|
47075
|
+
var MUSIC_MODELS = [
|
|
47076
|
+
{ id: "lyria-3.5", label: "Lyria 3.5", provider: "google" },
|
|
47077
|
+
{ id: "fal/mureka-9.5-song", label: "Mureka 9.5 Song", provider: "fal" },
|
|
47078
|
+
{ id: "fal/mureka-9.5-instrumental", label: "Mureka 9.5 Instrumental", provider: "fal" },
|
|
47079
|
+
{ id: "fal/mureka-9.5-soundtrack", label: "Mureka 9.5 Soundtrack", provider: "fal" }
|
|
47080
|
+
];
|
|
47081
|
+
var MUSIC_MODEL_IDS = ["lyria-3.5", "fal/mureka-9.5-song", "fal/mureka-9.5-instrumental", "fal/mureka-9.5-soundtrack"];
|
|
47082
|
+
var MUREKA_STYLES = ["pop", "rock", "jazz", "r&b", "edm", "ambient", "folk", "latin", "k-pop", "j-pop", "house", "gospel", "lo-fi"];
|
|
47083
|
+
var MUREKA_VOCALS = ["female", "male"];
|
|
47084
|
+
var MAX_SONG_LYRICS = 5e3;
|
|
47085
|
+
var SONG_SECONDS = { min: 120, max: 300 };
|
|
47086
|
+
var SONG_LENGTH = `Choose a length of ${SONG_SECONDS.min}\u2013${SONG_SECONDS.max} whole seconds.`;
|
|
47087
|
+
var SOUNDTRACK_IMAGE_MAX_BYTES = 50 * 1024 * 1024;
|
|
47088
|
+
var SOUNDTRACK_VIDEO_MAX_BYTES = 100 * 1024 * 1024;
|
|
47000
47089
|
var base = { name: external_exports.string().trim().min(1).max(80), prompt: external_exports.string().trim().min(3).max(4e3) };
|
|
47001
47090
|
var blob = external_exports.string().regex(/^[a-f0-9]{64}$/);
|
|
47002
47091
|
var cameraKeyframe = external_exports.object({
|
|
@@ -47197,6 +47286,12 @@ function videoChecks(p, ctx) {
|
|
|
47197
47286
|
if (options?.referencesOnly) {
|
|
47198
47287
|
for (const field of ["reference", "endReference", "middleReference"]) if (p[field]) issue2(field, "This video model's reference-to-video takes references only, without a first, last or middle frame.");
|
|
47199
47288
|
}
|
|
47289
|
+
const kinds = options?.mediaReferences;
|
|
47290
|
+
const files = [["images", "references", references.length], ["videos", "referenceVideos", p.referenceVideos?.length ?? 0], ["audio", "audioReferences", p.audioReferences.length]];
|
|
47291
|
+
if (kinds) {
|
|
47292
|
+
for (const [kind, field, count] of files) if (count && !kinds.includes(kind)) issue2(field, `This video model's reference-to-video takes reference ${kinds.join(" and ")}, not ${kind}.`);
|
|
47293
|
+
}
|
|
47294
|
+
if (options?.audioNeedsImages && p.audioReferences.length && !references.length && !p.referenceVideos?.length) issue2("audioReferences", "This video model needs a reference image beside reference audio.");
|
|
47200
47295
|
if (references.length + (p.referenceVideos?.length ?? 0) + p.audioReferences.length > MAX_REFERENCE_FILES) issue2("references", `reference-to-video takes at most ${MAX_REFERENCE_FILES} reference files in all.`);
|
|
47201
47296
|
const frames = !options?.referencesOnly && (p.reference || p.endReference);
|
|
47202
47297
|
if (!references.length && !p.referenceVideos?.length && !p.audioReferences.length && !frames) issue2("references", `reference-to-video needs reference images, videos or audio${options?.referencesOnly ? "" : ", or a first or last frame"}.`);
|
|
@@ -47290,6 +47385,60 @@ function vectorChecks(p, ctx) {
|
|
|
47290
47385
|
if (p.references.length) issue2("references", "image-to-vector traces its source alone and takes no references.");
|
|
47291
47386
|
}
|
|
47292
47387
|
var vectorDefaults = (p) => p.workflow === "text-to-vector" ? { ...p, quality: p.quality ?? "medium", aspectRatio: p.aspectRatio ?? "auto" } : { ...p, shapes: p.shapes ?? "detailed" };
|
|
47388
|
+
var musicAsset = external_exports.object({
|
|
47389
|
+
name: base.name,
|
|
47390
|
+
/** A soundtrack may leave it out, and so may a song sung from lyrics, where it sets the style. */
|
|
47391
|
+
prompt: external_exports.string().trim().max(4e3).default(""),
|
|
47392
|
+
type: external_exports.literal("music"),
|
|
47393
|
+
model: external_exports.enum(MUSIC_MODEL_IDS).default("lyria-3.5"),
|
|
47394
|
+
/** Mureka Song: the words to sing. */
|
|
47395
|
+
lyrics: external_exports.string().trim().min(1).max(MAX_SONG_LYRICS).optional(),
|
|
47396
|
+
/** Mureka Song written from the prompt: its genres. */
|
|
47397
|
+
styles: external_exports.array(external_exports.enum(MUREKA_STYLES)).min(1).max(MUREKA_STYLES.length).optional(),
|
|
47398
|
+
/** Mureka Song sung from lyrics: who sings. */
|
|
47399
|
+
vocals: external_exports.enum(MUREKA_VOCALS).optional(),
|
|
47400
|
+
/** Mureka Song: about how long, in whole seconds; the model chooses when it's left out. */
|
|
47401
|
+
seconds: external_exports.number().int(SONG_LENGTH).min(SONG_SECONDS.min, SONG_LENGTH).max(SONG_SECONDS.max, SONG_LENGTH).optional(),
|
|
47402
|
+
/** Mureka Soundtrack: the saved image or video to score. */
|
|
47403
|
+
source: blob.optional()
|
|
47404
|
+
});
|
|
47405
|
+
var MUSIC_ONLY = {
|
|
47406
|
+
lyrics: ["fal/mureka-9.5-song", "Only Mureka 9.5 Song sings lyrics."],
|
|
47407
|
+
styles: ["fal/mureka-9.5-song", "Only Mureka 9.5 Song takes styles; describe the genre in the prompt."],
|
|
47408
|
+
vocals: ["fal/mureka-9.5-song", "Only Mureka 9.5 Song takes vocals."],
|
|
47409
|
+
seconds: ["fal/mureka-9.5-song", "Only Mureka 9.5 Song takes a length; the other music models choose their own."],
|
|
47410
|
+
source: ["fal/mureka-9.5-soundtrack", "Only Mureka 9.5 Soundtrack scores a saved image or video."]
|
|
47411
|
+
};
|
|
47412
|
+
function musicChecks(p, ctx) {
|
|
47413
|
+
const issue2 = (path, message) => ctx.addIssue({ code: "custom", message, path: [path] });
|
|
47414
|
+
for (const [field, [model, message]] of Object.entries(MUSIC_ONLY)) if (p[field] !== void 0 && p.model !== model) issue2(field, message);
|
|
47415
|
+
const most = (max2) => {
|
|
47416
|
+
if (p.prompt.length > max2) issue2("prompt", `Describe the music in at most ${max2.toLocaleString("en-US")} characters.`);
|
|
47417
|
+
};
|
|
47418
|
+
if (p.model === "fal/mureka-9.5-song") {
|
|
47419
|
+
if (p.lyrics) {
|
|
47420
|
+
most(1024);
|
|
47421
|
+
if (p.styles) issue2("styles", "A song sung from lyrics takes its style from the prompt; leave out styles.");
|
|
47422
|
+
} else {
|
|
47423
|
+
if (p.prompt.length < 3) issue2("prompt", "Describe the song in at least 3 characters, or give lyrics to sing.");
|
|
47424
|
+
most(2e3);
|
|
47425
|
+
if (p.vocals) issue2("vocals", "Vocals choose who sings lyrics; describe the singer in the prompt instead.");
|
|
47426
|
+
}
|
|
47427
|
+
if (p.styles && new Set(p.styles).size !== p.styles.length) issue2("styles", "Choose each style once.");
|
|
47428
|
+
return;
|
|
47429
|
+
}
|
|
47430
|
+
if (p.model === "fal/mureka-9.5-soundtrack") {
|
|
47431
|
+
if (!p.source) issue2("source", "Choose a saved image or video to score.");
|
|
47432
|
+
return most(1024);
|
|
47433
|
+
}
|
|
47434
|
+
if (p.prompt.length < 3) issue2("prompt", "Describe the music in at least 3 characters.");
|
|
47435
|
+
if (p.model === "fal/mureka-9.5-instrumental") most(1024);
|
|
47436
|
+
}
|
|
47437
|
+
function musicCostUsd(p) {
|
|
47438
|
+
if (p.model === "lyria-3.5") return 0.08;
|
|
47439
|
+
if (p.model === "fal/mureka-9.5-song") return p.lyrics ? 0.15 : 0.5;
|
|
47440
|
+
return p.model === "fal/mureka-9.5-instrumental" ? 0.15 : 0.11;
|
|
47441
|
+
}
|
|
47293
47442
|
var animationClip = external_exports.union([external_exports.enum(MODEL_ANIMATION_IDS), external_exports.number().int().min(0).max(MAX_MESHY_ACTION)]);
|
|
47294
47443
|
var modelAsset = external_exports.object({
|
|
47295
47444
|
name: base.name,
|
|
@@ -47346,11 +47495,12 @@ var modelDefaults = (p) => ({ ...p, animations: p.rig && !p.animations.length ?
|
|
|
47346
47495
|
var assetRequest = external_exports.discriminatedUnion("type", [
|
|
47347
47496
|
imageAsset.superRefine(imageChecks),
|
|
47348
47497
|
videoAsset.superRefine(videoChecks).transform(videoDefaults),
|
|
47349
|
-
|
|
47350
|
-
external_exports.object({ ...base, type: external_exports.literal("speech"), model: external_exports.enum(["gemini-3.8-flash-tts", "gemini-3.8-flash-lite-tts", ...ELEVENLABS_SPEECH_MODEL_IDS]).default("gemini-3.8-flash-lite-tts"), voice: external_exports.string().trim().max(80).default(""), delivery: external_exports.string().trim().max(600).default("") }).superRefine((p, ctx) => {
|
|
47351
|
-
if (p.voice && (
|
|
47498
|
+
musicAsset.superRefine(musicChecks),
|
|
47499
|
+
external_exports.object({ ...base, type: external_exports.literal("speech"), model: external_exports.enum(["gemini-3.8-flash-tts", "gemini-3.8-flash-lite-tts", ...ELEVENLABS_SPEECH_MODEL_IDS, ...HEYGEN_SPEECH_MODEL_IDS]).default("gemini-3.8-flash-lite-tts"), voice: external_exports.string().trim().max(80).default(""), delivery: external_exports.string().trim().max(600).default("") }).superRefine((p, ctx) => {
|
|
47500
|
+
if (p.voice && !speechVoiceValid(p.model, p.voice)) ctx.addIssue({ code: "custom", message: "Choose a voice supported by the speech provider.", path: ["voice"] });
|
|
47352
47501
|
if (isElevenLabsSpeech(p.model) && p.delivery) ctx.addIssue({ code: "custom", message: "ElevenLabs uses audio tags in the transcript; separate delivery instructions are only supported by Gemini.", path: ["delivery"] });
|
|
47353
|
-
|
|
47502
|
+
if (isHeyGenSpeech(p.model) && p.delivery) ctx.addIssue({ code: "custom", message: "HeyGen Voice speaks the transcript as written; separate delivery instructions are only supported by Gemini.", path: ["delivery"] });
|
|
47503
|
+
}).transform((p) => ({ ...p, voice: p.voice || defaultSpeechVoice(p.model) })),
|
|
47354
47504
|
external_exports.object({ ...base, type: external_exports.literal("sfx"), model: external_exports.literal("eleven_text_to_sound_v2").default("eleven_text_to_sound_v2"), seconds: external_exports.number().min(0.5).max(30).default(5), loop: external_exports.boolean().default(false), promptInfluence: external_exports.number().min(0).max(1).default(0.3) }),
|
|
47355
47505
|
vectorAsset.superRefine(vectorChecks).transform(vectorDefaults),
|
|
47356
47506
|
modelAsset.superRefine(modelChecks).transform(modelDefaults)
|
|
@@ -47385,9 +47535,10 @@ function assetEstimate(p, now = Date.now()) {
|
|
|
47385
47535
|
if (p.type === "vector") return vectorEstimate(p);
|
|
47386
47536
|
if (p.type === "model") return modelEstimate(p);
|
|
47387
47537
|
if (p.type === "video") return spriteVideoEstimate(spriteVideoModel(p.model), p, videoExtras(p));
|
|
47388
|
-
if (p.type === "music") return
|
|
47538
|
+
if (p.type === "music") return Math.ceil(musicCostUsd(p) / 1e-3);
|
|
47389
47539
|
const units = (credits) => Math.max(1, Math.ceil(credits * UNITS_PER_CREDIT));
|
|
47390
47540
|
if (p.type === "sfx") return units(Math.max(0, p.seconds) * 0.2);
|
|
47541
|
+
if (isHeyGenSpeech(p.model)) return units(speechCharacters(p.prompt) * (p.model === "heygen-voice-1-turbo" ? 0.4 : 1.5) / 1e3);
|
|
47391
47542
|
if (isElevenLabsSpeech(p.model)) {
|
|
47392
47543
|
const promotion2 = now < Date.UTC(2026, 9, 13);
|
|
47393
47544
|
const perThousandCharacters = p.model === "eleven_v4_turbo" ? promotion2 ? 1.1 : 4 : promotion2 ? 2.2 : 8;
|
|
@@ -47411,7 +47562,7 @@ var VIDEO_PART_BYTES = 8 * 1024 * 1024;
|
|
|
47411
47562
|
var VIDEO_MAX_BYTES = { html5: 64 * 1024 * 1024, mp4: 512 * 1024 * 1024 };
|
|
47412
47563
|
var VIDEO_LIBRARY_BYTES = { user: 2 * 1024 ** 3, team: 10 * 1024 ** 3 };
|
|
47413
47564
|
var VIDEO_VISIBILITIES = ["private", "public"];
|
|
47414
|
-
var VIDEO_SHARING_AGREEMENT_VERSION = "2026-
|
|
47565
|
+
var VIDEO_SHARING_AGREEMENT_VERSION = "2026-11-02";
|
|
47415
47566
|
var videoAgreementAcceptance = external_exports.object({
|
|
47416
47567
|
version: external_exports.literal(VIDEO_SHARING_AGREEMENT_VERSION),
|
|
47417
47568
|
language: external_exports.enum(["en", "tr"])
|
|
@@ -48652,7 +48803,7 @@ var extras = {
|
|
|
48652
48803
|
"style",
|
|
48653
48804
|
"damage"
|
|
48654
48805
|
],
|
|
48655
|
-
music: [],
|
|
48806
|
+
music: ["lyrics", "styles", "vocals", "seconds", "source"],
|
|
48656
48807
|
speech: ["voice", "delivery"],
|
|
48657
48808
|
sfx: ["seconds", "loop", "prompt-influence"],
|
|
48658
48809
|
model: ["reference", "texture", "pbr", "faces", "rig", "animations", "height", "splats", "photo", "seed"],
|
|
@@ -48660,7 +48811,6 @@ var extras = {
|
|
|
48660
48811
|
};
|
|
48661
48812
|
var list2 = (items) => items.length < 2 ? items.join("") : `${items.slice(0, -1).join(", ")} and ${items.at(-1)}`;
|
|
48662
48813
|
function accepted(type) {
|
|
48663
|
-
if (type === "music") return "Music accepts only --name, --prompt and --model; the model chooses the length, so fit it during the edit.";
|
|
48664
48814
|
const options = extras[type];
|
|
48665
48815
|
if (!options) return "";
|
|
48666
48816
|
return `${type[0].toUpperCase()}${type.slice(1)} assets accept ${list2(["--name", "--prompt", "--model", ...options.map((option) => `--${option}`)])}.`;
|
|
@@ -48695,7 +48845,8 @@ function assetFromFlags(flags) {
|
|
|
48695
48845
|
const given2 = value !== void 0 && (value !== false || (name2 === "texture" || name2 === "pbr") && flags.type !== "model");
|
|
48696
48846
|
if (given2 && !extras[flags.type]?.includes(name2)) throw new Error(`--${name2} is not an option for ${flags.type} assets. ${accepted(flags.type)}`.trim());
|
|
48697
48847
|
}
|
|
48698
|
-
|
|
48848
|
+
const promptOptional = flags.type === "video" || flags.type === "vector" || flags.type === "model" && (flags.reference || isSplatGenerator(flags.model ?? "")) || flags.type === "music" && (flags.model === "fal/mureka-9.5-soundtrack" || flags.lyrics !== void 0);
|
|
48849
|
+
if (!promptOptional && flags.prompt === void 0) throw new Error(`--prompt is required for ${flags.type} assets${flags.type === "model" ? " unless --reference names an image to build from" : flags.type === "music" ? " unless Mureka 9.5 Song sings --lyrics or Mureka 9.5 Soundtrack scores --source" : ""}.`);
|
|
48699
48850
|
const base2 = { type: flags.type, name: flags.name, prompt: flags.prompt, model: flags.model };
|
|
48700
48851
|
if (flags.type === "image") return parseAsset({ ...base2, aspectRatio: flags["aspect-ratio"], transparent: flags.transparent, references: shas(flags.references), mask: regions(flags.mask) });
|
|
48701
48852
|
if (flags.type === "video") {
|
|
@@ -48733,6 +48884,7 @@ function assetFromFlags(flags) {
|
|
|
48733
48884
|
});
|
|
48734
48885
|
}
|
|
48735
48886
|
if (flags.type === "sfx") return parseAsset({ ...base2, seconds: flags.seconds, loop: flags.loop, promptInfluence: flags["prompt-influence"] });
|
|
48887
|
+
if (flags.type === "music") return parseAsset({ ...base2, lyrics: flags.lyrics, styles: shas(flags.styles), vocals: flags.vocals, seconds: flags.seconds, source: flags.source });
|
|
48736
48888
|
if (flags.type === "model") return parseAsset({ ...base2, reference: flags.reference, texture: flags.texture, pbr: flags.pbr, faces: flags.faces, rig: flags.rig, animations: clips(flags.animations), height: flags.height, splats: flags.splats, photo: flags.photo || void 0, seed: flags.seed });
|
|
48737
48889
|
if (flags.type === "vector") return parseAsset({ ...base2, workflow: flags.workflow, quality: flags.quality, aspectRatio: flags["aspect-ratio"], references: shas(flags.references), source: flags.source, shapes: flags.shapes, seed: flags.seed });
|
|
48738
48890
|
return parseAsset({ ...base2, ...flags.type === "speech" ? { voice: flags.voice, delivery: flags.delivery } : {} });
|
|
@@ -50843,13 +50995,13 @@ var catalogSections = {
|
|
|
50843
50995
|
image: ["assetTypes"],
|
|
50844
50996
|
vector: ["assetTypes", "vectorModels", "vectorOptions"],
|
|
50845
50997
|
video: ["assetTypes", "videoModels", "videoProfiles"],
|
|
50846
|
-
music: ["assetTypes", "musicModels"],
|
|
50847
|
-
speech: ["assetTypes", "speechModels", "voices", "elevenLabsVoices"],
|
|
50998
|
+
music: ["assetTypes", "musicModels", "musicOptions"],
|
|
50999
|
+
speech: ["assetTypes", "speechModels", "voices", "elevenLabsVoices", "heygenVoices"],
|
|
50848
51000
|
sfx: ["assetTypes", "sfxModels"],
|
|
50849
51001
|
model: ["assetTypes", "modelGenerators", "modelAnimations"],
|
|
50850
51002
|
avatars: ["avatarTypes", "avatarLookTypes"]
|
|
50851
51003
|
};
|
|
50852
|
-
var catalog = () => ({ styles: SPRITE_STYLES, kinds: SPRITE_KINDS, actions: ALL_SPRITE_ACTIONS, videoModels: SPRITE_VIDEO_MODEL_IDS, assetTypes: ASSET_TYPES, musicModels: MUSIC_MODELS.map((m) => m.id), speechModels: SPEECH_MODELS.map((m) => m.id), sfxModels: SFX_MODELS.map((m) => m.id), modelGenerators: MODEL_GENERATORS.map((g) => ({ id: g.id, label: g.label, output: g.output, ...g.output === "spz" ? { splats: g.splats } : { faces: g.faces } })), modelAnimations: MODEL_ANIMATIONS, vectorModels: VECTOR_MODELS.map((m) => m.id), vectorOptions: { workflows: VECTOR_WORKFLOWS, qualities: VECTOR_QUALITIES, aspectRatios: VECTOR_ASPECT_RATIOS, shapes: VECTOR_SHAPES, maxReferences: MAX_VECTOR_REFERENCES }, elevenLabsVoices: ELEVENLABS_VOICES, voices: SPEECH_VOICES, videoProfiles: SPRITE_VIDEO_MODELS, avatarTypes: AVATAR_CREATE_TYPES, avatarLookTypes: AVATAR_LOOK_TYPES });
|
|
51004
|
+
var catalog = () => ({ styles: SPRITE_STYLES, kinds: SPRITE_KINDS, actions: ALL_SPRITE_ACTIONS, videoModels: SPRITE_VIDEO_MODEL_IDS, assetTypes: ASSET_TYPES, musicModels: MUSIC_MODELS.map((m) => m.id), musicOptions: { styles: MUREKA_STYLES, vocals: MUREKA_VOCALS, songSeconds: SONG_SECONDS, maxLyrics: MAX_SONG_LYRICS }, speechModels: SPEECH_MODELS.map((m) => m.id), sfxModels: SFX_MODELS.map((m) => m.id), modelGenerators: MODEL_GENERATORS.map((g) => ({ id: g.id, label: g.label, output: g.output, ...g.output === "spz" ? { splats: g.splats } : { faces: g.faces } })), modelAnimations: MODEL_ANIMATIONS, vectorModels: VECTOR_MODELS.map((m) => m.id), vectorOptions: { workflows: VECTOR_WORKFLOWS, qualities: VECTOR_QUALITIES, aspectRatios: VECTOR_ASPECT_RATIOS, shapes: VECTOR_SHAPES, maxReferences: MAX_VECTOR_REFERENCES }, elevenLabsVoices: ELEVENLABS_VOICES, heygenVoices: HEYGEN_VOICES, voices: SPEECH_VOICES, videoProfiles: SPRITE_VIDEO_MODELS, avatarTypes: AVATAR_CREATE_TYPES, avatarLookTypes: AVATAR_LOOK_TYPES });
|
|
50853
51005
|
var modelFlags = [
|
|
50854
51006
|
{ name: "video-model", type: "string", choices: SPRITE_VIDEO_MODEL_IDS, description: "Video model override for this operation" }
|
|
50855
51007
|
];
|
|
@@ -51170,20 +51322,20 @@ Confirm code: ${device.user_code}`);
|
|
|
51170
51322
|
})))).command("assets", (assets) => assets.add(defineCommand("list", { description: "List saved assets, their blob hashes, and configured generation models" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" } }).args(id).action(async ({ args, flags, stdout, signal }) => out(stdout, await new Client(flags.url, signal).request(`${projectPath(args.id)}/assets`))))).add(defineCommand("generate", { description: "Generate an image, vector (SVG), video, music, speech, sound-effect or 3D model asset; --yes authorizes credits" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" } }).args(id).flags(
|
|
51171
51323
|
{ name: "type", type: "string", required: true, choices: ASSET_TYPES },
|
|
51172
51324
|
{ name: "name", type: "string", required: true },
|
|
51173
|
-
{ name: "prompt", type: "string", description: "Description to generate, or verbatim transcript for speech; video lip-sync and relight and vector image-to-vector take none, and camera-controls, insert-video, recast
|
|
51325
|
+
{ name: "prompt", type: "string", description: "Description to generate, or verbatim transcript for speech; video lip-sync and relight and vector image-to-vector take none, and camera-controls, insert-video, recast, 3d-to-video, a Mureka soundtrack and a song with --lyrics (where it sets the style) may leave it out" },
|
|
51174
51326
|
{ name: "model", type: "string", choices: assetModelIds, description: "Model for the chosen asset type" },
|
|
51175
51327
|
{ name: "aspect-ratio", type: "string", choices: [.../* @__PURE__ */ new Set([...IMAGE_ASPECT_RATIOS, "auto", ...VIDEO_ASPECT_RATIOS, ...VECTOR_ASPECT_RATIOS])], description: "Image: 1:1 (default), 3:2, 2:3, 16:9 or 9:16; a masked edit keeps Image 1's shape. Video from text or a style without --reference: 21:9\u20139:16 (default 16:9). Extension, reference-to-video, relight and keyframes-to-video: auto (default, the inputs' shape) or a ratio to crop to. Vector from text: auto (default, the model's choice) or 1:4\u20134:1" },
|
|
51176
51328
|
{ name: "transparent", type: "boolean", description: "Image: transparent background" },
|
|
51177
51329
|
{ name: "references", type: "string", description: "Comma-separated blob SHAs of this project's images or sprite art, named Image 1, Image 2\u2026 in the prompt. Image: up to 4 to follow, such as a character sheet. Vector from text: up to 5, the first leading. Video: subjects or looks to keep (reference-to-video and insert-video up to 9, 3d-to-video up to 8), or recast's new people, one photo each (up to 4)" },
|
|
51178
51330
|
{ name: "mask", type: "string", description: "Image: edit only these rectangles of Image 1 (the first --references image), as x,y,width,height fractions of its size from the top left, up to 8 separated by semicolons; the rest is kept" },
|
|
51179
|
-
{ name: "workflow", type: "string", choices: [...VIDEO_WORKFLOWS, ...VECTOR_WORKFLOWS], description: "Video: image-to-video (default), text-to-video or extend-video; H3 Max also reference-to-video, lip-sync, camera-controls, insert-video, recast, relight, 3d-to-video and style, FLUX 3 Max keyframes-to-video, HeyGen Video 1 reference-to-video, as the model's videoProfiles allow. Vector: text-to-vector (default) or image-to-vector, which traces --source" },
|
|
51331
|
+
{ name: "workflow", type: "string", choices: [...VIDEO_WORKFLOWS, ...VECTOR_WORKFLOWS], description: "Video: image-to-video (default), text-to-video or extend-video; H3 Max also reference-to-video, lip-sync, camera-controls, insert-video, recast, relight, 3d-to-video and style, FLUX 3 Max keyframes-to-video, HeyGen Video 1 and Seedance reference-to-video, as the model's videoProfiles allow. Vector: text-to-vector (default) or image-to-vector, which traces --source" },
|
|
51180
51332
|
{ name: "reference", type: "string", description: "Video: starting image blob SHA from this project's assets or sprites; the speaking face for lip-sync, the image the camera moves around for camera-controls. Model: the image or sprite art to build it from (image-to-3D); without one the prompt describes it" },
|
|
51181
51333
|
{ name: "end-reference", type: "string", description: "Video: ending image blob SHA; models with endFrameOnly accept it without --reference" },
|
|
51182
51334
|
{ name: "middle-reference", type: "string", description: "Reference-to-video: image blob SHA reached at --middle-seconds; needs --reference and --end-reference, 480p or 768p" },
|
|
51183
51335
|
{ name: "middle-seconds", type: "number", description: "Reference-to-video: when the middle image is reached, in seconds" },
|
|
51184
|
-
{ name: "source", type: "string", description: "Blob SHA of a video asset in this project: the clip to extend, insert a scene into, recast or relight, or the 3D render 3d-to-video turns into footage. Vector image-to-vector: the image or sprite art to trace" },
|
|
51336
|
+
{ name: "source", type: "string", description: "Blob SHA of a video asset in this project: the clip to extend, insert a scene into, recast or relight, or the 3D render 3d-to-video turns into footage. Vector image-to-vector: the image or sprite art to trace. Music with --model fal/mureka-9.5-soundtrack: the video (up to 100 MB), image or sprite art to score; a video's soundtrack runs as long as the video" },
|
|
51185
51337
|
{ name: "soundtrack", type: "string", description: "Video from an image or text: blob SHA of a music, speech or SFX asset pinned as the soundtrack (2 s or longer). Lip-sync: the speech to say (5 s\u201315 min), which sets the length" },
|
|
51186
|
-
{ name: "audio-references", type: "string", description: "Extension or reference-to-video: up to 3 comma-separated audio asset blob SHAs (on fal 2\u201315 s each, 15 s total) guiding the sound; refer to them as Audio 1, Audio 2\u2026 in the prompt" },
|
|
51338
|
+
{ name: "audio-references", type: "string", description: "Extension or reference-to-video: up to 3 comma-separated audio asset blob SHAs (on fal and Seedance 2\u201315 s each, 15 s total; Seedance 2.5 30 s) guiding the sound; refer to them as Audio 1, Audio 2\u2026 in the prompt" },
|
|
51187
51339
|
{ name: "reference-videos", type: "string", description: "Reference-to-video or insert-video: up to 3 comma-separated video asset blob SHAs (on fal 2\u201315 s each, 15 s total; HeyGen reads the first 5 s of each) guiding motion, named Video 1, Video 2\u2026 in the prompt" },
|
|
51188
51340
|
{ name: "camera", type: "string", description: 'Camera-controls: 2\u201312 keyframes time,azimuth,elevation,distance (time 0\u20131, angles in degrees, elevation \u221290\u201390) separated by semicolons, e.g. "0,0,0,1;1,90,15,1.2"' },
|
|
51189
51341
|
{ name: "keyframes", type: "string", description: 'Keyframes-to-video (FLUX 3 Max): 1\u201310 seconds,image-SHA pairs separated by semicolons, e.g. "0,SHA;2.5,SHA;5,SHA"; each image is reached at its second, on a frame of its own of the 24 fps clip, within --seconds' },
|
|
@@ -51197,14 +51349,17 @@ Confirm code: ${device.user_code}`);
|
|
|
51197
51349
|
{ name: "generated-references", type: "number", description: "3d-to-video without --references: how many reference images it may draw, 1\u20138 (default 2)" },
|
|
51198
51350
|
{ name: "style", type: "string", choices: VIDEO_STYLES, description: "Style workflow: the preset look, at 768p for 5\u201315 whole seconds" },
|
|
51199
51351
|
{ name: "damage", type: "string", choices: VHS_DAMAGE_LEVELS, description: "VHS style: tape damage (fal's default medium)" },
|
|
51200
|
-
{ name: "seconds", type: "number", description: "Video or
|
|
51352
|
+
{ name: "seconds", type: "number", description: "Video, SFX or song duration in seconds (default 5; a Mureka song picks its own); H3 takes fractions (6.5), FLUX 3 Max 5\u201320 whole seconds, HeyGen Video 1 5\u201315 (up to 30 from an image or text with --prompt-expansion balanced or quality), Seedance 4\u201315 whole seconds (2.5 up to 30); extensions add this many seconds, insert-video's scene is 5\u201313; lip-sync, recast, relight and 3d-to-video take their input's length; SFX supports 0.5\u201330; Mureka 9.5 Song 120\u2013300 whole seconds" },
|
|
51201
51353
|
{ name: "resolution", type: "string", choices: VIDEO_RESOLUTIONS, description: "Video resolution supported by the selected model and workflow (default its first)" },
|
|
51202
51354
|
{ name: "mode", type: "string", choices: ["cost", "speed", "quality"], description: "Video generation mode supported by the selected model (default its first)" },
|
|
51203
51355
|
{ name: "prompt-expansion", type: "string", choices: PROMPT_EXPANSION_MODES, description: "Video: how much the model may rewrite the prompt (default disabled); extensions treat any other value as on. FLUX 3 Max always reasons about the prompt: quality thoroughly, any other value lightly. HeyGen Video 1 needs balanced or quality for clips over 15 s" },
|
|
51204
51356
|
{ name: "seed", type: "number", description: "Video, vector from text, or model with --model idol: seed for repeatable results, where the model takes one" },
|
|
51205
51357
|
{ name: "extend-output", type: "string", choices: EXTEND_OUTPUTS, description: "Extension: extended (default, source plus new footage) or continuation (a 1.625 s overlap, then the new footage)" },
|
|
51206
|
-
{ name: "voice", type: "string", description: "Gemini voice name or ElevenLabs voice ID (defaults: Kore / George)" },
|
|
51207
|
-
{ name: "delivery", type: "string", description: "Gemini speech delivery instructions; ElevenLabs uses audio tags in the transcript" },
|
|
51358
|
+
{ name: "voice", type: "string", description: "Gemini voice name, or an ElevenLabs or HeyGen public voice ID (defaults: Kore / George / Nadine; catalog --type speech suggests more)" },
|
|
51359
|
+
{ name: "delivery", type: "string", description: "Gemini speech delivery instructions; ElevenLabs uses audio tags in the transcript, and HeyGen Voice reads it as written" },
|
|
51360
|
+
{ name: "lyrics", type: "string", description: `Music with --model fal/mureka-9.5-song: the words to sing, up to ${MAX_SONG_LYRICS.toLocaleString("en-US")} characters, sections tagged [Verse], [Chorus]\u2026; --prompt then sets the style. A sung song costs 15 credits, one written from the prompt 50` },
|
|
51361
|
+
{ name: "styles", type: "string", description: `Music with --model fal/mureka-9.5-song and no --lyrics: comma-separated genres from ${MUREKA_STYLES.join(", ")}` },
|
|
51362
|
+
{ name: "vocals", type: "string", choices: MUREKA_VOCALS, description: "Music with --model fal/mureka-9.5-song and --lyrics: who sings" },
|
|
51208
51363
|
{ name: "loop", type: "boolean", description: "SFX: create a seamless loop" },
|
|
51209
51364
|
{ name: "texture", type: "boolean", description: "Model: textured (default on); --no-texture makes a plain white model" },
|
|
51210
51365
|
{ name: "pbr", type: "boolean", description: "Model: metallic, roughness and normal maps with the texture (default on); --no-pbr leaves them out" },
|
package/package.json
CHANGED
|
@@ -62,10 +62,16 @@ animaguru assets generate PROJECT_ID --type speech --name "Welcome" \
|
|
|
62
62
|
--prompt "Welcome, traveler." --voice Kore --delivery "Warm and welcoming" --yes
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
Images use the staff-managed route automatically. Use `--model` to select a model for video, music, speech or sound effects; discover the choices with `catalog` and the server's configured subset with `assets list`. Asset defaults are per type, independently of sprite project defaults. Image backgrounds are retained unless `--transparent` is supplied. CLI 0.17.0 adds `--references`, `--mask` and the 16:9 and 9:16 image shapes. `--references SHA,SHA` (up to four) makes an image follow this project's saved images, uploads or sprite art. To keep a recurring character consistent, generate a character sheet once and reference its `file` SHA in every later image; refer to references in the prompt as Image 1, Image 2 and so on, and say what to take from each. `--aspect-ratio` is 1:1, 3:2, 2:3, 16:9 or 9:16; use 16:9 or 9:16 for video scenes. `--mask x,y,width,height[;…]` (up to eight rectangles, in fractions of Image 1 from the top left) edits only those parts of Image 1, the first reference, and keeps the rest and Image 1's shape. Look at the image before choosing the rectangles. Videos require an image asset's `file` SHA from `assets list`, or a character's `art` SHA from `projects get`, in the same project. Validate video options against the selected model's `videoProfiles` in `catalog`; omitted video settings use five seconds and that provider's first resolution/mode. MiniMax H3 Max and H3 Max Turbo (`fal/minimax-h3-max`, `fal/minimax-h3-max-turbo`) also take `--workflow text-to-video` (with `--aspect-ratio`) and `--workflow extend-video` (with `--source VIDEO_SHA`, 2K resolution, `--extend-output`, and up to three comma-separated `--audio-references`). From images, they accept `--end-reference` with or without `--reference` and a `--soundtrack AUDIO_SHA`. All workflows take `--prompt-expansion` and `--seed`. These need CLI 0.8.0 or newer. CLI 0.18.0 adds H3 Max's (not Turbo's) `--workflow reference-to-video` (keep a character across clips from up to nine `--references`, three `--reference-videos` and three `--audio-references`, named Image 1, Video 1, Audio 1 in the prompt; optional `--reference`, `--end-reference`, `--middle-reference` with `--middle-seconds`), `lip-sync` (the face in `--reference` says `--soundtrack` speech of 5 s–15 min; no `--prompt`; `--transcribe`), `camera-controls` (`--camera "time,azimuth,elevation,distance;…"`, 2–12 keyframes around `--reference`; without a prompt only the camera moves), `insert-video` (a 5–13 s scene inside `--source` from `--insert-at` to `--resume-at`, guided by `--references`/`--reference-videos`), `recast` (people in `--references` replace those in `--source`; pass `--subject-consent` only after each person agreed), `relight` (`--source` relit from a `--lighting` sphere image; no prompt), `3d-to-video` (a 3D render `--source` into footage, from `--references` or `--generated-references`) and `style` (`--style vhs|retro-toon-70s|low-poly|hand-drawn|16bit-pixel`, `--damage` for VHS, 768p, 5–15 whole seconds). Lip-sync, recast, relight and 3d-to-video take their input's length; their dry runs, like reference-to-video's and insert-video's, are server estimates because the price depends on the files. H3 takes fractional `--seconds` (6.5). CLI 0.21.0 adds FLUX 3 Max (`fal/flux-3-max`): image-to-video (with an optional `--end-reference`) and text-to-video for 5–20 whole seconds at 720p or 1080p with its own sound and no `--soundtrack`, and `--workflow keyframes-to-video`, which passes through 1–10 `--keyframes "SECONDS,SHA;…"` images, each reached at its second within `--seconds`. It always reasons about the prompt: `--prompt-expansion quality` thoroughly, other values lightly. CLI 0.30.0 adds HeyGen Video 1's (`heygen/heygen-video-1`) `--workflow text-to-video` (with `--aspect-ratio`) and `reference-to-video` (up to nine `--references`, three `--reference-videos`, of which it reads the first 5 s, and three `--audio-references`, named Image 1, Video 1, Audio 1 in the prompt; no `--reference`, `--end-reference` or `--middle-reference`), 1080p and 2K (16:9 or 9:16 from text or references), and `--seed`. From an image or text it runs to 30 whole seconds with `--prompt-expansion balanced` or `quality`, and every second past 15 costs more. For Gemini speech, `--prompt` is spoken verbatim and `--delivery` is a separate instruction. Music uses Lyria; the Gemini TTS models are for speech.
|
|
65
|
+
Images use the staff-managed route automatically. Use `--model` to select a model for video, music, speech or sound effects; discover the choices with `catalog` and the server's configured subset with `assets list`. Asset defaults are per type, independently of sprite project defaults. Image backgrounds are retained unless `--transparent` is supplied. CLI 0.17.0 adds `--references`, `--mask` and the 16:9 and 9:16 image shapes. `--references SHA,SHA` (up to four) makes an image follow this project's saved images, uploads or sprite art. To keep a recurring character consistent, generate a character sheet once and reference its `file` SHA in every later image; refer to references in the prompt as Image 1, Image 2 and so on, and say what to take from each. `--aspect-ratio` is 1:1, 3:2, 2:3, 16:9 or 9:16; use 16:9 or 9:16 for video scenes. `--mask x,y,width,height[;…]` (up to eight rectangles, in fractions of Image 1 from the top left) edits only those parts of Image 1, the first reference, and keeps the rest and Image 1's shape. Look at the image before choosing the rectangles. Videos require an image asset's `file` SHA from `assets list`, or a character's `art` SHA from `projects get`, in the same project. Validate video options against the selected model's `videoProfiles` in `catalog`; omitted video settings use five seconds and that provider's first resolution/mode. MiniMax H3 Max and H3 Max Turbo (`fal/minimax-h3-max`, `fal/minimax-h3-max-turbo`) also take `--workflow text-to-video` (with `--aspect-ratio`) and `--workflow extend-video` (with `--source VIDEO_SHA`, 2K resolution, `--extend-output`, and up to three comma-separated `--audio-references`). From images, they accept `--end-reference` with or without `--reference` and a `--soundtrack AUDIO_SHA`. All workflows take `--prompt-expansion` and `--seed`. These need CLI 0.8.0 or newer. CLI 0.18.0 adds H3 Max's (not Turbo's) `--workflow reference-to-video` (keep a character across clips from up to nine `--references`, three `--reference-videos` and three `--audio-references`, named Image 1, Video 1, Audio 1 in the prompt; optional `--reference`, `--end-reference`, `--middle-reference` with `--middle-seconds`), `lip-sync` (the face in `--reference` says `--soundtrack` speech of 5 s–15 min; no `--prompt`; `--transcribe`), `camera-controls` (`--camera "time,azimuth,elevation,distance;…"`, 2–12 keyframes around `--reference`; without a prompt only the camera moves), `insert-video` (a 5–13 s scene inside `--source` from `--insert-at` to `--resume-at`, guided by `--references`/`--reference-videos`), `recast` (people in `--references` replace those in `--source`; pass `--subject-consent` only after each person agreed), `relight` (`--source` relit from a `--lighting` sphere image; no prompt), `3d-to-video` (a 3D render `--source` into footage, from `--references` or `--generated-references`) and `style` (`--style vhs|retro-toon-70s|low-poly|hand-drawn|16bit-pixel`, `--damage` for VHS, 768p, 5–15 whole seconds). Lip-sync, recast, relight and 3d-to-video take their input's length; their dry runs, like reference-to-video's and insert-video's, are server estimates because the price depends on the files. H3 takes fractional `--seconds` (6.5). CLI 0.21.0 adds FLUX 3 Max (`fal/flux-3-max`): image-to-video (with an optional `--end-reference`) and text-to-video for 5–20 whole seconds at 720p or 1080p with its own sound and no `--soundtrack`, and `--workflow keyframes-to-video`, which passes through 1–10 `--keyframes "SECONDS,SHA;…"` images, each reached at its second within `--seconds`. It always reasons about the prompt: `--prompt-expansion quality` thoroughly, other values lightly. CLI 0.30.0 adds HeyGen Video 1's (`heygen/heygen-video-1`) `--workflow text-to-video` (with `--aspect-ratio`) and `reference-to-video` (up to nine `--references`, three `--reference-videos`, of which it reads the first 5 s, and three `--audio-references`, named Image 1, Video 1, Audio 1 in the prompt; no `--reference`, `--end-reference` or `--middle-reference`), 1080p and 2K (16:9 or 9:16 from text or references), and `--seed`. From an image or text it runs to 30 whole seconds with `--prompt-expansion balanced` or `quality`, and every second past 15 costs more. For Gemini speech, `--prompt` is spoken verbatim and `--delivery` is a separate instruction. Music uses Lyria (`lyria-3.5`, the default) or Mureka 9.5; the Gemini TTS models are for speech.
|
|
66
66
|
|
|
67
67
|
For ElevenLabs speech, choose `eleven_v4` or `eleven_v4_turbo`, pass an ElevenLabs voice ID with `--voice` (George is the default), and put audio tags in `--prompt` rather than using `--delivery`. For sound effects, use `--type sfx`; the only model is `eleven_text_to_sound_v2`. SFX supports `--seconds` from 0.5 to 30 (default 5), `--loop`, and `--prompt-influence` from 0 to 1 (default 0.3). These additions require CLI 0.5.0 or newer; check `catalog` before using them with an installed CLI.
|
|
68
68
|
|
|
69
|
+
CLI 0.36.0 adds Mureka 9.5 music on fal. `--model fal/mureka-9.5-song` sings `--lyrics` (up to 5,000 characters; tag sections `[Verse]`, `[Chorus]`) with `--vocals female|male`, and `--prompt` then sets the style (optional, up to 1,024 characters); without lyrics it writes the words from `--prompt` (up to 2,000 characters) in optional `--styles pop,rock,…` (`catalog --type music` lists them). `--seconds 120–300` asks for a length; otherwise Mureka chooses one, usually three to four minutes. A sung song costs 15 credits, one written from the prompt 50. `--model fal/mureka-9.5-instrumental` writes from `--prompt` alone (up to 1,024 characters, 15 credits). `--model fal/mureka-9.5-soundtrack --source SHA` scores a saved video (up to 100 MB), image or sprite art for 11 credits, with an optional mood `--prompt`; a video's soundtrack runs as long as the video, so score a finished cut, and an image gets a full-length track. Lyria takes none of these options and picks its own length. All of them return MP3.
|
|
70
|
+
|
|
71
|
+
Seedance on BytePlus (`byteplus/seedance-2.5`, `byteplus/seedance-2.0`, `byteplus/seedance-2.0-fast`, `byteplus/seedance-2.0-mini`) films from `--reference` (optionally ending on `--end-reference`; the clip keeps the image's shape), from text (`--workflow text-to-video --aspect-ratio …`) or from saved images and audio (`--workflow reference-to-video`, up to nine `--references` and three `--audio-references`, named Image 1 and Audio 1 in the prompt; all but 2.5 need an image beside audio). It runs 4–15 whole seconds (2.5 up to 30) at 480p or 720p (2.0 also 1080p) with its own sound, and takes no `--soundtrack`, `--seed`, `--prompt-expansion`, reference videos or extensions. It refuses images of real people's faces, so use illustrated or generated art. It is charged the tokens BytePlus counts, never more than the dry run's estimate.
|
|
72
|
+
|
|
73
|
+
HeyGen Voice (`heygen-voice-1`, or the faster and cheaper `heygen-voice-1-turbo`) speaks any of HeyGen's public voices: pass its ID with `--voice` (Nadine is the default; `catalog --type speech` lists `heygenVoices` to start from). It reads `--prompt` as written and detects the language, so it takes no `--delivery`; shape the read with punctuation and wording. It returns WAV and costs 1.5 credits per 1,000 characters, or 0.4 on Turbo.
|
|
74
|
+
|
|
69
75
|
CLI 0.27.0 adds vectors: `--type vector` draws an editable SVG with Ideogram on fal (`fal/ideogram-vector`), for logos, icons, mascots and flat illustrations that must stay sharp at any size or move shape by shape. `--workflow text-to-vector` (default) draws `--prompt` at `--quality low|medium|high` (13, 16 or 20 credits; 32 at high with references), with `--aspect-ratio auto` (default) or 1:4–4:1, `--seed`, and up to five `--references` (this project's images or sprite art, the first leading, named Image 1… in the prompt). `--workflow image-to-vector --source IMAGE_SHA` traces a saved image or sprite for 10 credits, with `--shapes detailed|simple` and no `--prompt`; to vectorize a brand logo or a generated picture, save it as an image asset first. `--download` saves `NAME.svg`. Vectors can't be used as image or video references. Check `catalog --type vector` before using them with an installed CLI.
|
|
70
76
|
|
|
71
77
|
```sh
|
|
@@ -16,9 +16,9 @@ animaguru videos list --scope shared
|
|
|
16
16
|
animaguru videos get VIDEO_ID
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
Submissions default to private. `--share` is a comma-separated list of verified AnimaGuru account emails; selected
|
|
19
|
+
Submissions default to private. `--share` is a comma-separated list of verified AnimaGuru account emails; AnimaGuru emails each selected viewer the watch link once the upload finishes, and they sign in to watch. `--visibility public` lists the animation at [Videos](https://animaguru.com/videos) and permits anyone to watch, download its export, and embed an HTML5 player. Choose the audience from the user's request; a request to make or export a film alone does not authorize sharing it. `--yes` acknowledges the upload and selected audience, and spends no generation credits.
|
|
20
20
|
|
|
21
|
-
The JSON result returns the video ID and watch URL. Owners manage details and recipients on that page, or run `animaguru videos share VIDEO_ID --visibility private --share "reviewer@example.com" --yes`; this replaces the entire recipient list. Public sharing uses `--visibility public` without `--share`. Removing a recipient or making a public film private blocks previous playback URLs immediately. `animaguru videos poster VIDEO_ID --file production/exports/film.jpg --yes` replaces the poster of an uploaded video with a PNG, JPEG or WebP up to 2 MiB, such as the designed thumbnail the MP4 export saves. A public video's new poster goes back to staff review and the video is hidden from the public until it is approved, so tell the user before replacing it. `animaguru videos delete VIDEO_ID --yes` removes the hosted files.
|
|
21
|
+
The JSON result returns the video ID and watch URL. Owners manage details and recipients on that page, or run `animaguru videos share VIDEO_ID --visibility private --share "reviewer@example.com" --yes`; this replaces the entire recipient list, and AnimaGuru emails the link to each newly added recipient (once per video, so re-adding someone sends nothing). Public sharing uses `--visibility public` without `--share`. Removing a recipient or making a public film private blocks previous playback URLs immediately. `animaguru videos poster VIDEO_ID --file production/exports/film.jpg --yes` replaces the poster of an uploaded video with a PNG, JPEG or WebP up to 2 MiB, such as the designed thumbnail the MP4 export saves. A public video's new poster goes back to staff review and the video is hidden from the public until it is approved, so tell the user before replacing it. `animaguru videos delete VIDEO_ID --yes` removes the hosted files.
|
|
22
22
|
|
|
23
23
|
`videos list` shows the selected workspace's library; add `--workspace personal` or `--workspace TEAM_ID` for another (CLI 0.20.0). When the user asks to move videos between their personal library and a team, run `animaguru videos move VIDEO_ID… --workspace TEAM_ID --yes` (or `--workspace personal`). Moving keeps each video's ID, links, subtitles, recipients and review, and every team member can watch it, so move only videos the user names. A video made from a project's animation stays with its project: the user transfers the project to the team on the website first. If one video can't be moved, the command stops and reports `moved`, `error` and `notMoved`; fix the cause, then rerun it with the same IDs, since a video already in the target library is left as it is.
|
|
24
24
|
|
|
@@ -214,15 +214,23 @@ export function normalize<T extends THREE.Object3D>(object: T, height: number):
|
|
|
214
214
|
return object;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
/** The narrowest field of view photoView() uses; Idol reports near-orthographic cameras (under 0.1°, ~1,000 units away) for some product shots. */
|
|
218
|
+
const MIN_PHOTO_FOV = 6;
|
|
219
|
+
|
|
217
220
|
/**
|
|
218
221
|
Puts the camera where an AnimaGuru splat's reference image was taken from (the asset's result.model.view), after
|
|
219
|
-
the splat is placed: a shot that opens on exactly the product photo, then moves into 3D.
|
|
222
|
+
the splat is placed: a shot that opens on exactly the product photo, then moves into 3D. A field of view under 6°
|
|
223
|
+
is widened to 6°, with the camera moved in along the same line so the product keeps its size in frame. Returns the
|
|
224
|
+
point it looks at.
|
|
220
225
|
*/
|
|
221
226
|
export function photoView(splat: THREE.Object3D, view: SplatView, camera: THREE.PerspectiveCamera) {
|
|
222
227
|
splat.updateMatrixWorld(true);
|
|
223
|
-
|
|
228
|
+
const fov = Math.max(view.fov, MIN_PHOTO_FOV);
|
|
229
|
+
const toward = new THREE.Vector3(...view.position);
|
|
230
|
+
toward.multiplyScalar(Math.tan((view.fov * Math.PI) / 360) / Math.tan((fov * Math.PI) / 360));
|
|
231
|
+
camera.position.copy(splat.localToWorld(toward));
|
|
224
232
|
const target = splat.localToWorld(new THREE.Vector3());
|
|
225
|
-
camera.fov =
|
|
233
|
+
camera.fov = fov;
|
|
226
234
|
camera.updateProjectionMatrix();
|
|
227
235
|
camera.lookAt(target);
|
|
228
236
|
return target;
|