Skip to content
Concepts

Concepts

Media generation, durable output retention and provenance with host-owned authority and billing

Generate an image, keep the output, and retry a failed save without paying for another generation. Your host supplies identity, permissions, a provider and a place to put the file.

The host chooses actorId, namespace, owner and destinationId. Request bodies cannot choose that authority. A durable operation captures its identity and input, retains provider bytes before saving, and reuses those bytes when a save fails. An ambiguous provider execution is never silently dispatched again.

Declare metering: "unmetered" when your host pays its provider directly. A metered host supplies idempotent admit and settle functions plus its own refusalMessages for insufficient credit, daily limits and denied spending. Quotes are estimates. Your metering owner decides the customer price and settlement.

A recognized provider safety refusal returns HTTP 400 with code: "SAFETY_FILTER_REFUSED", stage: "provider", and retryable: false. The public message asks you to reword the prompt; provider details stay redacted. Nothing is saved or charged. The owner retains only the bounded refusal reason, so same-ID replay and background video polling preserve that verdict without calling the provider again. Workers AI’s observed NSFW-input refusal and Veo’s documented input-policy refusal are classified; an error number by itself is not a safety verdict.

Pre-launch operation stores must use the current fresh schema. Hosts reset old disposable stores; Darkroom does not migrate or repair their missing refusal fact.

Video generation runs through the operation’s alarm. A 202 response tells you to retry the same request ID after the supplied Retry-After delay.

The root export owns mediaVideoSelectionSchema, validateMediaVideoSelection, MediaVideoSelectionInput and MediaVideoSelection. Apps select paths; their host supplies reference authority and the MP4 destination. For example:

TS
import {
estimateVideoMilliunits,
validateMediaVideoSelection,
} from "@fungi.computer/darkroom";
const selection = validateMediaVideoSelection({
model: "bytedance/seedance-2.0-mini",
prompt: "Fern fronds unfolding in morning light",
resolution: "720p",
aspectRatio: "16:9",
durationSeconds: 5,
references: [{ path: "fern.png", role: "first-frame" }],
});
const providerCostMilliunits = estimateVideoMilliunits(selection);

The strict input fields are model, prompt, optional resolution, aspectRatio, durationSeconds, generateAudio, and optional references. Each reference is {path, role}; role is first-frame, last-frame, or reference. Normalization returns nominal width/height, explicit resolution, aspect and duration, and the same path-only references. The host adds its admitted computerId before calling the existing service. A single untagged reference in that host service is first-frame mode, preserving the existing Workflow caller. Unsupported combinations throw MediaSettingsError; the service returns 400 INVALID_ARGUMENT before billing admission or dispatch.

The sole model catalog describes these verified Unified AI contracts: Seedance and Veo checked 2026-10-11, MiniMax H3 Max checked 2026-10-14. They run through Workers AI.run with unprefixed IDs. Cloudflare’s Workers AI @cf/ catalog does not supply these video IDs.

Model Resolution Duration Reference modes Provider USD / output second
Seedance 2.0 480p / 720p / 1080p / 4k integers 4–12; default 5 first frame; first + last; 1–4 reference images except at 1080p .07 / .15 / .37 / .78
Seedance 2.0 Fast 480p / 720p integers 4–12; default 5 first frame; first + last; 1–4 reference images .06 / .12
Seedance 2.0 Mini 480p / 720p integers 4–12; default 5 first frame; first + last; 1–4 reference images .04 / .09
Veo 3.1 720p / 1080p exactly 4 / 6 / 8; default 6 one first image .20 silent / .40 audio at either resolution
Veo 3.1 Fast 720p / 1080p exactly 4 / 6 / 8; default 6 one first image 720p .08 silent / .10 audio; 1080p .10 silent / .12 audio
MiniMax H3 Max 480p / 768p integers 5–15; default 5 first frame; first + last; 1–4 reference images, either resolution .05 / .08 (no documented audio surcharge)

