npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@qvac/diffusion-cpp

v0.35.1

Published

stable-diffusion.cpp addon for qvac image/video generation

Readme

diffusion-cpp

Native C++ addon for image, video, interactive world-walk, and ESRGAN inference through qvac-ext-stable-diffusion.cpp, built for the Bare Runtime.

The package exposes four JS entry points:

| API | Entry point | Use case | | ---------------------- | ------------------------------------------- | ------------------------------------------------------------------------------- | | ImgStableDiffusion | @qvac/diffusion-cpp | Text-to-image, image-to-image, FLUX.2 reference fusion, optional ESRGAN upscale | | VideoStableDiffusion | @qvac/diffusion-cpp/video or named export | Wan, LTX, and MiniMax-H3 text-to-video / image-to-video | | WorldStableDiffusion | @qvac/diffusion-cpp/world | ABot-World interactive walk: block-by-block generation under keyboard input | | EsrganUpscaler | named export from @qvac/diffusion-cpp | Standalone PNG/JPEG upscaling |

Table of Contents

Supported Models

| Family | Mode | Notes | | ---------------------------- | -------------------------------------- | --------------------------------------------------------------------------------- | | SD1.x / SD2.x | image | All-in-one checkpoints through files.model | | SDXL | image | All-in-one checkpoints or split encoders when required | | SD3 | image | Supports split CLIP-L / CLIP-G / T5-XXL inputs | | FLUX.2 [klein] | image, img2img, multi-reference fusion | Split diffusion + Qwen3 LLM + VAE | | FLUX.3 Image Klein | image, reference editing | Split diffusion + Qwen3-VL 4B + FLUX.2 VAE; see FLUX.3 setup | | Wan 2.1 | text-to-video, image-to-video | Single diffusion expert; I2V requires CLIP vision | | Wan 2.2 TI2V-5B Turbo Q5_K_S | text-to-video | Community-distilled GGUF with Wan 2.2 VAE; use scripts/download-model-wan2.2.sh | | LTX-2 / LTXAV | text-to-video + audio | Gemma text encoder, video VAE, audio VAE, embedding connectors | | MiniMax-H3 FL2VA ConvRot | text-to-video, image-to-video + audio | Qwen3-VL text encoder, video VAE, audio VAE; see H3 setup | | ABot-World | interactive world walk | Causal block-by-block generation under keyboard input; see ABot-World guide | | ESRGAN | upscale | Standalone or post-generation image upscale |

Qwen-Image-2.1 integration

See Qwen-Image-2.1 for the native registry port, pinned downloads, text-to-image, ordered reference editing, and RGBA handling.

FLUX.3 setup

See FLUX.3 Image Klein for pinned, checksum-verified downloads, the shared MOSS registry baseline, and text-to-image and reference-editing examples.

MOSS-Image setup

Download the pinned SFT diffusion model, Qwen3.5 encoder, small FLUX.2 VAE, and external tokenizer with checksum verification:

bash scripts/download-model-moss.sh

The default directory is models/moss-image; override it with MOSS_MODELS_DIR. Pass absolute paths to the image constructor:

const files = {
  model: '/absolute/models/moss-image/moss_image_sft_bf16.safetensors',
  llm: '/absolute/models/moss-image/Qwen3.5-9B-Q4_K_M.gguf',
  vae: '/absolute/models/moss-image/flux2-vae_small.safetensors',
  tokenizer: '/absolute/models/moss-image/tokenizer.json'
}

files.tokenizer is passed to the native engine for both loading and fit assessment. Use Euler sampling, the discrete scheduler, CFG 3, and 50 steps as the initial SFT settings. Layout prompts can be supplied as a JSON string. This requires a native addon rebuilt with the 2026-11-01 registry ports; previously published native binaries do not expose the tokenizer option.

Supported Platforms

| Platform | Architecture | Status | GPU backend | | -------- | ------------ | ------ | -------------- | | macOS | arm64, x64 | Tier 1 | Metal | | Linux | arm64 | Tier 1 | Vulkan, CUDA | | Linux | x64 | Tier 1 | Vulkan, CUDA | | Android | arm64 | Tier 1 | Vulkan, OpenCL | | iOS | arm64 | Tier 1 | Metal | | Windows | x64 | Tier 1 | Vulkan |

Dependencies:

  • qvac-ext-stable-diffusion.cpp
  • ggml
  • Bare Runtime >= 1.24.0
  • CMake >= 3.25 and a C++20-capable compiler

Platform packages

@qvac/diffusion-cpp is a meta package that ships the JavaScript wrapper only. The native prebuild for each desktop host lives in a version-locked platform package selected at install time through os/cpu filtered optionalDependencies:

| Host | Package | | --- | --- | | linux-x64 (glibc) | @qvac/diffusion-cpp-linux-x64 | | linux-arm64 (glibc) | @qvac/diffusion-cpp-linux-arm64 | | darwin-arm64 | @qvac/diffusion-cpp-darwin-arm64 | | darwin-x64 | @qvac/diffusion-cpp-darwin-x64 | | win32-x64 | @qvac/diffusion-cpp-win32-x64 |

Do not depend on desktop platform packages directly. Supported installers are npm 7+, pnpm, bun, and Yarn Berry. Yarn v1 and --omit=optional installs skip the platform package and fail at require time, and at bare-pack time, naming the missing package. Each platform package is an ordinary Bare addon whose prebuilds/<host>/ holds the native module and, next to it, the dynamically loaded ggml backends the module finds on its own. A source build becomes loadable once npm run link:platform (run by npm run build, build:vulkan, and build:cuda) stages it as the host's platform package in node_modules/.

Mobile targets are cross-built, so no install host ever matches their os, and optionalDependencies filtering can never select them. Mobile applications must declare the target's platform package as a direct dependency, pinned to the exact @qvac/diffusion-cpp version:

| Target | Package | | --- | --- | | android-arm64 | @qvac/diffusion-cpp-android-arm64 | | ios (device + simulators) | @qvac/diffusion-cpp-ios |

Building From Source

See build.md for prerequisites, platform setup, cross-compilation, and troubleshooting.

npm install -g bare bare-make
npm install
npm run build

