[docs] refresh consumer guide recipes and deployment

This commit is contained in:
SolitaryThinker
2026-08-09 14:33:27 -07:00
parent c46601a673
commit 44a85cc180
18 changed files with 1027 additions and 1617 deletions
+9 -2
View File
@@ -54,6 +54,7 @@ jobs:
run: uv pip install --system -r requirements-mkdocs.txt
- name: Setup Pages
id: pages
uses: actions/configure-pages@v4
- name: Build documentation
@@ -65,7 +66,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
node-version: '24'
- name: Enable pnpm
run: corepack enable
@@ -76,13 +77,19 @@ jobs:
- name: Build config generator
working-directory: consumer-guide
run: NEXT_BASE_PATH=/config-generator pnpm build
env:
NEXT_BASE_PATH: ${{ steps.pages.outputs.base_path }}/config-generator
NEXT_TELEMETRY_DISABLED: '1'
run: pnpm build
- name: Copy config generator into docs site
run: |
mkdir -p site/config-generator
cp -R consumer-guide/out/. site/config-generator/
- name: Verify config generator asset paths
run: grep -Fq "${{ steps.pages.outputs.base_path }}/config-generator/_next/" site/config-generator/index.html
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
+33 -54
View File
@@ -1,12 +1,15 @@
# FastVideo Config Generator
A standalone Next.js app that helps users generate FastVideo inference commands.
Deployed under `/config-generator` on the FastVideo docs site.
A standalone Next.js app that turns maintained FastVideo inference recipes into
executable YAML or Python. The docs build exports it beneath the GitHub Pages
base path at `config-generator/`.
Two pages:
Two pages are available:
- **Quick Start** (`/config-generator/`) — pick a task + hardware + output mode, get a ready-to-run command.
- **Advanced Tuning** (`/config-generator/tuning/`) — tune generation parameters and see the real benchmarked time.
- **Quick Start** (`/config-generator/`) — choose a task, model profile, and GPU
count.
- **Advanced Tuning** (`/config-generator/tuning/`) — start from an exact model
recipe and adjust supported configuration fields.
## Run locally
@@ -15,65 +18,41 @@ pnpm install
pnpm dev
```
Open **http://localhost:3003/config-generator/** (the app is served under the `/config-generator` base path).
Open <http://localhost:3003/config-generator/>.
## Build
```bash
pnpm build # static export to ./out
pnpm build
```
## Data files
The build first runs `scripts/validate-data.mjs`, then writes a static export to
`out/`.
All data lives in `data/`. The `.tsx` pages contain no hardcoded model or benchmark
data — they read these JSON files:
## Recipe data
- **`data/quickstart.json`** — drives the Quick Start page: curated product `profiles`,
plus task / tier / hardware option lists and defaults.
- **`data/tuning.json`** — drives the Advanced Tuning page: every benchmark `run` is one
real measured configuration, plus model / workload / gpu / preset option lists and defaults.
`data/tuning.json` is the app's recipe source. Its `source` block pins the exact
FastVideo revision and repository paths used to transcribe model defaults,
pipeline settings, examples, and verified attention compatibility.
Both are the machine-readable record of the RTX 5090 / 4090 inference benchmarks
(`5090_inference.xlsx`, `4090_inference.xlsx`). A configuration is included only when the
benchmark actually recorded a generation time — **nothing is estimated**.
`data/quickstart.json` contains only the curated task/profile choices and engine
offload settings. Each profile references a model from `tuning.json`; the build
fails on missing models, task mismatches, duplicate profiles, unknown attention
backends, or unsupported performance fields.
## Adding a configuration
The guide intentionally publishes no latency, VRAM, RAM, or speedup claims.
Add those only when a reproducible benchmark record includes the FastVideo and
model revisions, GPU type/count, complete resolved recipe, software environment,
prompt/seed, warmup/sample protocol, latency statistic, and peak memory.
The pages are data-driven — to add or change a configuration, edit the JSON, not the `.tsx`:
## Updating a recipe
- **Quick Start** — add an entry to `profiles[]` in `data/quickstart.json`. If it
introduces a new task / hardware / tier, also add it to the matching option list.
- **Advanced Tuning** — add an entry to `runs[]` in `data/tuning.json`. If it
introduces a new model / workload / gpu / preset, also add it to the matching list.
1. Check the current registry, model-family preset, pipeline config, maintained
example, and support matrix.
2. Update the model entry in `data/tuning.json` and advance
`source.fastvideoCommit` to the inspected revision.
3. Update `data/quickstart.json` only if the curated profile selection changes.
4. Run `pnpm build`.
The only thing not in JSON: a task's `icon` must be one of the lucide-react icons
imported in `basic_page.tsx` (`Film`, `Image`, `Sparkles`, `Gamepad2`). A new icon
needs a small `.tsx` edit.
## Quick Start page logic
- Matches the user's selection (**task + tier + gpu + vram**) against `quickstart.json`
`profiles[]`. One profile per combination.
- Tier rule: **Quick Generate** = fastest small/distilled model; **High Quality** = largest
model. Prefer FastVideo-owned models; fall back to other models. Both must have a passing
benchmark.
- If no profile matches, the combination shows "Not suitable" — no command is generated.
- All displayed numbers (time, VRAM) come straight from the benchmark.
## Advanced Tuning page logic
- The **Model** dropdown is filtered by **Workload Type + GPU**: it only lists models with a
passing benchmark for that combination. Models that ran out of memory on a GPU do not
appear for it.
- **Est. Time** is a real measured generation time, looked up by model + GPU + attention
backend — there is no formula. Selecting a model snaps resolution / frames / steps /
attention to its benchmarked values; tuning them away flags the time with `⚠`.
- Top metrics — Video Length (`frames/fps`), Total Pixels (`h*w*frames`), Latent Tokens
(`((frames-1)/4+1)*(h/8)*(w/8)`) — are deterministic arithmetic on the chosen config.
- The generated Python command maps each control to a real FastVideo API field
(`VideoGenerator.from_pretrained` kwargs, `SamplingParam` attributes).
## Notes
This app is independent from the main FastVideo Python package. Run all commands from
this `consumer-guide/` directory.
The UI reads the JSON directly; model defaults do not belong in the `.tsx`
components.
+159 -264
View File
@@ -1,35 +1,26 @@
"use client"
import { useEffect, useState, useMemo } from "react"
import { Monitor, Cpu, HardDrive, Layers, Info, Copy, Check, Film, Image, Sparkles, Gamepad2 } from "lucide-react"
import { Layers, Copy, Check, Film, Image, Sparkles, Gamepad2 } from "lucide-react"
import quickstartData from "@/data/quickstart.json"
import tuningData from "@/data/tuning.json"
type IconName = "Film" | "Image" | "Sparkles" | "Gamepad2"
interface Config {
model: string
modelShort: string
attn: string
h: number
w: number
frames: number
steps: number
cfg: number
vramMin: number
ramMin: number
timeSec: number
firstRunSec?: number
vram: string
offload: boolean
ditCpuOffload?: boolean
ditLayerwiseOffload?: boolean
vaeCpuOffload?: boolean
textEncoderCpuOffload?: boolean
pinCpuMemory?: boolean
useFsdpInference?: boolean
fps?: number
keyboardDim?: number
extra?: string
interface Recipe {
height: number
width: number
numFrames: number
fps: number
numInferenceSteps: number
guidanceScale: number
guidanceScale2: number | null
embeddedCfgScale: number
boundaryRatio: number | null
dmdDenoisingSteps: number[] | null
attentionBackends: string[]
defaultAttentionBackend: string
vsaSparsity: number
}
interface TaskOption {
@@ -39,11 +30,13 @@ interface TaskOption {
icon: string
}
interface HardwareOption {
interface ModelOption {
id: string
label: string
defaultVramGb: number
vramOptionsGb: number[]
name: string
workload: string
keyboardDim?: number
usesMouse?: boolean
recipe: Recipe
}
interface TierOption {
@@ -53,45 +46,25 @@ interface TierOption {
badge?: string
}
interface Profile extends Config {
gpu: string
vramGb: number
interface Profile {
task: string
tier: string
status: "available"
model: string
ditCpuOffload: boolean
ditLayerwiseOffload: boolean
vaeCpuOffload: boolean
textEncoderCpuOffload: boolean
imageEncoderCpuOffload: boolean
pinCpuMemory: boolean
useFsdpInference: boolean
}
interface QuickstartDefaults {
task: string
tier: string
gpu: string
ramGb: number
numGpus: number
}
function formatTime(sec: number): string {
if (sec < 90) return `~${Math.round(sec)} s`
return `~${Math.round(sec / 60)} min`
}
function InfoTip({ content }: { content: string }) {
const [show, setShow] = useState(false)
return (
<span
className="relative inline-flex"
onMouseEnter={() => setShow(true)}
onMouseLeave={() => setShow(false)}
>
<Info className="h-3 w-3 cursor-help" />
{show && (
<span className="absolute bottom-full left-0 z-50 mb-1.5 w-56 rounded-lg border border-border bg-white p-2.5 text-left text-xs font-normal leading-relaxed text-muted-foreground shadow-xl">
{content}
</span>
)}
</span>
)
}
const ICONS: Record<IconName, typeof Film> = {
Film,
Image,
@@ -100,125 +73,75 @@ const ICONS: Record<IconName, typeof Film> = {
}
const DEFAULTS = quickstartData.defaults as QuickstartDefaults
const RAM_OPTIONS = quickstartData.ramOptionsGb as number[]
const GPU_COUNT_OPTIONS = quickstartData.gpuCountOptions as number[]
const HARDWARE = quickstartData.hardware as HardwareOption[]
const HARDWARE_BY_ID = Object.fromEntries(HARDWARE.map((hardware) => [hardware.id, hardware])) as Record<string, HardwareOption>
const PROFILES = quickstartData.profiles as Profile[]
const TASKS = quickstartData.tasks as TaskOption[]
const TIERS = quickstartData.tiers as TierOption[]
const MODELS = tuningData.models as ModelOption[]
const MODEL_BY_ID = Object.fromEntries(MODELS.map((model) => [model.id, model])) as Record<string, ModelOption>
function getProfile(task: string, tier: string, gpu: string, vramGb: number): Profile | undefined {
return PROFILES.find((profile) =>
profile.task === task &&
profile.tier === tier &&
profile.gpu === gpu &&
profile.vramGb === vramGb
)
function getProfile(task: string, tier: string): Profile | undefined {
return PROFILES.find((profile) => profile.task === task && profile.tier === tier)
}
export default function FastVideoConfigSelector() {
const [task, setTask] = useState(DEFAULTS.task)
const [tier, setTier] = useState(DEFAULTS.tier)
const [gpu, setGpu] = useState(DEFAULTS.gpu)
const [vram, setVram] = useState(HARDWARE_BY_ID[DEFAULTS.gpu]?.defaultVramGb ?? HARDWARE[0]?.defaultVramGb ?? 0)
const [ram, setRam] = useState(DEFAULTS.ramGb)
const [ngpu, setNgpu] = useState(DEFAULTS.numGpus)
const [copied, setCopied] = useState(false)
const hardware = HARDWARE_BY_ID[gpu] ?? HARDWARE[0]
const config = getProfile(task, tier, gpu, vram)
useEffect(() => {
const selectedHardware = HARDWARE_BY_ID[gpu]
if (!selectedHardware) return
const options = selectedHardware.vramOptionsGb
if (!options.includes(vram)) {
setVram(selectedHardware.defaultVramGb)
}
}, [gpu, vram])
const profile = getProfile(task, tier)
const selectedModel = profile ? MODEL_BY_ID[profile.model] : undefined
const config = profile && selectedModel ? { ...profile, ...selectedModel.recipe, ...selectedModel } : undefined
// Report content height to the parent docs page so the embedding iframe can
// auto-resize — same mechanism as the Advanced Tuning guide.
useEffect(() => {
if (typeof window === "undefined" || window.parent === window) return
const root = document.getElementById("config-generator-root")
if (!root) return
let frame = 0
const timers: number[] = []
const sendHeight = () => {
window.cancelAnimationFrame(frame)
frame = window.requestAnimationFrame(() => {
const height = Math.max(
document.body.scrollHeight,
document.body.offsetHeight,
document.documentElement.scrollHeight,
document.documentElement.offsetHeight,
window.parent.postMessage(
{ type: "fastvideo-config-generator:resize", height: Math.ceil(root.getBoundingClientRect().height) },
window.location.origin,
)
window.parent.postMessage({ type: "quick-start-guide-height", height }, "*")
})
}
sendHeight()
const ro = new ResizeObserver(sendHeight)
ro.observe(document.documentElement)
ro.observe(document.body)
const mo = new MutationObserver(sendHeight)
mo.observe(document.documentElement, {
attributes: true,
childList: true,
characterData: true,
subtree: true,
})
window.addEventListener("load", sendHeight)
window.addEventListener("resize", sendHeight)
for (const delay of [100, 300, 1000]) {
timers.push(window.setTimeout(sendHeight, delay))
}
ro.observe(root)
sendHeight()
return () => {
window.cancelAnimationFrame(frame)
timers.forEach((timer) => window.clearTimeout(timer))
window.removeEventListener("load", sendHeight)
window.removeEventListener("resize", sendHeight)
mo.disconnect()
ro.disconnect()
}
}, [])
const warning = useMemo(() => {
if (!config) {
return null
}
if (vram < config.vramMin) {
return `This mode requires ${config.vramMin} GB VRAM. Your selection is ${vram} GB — consider switching to Quick Try.`
}
if (ram < config.ramMin) {
return `This mode requires ${config.ramMin} GB RAM. Your selection is ${ram} GB.`
}
return null
}, [vram, ram, config])
const command = useMemo(() => {
if (!config) return ""
const fps = config.fps ?? 24
const workloadType = task === "ti2v" ? "i2v" : task
const pythonBoolean = (value: boolean) => value ? "True" : "False"
const presetOverrideEntries = [
task === "game" ? null : `["embedded_cfg_scale", ${config.embeddedCfgScale}]`,
config.dmdDenoisingSteps === null
? null
: `["dmd_denoising_steps", [${config.dmdDenoisingSteps.join(", ")}]]`,
].filter((entry): entry is string => Boolean(entry))
if (task === "game") {
const offloadKwargs = [
config.ditCpuOffload ? " dit_cpu_offload=True," : null,
config.ditLayerwiseOffload ? " dit_layerwise_offload=True," : null,
config.vaeCpuOffload ? " vae_cpu_offload=True," : null,
config.textEncoderCpuOffload ? " text_encoder_cpu_offload=True," : null,
config.pinCpuMemory ? " pin_cpu_memory=True," : null,
config.useFsdpInference ? " use_fsdp_inference=True," : null,
].filter((line): line is string => Boolean(line))
const keyboardDim = config.keyboardDim ?? 4
const inputLines = [
' "image_path": "./input.png",',
config.usesMouse === false ? null : ' "mouse_cond": actions["mouse"].unsqueeze(0),',
' "keyboard_cond": actions["keyboard"].unsqueeze(0),',
' "grid_sizes": grid_sizes,',
].filter((line): line is string => Boolean(line))
return [
"# Game control uses the Python API because mouse/keyboard",
"# conditions are tensors, not simple CLI fields.",
@@ -231,46 +154,63 @@ export default function FastVideoConfigSelector() {
"import os",
"import torch",
"from fastvideo import VideoGenerator",
"from fastvideo.models.dits.matrixgame.utils import create_action_presets",
"from fastvideo.models.dits.matrixgame2.utils import create_action_presets",
"",
`os.environ["FASTVIDEO_ATTENTION_BACKEND"] = "${config.attn}"`,
`os.environ["FASTVIDEO_ATTENTION_BACKEND"] = "${config.defaultAttentionBackend}"`,
"",
"generator = VideoGenerator.from_pretrained(",
` "${config.model}",`,
` num_gpus=${ngpu},`,
...offloadKwargs,
")",
"generator = VideoGenerator.from_config({",
` "model_path": "${config.model}",`,
" \"engine\": {",
` "num_gpus": ${ngpu},`,
` "use_fsdp_inference": ${pythonBoolean(config.useFsdpInference)},`,
" \"offload\": {",
` "dit": ${pythonBoolean(config.ditCpuOffload)},`,
` "dit_layerwise": ${pythonBoolean(config.ditLayerwiseOffload)},`,
` "text_encoder": ${pythonBoolean(config.textEncoderCpuOffload)},`,
` "image_encoder": ${pythonBoolean(config.imageEncoderCpuOffload)},`,
` "vae": ${pythonBoolean(config.vaeCpuOffload)},`,
` "pin_cpu_memory": ${pythonBoolean(config.pinCpuMemory)},`,
" },",
" },",
" \"pipeline\": {",
" \"workload_type\": \"i2v\",",
" \"preset_overrides\": dict([",
...presetOverrideEntries.map((entry) => ` ${entry},`),
" ]),",
" },",
"})",
"",
`num_frames = ${config.frames}`,
`actions = create_action_presets(num_frames, keyboard_dim=${keyboardDim})`,
`grid_sizes = torch.tensor([${Math.floor((config.frames - 1) / 4) + 1}, ${Math.floor(config.h / 8)}, ${Math.floor(config.w / 8)}])`,
`num_frames = ${config.numFrames}`,
`actions = create_action_presets(num_frames, keyboard_dim=${keyboardDim}, seed=1024)`,
`grid_sizes = torch.tensor([${Math.floor((config.numFrames - 1) / 4) + 1}, ${Math.floor(config.height / 8)}, ${Math.floor(config.width / 8)}])`,
"",
"generator.generate_video(",
' prompt="",',
' image_path="./input.png",',
' mouse_cond=actions["mouse"].unsqueeze(0),',
' keyboard_cond=actions["keyboard"].unsqueeze(0),',
" grid_sizes=grid_sizes,",
` height=${config.h},`,
` width=${config.w},`,
` fps=${fps},`,
" seed=42,",
` num_frames=${config.frames},`,
` num_inference_steps=${config.steps},`,
` guidance_scale=${config.cfg.toFixed(1)},`,
' output_path="outputs/",',
" save_video=True,",
")",
"generator.generate({",
' "prompt": "",',
" \"inputs\": {",
...inputLines,
" },",
" \"sampling\": {",
` "height": ${config.height},`,
` "width": ${config.width},`,
` "fps": ${config.fps},`,
" \"seed\": 1024,",
` "num_frames": ${config.numFrames},`,
` "num_inference_steps": ${config.numInferenceSteps},`,
...(config.dmdDenoisingSteps === null ? [` "guidance_scale": ${config.guidanceScale},`] : []),
...(config.boundaryRatio === null ? [] : [` "boundary_ratio": ${config.boundaryRatio},`]),
" },",
' "output": {"output_path": "outputs/", "save_video": True},',
"})",
].join("\n")
}
const offloadYaml = [
` dit: ${Boolean(config.ditCpuOffload)}`,
` dit_layerwise: ${Boolean(config.ditLayerwiseOffload)}`,
` text_encoder: ${Boolean(config.textEncoderCpuOffload)}`,
" image_encoder: false",
` vae: ${Boolean(config.vaeCpuOffload)}`,
` pin_cpu_memory: ${Boolean(config.pinCpuMemory)}`,
` dit: ${config.ditCpuOffload}`,
` dit_layerwise: ${config.ditLayerwiseOffload}`,
` text_encoder: ${config.textEncoderCpuOffload}`,
` image_encoder: ${config.imageEncoderCpuOffload}`,
` vae: ${config.vaeCpuOffload}`,
` pin_cpu_memory: ${config.pinCpuMemory}`,
]
const inputsYaml = task === "i2v" || task === "ti2v"
? [
@@ -278,45 +218,56 @@ export default function FastVideoConfigSelector() {
" image_path: ./input.png",
]
: []
const fsdpYaml = config.useFsdpInference ? [" use_fsdp_inference: true"] : []
const presetOverridesYaml = [
" preset_overrides:",
` embedded_cfg_scale: ${config.embeddedCfgScale}`,
...(config.dmdDenoisingSteps === null
? []
: [` dmd_denoising_steps: [${config.dmdDenoisingSteps.join(", ")}]`]),
]
const experimentalYaml = config.defaultAttentionBackend === "VIDEO_SPARSE_ATTN"
? [" experimental:", ` VSA_sparsity: ${config.vsaSparsity}`]
: []
return [
"# Install once:",
"# pip install fastvideo",
"",
`# ${hardware.label} benchmark: ${formatTime(config.timeSec)} generation time${config.firstRunSec ? `, ${formatTime(config.firstRunSec)} first run including model load` : ""}.`,
"",
"cat > fastvideo-generate.yaml <<'YAML'",
"generator:",
` model_path: ${config.model}`,
" engine:",
` num_gpus: ${ngpu}`,
` use_fsdp_inference: ${config.useFsdpInference}`,
" offload:",
...offloadYaml,
...fsdpYaml,
" pipeline:",
` workload_type: ${workloadType}`,
...presetOverridesYaml,
...experimentalYaml,
"",
"request:",
' prompt: "your prompt here"',
...inputsYaml,
" sampling:",
` height: ${config.h}`,
` width: ${config.w}`,
` fps: ${fps}`,
" seed: 42",
` num_frames: ${config.frames}`,
` num_inference_steps: ${config.steps}`,
` guidance_scale: ${config.cfg.toFixed(1)}`,
` height: ${config.height}`,
` width: ${config.width}`,
` fps: ${config.fps}`,
" seed: 1024",
` num_frames: ${config.numFrames}`,
` num_inference_steps: ${config.numInferenceSteps}`,
...(config.dmdDenoisingSteps === null ? [` guidance_scale: ${config.guidanceScale}`] : []),
...(config.guidanceScale2 === null ? [] : [` guidance_scale_2: ${config.guidanceScale2}`]),
...(config.boundaryRatio === null ? [] : [` boundary_ratio: ${config.boundaryRatio}`]),
" output:",
" output_path: outputs/",
" save_video: true",
"YAML",
"",
`FASTVIDEO_ATTENTION_BACKEND=${config.attn} \\`,
`FASTVIDEO_ATTENTION_BACKEND=${config.defaultAttentionBackend} \\`,
" fastvideo generate --config fastvideo-generate.yaml",
].join("\n")
}, [config, hardware.label, ngpu, task])
}, [config, ngpu, task])
const copyCommand = async () => {
if (!command) return
@@ -326,7 +277,7 @@ export default function FastVideoConfigSelector() {
}
return (
<div className="min-h-screen bg-white text-foreground">
<div id="config-generator-root" className="bg-white text-foreground">
<div className="max-w-4xl px-6 py-8">
{/* Step 1: Task Selection */}
<section className="mb-8">
@@ -339,8 +290,10 @@ export default function FastVideoConfigSelector() {
const Icon = ICONS[icon as IconName] ?? Film
return (
<button
type="button"
key={id}
onClick={() => setTask(id)}
aria-pressed={task === id}
className={`group relative rounded-xl border p-4 text-left transition-all duration-200 hover:border-primary/50 ${
task === id
? "border-primary bg-primary/10 shadow-lg shadow-primary/10"
@@ -362,68 +315,19 @@ export default function FastVideoConfigSelector() {
</div>
</section>
{/* Step 2: Machine Specs */}
{/* Step 2: Parallelism */}
<section className="mb-8">
<div className="mb-4 flex items-center gap-2">
<span className="flex h-6 w-6 items-center justify-center rounded-full bg-primary text-xs font-medium text-primary-foreground">2</span>
<h2 className="text-sm font-semibold uppercase tracking-wider text-primary">Your machine specs</h2>
<h2 className="text-sm font-semibold uppercase tracking-wider text-primary">Parallelism</h2>
</div>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
<div className="rounded-xl border border-border bg-card p-4">
<div className="mb-2 flex items-center gap-2 text-primary">
<Monitor className="h-4 w-4" />
<span className="text-xs font-semibold uppercase tracking-wide">GPU Model</span>
</div>
<select
value={gpu}
onChange={(e) => {
const nextGpu = e.target.value
setGpu(nextGpu)
setVram(HARDWARE_BY_ID[nextGpu].defaultVramGb)
}}
className="w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-card-foreground outline-none transition-colors focus:border-primary/50"
>
{HARDWARE.map((option) => (
<option key={option.id} value={option.id}>{option.label}</option>
))}
</select>
</div>
<div className="rounded-xl border border-border bg-card p-4">
<div className="mb-2 flex items-center gap-2 text-primary">
<Cpu className="h-4 w-4" />
<span className="text-xs font-semibold uppercase tracking-wide">VRAM (GB)</span>
</div>
<select
value={vram}
onChange={(e) => setVram(Number(e.target.value))}
className="w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-card-foreground outline-none transition-colors focus:border-primary/50"
>
{hardware.vramOptionsGb.map((option) => (
<option key={option} value={option}>{option} GB</option>
))}
</select>
</div>
<div className="rounded-xl border border-border bg-card p-4">
<div className="mb-2 flex items-center gap-2 text-primary">
<HardDrive className="h-4 w-4" />
<span className="text-xs font-semibold uppercase tracking-wide">RAM (GB)</span>
</div>
<select
value={ram}
onChange={(e) => setRam(Number(e.target.value))}
className="w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-card-foreground outline-none transition-colors focus:border-primary/50"
>
{RAM_OPTIONS.map((option) => (
<option key={option} value={option}>{option} GB</option>
))}
</select>
</div>
<div className="rounded-xl border border-border bg-card p-4">
<div className="mb-2 flex items-center gap-2 text-primary">
<div className="max-w-xs rounded-xl border border-border bg-card p-4">
<label htmlFor="quick-gpu-count" className="mb-2 flex items-center gap-2 text-primary">
<Layers className="h-4 w-4" />
<span className="text-xs font-semibold uppercase tracking-wide">Number of GPUs</span>
</div>
</label>
<select
id="quick-gpu-count"
value={ngpu}
onChange={(e) => setNgpu(Number(e.target.value))}
className="w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-card-foreground outline-none transition-colors focus:border-primary/50"
@@ -432,23 +336,25 @@ export default function FastVideoConfigSelector() {
<option key={option} value={option}>{option} GPU{option === 1 ? "" : "s"}</option>
))}
</select>
</div>
</div>
</section>
{/* Step 3: Output Mode */}
{/* Step 3: Model profile */}
<section className="mb-8">
<div className="mb-4 flex items-center gap-2">
<span className="flex h-6 w-6 items-center justify-center rounded-full bg-primary text-xs font-medium text-primary-foreground">3</span>
<h2 className="text-sm font-semibold uppercase tracking-wider text-primary">Output mode</h2>
<h2 className="text-sm font-semibold uppercase tracking-wider text-primary">Model profile</h2>
</div>
<div className="grid gap-3 sm:grid-cols-4">
{TIERS.map(({ id, name, desc, badge }) => {
const tierConfig = getProfile(task, id, gpu, vram)
const tierConfig = getProfile(task, id)
const tierModel = tierConfig ? MODEL_BY_ID[tierConfig.model] : undefined
return (
<button
type="button"
key={id}
onClick={() => setTier(id)}
aria-pressed={tier === id}
className={`group relative rounded-xl border p-4 text-left transition-all duration-200 sm:col-span-2 ${
tier === id
? "border-primary bg-primary/10 shadow-lg shadow-primary/10"
@@ -465,18 +371,11 @@ export default function FastVideoConfigSelector() {
</div>
<p className="mt-1 text-xs leading-relaxed text-muted-foreground">{desc}</p>
<div className="mt-3 space-y-1 border-t border-border pt-3">
{tierConfig ? (
<>
<div className="flex items-center gap-1.5 text-xs text-muted-foreground">
<span className="font-semibold">INF</span>
<InfoTip content="Inference time only — the compute to generate the video once the model is loaded. The first run takes longer because it also loads the model." />
<span>{formatTime(tierConfig.timeSec)}</span>
</div>
<div className="flex items-center gap-1.5 text-xs text-muted-foreground">
<span className="font-semibold">VRAM</span>
<span>{tierConfig.vram}</span>
</div>
</>
{tierModel ? (
<div className="text-xs text-muted-foreground">
<span className="font-semibold">{tierModel.name}</span>
{` · ${tierModel.recipe.width}×${tierModel.recipe.height} · ${tierModel.recipe.numInferenceSteps} steps`}
</div>
) : (
<div className="text-xs font-medium text-muted-foreground">
Not suitable
@@ -487,11 +386,6 @@ export default function FastVideoConfigSelector() {
)
})}
</div>
{warning && (
<div className="mt-3 rounded-lg border border-destructive/20 bg-destructive/10 px-4 py-3 text-sm text-destructive">
{warning}
</div>
)}
</section>
{/* Output Configuration */}
@@ -504,24 +398,25 @@ export default function FastVideoConfigSelector() {
</div>
<div className="overflow-hidden rounded-2xl border border-border bg-card">
{/* Meta Cards */}
<div className="grid grid-cols-3 divide-x divide-border border-b border-border">
<div className="grid grid-cols-1 divide-y divide-border border-b border-border sm:grid-cols-3 sm:divide-x sm:divide-y-0">
<div className="p-4">
<div className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Model</div>
<div className="mt-1 font-mono text-sm text-card-foreground">{config?.modelShort ?? "Unavailable"}</div>
<div className="mt-1 font-mono text-sm text-card-foreground">{config?.name ?? "Unavailable"}</div>
</div>
<div className="p-4">
<div className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Est. Generation Time</div>
<div className="mt-1 font-mono text-sm text-card-foreground">{config ? formatTime(config.timeSec) : "Unavailable"}</div>
<div className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Resolution</div>
<div className="mt-1 font-mono text-sm text-card-foreground">{config ? `${config.width}×${config.height}` : "Unavailable"}</div>
</div>
<div className="p-4">
<div className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Peak VRAM</div>
<div className="mt-1 font-mono text-sm text-card-foreground">{config?.vram ?? "Unavailable"}</div>
<div className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Denoising</div>
<div className="mt-1 font-mono text-sm text-card-foreground">{config ? `${config.numInferenceSteps} steps` : "Unavailable"}</div>
</div>
</div>
{/* Command Block */}
<div className="relative p-4">
{command && (
<button
type="button"
onClick={copyCommand}
className="absolute right-4 top-4 flex items-center gap-2 rounded-lg border border-border bg-card px-4 py-2 text-sm font-medium text-muted-foreground transition-all hover:border-primary/50 hover:bg-primary/10 hover:text-primary"
>
@@ -535,7 +430,7 @@ export default function FastVideoConfigSelector() {
</pre>
) : (
<div className="rounded-lg border border-dashed border-border px-4 py-6 text-sm text-muted-foreground">
{`${hardware.label} (${vram} GB) is not suitable for ${tier === "quick" ? "Quick Generate" : "High Quality"} on this task.`}
No maintained profile is available for this task and model choice.
</div>
)}
</div>
+2 -2
View File
@@ -75,8 +75,8 @@
}
@theme inline {
--font-sans: 'Geist', 'Geist Fallback';
--font-mono: 'Geist Mono', 'Geist Mono Fallback';
--font-sans: ui-sans-serif, system-ui, sans-serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
+1 -5
View File
@@ -1,13 +1,9 @@
import type { Metadata } from 'next'
import { Geist, Geist_Mono } from 'next/font/google'
import './globals.css'
const _geist = Geist({ subsets: ["latin"] });
const _geistMono = Geist_Mono({ subsets: ["latin"] });
export const metadata: Metadata = {
title: 'FastVideo Config Generator',
description: 'Choose your hardware and task to generate a FastVideo configuration command',
description: 'Choose a maintained FastVideo recipe and generate an executable configuration',
}
export default function RootLayout({
File diff suppressed because it is too large Load Diff
+66 -322
View File
@@ -2,380 +2,124 @@
"defaults": {
"task": "t2v",
"tier": "quick",
"gpu": "5090",
"ramGb": 64,
"numGpus": 1
},
"ramOptionsGb": [128, 64, 32],
"gpuCountOptions": [1, 2, 4],
"hardware": [
{
"id": "4090",
"label": "RTX 4090",
"defaultVramGb": 24,
"vramOptionsGb": [24]
},
{
"id": "5090",
"label": "RTX 5090",
"defaultVramGb": 32,
"vramOptionsGb": [32]
}
],
"tasks": [
{
"id": "t2v",
"label": "Text to Video",
"sub": "T2V",
"icon": "Film"
},
{
"id": "i2v",
"label": "Image to Video",
"sub": "I2V",
"icon": "Image"
},
{
"id": "ti2v",
"label": "Text + Image",
"sub": "TI2V",
"icon": "Sparkles"
},
{
"id": "game",
"label": "Game",
"sub": "Matrix Game",
"icon": "Gamepad2"
}
{ "id": "t2v", "label": "Text to Video", "sub": "T2V", "icon": "Film" },
{ "id": "i2v", "label": "Image to Video", "sub": "I2V", "icon": "Image" },
{ "id": "ti2v", "label": "Text + Image", "sub": "TI2V", "icon": "Sparkles" },
{ "id": "game", "label": "Game", "sub": "Matrix Game", "icon": "Gamepad2" }
],
"tiers": [
{
"id": "quick",
"name": "Quick Generate",
"desc": "FastVideo model with a benchmarked fast profile.",
"badge": "Recommended"
"name": "Recommended",
"desc": "The maintained FastVideo example for this task.",
"badge": "Start here"
},
{
"id": "best",
"name": "High Quality",
"desc": "FastVideo model with a benchmarked quality-oriented profile."
"name": "Alternative",
"desc": "Another maintained model or task variant."
}
],
"profiles": [
{
"status": "available",
"gpu": "5090",
"vramGb": 32,
"task": "t2v",
"tier": "quick",
"model": "FastVideo/FastWan2.1-T2V-1.3B-Diffusers",
"modelShort": "FastWan2.1-T2V-1.3B",
"attn": "VIDEO_SPARSE_ATTN",
"h": 480,
"w": 832,
"frames": 81,
"steps": 40,
"cfg": 5,
"fps": 16,
"vramMin": 18,
"ramMin": 64,
"timeSec": 22.91,
"firstRunSec": 139.44,
"vram": "~16.0 GB",
"offload": true,
"ditCpuOffload": true,
"ditLayerwiseOffload": true,
"vaeCpuOffload": true,
"ditCpuOffload": false,
"ditLayerwiseOffload": false,
"vaeCpuOffload": false,
"textEncoderCpuOffload": true,
"pinCpuMemory": true
"imageEncoderCpuOffload": false,
"pinCpuMemory": true,
"useFsdpInference": false
},
{
"status": "available",
"gpu": "5090",
"vramGb": 32,
"task": "t2v",
"tier": "best",
"model": "FastVideo/FastHunyuan-diffusers",
"modelShort": "FastHunyuan",
"attn": "FLASH_ATTN",
"h": 720,
"w": 1280,
"frames": 81,
"steps": 50,
"cfg": 1,
"fps": 24,
"vramMin": 32,
"ramMin": 64,
"timeSec": 1389.71,
"firstRunSec": 1492.36,
"vram": "~27.1 GB",
"offload": true,
"model": "Wan-AI/Wan2.1-T2V-14B-Diffusers",
"ditCpuOffload": true,
"ditLayerwiseOffload": true,
"vaeCpuOffload": true,
"textEncoderCpuOffload": true,
"pinCpuMemory": true
},
{
"status": "available",
"gpu": "5090",
"vramGb": 32,
"task": "ti2v",
"tier": "quick",
"model": "FastVideo/FastWan2.2-TI2V-5B-FullAttn-Diffusers",
"modelShort": "FastWan2.2-TI2V-5B",
"attn": "VIDEO_SPARSE_ATTN",
"h": 480,
"w": 832,
"frames": 81,
"steps": 40,
"cfg": 5,
"fps": 16,
"vramMin": 18,
"ramMin": 64,
"timeSec": 17.39,
"firstRunSec": 116.57,
"vram": "~17.2 GB",
"offload": true,
"ditCpuOffload": true,
"ditLayerwiseOffload": true,
"ditLayerwiseOffload": false,
"vaeCpuOffload": false,
"textEncoderCpuOffload": true,
"imageEncoderCpuOffload": false,
"pinCpuMemory": true,
"extra": "--image ./input.png"
"useFsdpInference": false
},
{
"status": "available",
"gpu": "5090",
"vramGb": 32,
"task": "game",
"tier": "quick",
"model": "FastVideo/Matrix-Game-2.0-Base-Diffusers",
"modelShort": "Matrix-Game-2.0-Base",
"attn": "FLASH_ATTN",
"h": 352,
"w": 640,
"frames": 81,
"steps": 3,
"cfg": 5,
"fps": 16,
"vramMin": 12,
"ramMin": 32,
"timeSec": 12.29,
"firstRunSec": 247.2,
"vram": "~10.4 GB",
"offload": true,
"ditCpuOffload": true,
"ditLayerwiseOffload": true,
"textEncoderCpuOffload": true,
"pinCpuMemory": true,
"keyboardDim": 4,
"extra": "--image ./input.png --action forward"
},
{
"status": "available",
"gpu": "5090",
"vramGb": 32,
"task": "game",
"tier": "best",
"model": "FastVideo/Matrix-Game-2.0-GTA-Diffusers",
"modelShort": "Matrix-Game-2.0-GTA",
"attn": "FLASH_ATTN",
"h": 352,
"w": 640,
"frames": 81,
"steps": 3,
"cfg": 5,
"fps": 16,
"vramMin": 12,
"ramMin": 32,
"timeSec": 13.03,
"firstRunSec": 212.37,
"vram": "~10.4 GB",
"offload": true,
"ditCpuOffload": true,
"ditLayerwiseOffload": true,
"textEncoderCpuOffload": true,
"pinCpuMemory": true,
"keyboardDim": 2,
"extra": "--image ./input.png --action forward"
},
{
"status": "available",
"gpu": "5090",
"vramGb": 32,
"task": "ti2v",
"tier": "best",
"model": "Wan-AI/Wan2.2-TI2V-5B-Diffusers",
"modelShort": "Wan2.2-TI2V-5B",
"attn": "FLASH_ATTN",
"h": 480,
"w": 832,
"frames": 81,
"steps": 40,
"cfg": 5,
"fps": 16,
"vramMin": 18,
"ramMin": 64,
"timeSec": 71.01,
"firstRunSec": 223.29,
"vram": "~15.5 GB",
"offload": true,
"ditCpuOffload": true,
"ditLayerwiseOffload": true,
"textEncoderCpuOffload": true,
"pinCpuMemory": true,
"extra": "--image ./input.png"
},
{
"status": "available",
"gpu": "5090",
"vramGb": 32,
"task": "i2v",
"tier": "best",
"model": "Wan-AI/Wan2.1-I2V-14B-720P-Diffusers",
"modelShort": "Wan2.1-I2V-720P",
"attn": "FLASH_ATTN",
"h": 720,
"w": 1280,
"frames": 81,
"steps": 40,
"cfg": 5,
"fps": 16,
"vramMin": 32,
"ramMin": 64,
"timeSec": 2832.76,
"firstRunSec": 3026.41,
"vram": "~28.9 GB",
"offload": true,
"ditCpuOffload": true,
"vaeCpuOffload": true,
"textEncoderCpuOffload": true,
"pinCpuMemory": true,
"useFsdpInference": true,
"extra": "--image ./input.png"
},
{
"status": "available",
"gpu": "5090",
"vramGb": 32,
"task": "i2v",
"tier": "quick",
"model": "loayrashid/TurboWan2.2-I2V-A14B-Diffusers",
"modelShort": "TurboWan2.2-I2V-A14B",
"attn": "SLA_ATTN",
"h": 480,
"w": 832,
"frames": 81,
"steps": 4,
"cfg": 1,
"fps": 16,
"vramMin": 32,
"ramMin": 64,
"timeSec": 364,
"vram": "~10.6 GB",
"offload": true,
"ditCpuOffload": true,
"ditLayerwiseOffload": false,
"vaeCpuOffload": false,
"textEncoderCpuOffload": true,
"imageEncoderCpuOffload": true,
"pinCpuMemory": true,
"useFsdpInference": true,
"extra": "--image ./input.png"
"useFsdpInference": false
},
{
"status": "available",
"gpu": "4090",
"vramGb": 24,
"task": "t2v",
"tier": "quick",
"model": "FastVideo/FastWan2.1-T2V-1.3B-Diffusers",
"modelShort": "FastWan2.1-T2V-1.3B",
"attn": "VIDEO_SPARSE_ATTN",
"h": 480,
"w": 832,
"frames": 81,
"steps": 3,
"cfg": 6,
"fps": 16,
"vramMin": 12,
"ramMin": 32,
"timeSec": 32.42,
"vram": "~11.0 GB",
"offload": true,
"ditLayerwiseOffload": true,
"textEncoderCpuOffload": true
"task": "i2v",
"tier": "best",
"model": "Wan-AI/Wan2.1-I2V-14B-720P-Diffusers",
"ditCpuOffload": true,
"ditLayerwiseOffload": false,
"vaeCpuOffload": false,
"textEncoderCpuOffload": true,
"imageEncoderCpuOffload": true,
"pinCpuMemory": true,
"useFsdpInference": false
},
{
"status": "available",
"gpu": "4090",
"vramGb": 24,
"task": "ti2v",
"tier": "quick",
"model": "FastVideo/FastWan2.2-TI2V-5B-FullAttn-Diffusers",
"modelShort": "FastWan2.2-TI2V-5B",
"attn": "FLASH_ATTN",
"h": 480,
"w": 832,
"frames": 81,
"steps": 3,
"cfg": 6,
"fps": 16,
"vramMin": 12,
"ramMin": 64,
"timeSec": 17.81,
"vram": "~10.8 GB",
"offload": true,
"ditLayerwiseOffload": true,
"ditCpuOffload": true,
"ditLayerwiseOffload": false,
"vaeCpuOffload": false,
"textEncoderCpuOffload": true,
"extra": "--image ./input.png"
"imageEncoderCpuOffload": true,
"pinCpuMemory": true,
"useFsdpInference": false
},
{
"task": "ti2v",
"tier": "best",
"model": "Wan-AI/Wan2.2-TI2V-5B-Diffusers",
"ditCpuOffload": true,
"ditLayerwiseOffload": false,
"vaeCpuOffload": false,
"textEncoderCpuOffload": true,
"imageEncoderCpuOffload": true,
"pinCpuMemory": true,
"useFsdpInference": false
},
{
"status": "available",
"gpu": "4090",
"vramGb": 24,
"task": "game",
"tier": "quick",
"model": "FastVideo/Matrix-Game-2.0-Base-Diffusers",
"modelShort": "Matrix-Game-2.0-Base",
"attn": "FLASH_ATTN",
"h": 480,
"w": 832,
"frames": 81,
"steps": 3,
"cfg": 6,
"fps": 16,
"vramMin": 12,
"ramMin": 32,
"timeSec": 23.81,
"vram": "~11.2 GB",
"offload": true,
"ditLayerwiseOffload": true,
"model": "FastVideo/Matrix-Game-2.0-Base-Distilled-Diffusers",
"ditCpuOffload": true,
"ditLayerwiseOffload": false,
"vaeCpuOffload": false,
"textEncoderCpuOffload": true,
"keyboardDim": 4,
"extra": "--image ./input.png --action forward"
"imageEncoderCpuOffload": true,
"pinCpuMemory": true,
"useFsdpInference": false
},
{
"status": "available",
"gpu": "4090",
"vramGb": 24,
"task": "game",
"tier": "best",
"model": "FastVideo/Matrix-Game-2.0-GTA-Diffusers",
"modelShort": "Matrix-Game-2.0-GTA",
"attn": "FLASH_ATTN",
"h": 480,
"w": 832,
"frames": 81,
"steps": 3,
"cfg": 6,
"fps": 16,
"vramMin": 12,
"ramMin": 32,
"timeSec": 24.24,
"vram": "~11.2 GB",
"offload": true,
"ditLayerwiseOffload": true,
"model": "FastVideo/Matrix-Game-2.0-GTA-Distilled-Diffusers",
"ditCpuOffload": true,
"ditLayerwiseOffload": false,
"vaeCpuOffload": false,
"textEncoderCpuOffload": true,
"keyboardDim": 2,
"extra": "--image ./input.png --action forward"
"imageEncoderCpuOffload": true,
"pinCpuMemory": true,
"useFsdpInference": false
}
]
}
+149 -82
View File
@@ -1,103 +1,170 @@
{
"_comment": "Single data source for the Advanced Tuning page (app/tuning/adv_page.tsx). Each benchmark run is one real measured configuration. The page filters by workload + GPU and never estimates benchmark values.",
"source": {
"fastvideoCommit": "a2bfc7cdb2a1de2b138258412e42d183444ffe09",
"description": "Defaults transcribed from FastVideo's registered inference presets, pipeline configs, maintained examples, and support matrix at this commit.",
"paths": [
"fastvideo/registry.py",
"fastvideo/pipelines/basic/*/presets.py",
"fastvideo/configs/pipelines/*.py",
"examples/inference/basic/*.py",
"docs/inference/support_matrix.md"
]
},
"defaults": {
"model_id": "FastVideo/FastWan2.1-T2V-1.3B-Diffusers",
"workload_type": "t2v",
"gpu": "rtx5090",
"num_gpus": 1,
"height": 480,
"width": 832,
"num_frames": 81,
"fps": 24,
"num_inference_steps": 40,
"guidance_scale": 5,
"embedded_cfg_scale": 6,
"flow_shift": null,
"seed": -1,
"attention_backend": "VIDEO_SPARSE_ATTN",
"VSA_sparsity": 0,
"dmd_denoising_steps": "1000,757,522",
"seed": 1024,
"dit_cpu_offload": false,
"dit_layerwise_offload": false,
"vae_cpu_offload": false,
"text_encoder_cpu_offload": false,
"text_encoder_cpu_offload": true,
"image_encoder_cpu_offload": false,
"pin_cpu_memory": false,
"pin_cpu_memory": true,
"use_fsdp_inference": false
},
"workloads": [
{ "id": "t2v", "name": "Text to Video", "icon": "Film" },
{ "id": "i2v", "name": "Image to Video", "icon": "Sparkles" },
{ "id": "ti2v", "name": "Text+Image to Video", "icon": "Layers" },
{ "id": "ti2v", "name": "Text + Image to Video", "icon": "Layers" },
{ "id": "game", "name": "Game", "icon": "Zap" }
],
"gpus": [
{ "id": "rtx4090", "name": "RTX 4090", "vram": "24GB" },
{ "id": "rtx5090", "name": "RTX 5090", "vram": "32GB" }
],
"resolutionPresets": [
{ "height": 480, "width": 832, "label": "480p (832x480)" },
{ "height": 720, "width": 1280, "label": "720p (1280x720)" },
{ "height": 1080, "width": 1920, "label": "1080p (1920x1080)" }
],
"framePresets": [
{ "frames": 49, "label": "49 frames (~2s @24fps)" },
{ "frames": 81, "label": "81 frames (~3.4s @24fps)" },
{ "frames": 121, "label": "121 frames (~5s @24fps)" }
],
"attentionBackends": [
{ "id": "FLASH_ATTN", "name": "Flash Attention", "shortName": "Flash", "desc": "Best quality-speed trade-off", "speed": "Baseline" },
{ "id": "VIDEO_SPARSE_ATTN", "name": "Video Sparse Attention", "shortName": "VSA", "desc": "~30% faster, minimal quality loss", "speed": "Fast" },
{ "id": "SAGE_ATTN", "name": "Sage Attention", "shortName": "SAGE", "desc": "~40% faster, visible at high motion", "speed": "Faster" },
{ "id": "SLA_ATTN", "name": "Sparse-Linear Attention", "shortName": "SLA", "desc": "Requires SLA-tuned model checkpoint", "speed": "Fast" }
{ "id": "FLASH_ATTN", "name": "Flash Attention", "shortName": "Flash", "desc": "Default dense attention backend." },
{ "id": "VIDEO_SPARSE_ATTN", "name": "Video Sparse Attention", "shortName": "VSA", "desc": "Use only with models marked VSA-compatible." },
{ "id": "SAGE_ATTN", "name": "Sage Attention", "shortName": "SAGE", "desc": "Quantized attention for models marked Sage-compatible." },
{ "id": "SLA_ATTN", "name": "Sparse-Linear Attention", "shortName": "SLA", "desc": "Required by TurboDiffusion checkpoints." }
],
"models": [
{ "id": "FastVideo/FastWan2.1-T2V-1.3B-Diffusers", "name": "FastWan2.1 T2V", "size": "1.3B", "workload": "t2v", "dmdMode": true, "dmdNote": "FastWan DMD uses 3-step distillation for faster generation." },
{ "id": "FastVideo/FastWan2.2-TI2V-5B-FullAttn-Diffusers", "name": "FastWan2.2 TI2V FullAttn", "size": "5B", "workload": "ti2v", "dmdMode": true, "dmdNote": "FastWan DMD uses 3-step distillation for faster generation." },
{ "id": "Wan-AI/Wan2.2-TI2V-5B-Diffusers", "name": "Wan2.2 TI2V", "size": "5B", "workload": "ti2v" },
{ "id": "Wan-AI/Wan2.2-T2V-A14B-Diffusers", "name": "Wan2.2 T2V", "size": "A14B", "workload": "t2v" },
{ "id": "Wan-AI/Wan2.2-I2V-A14B-Diffusers", "name": "Wan2.2 I2V", "size": "A14B", "workload": "i2v" },
{ "id": "hunyuanvideo-community/HunyuanVideo", "name": "HunyuanVideo", "size": "13B", "workload": "t2v" },
{ "id": "FastVideo/FastHunyuan-diffusers", "name": "FastHunyuan", "size": "13B", "workload": "t2v" },
{ "id": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", "name": "Wan2.1 T2V", "size": "1.3B", "workload": "t2v" },
{ "id": "Wan-AI/Wan2.1-T2V-14B-Diffusers", "name": "Wan2.1 T2V", "size": "14B", "workload": "t2v" },
{ "id": "Wan-AI/Wan2.1-I2V-14B-480P-Diffusers", "name": "Wan2.1 I2V 480P", "size": "14B", "workload": "i2v" },
{ "id": "Wan-AI/Wan2.1-I2V-14B-720P-Diffusers", "name": "Wan2.1 I2V 720P", "size": "14B", "workload": "i2v" },
{ "id": "loayrashid/TurboWan2.1-T2V-1.3B-Diffusers", "name": "TurboWan2.1 T2V", "size": "1.3B", "workload": "t2v" },
{ "id": "loayrashid/TurboWan2.1-T2V-14B-Diffusers", "name": "TurboWan2.1 T2V", "size": "14B", "workload": "t2v" },
{ "id": "loayrashid/TurboWan2.2-I2V-A14B-Diffusers", "name": "TurboWan2.2 I2V", "size": "A14B", "workload": "i2v" },
{ "id": "FastVideo/LongCat-Video-T2V-Diffusers", "name": "LongCat T2V", "size": "13.6B", "workload": "t2v" },
{ "id": "FastVideo/Matrix-Game-2.0-Base-Diffusers", "name": "Matrix Game 2.0 Base", "size": "1.3B", "workload": "game", "keyboardDim": 4 },
{ "id": "FastVideo/Matrix-Game-2.0-GTA-Diffusers", "name": "Matrix Game 2.0 GTA", "size": "1.3B", "workload": "game", "keyboardDim": 2 },
{ "id": "FastVideo/Matrix-Game-2.0-TempleRun-Diffusers", "name": "Matrix Game 2.0 TempleRun", "size": "1.3B", "workload": "game", "keyboardDim": 7 }
],
"runs": [
{ "model": "FastVideo/FastWan2.1-T2V-1.3B-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 40, "attention": "VIDEO_SPARSE_ATTN", "generationSeconds": 22.91, "runtimeSeconds": 139.44 },
{ "model": "FastVideo/FastWan2.2-TI2V-5B-FullAttn-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 40, "attention": "VIDEO_SPARSE_ATTN", "generationSeconds": 17.39, "runtimeSeconds": 116.57 },
{ "model": "Wan-AI/Wan2.2-TI2V-5B-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 40, "attention": "FLASH_ATTN", "generationSeconds": 71.01, "runtimeSeconds": 223.29 },
{ "model": "Wan-AI/Wan2.2-T2V-A14B-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 40, "attention": "FLASH_ATTN", "generationSeconds": 782.09, "runtimeSeconds": 1144.85 },
{ "model": "Wan-AI/Wan2.2-I2V-A14B-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 40, "attention": "FLASH_ATTN", "generationSeconds": 827.48, "runtimeSeconds": 1169.64 },
{ "model": "hunyuanvideo-community/HunyuanVideo", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 40, "attention": "FLASH_ATTN", "generationSeconds": 575.39, "runtimeSeconds": 713.74 },
{ "model": "FastVideo/FastHunyuan-diffusers", "gpu": "rtx5090", "height": 720, "width": 1280, "frames": 81, "steps": 50, "attention": "FLASH_ATTN", "generationSeconds": 1389.71, "runtimeSeconds": 1492.36 },
{ "model": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 40, "attention": "FLASH_ATTN", "generationSeconds": 155.86, "runtimeSeconds": 227.07 },
{ "model": "Wan-AI/Wan2.1-T2V-14B-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 40, "attention": "FLASH_ATTN", "generationSeconds": 780.44, "runtimeSeconds": 954.84 },
{ "model": "Wan-AI/Wan2.1-I2V-14B-480P-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 40, "attention": "FLASH_ATTN", "generationSeconds": 842.11, "runtimeSeconds": 1058.56 },
{ "model": "Wan-AI/Wan2.1-I2V-14B-720P-Diffusers", "gpu": "rtx5090", "height": 720, "width": 1280, "frames": 81, "steps": 40, "attention": "FLASH_ATTN", "generationSeconds": 2832.76, "runtimeSeconds": 3026.41 },
{ "model": "loayrashid/TurboWan2.1-T2V-1.3B-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 4, "attention": "SLA_ATTN", "generationSeconds": 16.16, "runtimeSeconds": 92.77 },
{ "model": "loayrashid/TurboWan2.1-T2V-14B-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 4, "attention": "SLA_ATTN", "generationSeconds": 60.35, "runtimeSeconds": 604.26 },
{ "model": "loayrashid/TurboWan2.2-I2V-A14B-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 81, "steps": 4, "attention": "SLA_ATTN", "runtimeSeconds": 364.0 },
{ "model": "FastVideo/LongCat-Video-T2V-Diffusers", "gpu": "rtx5090", "height": 480, "width": 832, "frames": 93, "steps": 40, "attention": "FLASH_ATTN", "generationSeconds": 915.89, "runtimeSeconds": 1061.24 },
{ "model": "FastVideo/Matrix-Game-2.0-Base-Diffusers", "gpu": "rtx5090", "height": 352, "width": 640, "frames": 81, "steps": 3, "attention": "FLASH_ATTN", "generationSeconds": 12.29, "runtimeSeconds": 247.2 },
{ "model": "FastVideo/Matrix-Game-2.0-GTA-Diffusers", "gpu": "rtx5090", "height": 352, "width": 640, "frames": 81, "steps": 3, "attention": "FLASH_ATTN", "generationSeconds": 13.03, "runtimeSeconds": 212.37 },
{ "model": "FastVideo/Matrix-Game-2.0-TempleRun-Diffusers", "gpu": "rtx5090", "height": 352, "width": 640, "frames": 81, "steps": 3, "attention": "FLASH_ATTN", "generationSeconds": 12.85, "runtimeSeconds": 176.79 },
{ "model": "FastVideo/FastWan2.1-T2V-1.3B-Diffusers", "gpu": "rtx4090", "height": 480, "width": 832, "frames": 81, "steps": 3, "attention": "VIDEO_SPARSE_ATTN", "generationSeconds": 32.42 },
{ "model": "FastVideo/FastWan2.2-TI2V-5B-FullAttn-Diffusers", "gpu": "rtx4090", "height": 480, "width": 832, "frames": 81, "steps": 3, "attention": "VIDEO_SPARSE_ATTN", "generationSeconds": 22.78 },
{ "model": "FastVideo/FastWan2.2-TI2V-5B-FullAttn-Diffusers", "gpu": "rtx4090", "height": 480, "width": 832, "frames": 81, "steps": 3, "attention": "FLASH_ATTN", "generationSeconds": 17.81 },
{ "model": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", "gpu": "rtx4090", "height": 480, "width": 832, "frames": 81, "steps": 3, "attention": "FLASH_ATTN", "generationSeconds": 28.62 },
{ "model": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", "gpu": "rtx4090", "height": 480, "width": 832, "frames": 81, "steps": 3, "attention": "SAGE_ATTN", "generationSeconds": 24.62 },
{ "model": "loayrashid/TurboWan2.1-T2V-1.3B-Diffusers", "gpu": "rtx4090", "height": 480, "width": 832, "frames": 81, "steps": 3, "attention": "SLA_ATTN", "generationSeconds": 20.13 },
{ "model": "FastVideo/Matrix-Game-2.0-Base-Diffusers", "gpu": "rtx4090", "height": 480, "width": 832, "frames": 81, "steps": 3, "attention": "FLASH_ATTN", "generationSeconds": 23.81 },
{ "model": "FastVideo/Matrix-Game-2.0-GTA-Diffusers", "gpu": "rtx4090", "height": 480, "width": 832, "frames": 81, "steps": 3, "attention": "FLASH_ATTN", "generationSeconds": 24.24 },
{ "model": "FastVideo/Matrix-Game-2.0-TempleRun-Diffusers", "gpu": "rtx4090", "height": 480, "width": 832, "frames": 81, "steps": 3, "attention": "FLASH_ATTN", "generationSeconds": 23.38 }
{
"id": "FastVideo/FastWan2.1-T2V-1.3B-Diffusers",
"name": "FastWan2.1 T2V",
"size": "1.3B",
"workload": "t2v",
"recipe": { "height": 448, "width": 832, "numFrames": 61, "fps": 16, "numInferenceSteps": 3, "guidanceScale": 3, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 8, "boundaryRatio": null, "dmdDenoisingSteps": [1000, 757, 522], "attentionBackends": ["VIDEO_SPARSE_ATTN", "FLASH_ATTN"], "defaultAttentionBackend": "VIDEO_SPARSE_ATTN", "vsaSparsity": 0.8 }
},
{
"id": "FastVideo/FastWan2.2-TI2V-5B-FullAttn-Diffusers",
"name": "FastWan2.2 TI2V FullAttn",
"size": "5B",
"workload": "ti2v",
"recipe": { "height": 704, "width": 1280, "numFrames": 121, "fps": 24, "numInferenceSteps": 3, "guidanceScale": 5, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 5, "boundaryRatio": null, "dmdDenoisingSteps": [1000, 757, 522], "attentionBackends": ["FLASH_ATTN", "VIDEO_SPARSE_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "Wan-AI/Wan2.2-TI2V-5B-Diffusers",
"name": "Wan2.2 TI2V",
"size": "5B",
"workload": "ti2v",
"recipe": { "height": 704, "width": 1280, "numFrames": 121, "fps": 24, "numInferenceSteps": 50, "guidanceScale": 5, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 5, "boundaryRatio": null, "dmdDenoisingSteps": null, "attentionBackends": ["FLASH_ATTN", "SAGE_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "Wan-AI/Wan2.2-T2V-A14B-Diffusers",
"name": "Wan2.2 T2V",
"size": "A14B",
"workload": "t2v",
"recipe": { "height": 720, "width": 1280, "numFrames": 81, "fps": 16, "numInferenceSteps": 40, "guidanceScale": 4, "guidanceScale2": 3, "embeddedCfgScale": 6, "flowShift": 12, "boundaryRatio": 0.875, "dmdDenoisingSteps": null, "attentionBackends": ["FLASH_ATTN", "SAGE_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "Wan-AI/Wan2.2-I2V-A14B-Diffusers",
"name": "Wan2.2 I2V",
"size": "A14B",
"workload": "i2v",
"recipe": { "height": 832, "width": 480, "numFrames": 81, "fps": 16, "numInferenceSteps": 40, "guidanceScale": 3.5, "guidanceScale2": 3.5, "embeddedCfgScale": 6, "flowShift": 5, "boundaryRatio": 0.9, "dmdDenoisingSteps": null, "attentionBackends": ["FLASH_ATTN", "SAGE_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "hunyuanvideo-community/HunyuanVideo",
"name": "HunyuanVideo",
"size": "13B",
"workload": "t2v",
"recipe": { "height": 720, "width": 1280, "numFrames": 125, "fps": 24, "numInferenceSteps": 50, "guidanceScale": 1, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 7, "boundaryRatio": null, "dmdDenoisingSteps": null, "attentionBackends": ["FLASH_ATTN", "SAGE_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "FastVideo/FastHunyuan-diffusers",
"name": "FastHunyuan",
"size": "13B",
"workload": "t2v",
"recipe": { "height": 720, "width": 1280, "numFrames": 125, "fps": 24, "numInferenceSteps": 6, "guidanceScale": 1, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 17, "boundaryRatio": null, "dmdDenoisingSteps": null, "attentionBackends": ["FLASH_ATTN", "SAGE_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers",
"name": "Wan2.1 T2V",
"size": "1.3B",
"workload": "t2v",
"recipe": { "height": 480, "width": 832, "numFrames": 81, "fps": 16, "numInferenceSteps": 50, "guidanceScale": 3, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 3, "boundaryRatio": null, "dmdDenoisingSteps": null, "attentionBackends": ["FLASH_ATTN", "SAGE_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "Wan-AI/Wan2.1-T2V-14B-Diffusers",
"name": "Wan2.1 T2V",
"size": "14B",
"workload": "t2v",
"recipe": { "height": 720, "width": 1280, "numFrames": 81, "fps": 16, "numInferenceSteps": 50, "guidanceScale": 5, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 5, "boundaryRatio": null, "dmdDenoisingSteps": null, "attentionBackends": ["FLASH_ATTN", "SAGE_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "Wan-AI/Wan2.1-I2V-14B-480P-Diffusers",
"name": "Wan2.1 I2V 480P",
"size": "14B",
"workload": "i2v",
"recipe": { "height": 480, "width": 832, "numFrames": 81, "fps": 16, "numInferenceSteps": 40, "guidanceScale": 5, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 3, "boundaryRatio": null, "dmdDenoisingSteps": null, "attentionBackends": ["FLASH_ATTN", "SAGE_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "Wan-AI/Wan2.1-I2V-14B-720P-Diffusers",
"name": "Wan2.1 I2V 720P",
"size": "14B",
"workload": "i2v",
"recipe": { "height": 720, "width": 1280, "numFrames": 81, "fps": 16, "numInferenceSteps": 40, "guidanceScale": 5, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 5, "boundaryRatio": null, "dmdDenoisingSteps": null, "attentionBackends": ["FLASH_ATTN", "SAGE_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "loayrashid/TurboWan2.1-T2V-1.3B-Diffusers",
"name": "TurboWan2.1 T2V",
"size": "1.3B",
"workload": "t2v",
"recipe": { "height": 480, "width": 832, "numFrames": 81, "fps": 16, "numInferenceSteps": 4, "guidanceScale": 1, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 3, "boundaryRatio": null, "dmdDenoisingSteps": null, "attentionBackends": ["SLA_ATTN"], "defaultAttentionBackend": "SLA_ATTN", "vsaSparsity": 0 }
},
{
"id": "loayrashid/TurboWan2.1-T2V-14B-Diffusers",
"name": "TurboWan2.1 T2V",
"size": "14B",
"workload": "t2v",
"recipe": { "height": 720, "width": 1280, "numFrames": 81, "fps": 16, "numInferenceSteps": 4, "guidanceScale": 1, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 5, "boundaryRatio": null, "dmdDenoisingSteps": null, "attentionBackends": ["SLA_ATTN"], "defaultAttentionBackend": "SLA_ATTN", "vsaSparsity": 0 }
},
{
"id": "loayrashid/TurboWan2.2-I2V-A14B-Diffusers",
"name": "TurboWan2.2 I2V",
"size": "A14B",
"workload": "i2v",
"recipe": { "height": 720, "width": 1280, "numFrames": 81, "fps": 16, "numInferenceSteps": 4, "guidanceScale": 1, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 5, "boundaryRatio": 0.9, "dmdDenoisingSteps": null, "attentionBackends": ["SLA_ATTN"], "defaultAttentionBackend": "SLA_ATTN", "vsaSparsity": 0 }
},
{
"id": "FastVideo/LongCat-Video-T2V-Diffusers",
"name": "LongCat T2V",
"size": "13.6B",
"workload": "t2v",
"recipe": { "height": 480, "width": 848, "numFrames": 121, "fps": 24, "numInferenceSteps": 50, "guidanceScale": 1, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": null, "boundaryRatio": null, "dmdDenoisingSteps": null, "attentionBackends": ["FLASH_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "FastVideo/Matrix-Game-2.0-Base-Distilled-Diffusers",
"name": "Matrix Game 2.0 Base",
"size": "1.3B",
"workload": "game",
"keyboardDim": 4,
"recipe": { "height": 352, "width": 640, "numFrames": 57, "fps": 25, "numInferenceSteps": 3, "guidanceScale": 1, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 5, "boundaryRatio": null, "dmdDenoisingSteps": [1000, 666, 333], "attentionBackends": ["FLASH_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "FastVideo/Matrix-Game-2.0-GTA-Distilled-Diffusers",
"name": "Matrix Game 2.0 GTA",
"size": "1.3B",
"workload": "game",
"keyboardDim": 2,
"recipe": { "height": 352, "width": 640, "numFrames": 57, "fps": 25, "numInferenceSteps": 3, "guidanceScale": 1, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 5, "boundaryRatio": null, "dmdDenoisingSteps": [1000, 666, 333], "attentionBackends": ["FLASH_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
},
{
"id": "FastVideo/Matrix-Game-2.0-TempleRun-Distilled-Diffusers",
"name": "Matrix Game 2.0 TempleRun",
"size": "1.3B",
"workload": "game",
"keyboardDim": 7,
"usesMouse": false,
"recipe": { "height": 352, "width": 640, "numFrames": 57, "fps": 25, "numInferenceSteps": 3, "guidanceScale": 1, "guidanceScale2": null, "embeddedCfgScale": 6, "flowShift": 5, "boundaryRatio": null, "dmdDenoisingSteps": [1000, 666, 333], "attentionBackends": ["FLASH_ATTN"], "defaultAttentionBackend": "FLASH_ATTN", "vsaSparsity": 0 }
}
]
}
-1
View File
@@ -5,7 +5,6 @@ const nextConfig = {
output: "export",
trailingSlash: true,
basePath,
assetPrefix: basePath,
typescript: {
ignoreBuildErrors: false,
},
+1 -1
View File
@@ -5,7 +5,7 @@
"packageManager": "pnpm@10.28.0",
"scripts": {
"dev": "next dev -p 3003",
"build": "next build"
"build": "node scripts/validate-data.mjs && next build"
},
"dependencies": {
"lucide-react": "^0.564.0",
+52
View File
@@ -0,0 +1,52 @@
import assert from "node:assert/strict"
import { readFile } from "node:fs/promises"
const load = async (name) => JSON.parse(await readFile(new URL(`../data/${name}`, import.meta.url), "utf8"))
const [quickstart, tuning] = await Promise.all([load("quickstart.json"), load("tuning.json")])
assert.match(tuning.source.fastvideoCommit, /^[0-9a-f]{40}$/)
const backendIds = new Set(tuning.attentionBackends.map(({ id }) => id))
const workloadIds = new Set(tuning.workloads.map(({ id }) => id))
const modelIds = new Set()
for (const model of tuning.models) {
assert(!modelIds.has(model.id), `duplicate model: ${model.id}`)
modelIds.add(model.id)
assert(workloadIds.has(model.workload), `${model.id}: unknown workload ${model.workload}`)
const { recipe } = model
for (const key of ["height", "width", "numFrames", "fps", "numInferenceSteps"]) {
assert(Number.isInteger(recipe[key]) && recipe[key] > 0, `${model.id}: invalid ${key}`)
}
if (model.workload === "game") {
assert(recipe.numFrames % 12 === 9, `${model.id}: Matrix frames must be 9 + 12k`)
}
assert(recipe.guidanceScale > 0, `${model.id}: guidance must be positive`)
assert(recipe.vsaSparsity >= 0 && recipe.vsaSparsity <= 1, `${model.id}: invalid VSA sparsity`)
if (recipe.dmdDenoisingSteps !== null) {
assert(recipe.dmdDenoisingSteps.length > 0 &&
recipe.dmdDenoisingSteps.every((step) => Number.isInteger(step) && step > 0),
`${model.id}: invalid DMD schedule`)
}
assert(recipe.attentionBackends.length > 0, `${model.id}: no attention backend`)
assert(recipe.attentionBackends.includes(recipe.defaultAttentionBackend), `${model.id}: invalid default backend`)
for (const backend of recipe.attentionBackends) {
assert(backendIds.has(backend), `${model.id}: unknown backend ${backend}`)
}
}
assert(modelIds.has(tuning.defaults.model_id), "unknown default model")
const profileKeys = new Set()
for (const profile of quickstart.profiles) {
assert(modelIds.has(profile.model), `quick-start profile uses unknown model: ${profile.model}`)
assert(tuning.models.find(({ id }) => id === profile.model).workload === profile.task,
`${profile.model}: quick-start task does not match recipe workload`)
const key = `${profile.task}:${profile.tier}`
assert(!profileKeys.has(key), `duplicate quick-start profile: ${key}`)
profileKeys.add(key)
}
const unsupportedClaims = /"(?:generationSeconds|runtimeSeconds|timeSec|firstRunSec|vramMin|ramMin)"/
assert(!unsupportedClaims.test(JSON.stringify({ quickstart, tuning })), "unproven performance claim in recipe data")
console.log(`Validated ${tuning.models.length} recipes and ${quickstart.profiles.length} quick-start profiles.`)
+4 -4
View File
@@ -3,10 +3,10 @@
This directory contains the FastVideo documentation built with MkDocs.
The Quick Start and Advanced Tuning pages embed an interactive **config
generator** — a separate Next.js app in [`consumer-guide/`](../consumer-guide/)
that is built independently and copied into the docs site under
`/config-generator/`. To work on that app itself, see
[`consumer-guide/README.md`](../consumer-guide/README.md).
generator** — a separate Next.js app documented in
[`consumer-guide/README.md`](../consumer-guide/README.md). It is built
independently and copied into the docs artifact under `config-generator/`. Its
asset URLs use the GitHub Pages base path reported by `actions/configure-pages`.
## Build the docs locally
+15
View File
@@ -0,0 +1,15 @@
(() => {
const resizeType = "fastvideo-config-generator:resize";
window.addEventListener("message", (event) => {
if (event.origin !== window.location.origin) return;
if (!event.data || typeof event.data !== "object" || event.data.type !== resizeType) return;
const frame = Array.from(document.querySelectorAll("iframe[data-config-generator]"))
.find((candidate) => candidate.contentWindow === event.source);
const height = Number(event.data.height);
if (!frame || !Number.isFinite(height) || height < 320 || height > 20000) return;
frame.style.height = `${Math.ceil(height)}px`;
});
})();
+2 -2
View File
@@ -62,11 +62,11 @@ img {
}
.adv-tuning-guide-wrap {
width: calc(100vw - 26rem);
width: 100%;
max-width: none;
overflow: hidden;
background: #fff;
margin-right: 1rem;
margin-right: 0;
}
.adv-tuning-guide-frame {
+4 -11
View File
@@ -1,21 +1,14 @@
---
hide:
- toc
- toc
---
<div class="adv-tuning-guide-wrap">
<iframe
class="adv-tuning-guide-frame"
src="/config-generator/tuning/"
src="../../config-generator/tuning/"
title="FastVideo Advanced Tuning Guide"
data-config-generator
loading="lazy"
></iframe>
</div>
<script>
window.addEventListener("message", (e) => {
if (e.data && e.data.type === "adv-tuning-guide-height") {
const frame = document.querySelector(".adv-tuning-guide-frame");
if (frame) frame.style.height = e.data.height + "px";
}
});
</script>
+2 -2
View File
@@ -68,5 +68,5 @@ uv pip install flash-attn --no-build-isolation -v
Now that FastVideo is installed, head to the [Quick Start](quick_start.md) to generate your first video.
!!! tip "Not sure which command to run?"
- The [Quick Start](quick_start.md) page has an interactive Config Generator. Select your task and hardware to get a ready-to-copy `fastvideo generate` command instantly.
- For fine-grained control over all parameters, use the [Advanced Tuning Guide](advanced_tuning_guide.md).
- The [Quick Start](quick_start.md) page has an interactive Config Generator. Select your task, maintained model profile, and GPU count to get a ready-to-copy `fastvideo generate` command.
- For fine-grained control over all parameters, use the [Advanced Tuning Guide](advanced_tuning_guide.md).
+4 -66
View File
@@ -25,83 +25,21 @@ uv pip install flash-attn --no-build-isolation -v
## ⚡ Generate Your Command
Select your task and hardware to get a ready-to-run command:
Select your task, model profile, and GPU count to get a ready-to-run command:
<div class="quick-start-guide-wrap">
<iframe
class="quick-start-guide-frame"
src="/config-generator/"
src="../../config-generator/"
title="FastVideo Guided Config Generator"
data-config-generator
loading="lazy"
></iframe>
</div>
<script>
window.addEventListener("message", (e) => {
if (e.data && e.data.type === "quick-start-guide-height") {
const frame = document.querySelector(".quick-start-guide-frame");
if (frame) frame.style.height = e.data.height + "px";
}
});
</script>
!!! tip "Need more control?"
Use the [Advanced Tuning Guide](advanced_tuning_guide.md) to tune all parameters — resolution, attention backend, memory offloading, and more.
## Python API
Prefer Python over the CLI? Here are equivalent examples:
### Text-to-Video Generation
```python
from fastvideo import VideoGenerator
def main():
# Create a video generator with a pre-trained model
generator = VideoGenerator.from_pretrained(
"Wan-AI/Wan2.1-T2V-1.3B-Diffusers",
num_gpus=1, # Adjust based on your hardware
)
# Define a prompt for your video
prompt = "A curious raccoon peers through a vibrant field of yellow sunflowers, its eyes wide with interest."
# Generate the video
video = generator.generate_video(
prompt,
output_path="my_videos/", # Controls where videos are saved
save_video=True
)
if __name__ == '__main__':
main()
```
### Image-to-Video Generation
```python
from fastvideo import VideoGenerator, SamplingParam
def main():
# Create the generator
model_name = "Wan-AI/Wan2.1-I2V-14B-480P-Diffusers"
generator = VideoGenerator.from_pretrained(model_name, num_gpus=1)
# Set up parameters with an initial image
sampling_param = SamplingParam.from_pretrained(model_name)
sampling_param.image_path = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/astronaut.jpg"
sampling_param.num_frames = 107
# Generate video based on the image
prompt = "A photograph coming to life with gentle movement"
generator.generate_video(prompt, sampling_param=sampling_param,
output_path="my_videos/",
save_video=True)
if __name__ == '__main__':
main()
```
## Next Steps
- [Advanced Tuning Guide](advanced_tuning_guide.md) - Fine-grained parameter tuning
+2 -1
View File
@@ -78,7 +78,7 @@ plugins:
minify_js: true
minify_css: true
cache_safe: true
js_files: [assets/copy-page.js]
js_files: [assets/copy-page.js, assets/config-generator.js]
css_files: [assets/custom.css]
- api-autonav:
modules: ["fastvideo"]
@@ -238,3 +238,4 @@ extra_css:
# Custom JavaScript
extra_javascript:
- assets/copy-page.js
- assets/config-generator.js