Seedance and Veo default to 720p and 16:9; MiniMax H3 Max defaults to 768p and 16:9. Seedance aspects are 16:9, 4:3, 1:1, 3:4, 9:16, 21:9, and 9:21, with fixed 24 FPS. Veo aspects are 16:9, 9:16 and 1:1. MiniMax H3 Max aspects are 16:9, 4:3, 1:1, 3:4, 9:16 and 21:9 (no 9:21; its documented adaptive selector, which follows the input image’s own aspect instead of a fixed box, has no nominal pixel size and is not exposed by this catalog). Seedance prompts are at most 2,000 characters; Veo uses Darkroom’s retained 2,048-character host limit because the provider page states no prompt maximum; MiniMax H3 Max’s own limit is 7,000 but Darkroom’s 2,048-character host cap binds first. Paths are trimmed, nonblank and at most 4,096 characters; references are bounded at four overall and refined per model (MiniMax H3 Max’s own page documents up to nine, which this four-reference host ceiling cannot reach). Last frame requires exactly one first frame. Frame mode cannot mix with reference-image mode. Seedance’s first image can override the requested aspect; returned width/height are nominal selectors, not measured MP4 dimensions.

Veo audio defaults to true and is always explicit in the provider request and quote. Seedance leaves generate_audio unset when generateAudio is omitted, because its audio default is undocumented; its non-video-input rates are the same for either audio choice. MiniMax H3 Max has no audio field at all: its catalog entry carries the same silent and audio rate, and gatewayInput throws MediaSettingsError if a caller sets generateAudio explicitly, rather than silently dropping the choice. estimateVideoMilliunits and the gateway estimator read the catalog prices: 1 USD = 100,000 milliunits, 1 cent = 1,000. mediaUnits returns {unit: "video_second", units: durationSeconds}. The host still owns admission, settlement, markup and refusal copy.

Reference limits follow the explicit Seedance parameter section’s four-image grammar; its overview’s larger counts remain unsupported. Veo 4k pricing does not establish a supported 4k input, and Seedance 2.5’s duration grammar remains unverified. Video/audio references and undocumented options are refused, never silently dropped. Seedance frames and references become data URIs; Veo’s image_input is plain base64; MiniMax H3 Max’s are data URIs inside a multimodal content[] array ({type: "image_url", image_url: {url}, role}), alongside the leading {type: "text", text: prompt} entry — a different provider body than Seedance or Veo’s flat prompt/image fields, documented only by the raw request/response JSON schemas the Cloudflare page links, not its prose parameter list. MiniMax H3 Max also sends its resolution selector uppercase (480P/768P) where every other model sends it lowercase. Every admitted image is translated, preserving its role. All successful responses use the existing bounded HTTPS MP4 fetch and retention path (64 MiB maximum). Seedance and Veo answer with the Unified gateway’s normalized {state: "Completed", result: {video}}; MiniMax H3 Max instead answers with its own documented {task: {status, content: {url}}} wrapper, decoded separately and treated as failed unless status is exactly "succeeded". The provider returns {bytes, format: "mp4"}; the service returns {bytes, costMilliunits, path, format, height, model, width} on completion. While the alarm is running, HTTP returns 202 with {status: "pending", retryAfterSeconds: 5}. Retry the same request ID, destination and settings to recover the retained result. The host chooses the output path, such as prints-<requestId>.mp4; Darkroom adds no output-naming rule or human-review gate.

The shared @fungi.computer/darkroom/server binding grammar and reply decoder are used by Hub and standalone Oyster. The internal generation command carries its image/video kind, stable request ID and App-owned library folder. Hosts attach the admitted Computer to reference paths, read and fit those references, and use createMediaService for generation, retention, replay and saving. Guests cannot supply a principal or reference Computer ID.

Image encoding is model-native when outputFormat is omitted. An explicit PNG, JPEG or WebP pin must be supported by the model; the saved result reports its actual encoding. Catalogs retain reference support declared by the model and available through that host. Unsupported reference selections are typed INVALID_ARGUMENT settings refusals before dispatch.

Runtime-neutral App definitions import the shared binding schemas from @fungi.computer/darkroom/media-binding; the server entry also re-exports them for host composition.