CUDA is opt-in for source builds. Ordinary Linux and Windows builds use Vulkan and CPU without requiring a CUDA toolkit. To include CUDA, install the toolkit and run the explicit build command below. Linux and Windows release prebuilds enable SD_CUDA through platformCmakeDefines. The QVAC_CUDA_TOOLKIT marker exported by CI setup also enables CUDA for Linux builds without tests or fuzzing, so automatic PR builds work before the updated build metadata reaches main. An explicit -D SD_CUDA=OFF overrides this default. CI provisions the toolkit with includeCuda, includeCudaArm64, and includeCudaWin32.

npm run build:cuda

Linux ARM64/x64 and Windows x64 platform packages include dynamically loaded CUDA modules. Installing @qvac/diffusion-cpp selects @qvac/diffusion-cpp-linux-arm64 on DGX Spark or @qvac/diffusion-cpp-linux-x64 on an x64 PC. Each platform package carries its host addon and the CUDA and Vulkan backend modules. CUDA execution requires the NVIDIA driver and CUDA 13 runtime/cuBLAS libraries on the host; the addon itself retains CPU-only load compatibility. Windows uses @qvac/diffusion-cpp-win32-x64, with qvac-diffusion-ggml-cuda.dll alongside the Vulkan DLL. CUDA 13 runtime and cuBLAS DLLs must be discoverable on PATH (for example, from the CUDA toolkit installation); they are not bundled in the platform package.

The server CUDA build uses CUDA 13.0.3 (nvcc 13.0.88) and matches qvac-fabric's packaged architectures for each platform:

| Platform package | CUDA architectures | | --- | --- | | Linux/Windows x64 | 75-virtual;80-real;86-real;89-real;90-virtual;120a-real | | Linux ARM64 | 121a-real |

virtual targets carry PTX that the driver compiles on first use; real targets carry native GPU code. The x64 module includes T4 PTX, native A100 code, and RTX 5090 code. The ARM64 CUDA module ships DGX Spark code only to keep the npm platform package within its size limit. The host addon must also match the CPU architecture. This package does not ship a separate Jetson CUDA module.

Any non-empty QVAC_CUDA_TOOLKIT marker requires nvcc 13.0.88; its text is hashed into the build's cache identity. Unmarked source builds with another compiler version warn and continue; nvcc rejects unsupported architectures. CUDACXX selects the compiler explicitly. Otherwise discovery follows Fabric: CUDA_PATH hints, then the default search including PATH, then /usr/local/cuda. Compiler paths are kept through VCPKG_KEEP_ENV_VARS, which the shared setup-cuda action exports.

With automatic backend selection, CUDA devices whose code cannot run are skipped, allowing Vulkan or ultimately CPU to be selected. Auto-fit prefers a dedicated GPU with a positive memory budget, falling back to integrated GPUs when none is available. Within each class, the largest available budget wins; shared system memory does not make an integrated GPU outrank a dedicated GPU. Explicit backend assignments remain unchanged. Set GGML_DISABLE_CUDA=1 before starting the process to disable CUDA, or use backend: 'vulkan0' to select Vulkan explicitly. An explicit backend: 'cuda0' requires that CUDA device and fails if it is unavailable. Diffusion's comma-separated backend syntax assigns modules (for example, diffusion=cuda0,te=cpu); it is not an ordered fallback list.

To verify automatic selection on a CUDA-capable host, run these from this package directory after building the addon. Each command starts a fresh process, generates an SD2 image, and checks the engine's resolved backend:

QVAC_EXPECT_BACKEND=CUDA bare test/integration/backend-fallback.js --exit
GGML_DISABLE_CUDA=1 QVAC_EXPECT_BACKEND=Vulkan bare test/integration/backend-fallback.js --exit
GGML_DISABLE_CUDA=1 GGML_DISABLE_VULKAN=1 QVAC_EXPECT_BACKEND=CPU bare test/integration/backend-fallback.js --exit

Set SD_TEST_MODEL_PATH to an existing SD2 Q8_0 GGUF to avoid downloading it. Set QVAC_TEST_BACKENDS_DIR to test modules from a separate build, including a directory containing only Vulkan or a CUDA module incompatible with the GPU.

Downloading Models

Download scripts populate packages/diffusion-cpp/models/ with the files used by the examples.

| Script | Model set | | ------------------------------------- | ----------------------------- | | ./scripts/download-model.sh | FLUX.2 [klein] 4B image model | | ./scripts/download-model-sd2.sh | SD2.x example model | | ./scripts/download-model-sd3.sh | SD3 example files | | ./scripts/download-model-sdxl.sh | SDXL example files | | ./scripts/download-model-wan.sh | Wan 2.1 T2V 1.3B | | ./scripts/download-model-wan-14b.sh | Wan larger T2V variant | | ./scripts/download-model-wan-i2v.sh | Wan 2.1 I2V 14B + CLIP vision | | ./scripts/download-model-ltx.sh | LTX-2.3 video + audio files | | ./scripts/download-minimax-h3-convrot.sh | MiniMax-H3 FL2VA ConvRot T2V/I2V files | | ./scripts/download-model-abot.sh | ABot-World set into test/model/abot (from the P2P model registry, no credentials) |

The FLUX.2 [klein] default image example uses:

| Role | File | | --------------- | --------------------------- | | Diffusion model | flux-2-klein-4b-Q8_0.gguf | | Text encoder | Qwen3-4B-Q4_K_M.gguf | | VAE | flux2-vae.safetensors |

LTX-2.3 requires more companion files:

| Role | Default file | | -------------------- | --------------------------------------------------------- | | Diffusion model | LTX-2.3-22B-distilled-1.1-Q5_K_M.gguf | | Text encoder | gemma-3-12b-it-UD-Q4_K_XL.gguf | | Video VAE | ltx-2.3-22b-distilled_video_vae.safetensors | | Audio VAE | ltx-2.3-22b-distilled_audio_vae.safetensors | | Embedding connectors | ltx-2.3-22b-distilled_embeddings_connectors.safetensors |

Downloads are resumable where supported by the script.

Examples

| Command | Description | | -------------------------------------------- | ------------------------------------------- | | npm run example | Load/unload the default FLUX.2 model | | npm run generate | FLUX.2 text-to-image | | npm run generate:flux2-cuda | Distilled Klein 4B on Spark / RTX 5090 CUDA | | npm run generate:sd2 | SD2.x text-to-image | | npm run generate:sd3 | SD3 text-to-image | | npm run generate:sdxl | SDXL text-to-image | | bare examples/generate-fusion.js | FLUX.2 multi-reference fusion | | bare examples/img2img-flux2.js | FLUX.2 single-reference img2img | | bare examples/img2img-sd3.js | SD3 SDEdit img2img | | bare examples/generate-video-wan.js | Wan 2.1 text-to-video | | bare examples/img2vid-wan.js | Wan 2.1 image-to-video | | npm run generate:video | Wan text-to-video | | npm run generate:ltx | LTX-2.3 text-to-video with audio | | npm run generate:ltx-coffee | 9-second LTX Ingredients coffee example | | bare examples/generate-video-minimax-h3-comfy-t2v.js | MiniMax-H3 text-to-video with audio | | bare examples/generate-video-minimax-h3-comfy-i2v.js | MiniMax-H3 image-to-video with audio | | npm run generate:esrgan | Image generation followed by ESRGAN upscale | | bare examples/standalone-esrgan-upscale.js | Standalone ESRGAN upscale | | npm run walk:world | ABot-World browser demo (generate + walk a world) |

Outputs are written to packages/diffusion-cpp/output/.

Distilled FLUX.2 Klein 4B on DGX Spark and RTX 5090

npm run generate:flux2-cuda uses four Euler steps, cfg_scale: 1, guidance: 1, and the engine's automatic FLUX.2 noise schedule. The fields have separate meanings: cfg_scale controls text classifier-free guidance, while guidance supplies the model's optional guidance embedding. Klein 4B has no guidance embedding, so text CFG is the field that must be set to 1. The existing generic image example's 20-step settings are not the distilled four-step recipe.

The CUDA example selects cuda0, keeps weights resident there, enables diffusion flash attention, and sets vae_conv_direct: false. On both GPUs, the existing im2col/matrix-multiplication path substantially reduces VAE decode time compared with direct convolution. This trades additional graph memory for lower latency; use the measured recipe when memory permits.

With four steps, diffusion Q8_0 and Qwen3 Q4_K_M, measured mean request-to-returned-PNG latency was:

| GPU | Native output size | Direct VAE, mean ± SD | Im2col VAE, mean ± SD | Speedup | | --- | --- | ---: | ---: | ---: | | DGX Spark GB10 | 864×480 | 12.574 ± 0.055 s | 2.865 ± 0.005 s | 4.39× | | DGX Spark GB10 | 1024×1024 | 32.981 ± 0.075 s | 7.392 ± 0.010 s | 4.46× | | RTX 5090 | 864×480 | 2.835 ± 0.006 s | 0.590 ± 0.002 s | 4.81× | | RTX 5090 | 1024×1024 | 7.383 ± 0.035 s | 1.404 ± 0.003 s | 5.26× |

Each cell summarizes 12 formal requests: three prompts, seeds 0/43, two repeats, following a separate warmup at each resolution. Loading and warmups are excluded. Timers include fresh prompt encoding through returned PNG, and exclude subsequent sample-file writes. Both variants use the same settings and model files on each machine, changing only vae_conv_direct.

The Spark measurements used diffusion-cpp 0.28.1, engine commit 8b3efc68c64befbf01ccc2ac9816ee1cde4dda4f, ggml commit 9a7d2b36e96a198c1c67c013cafcde4e4c2c60eb, LLVM 22, CUDA 13.3, and driver 580.178.04 on one DGX Spark.

The RTX 5090 measurements used one 32 GB GPU, diffusion-cpp 0.29.2, engine commit 886c66f60aca623145da6ec6261b02e5728ac109, ggml commit 9f94f330ac196e0a2e3176e798b36226b22091a5, Clang 20.1.8, statically linked libc++ 19, CUDA 13.3.73, and driver 595.71.05. The Linux x64 source build contains native SM120a cubins. A second 5090 was idle and was not used. At 1024×1024, mean VAE decode dropped from 6.253 s to 0.276 s while denoising stayed approximately 0.95 s.

The published build uses the pinned CI toolchain. These measurements use different source/toolchain revisions across machines, so they establish the within-machine VAE speedup rather than a controlled hardware ranking or a guarantee for every release or prompt.

Each machine produced 24 matched image pairs. Worst RGB RMSE on the 0–255 scale was 0.295 on Spark and 0.298 on RTX 5090.

Download the revision-pinned bundle with ./scripts/download-model-flux2-ingredients.sh; that script requires an authorized HF_TOKEN for the VAE. Set FLUX_MODELS_DIR when assets are in a different directory. H3's Qwen3-VL encoder is not the FLUX.2 Qwen3-4B encoder.

FLUX_WIDTH=864 FLUX_HEIGHT=480 npm run generate:flux2-cuda
FLUX_WIDTH=1024 FLUX_HEIGHT=1024 FLUX_IMAGES=3 npm run generate:flux2-cuda

The same commands work on either machine; generate:flux2-spark remains an alias. On a multi-GPU host, CUDA_VISIBLE_DEVICES=0 limits the example to the first card. FLUX_PROMPT, FLUX_SEED, and FLUX_OUTPUT_DIR customize the requests. FLUX_IMAGES issues sequential requests through one loaded model; every request freshly encodes its prompt. The example logs model loading, request-to-returned-PNG latency, progress, and native phase statistics, and unloads in finally. conditionerMs includes pre-sampler setup; postProcessMs includes PNG encoding and output callbacks. Neither is an isolated encoder timer. Cancellation uses model.cancel() and rejects the active response; a cancelled request supplies no partial PNG.

Image API

const path = require('bare-path')
const ImgStableDiffusion = require('@qvac/diffusion-cpp')

const MODELS_DIR = path.resolve(__dirname, './models')

const model = new ImgStableDiffusion({
  files: {
    model: path.join(MODELS_DIR, 'flux-2-klein-4b-Q8_0.gguf'),
    llm: path.join(MODELS_DIR, 'Qwen3-4B-Q4_K_M.gguf'),
    vae: path.join(MODELS_DIR, 'flux2-vae.safetensors')
  },
  config: {
    threads: 4,
    device: 'gpu',
    diffusion_fa: true
  },
  opts: { stats: true },
  logger: console
})

await model.load()

const response = await model.run({
  prompt: 'a majestic red fox in a snowy forest, golden light, photorealistic',
  width: 512,
  height: 512,
  steps: 20,
  guidance: 3.5,
  seed: 42
})

const images = []
await response
  .onUpdate((data) => {
    if (data instanceof Uint8Array) images.push(data) // PNG bytes
  })
  .await()

require('bare-fs').writeFileSync('output.png', images[0])
await model.unload()

Constructor Files

All file paths must be absolute.

| Key | Required | Description | | ------------------------------- | -------: | --------------------------------------------------------------------------- | | files.model | yes | Main model. All-in-one checkpoint for SD, diffusion model for split layouts | | files.clipL | no | CLIP-L text encoder for SD3 / split layouts | | files.clipG | no | CLIP-G text encoder for SDXL / SD3 | | files.t5Xxl | no | T5-XXL text encoder for SD3 | | files.llm | no | Qwen3 LLM text encoder for FLUX.2 [klein] | | files.vae | no | Separate VAE | | files.esrgan | no | ESRGAN model for post-generation upscale | | files.highNoiseDiffusionModel | no | Wan 2.2 high-noise expert path; normally used by VideoStableDiffusion |

Passing any separate text encoder (llm, t5Xxl, clipL, clipG) makes the wrapper route files.model to stable-diffusion.cpp's diffusion_model_path. All-in-one checkpoints are routed to model_path.

Image Config

config is part of the constructor object. There is no second constructor argument.

| Key | Type | Default | Description | | ----------------------- | ----------------------------------------- | ----------------- | ------------------------------------------------------------------------- | | threads | number | auto | CPU threads for loading / CPU ops | | device | 'gpu' | 'cpu' | 'gpu' | Prefer GPU backends or force CPU | | main-gpu | number | 'integrated' | 'dedicated' | unset | Pin the GPU selected by stable-diffusion.cpp | | type | weight type | auto | Override weight quantization | | rng | 'cpu' | 'cuda' | 'std_default' | 'cuda' | Context RNG; cuda means Philox and is not GPU-specific | | sampler_rng | RNG type | auto | Sampler RNG override | | vae_decode_only | boolean | false | Load only VAE decoder weights; leave false for img2img/fusion/hires paths | | vae_tiling | boolean | false | Tile VAE decode to reduce peak VRAM | | flash_attn | boolean | false | Enable flash attention globally | | diffusion_fa | boolean | true | Enable diffusion-model flash attention; important for FLUX/LTX memory use | | mmap | boolean | backend default | Memory-map weights when supported | | offload_to_cpu | boolean | backend default | Keep weights on CPU/offload as supported by backend | | backend | string | auto | Runtime backend for all modules or per-module assignments | | params_backend | string | runtime backend | Parameter residency on a backend, CPU RAM, or disk | | max_vram | number | string | 0 | VRAM budget in GiB for graph-cut segmented execution | | stream_layers | boolean | false | Stream diffusion layers from CPU RAM when graph cutting is active | | prediction | prediction type | auto | Recommended for FLUX.2 sizing and prompt warnings: 'flux2_flow'; leave automatic for Qwen | | flow_shift | number | model default | Flow-matching noise schedule shift | | diffusion_conv_direct | boolean | true | Use direct convolution in diffusion model | | vae_conv_direct | boolean | true | Use direct convolution in VAE | | backendsDir | string | beside the loaded module | Directory of ggml backend modules, scanned as given | | lora_apply_mode | string | auto | LoRA application mode | | upscaler_tile_size | number | 128 | ESRGAN tile size | | max_image_pixels | positive integer | 67108864 | Maximum decoded input or ESRGAN output pixels per image | | max_job_pixels | positive integer | 134217728 | Maximum decoded input pixels retained by a multi-image or video job |

main-gpu is resolved against the addon's own ggml device enumeration and then pinned through sd_ctx_params_t.backend. If an explicit request cannot be satisfied ('integrated' with no integrated GPU, 'dedicated' with no discrete GPU, or an out-of-range index), the addon falls back to CPU instead of silently choosing another GPU. Mobile targets reject main-gpu because they are single-GPU devices. An explicit backend assignment takes precedence over main-gpu.

backend controls where graphs execute. params_backend controls where model weights remain between uses. For example, backend: 'diffusion=cuda0,te=cpu' runs the diffusion model on CUDA and the text encoder on CPU.

params_backend: 'diffusion=cpu' keeps diffusion weights in CPU RAM and stages them to the runtime backend. params_backend: 'diffusion=disk' reloads those weights from the model file on demand and releases them after use — on every job, not only the first — so a disk-backed module also disables eager weight loading for the whole context. Disk is not selected automatically.

offload_to_cpu: true supplies a *=cpu default. An explicit params_backend entry written in module=backend form overrides that default for that module only: params_backend: 'te=disk' with offload_to_cpu: true keeps TE weights on disk while other parameters remain in CPU RAM.

A bare entry or an assignment to *, all, or default sets the whole-spec default rather than a per-module override, and the last default wins. For example, params_backend: 'cuda0' with offload_to_cpu: true puts every module on cuda0 and offloads nothing. The addon logs when the final whole-spec default differs from CPU. Equivalent defaults such as all=cpu do not produce an error. Write params_backend: 'diffusion=cuda0' to move one module and leave the rest offloaded.

A nonzero max_vram enables graph-cut segmentation even without stream_layers. Positive values cap the VRAM budget in GiB. Negative values use detected free VRAM while reserving the absolute value as headroom, and 0 disables graph cutting. Backend assignments such as max_vram: 'cuda0=6,vulkan0=4' apply one budget per device.

stream_layers adds diffusion-layer prefetch and eviction only when graph cutting is active and the diffusion parameter backend is CPU, for example:

config: {
  backend: 'cuda0',
  params_backend: 'diffusion=cpu',
  max_vram: -1,
  stream_layers: true
}

It does not stream from disk. Use params_backend: 'diffusion=disk' for on-demand reads from the model file.

stream_layers is forwarded to the engine as configured; the engine itself skips streaming when its prerequisites are unmet. The addon reports the cases it can prove before engine initialization: max_vram is unset, 0, or an all-zero assignment such as 'cuda0=0'. Per-backend and automatic negative budgets are resolved by the engine using the selected runtime backend and its free memory. That message, and the main-gpu and params_backend notices above, are the only diagnostics emitted at the default verbosity: 0; set verbosity: 2 to also see the effective backend, params_backend and max_vram assignments the addon passes to the engine.

The 16-case Linux hardware matrix is available in scripts/validate-layer-streaming.sh. It expects the MiniMax-H3 files under /home/shared/models/minimax-h3-q2 by default. Override that location with H3_MODELS_DIR. The runtime backend defaults to vulkan0; override it with BACKEND, for example BACKEND=cuda0. Then run the script from the package directory. Each case requires a non-empty AVI and checks the engine log for the expected graph-cut, streaming, CPU RAM, or disk behavior.

Image Generation Parameters

| Key | Type | Description | | ----------------------------- | ----------------- | ------------------------------------------------------------------- | | prompt | string | Required non-empty prompt | | negative_prompt | string | Negative prompt | | width, height | number | Positive multiples of 8; FLUX img2img defaults omitted axes to 1024 | | steps | number | Diffusion step count | | cfg_scale | number | Classifier-free guidance for SD/SDXL/SD3 and FLUX img2img examples | | guidance | number | Distilled guidance for FLUX.2 | | sampling_method / sampler | string | Sampler name; omit for auto-selection | | scheduler | string | Scheduler name; omit for auto-selection | | seed | number | -1 for random | | batch_count | number | Number of images | | lora | string | Absolute path to a LoRA adapter | | upscale | boolean | object | Post-generation ESRGAN upscale; requires files.esrgan | | vae_tiling | boolean | Per-job VAE tiling | | vae_tile_size | number | string | VAE tile size in latent pixels, e.g. 64 or '64x64' | | vae_tile_overlap | number | Tile overlap fraction | | cache_mode | string | Step-caching algorithm | | cache_preset | string | Cache preset: slow, medium, fast, ultra | | cache_threshold | number | Cache reuse threshold | | eta | number | DDIM/TCD stochasticity | | clip_skip | number | Skip last N CLIP layers |

Do not force sampling_method: 'euler_a' for FLUX.2 models. Leave the sampler unset unless you know the model family requires an override.

Image-to-Image and FLUX.2 Fusion

init_image accepts PNG/JPEG bytes and selects image-to-image mode.

  • FLUX.2 uses in-context conditioning: the reference image is VAE-encoded into separate latent tokens and the target starts from pure noise.
  • SD1.x / SD2.x / SDXL / SD3 use SDEdit: the input is noised according to strength and denoised with the prompt.

For FLUX.2 img2img, load the context with files.llm and keep config.prediction: 'flux2_flow' for the full FLUX.2 convenience behavior. Native model detection selects reference conditioning even when prediction is omitted or 'auto'. However, the single-reference size fallback (replacing 512×512 with the reference dimensions) still requires 'flux2_flow', and the JavaScript @imageN prompt warnings require both files.llm and that setting. Without it, pass explicit output dimensions and check reference tags yourself. Leave prediction automatic for Qwen-Image-2.1.

Reference-validation compatibility: init_images on SD1/SD2/SDXL is now rejected by the loaded native model after job submission, rather than by the JavaScript file/prediction checks. Await the response's .await() promise to handle the error. The native message is img2img: init_images requires a model supporting reference editing (FLUX.2 or Qwen-Image-2.1). Callers matching the former JavaScript error text must update their handling. The former rejection of init_image with files.llm but no explicit 'flux2_flow' prediction is also removed; native model capabilities determine the conditioning path. JavaScript still validates input types, empty arrays, and mutual exclusion of init_image and init_images before submission.

const inputImage = require('bare-fs').readFileSync('assets/source.jpg')

const response = await model.run({
  prompt: 'a cinematic portrait of the same person, professional lighting',
  init_image: inputImage,
  width: 1024,
  height: 1024,
  cfg_scale: 1.0,
  guidance: 3.5,
  steps: 20,
  seed: 42
})

FLUX.2 multi-reference fusion uses init_images, an array of PNG/JPEG buffers. It is mutually exclusive with init_image. Keep config.prediction: 'flux2_flow' for the convenience behavior described above.

const response = await model.run({
  prompt: 'blend @image1 and @image2 into one scientist in a black studio',
  init_images: [image1Bytes, image2Bytes],
  width: 624,
  height: 624,
  cfg_scale: 1.0,
  guidance: 3.5,
  steps: 10,
  seed: 10
})

@image1, @image2, etc. are prose anchors for the text encoder. The FLUX.2 Qwen3 text encoder does not receive vision tokens; visual fusion happens in the DiT through attention over reference latents. Keep increase_ref_index unset or false for FLUX.2-klein fusion.

Video API

const path = require('bare-path')
const fs = require('bare-fs')
const VideoStableDiffusion = require('@qvac/diffusion-cpp/video')

const MODELS_DIR = path.resolve(__dirname, './models')

const model = new VideoStableDiffusion({
  files: {
    model: path.join(MODELS_DIR, 'wan2.1_t2v_1.3B_fp16.safetensors'),
    t5Xxl: path.join(MODELS_DIR, 'umt5_xxl_fp16.safetensors'),
    vae: path.join(MODELS_DIR, 'wan_2.1_vae.safetensors')
  },
  config: {
    threads: 4,
    device: 'gpu',
    diffusion_fa: true,
    offload_to_cpu: true,
    vae_tiling: true
  },
  logger: console
})

await model.load()

const response = await model.run({
  mode: 'txt2vid',
  prompt: 'a colorful bird flapping its wings',
  negative_prompt: 'blurry, low quality, static, jittery, watermark',
  width: 480,
  height: 832,
  video_frames: 81,
  fps: 16,
  steps: 30,
  cfg_scale: 6.0,
  flow_shift: 3.0,
  seed: 42
})

let avi = null
await response
  .onUpdate((data) => {
    if (data instanceof Uint8Array) avi = data // MJPG AVI bytes
  })
  .await()

fs.writeFileSync('wan_t2v_seed42.avi', avi)
await model.unload()

The default export from @qvac/diffusion-cpp/video and the named VideoStableDiffusion export from @qvac/diffusion-cpp are the same class.

Video Files

| Key | Model family | Description | | ------------------------------- | ------------ | --------------------------------------------------------------- | | files.model | all video | Wan, LTX, or MiniMax-H3 diffusion transformer | | files.t5Xxl | Wan | UMT5-XXL text encoder | | files.vae | all video | Matching video VAE | | files.clipVision | Wan I2V | OpenCLIP ViT-H/14; required for mode: 'img2vid' on Wan | | files.llm | LTX / H3 | Gemma or Qwen3-VL text encoder | | files.audioVae | LTX / H3 | Audio VAE for synchronized audio | | files.embeddingsConnectors | LTX | Text-embedding connector weights; also marks the context as LTX |

Video Parameters

| Key | Description | | ------------------------------------------------------------ | ------------------------------------------------------------------ | | mode | Required: 'txt2vid' or 'img2vid' | | prompt, negative_prompt | Text conditioning | | width, height | Wan 2.1: multiples of 16. LTX, Wan TI2V, H3: multiples of 32 | | video_frames | Wan: (4*k + 1). LTX: (8*k + 1), max 257. H3: (17*k + 5) | | fps | Generation rate and AVI rate; H3 is fixed at 24 FPS | | steps, cfg_scale, sampling_method, scheduler, seed | Sampling controls | | flow_shift | Per-job flow-shift override; Wan 2.1 T2V 1.3B works well at 3.0 | | init_image | First frame for img2vid; required by that mode | | control_frames, vace_strength | Optional VACE guidance | | temporal_tiling | LTX-only temporal VAE tiling to reduce peak VRAM | | cache_mode, cache_preset, cache_threshold | Step-cache controls |

Decoded init_image, control_frames, and reference_images together are limited to 128 Mi pixels per job by default; each image is limited to 64 Mi pixels by default. At 1920×1080, up to 64 control frames fit when there are no other input images. An initial or reference image reduces the available control-frame budget. Set config.max_job_pixels and config.max_image_pixels to positive pixel counts when the target device can support a different budget. The fixed 16,384-pixel edge and compressed-source safeguards still apply.

Video output is a single MJPG AVI Uint8Array. For LTX-2 and H3 models loaded with audioVae, the AVI also contains a second IEEE-float PCM audio stream: 48 kHz for LTX-2 and 32 kHz for H3. VLC handles these files well.

Wan 2.2

The supported Wan 2.2 workflow is the community-distilled TI2V-5B Turbo Q5_K_S GGUF for text-to-video. The downloader does not include the CLIP vision encoder required by the wrapper's image-to-video path. Download its complete text-to-video model layout before running the example:

# TI2V-5B Turbo Q5_K_S (4 steps, CFG 1)
./scripts/download-model-wan2.2.sh
npm run generate:wan22

The download is approximately 16.4 GB: 3.56 GB for the Q5_K_S diffusion model, 11.4 GB for the fp16 UMT5-XXL encoder, and 1.41 GB for the Wan 2.2 VAE. The backend runs one process on one device with optional CPU offload. Use dimensions that are multiples of 32 for this TI2V model so the emitted AVI dimensions match the requested dimensions.

MiniMax-H3 Text-to-Video and Image-to-Video

The Comfy-Org FL2VA ConvRot checkpoint supports both modes through VideoStableDiffusion.run(). Its init_image is a PNG/JPEG first frame, copied into the asynchronous native job and encoded into H3's keyframe conditioning. H3 does not use Wan's CLIP vision encoder. The video VAE must include encoder weights for I2V (vae_decode_only: false, the default).

From the repository root, install the Hugging Face CLI, read the MiniMax-H3 license, and download the four matching files. If access requires authentication, run hf auth login first. --dry-run lists the files and sizes without fetching the weights. The downloader defaults to the validated model repository commit e5eb578a89295337b8ff433a035929ce0279e0b6; set HF_REVISION to use another commit.

python -m pip install -U huggingface_hub
bash packages/diffusion-cpp/scripts/download-minimax-h3-convrot.sh --dry-run
bash packages/diffusion-cpp/scripts/download-minimax-h3-convrot.sh

The four files total about 55 GB. The QVAC vcpkg registry pins stable-diffusion-cpp 2026-08-11#4 to qvac-ext-stable-diffusion.cpp commit 107121df3ee9664cd47f80b19add495002d0232f (merged PR #44) and ggml 2026-08-11#1 to qvac-ext-ggml commit 9a7d2b36e96a198c1c67c013cafcde4e4c2c60eb.

At the validated model revision, the four checkpoint SHA-256 hashes are:

| File | SHA-256 | | --- | --- | | diffusion_models/minimax_h3_fl2va_pruned_int8_convrot.safetensors | e889202c41dafb67b10d67b97f0d8541508036a6090af23425a5c2615d03c47a | | text_encoders/qwen3vl_32b_minimax_h3_int8_convrot.safetensors | bc2ced0fbea64757fa9acddccfc0b3f4819d1dcf1da6c124d690d368be283923 | | vae/minimax_h3_video_vae_fp16.safetensors | 7c1f131492e7eddacaac9069a61b81bdd39de5cc96561e677c5eab1cdce5e522 | | vae/minimax_h3_audio_vae_fp32.safetensors | 8e505d95dd1561d47abd43d4238fd40d9bb1ae9e147ed0a4cba778d76ae4db48 |

From packages/diffusion-cpp, run the separate examples. Set H3_MODELS_DIR if the checkpoint is elsewhere, H3_BACKEND to select a backend, and H3_OUTPUT for the AVI path. The I2V example defaults to the FLUX.2-generated 960×544 assets/h3-keyframe-boat.png; set H3_INPUT_IMAGE to a different PNG/JPEG of the same dimensions. Use H3_FRAMES=22 for a short clip or 124 for the longer reference workload.

bare examples/generate-video-minimax-h3-comfy-t2v.js
bare examples/generate-video-minimax-h3-comfy-i2v.js

example-h3-minimax-comfy.js first generates a commercial keyframe with FLUX.2 [klein] 4B and then passes that saved PNG to H3 I2V. Set H3_SKIP_FLUX=1 and H3_INPUT_IMAGE=/path/to/keyframe.png to rerun H3 with an existing image. FLUX_MODELS_DIR, FLUX_MODEL, FLUX_LLM, FLUX_VAE, FLUX_SEED, FLUX_STEPS, and FLUX_IMAGE_PROMPT customize the first stage.

bare examples/example-h3-minimax-comfy.js

H3 requires dimensions on a 32-pixel grid and frame counts of 17*k + 5 (5, 22, 39, …). Its distilled guidance uses cfg_scale: 1.0, and output is always 24 FPS. The addon writes MJPG AVI with the decoded audio stream when audioVae is provided. Control frames, Ref2VA references, Wan MoE settings, and image-conditioning strength are rejected for this FL2VA path. The existing Unsloth GGUF T2V example remains available as npm run generate:h3-coffee.

LTX-2 Text-to-Video With Audio

const model = new VideoStableDiffusion({
  files: {
    model: path.join(MODELS_DIR, 'LTX-2.3-22B-distilled-1.1-Q5_K_M.gguf'),
    llm: path.join(MODELS_DIR, 'gemma-3-12b-it-UD-Q4_K_XL.gguf'),
    vae: path.join(MODELS_DIR, 'ltx-2.3-22b-distilled_video_vae.safetensors'),
    audioVae: path.join(MODELS_DIR, 'ltx-2.3-22b-distilled_audio_vae.safetensors'),
    embeddingsConnectors: path.join(
      MODELS_DIR,
      'ltx-2.3-22b-distilled_embeddings_connectors.safetensors'
    )
  },
  config: {
    threads: 4,
    device: 'gpu',
    diffusion_fa: true,
    vae_tiling: true,
    vae_conv_direct: true
  },
  opts: { stats: true },
  logger: console
})

const response = await model.run({
  mode: 'txt2vid',
  prompt: 'a claymation cat playing jazz on a piano',
  negative_prompt: 'blurry, low quality, static, jittery, watermark, distorted audio',
  width: 512,
  height: 320,
  video_frames: 241,
  fps: 24,
  steps: 10,
  cfg_scale: 1.0,
  temporal_tiling: true,
  seed: 42
})

LTX distilled variants are designed for low step counts and low CFG values. For full dev weights, use higher steps and a larger CFG.

ABot-World Interactive Walk

ABot-World is a causal world model: it generates video block-by-block under live keyboard input instead of one batch call, exposed via @qvac/diffusion-cpp/world (WorldStableDiffusion). Worlds are created natively from a prompt + first-frame image (createScene()), then walked with WASD/IJKL (step()), streaming decoded PNG/JPEG frames. The four model files ship in the QVAC P2P registry.

# models (P2P registry, no credentials) + browser demo
npm install -g @qvac/registry-client   # then see docs/abot-world.md for the 4 downloads
export ABOT_MODELS_DIR=~/abot-models ABOT_KV_CACHE=1
npm run walk:world                     # open http://127.0.0.1:8787
const WorldStableDiffusion = require('@qvac/diffusion-cpp/world')

const world = new WorldStableDiffusion({
  files: { model: ditGguf, taehv: taehvGguf, scene: scenePack },
  config: { seed: 42, kvCache: true }
})
await world.load()
const response = await world.step({ W: true }) // one generated block forward
await response
  .onUpdate((data) => {
    if (data instanceof Uint8Array) frames.push(data) // PNG/JPEG frames
  })
  .await()
await world.unload()

Hardware requirements (interactive walk, Q8 DiT + KV cache):

| tier | GPU | host RAM | disk | measured | |---|---|---|---|---| | minimum @ 832x480 | 24 GB card, >= 20 GB VRAM free (16.3 GB steady + ~2.7 GB transient at block 0) | 8 GB | 14 GB | RTX 5090: 1.78 s/block | | low-VRAM @ 448x256 | ~6 GB | 8 GB | 14 GB | laptop RTX 4050 | | optimal | RTX 5090-class, dedicated (no co-tenant VRAM); optional dual-GPU split ABOT_BACKEND="diffusion=cuda0,vae=cuda1" | 16 GB | NVMe | 6.7-6.8 fps generation |

Performance vs the PyTorch reference (same 5090, same walk): the QVAC build generates 6.7 fps vs ~28.5 fps for the reference's fp8 Triton pipeline — about 4.2x slower per block, the main known trade-off of this implementation today. In exchange it starts 36x faster (first frame in 1.5 s vs ~54 s), uses 14x less host RAM (3.1 GB vs 43.6 GB peak), one CPU core instead of two-plus, 14 GB on disk instead of ~38 GB, and needs no Python runtime.

Model fidelity: the weights are converted to GGUF (DiT and umT5 at Q8_0, VAE and taehv at F16), so outputs are not bit-exact vs the PyTorch reference — parity is held by cosine-similarity gates instead (golden walk replays 0.993-0.99995, scene packs >= 0.997, ~32-38 dB walk-level PSNR), and walks are visually indistinguishable in validation.

Full guide — building, the demo server (local and over-SSH playback), the world API for app developers, resolutions, performance details and troubleshooting: docs/abot-world.md.

ESRGAN Upscaler

const { EsrganUpscaler } = require('@qvac/diffusion-cpp')
const fs = require('bare-fs')

const upscaler = new EsrganUpscaler({
  files: {
    esrgan: '/absolute/path/to/RealESRGAN_x4plus_anime_6B.pth'
  },
  config: {
    device: 'gpu',
    upscaler_tile_size: 128
  },
  logger: console
})

await upscaler.load()

const response = await upscaler.upscale(fs.readFileSync('input.png'), {
  repeats: 1
})

const images = []
await response
  .onUpdate((data) => {
    if (data instanceof Uint8Array) images.push(data)
  })
  .await()

fs.writeFileSync('upscaled.png', images[0])
await upscaler.unload()

repeats controls how many ESRGAN passes are applied. One pass typically scales by 4x; two passes scale by 16x.

Response Streams and Stats

All three wrappers return a QvacResponse.

  • Progress updates are JSON strings like {"step":1,"total":20,"elapsed_ms":...}. The stream is multi-phase: sampler sequences (one per image batch item / video expert, total = its step count) and, when vae_tiling is enabled, VAE tile passes (total = tile count). Each sequence restarts at step: 0, so a bar renderer should key on total changes rather than assume a single monotonic sequence. Model weights normally load eagerly at load(), so generation emits no loader ticks. Two configurations load lazily instead and do emit loader ticks inside generation: mobile targets, and any params_backend naming disk for one or more modules — the latter on every job, since disk-backed weights are released after each phase. In those cases the first job's conditionerMs also absorbs weight-load time.
  • Image generation and ESRGAN emit PNG Uint8Array values.
  • Video generation emits one MJPG AVI Uint8Array.
  • If opts.stats is enabled, a stats event is emitted before completion.

Image stats include load time, generation time, cumulative steps/images/pixels, dimensions, and seed. Video stats additionally include cumulative videos, frames, fps, hasAudio, and audioSampleRate. ESRGAN stats include upscale timing, output dimensions, repeats, and the backend device actually used.

Cancellation and Unload

Each wrapper has cancel() and unload() methods. Only one job may run per model instance at a time; overlapping run() calls fail with a busy error.

const response = await model.run({ prompt: '...', steps: 30 })
await model.cancel()
await response.await().catch(() => {})
await model.unload()

During ESRGAN upscale, cancellation is honored between repeat passes.

Assessing fit

assessFit projects a load against the memory free right now. It reads model metadata and never weight data, so GGUF and safetensors files can be the registry's header-only copies and the projection can run before weights are downloaded. It is a module export, not an instance method — nothing is loaded to call it.

const { assessFit } = require('@qvac/diffusion-cpp')

const fit = await assessFit({
  files: { model: '/models/model.gguf' },
  config: { backendsDir: '/opt/backends' },
  workload: { prompt: 'a lighthouse at dusk', width: 1024, height: 1024 }
})

fit.status // 'fits' | 'does-not-fit' | 'unknown'
fit.devices // [{ id, name, unified, usedBytes, freeBytes, totalBytes }]
fit.stats // {}

devices lists the GPU devices the placement uses, then the host. id is the device's PCI bus ID when the backend reports one, and its name otherwise. unified marks memory the host owns: the CPU, an integrated GPU, the Metal device on Apple silicon, Android's OpenCL GPU, and a device that reports no memory of its own, which carries the host's figures. A unified row's free memory is capped at the host's, which on iOS is the app's own limit. usedBytes is the engine's measured projection for that device, and freeBytes and totalBytes are read while planning. A shared-memory GPU's use is in its own row and is not repeated in the host row. A load on the CPU is one host row, and unknown has no rows.

files and config are what createInstance takes, plus files.clipVision, files.audioVae and files.embeddingsConnectors. Paths must be absolute. workload describes the generation the projection is sized for, and its defaults are the generation defaults:

| Field | Default | Description | | --- | --- | --- | | prompt | a stand-in prompt | Token count drives the text-encoder memory. | | width, height | 512 | Output dimensions. | | videoFrames | 1 | 1 or less projects image generation. A video-only model is projected at one frame unless this is passed, while run() defaults to 33. | | vaeTiling | false | Tiled decoding trades speed for a much smaller VAE arena. | | vaeTileSizeX, vaeTileSizeY | 512 | The tile geometry, in pixels. | | vaeTileOverlap | 0.5 | Fraction of a tile used as the overlap seam. | | upscaleRepeats | 1 | ESRGAN passes, each applying the checkpoint's scale factor. |

Every number must be finite, whole and in range; anything else rejects.

The engine chooses the placement, so it has to be given an unpinned configuration. A config.mainGpu, a config.device of cpu, a paramsBackend naming individual modules, or an OpenCL preference that does not name the first GPU is status: "unknown".

For standalone ESRGAN, use mode: 'upscale', files: { esrgan } and the same config as EsrganUpscaler. This mode supports device: 'cpu'. workload.width and height describe the input image. The estimate includes weights, the tiled graph and full-image RAM buffers; smaller tiles do not remove full-image allocations.

For post-generation upscaling, include files.esrgan and the upscaler_* config fields in the diffusion request. The estimate includes ESRGAN weights retained alongside diffusion, including GPU staging when its parameters are offloaded to CPU. Set workload.upscaleRepeats to the number of passes to assess.

For ABot, use mode: 'world', the same files: { model, taehv, scene } and config as WorldSession, and workload: { walkSteps: 100 }. The default is 100 walk steps; an explicit value must be a whole number from 1 to 1,000,000. The scene header supplies the resolution and reference slots. The check sizes the configured placement, including CPU offload, graph cuts, KV caches, the decoder and retained latent history. It does not change generation settings or limit the walk. Scene creation with umT5 and the Wan VAE is outside this session estimate.

A load the engine can place only by moving modules between backends is status: "does-not-fit", since the configuration as given does not fit, and its rows describe the placement the engine found. A paramsBackend of *=cpu is the exception: the engine replans every module for it, so the plan is compared against the placement that load already uses, and an equal one is fits.

A malformed request, a model the engine cannot read, or an ESRGAN output above the pixel limit rejects. A world placement naming a device the fitter cannot plan for is status: "unknown".

assessFit returns a Promise. Concurrent calls run one at a time within the addon.

The projection runs in the calling process and shares its engine state: the GPU backend modules load once per process, so the first config.backendsDir any call supplies is the one every later load uses, and the native log callback is process-global like everywhere else.

Operational Notes

  • Native C++ logs are process-global. Configure them once with require('@qvac/diffusion-cpp/addonLogging').setLogger(...).
  • Leave sampler and scheduler unset for normal use; the addon preserves stable-diffusion.cpp auto-detection for model-specific defaults.
  • diffusion_fa defaults to true and is important for FLUX/LTX memory use.
  • For FLUX.2 img2img/fusion, set config.prediction: 'flux2_flow' so the JS prompt warnings and single-reference size fallback remain enabled. Native model detection selects the conditioning path independently of this setting.
  • Wan I2V requires files.clipVision; LTX and MiniMax-H3 img2vid do not.
  • Wan 2.1 dimensions must be multiples of 16; LTX and H3 dimensions must be multiples of 32.
  • Wan frame counts use (4*k + 1); LTX uses (8*k + 1) and H3 uses (17*k + 5).
  • LTX and H3 audio is muxed into AVI as IEEE-float PCM.
  • On Linux the shipped prebuild must not hard-link any GPU loader (libvulkan/libOpenCL/libcuda/libcudart) — an integration test asserts this. GPU dependencies belong to the dynamically loaded backend modules. Linux ARM64 and x64 prebuilds must ship both CUDA and Vulkan modules. A custom source build using a different backend layout can opt out of this shipped layout check with QVAC_SKIP_PREBUILD_LINK_CHECK=true.

Credits

Test Images

assets/h3-keyframe-boat.png and assets/h3-keyframe-balloon.png are 960×544 FLUX.2 [klein] 4B images generated by examples/generate-h3-keyframes-flux2.js. Run bare examples/generate-h3-keyframes-flux2.js from this package to recreate them with the FLUX.2 models listed above. Set FLUX_MODELS_DIR if the models are elsewhere, or H3_KEYFRAME=boat to generate only the boat. They are included under this package's Apache-2.0 license for I2V examples and fixed-seed conditioning comparisons.

assets/von-neumann.jpg — John von Neumann (1956). Source: U.S. Department of Energy, File ID: HD.3F.191. This image is in the Public Domain as a work of the U.S. Federal Government.

assets/claude-shannon.jpg — Claude Shannon. Source: Bell Labs / Wikimedia Commons. Licensed under Creative Commons Attribution-ShareAlike (CC BY-SA). Attribution must be preserved; any redistribution of this image or a derivative must be released under a compatible CC BY-SA license.

License

Apache-2.0 — see LICENSE for details.