Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/gratitude5dee/wzrd-studio-desktopfinal/llms.txt

Use this file to discover all available pages before exploring further.

WZRD Studio’s generation layer is a set of Supabase Edge Functions that sit behind a client-side Unified Generation Service. Every AI generation request — whether fired from the storyboard, a Studio node, or the editor — is normalized into a GenerationInput object, routed to the correct edge function, and returned in a consistent GenerationResult envelope. This page documents the HTTP contracts for each generation endpoint and explains how the client-side routing layer dispatches to them.
All generation endpoints are deployed as Supabase Edge Functions. The base URL is your project’s VITE_SUPABASE_URL environment variable. Every function lives at /functions/v1/<name>.Base URL: https://<your-project-ref>.supabase.co/functions/v1/

Authentication

Every request must carry a valid Supabase JWT in the Authorization header.
Authorization: Bearer <supabase-access-token>
Obtain the token via supabase.auth.getSession() in the client or by exchanging a Thirdweb wallet signature through /functions/v1/wallet-auth.

POST /functions/v1/gen-shots

Streams incremental shot generation updates for a storyboard scene over Server-Sent Events (SSE). The server uses Groq (Llama 3.3 70B) to generate cinematic shot descriptions, inserts shot rows into the shots table, and pushes each phase transition as a named SSE event.
This endpoint is gated by the VITE_ENABLE_SHOT_STREAM feature flag (default: true). When the flag is false, clients must fall back to the Supabase CRUD flow for shot creation instead of calling this endpoint.

Request

POST /functions/v1/gen-shots
Authorization: Bearer <supabase-jwt>
Content-Type: application/json
Accept: text/event-stream

Body

projectId
string
required
Supabase project identifier. Must belong to the authenticated user.
sceneId
string
Scene to generate shots for. Defaults to the first scene ordered by scene_number when omitted.
existingShots
array
Array of previously created shot summaries used to assign the next sequential shot number server-side. Clients should send the current ordered list when present.
shotCount
integer
Number of shots to generate (1–6). Defaults to 3.
requestId
string
Client-supplied idempotency key. A UUID is generated server-side when omitted.

Example

{
  "projectId": "a1b2c3d4-...",
  "sceneId": "scene-uuid",
  "existingShots": [
    { "id": "shot-uuid-1", "shot_number": 1 },
    { "id": "shot-uuid-2", "shot_number": 2 }
  ],
  "shotCount": 3
}

SSE Response Stream

The response is Content-Type: text/event-stream with Cache-Control: no-cache, no-transform and Connection: keep-alive. Events are emitted in FIFO order per connection. Clients should merge shot events by id rather than appending blindly.

meta — Stream Established

Emitted immediately after the SSE connection is open and the project/scene context is resolved.
requestId
string
The request ID (provided or server-generated).
projectId
string
Confirmed project UUID.
sceneId
string
Resolved scene UUID.
latency
integer
Milliseconds elapsed until the first chunk was sent.
event: meta
data: {"requestId":"...","projectId":"...","sceneId":"...","latency":0}

shot — Incremental Shot Update

Emitted multiple times per shot as it progresses through phases. Each event represents the latest known state for that shot.
id
string
Shot UUID (stable across phase updates).
project_id
string
Parent project UUID.
scene_id
string
Parent scene UUID.
shot_number
integer
Sequential shot number within the scene.
status
string
Current generation phase: creatingdraftingenrichingready.
title
string | null
Short title derived from the shot idea (available from drafting phase).
description
string | null
Narrative description / prompt idea text.
visual_prompt
string | null
Full enriched visual prompt for image generation. null during creating phase; set from drafting phase onward.
thumbnail
string | null
Thumbnail URL (populated after image generation; null in the stream itself).
event: shot
data: {"id":"shot-uuid","project_id":"...","scene_id":"...","shot_number":3,"status":"enriching","title":"Golden Hour Chase","description":"A motorcycle speeds through narrow alleyways as the sun dips below the horizon.","visual_prompt":"A motorcycle speeds through narrow alleyways...Cinematic lighting, professional framing, filmic detail.","thumbnail":null}
1

creating

Shot row inserted. visual_prompt is null in the event payload.
2

drafting

prompt_idea and shot_type written to the database. title and visual_prompt are now populated in the event payload.
3

enriching

visual_prompt and image_status: prompt_ready written to the database.
4

ready

All fields populated. Trigger onShotReady in your UI hook to merge the shot into the timeline.

done — Stream Complete

Terminal event. No more shot events will follow.
completed
boolean
Always true on a clean completion.
total
integer
Number of shots that were streamed.
requestId
string
Echo of the request ID.
event: done
data: {"completed":true,"total":3,"requestId":"..."}

error — Stream Error

Emitted if the server encounters an error mid-stream. Abort the stream and surface the message to the user.
error
string
Human-readable error message.
requestId
string
Echo of the request ID.
event: error
data: {"error":"Streaming failed","requestId":"..."}

Feature Flags

VITE_ENABLE_SHOT_STREAM

Default: trueEnables the SSE streaming workflow. When false, bypass useShotStream entirely and revert to the Supabase shots CRUD flow.

VITE_ENABLE_STREAM_TELEMETRY

Default: trueEnables client-side logging of meta/latency metrics emitted by the stream. When disabled, telemetry hooks become no-ops — the core streaming UX continues to function.

Credit Billing

Credits are reserved at request time and committed on completion. The formula is getWorkflowCreditCost('gen-shots', insertedShots / 2). If the stream errors before any shots are inserted, the hold is released.

POST /functions/v1/project-auto-generate

Queues parallel generation for all shots in a project. This is the batch trigger that fires image and video generation for every shot at once rather than one at a time.

Request

POST /functions/v1/project-auto-generate
Authorization: Bearer <supabase-jwt>
Content-Type: application/json

Body

project_id
string
required
UUID of the project whose shots should be generated.
phase
string
required
Generation phase to run. Either "images" or "videos".
{
  "project_id": "a1b2c3d4-...",
  "phase": "images"
}

POST /functions/v1/compute-execute

Executes a saved Studio compute graph for a project. The function fetches all compute_nodes and compute_edges for the project, performs a topological sort, and processes each level in parallel. Results are streamed back via SSE as nodes transition through runningsucceeded / failed / skipped.

Request

POST /functions/v1/compute-execute
Authorization: Bearer <supabase-jwt>
Content-Type: application/json
Accept: text/event-stream

Body

projectId
string
required
UUID of the project whose compute graph should be executed.
nodeIds
array
Optional subset of node IDs to execute. When omitted, all executable nodes in the graph run. The function automatically resolves upstream dependencies for any specified nodes.
useCache
boolean
Whether to use cached node outputs where available. Defaults to true.
requestId
string
Client-supplied idempotency key for credit deduplication.

SSE Events

meta
object
Emitted first. Contains run_id, project_id, and total_nodes.
node_status
object
Emitted whenever a node changes state. Fields: node_id, status (running | succeeded | failed | skipped), output (on success), error (on failure), processing_time_ms.
node_progress
object
Progress updates from long-running nodes. Fields: node_id, progress (0–100), message, logs.
complete
object
Terminal event. Fields: run_id, status, outputs (map of nodeId → result), completed_nodes, total_nodes, failed_nodes.
error
object
Emitted on fatal execution errors. Fields: run_id, error.

POST /functions/v1/director-cut

Orchestrates Director’s Cut assembly — syncing timeline assets, performing preflight readiness checks, and launching the export render job. Supports four actions via the action field.

Request

POST /functions/v1/director-cut
Authorization: Bearer <supabase-jwt>
Content-Type: application/json

Body

action
string
required
One of "sync", "create", "retry", or "status".
projectId
string
Required for sync, create, and retry actions.
jobId
string
Required for the status action.
settings
object
Optional export settings passed to the render pipeline.

Actions

Rebuilds the timeline_assets table for the project by walking scenes and shots in order. Returns a DirectorCutSummary without starting a render job.
{ "action": "sync", "projectId": "..." }
Response:
{
  "success": true,
  "summary": {
    "totalShots": 12,
    "syncedAssets": 14,
    "visualAssets": 12,
    "readyShots": 12,
    "readyVideos": 8,
    "fallbackImages": 4,
    "missingShots": 0,
    "audioAssets": 2,
    "canExport": true,
    "blockingReason": null
  }
}
Syncs timeline assets, runs preflight checks, and creates a new export_jobs row if the project is ready. Returns a job ID immediately; the render runs asynchronously.
{ "action": "create", "projectId": "..." }
Response (success):
{
  "success": true,
  "status": "processing",
  "jobId": "job-uuid",
  "progress": 5,
  "provider": "fal_remote",
  "providerStatus": "queued",
  "fallbackUsed": false
}
Response (preflight failure — HTTP 409):
{
  "success": false,
  "error": "DIRECTOR_CUT_PREFLIGHT_FAILED",
  "message": "3 ordered shots are missing an image or video.",
  "summary": { ... }
}
Similar to create but skips the sync step. Checks readiness on existing timeline data and creates a new job if the project can export.
Returns the current state of a running or completed export job.
{ "action": "status", "jobId": "job-uuid" }
Response:
{
  "status": "completed",
  "progress": 100,
  "outputUrl": "https://storage.example.com/final-exports/...",
  "error": null,
  "provider": "fal_remote",
  "providerStatus": "completed",
  "fallbackUsed": false
}

GET /functions/v1/model-catalog

Returns the full catalog of AI models available in WZRD Studio, including credit costs, provider information, and media type classifications.

Request

GET /functions/v1/model-catalog
Authorization: Bearer <supabase-jwt>

Response

An array of model objects:
id
string
Canonical model ID used in generation requests (e.g., fal-ai/flux/schnell).
name
string
Human-readable display name (e.g., FLUX Schnell).
provider
string
AI provider: fal-ai, gmi-cloud, lovable-ai, etc.
credits
integer
Credit cost per generation.
mediaType
string
Output type: image, video, audio, or text.
workflowType
string
Workflow classification: e.g., text-to-image, image-to-video, text-to-video, video-edit.
[
  {
    "id": "fal-ai/flux/schnell",
    "name": "FLUX Schnell",
    "provider": "fal-ai",
    "credits": 3,
    "mediaType": "image",
    "workflowType": "text-to-image"
  },
  {
    "id": "fal-ai/kling-video/o3/standard/text-to-video",
    "name": "Kling O3 Standard T2V",
    "provider": "fal-ai",
    "credits": 20,
    "mediaType": "video",
    "workflowType": "text-to-video"
  }
]

Unified Generation Service

The client-side Unified Generation Service (src/services/unifiedGenerationService.ts) is the single entry point for all AI generation in WZRD Studio. It normalizes inputs, selects the correct edge function, handles queue polling, optionally stores outputs to Supabase Storage, and returns a consistent result.

GenerationInput Interface

interface GenerationInput {
  /** Model ID from the catalog or a provider-specific ID */
  model: string;
  /** Primary prompt / instruction text */
  prompt: string;
  /** Additional model-specific parameters */
  parameters?: Record<string, unknown>;
  /** Reference assets (input images, videos, audio for conditioning) */
  referenceAssets?: ReferenceAsset[];
  /** Output configuration */
  outputConfig?: OutputConfig;
  /** Metadata for tracking / context */
  metadata?: GenerationMetadata;
}

interface ReferenceAsset {
  url: string;
  type: 'image' | 'video' | 'audio' | 'text' | 'model';
  role?: string;  // e.g. 'input_image', 'style_reference'
}

interface OutputConfig {
  format?: string;            // 'png', 'mp4', 'mp3', etc.
  count?: number;             // Number of outputs
  storageBucket?: string;     // Supabase Storage bucket
  storagePathPrefix?: string;
  autoStore?: boolean;        // Auto-upload to Supabase Storage (default: true)
}

interface GenerationMetadata {
  source?: 'project-setup' | 'studio' | 'editor' | 'storyboard' | 'timeline';
  projectId?: string;
  entityId?: string;   // Node / shot / clip ID
  custom?: Record<string, unknown>;
}

GenerationResult Interface

interface GenerationResult {
  url: string;
  metadata: GenerationResultMetadata;
  status: 'pending' | 'running' | 'completed' | 'failed';
}

interface GenerationResultMetadata {
  generationId: string;
  resolvedModel: string;    // Actual model used (may differ due to fallback)
  requestedModel: string;   // Originally requested model
  fallbackUsed: boolean;
  fallbackReason?: string;
  mediaType: 'image' | 'video' | 'audio' | 'text' | 'unknown';
  credits?: number;
  durationSeconds?: number;
  raw?: unknown;            // Raw provider response
  storageUrl?: string;      // Supabase Storage URL if auto-stored
  width?: number;
  height?: number;
}

Routing Logic

The service selects a backend route by inspecting the model ID:
RouteTriggerEdge Function
fal-streamDefault for all fal-ai/* models/functions/v1/fal-stream
gmi-cloudmodel.provider === 'gmi-cloud' or modelId.startsWith('gmi/')/functions/v1/gmi-execute
gemini-textgoogle/gemini-* or openai/gpt-* text models/functions/v1/gemini-text-generation
groq-textgroq/* or llama-* models/functions/v1/groq-chat
elevenlabs-ttselevenlabs-tts model ID/functions/v1/elevenlabs-tts
elevenlabs-sfxelevenlabs-sfx model ID/functions/v1/elevenlabs-sfx
elevenlabs-musicelevenlabs-music model ID/functions/v1/elevenlabs-music
edge-functionparameters._edgeFunction is setNamed edge function
For video models, the service also checks referenceAssets to automatically upgrade the model to an image-to-video or reference-to-video variant when input images or videos are provided and the requested model is incompatible.

Usage Examples

import { unifiedGenerationService } from '@/services/unifiedGenerationService';

// Generate an image
const image = await unifiedGenerationService.generateImage(
  'A cinematic wide shot of a futuristic city at sunset',
  {
    model: 'fal-ai/flux/schnell',
    parameters: { image_size: 'landscape_16_9' },
    projectId: 'my-project-id',
    autoStore: true,
  }
);
console.log(image.url); // Supabase Storage URL

// Generate a video with progress tracking
const video = await unifiedGenerationService.generateVideo(
  'A drone flyover of a tropical island, golden hour',
  {
    model: 'fal-ai/kling-video/o3/standard/text-to-video',
    parameters: { duration: '5', aspect_ratio: '16:9', generate_audio: true },
    projectId: 'my-project-id',
  },
  (progress) => console.log(`${progress.percent}% — ${progress.message}`)
);

// Generate text
const result = await unifiedGenerationService.generateText(
  'Write a 3-sentence storyline for a sci-fi short film.',
  { model: 'google/gemini-2.5-flash' }
);
const text = (result.metadata.raw as { text: string }).text;

Error Types

import { GenerationError, InsufficientCreditsError } from '@/services/unifiedGenerationService';

try {
  const result = await unifiedGenerationService.generate(input);
} catch (error) {
  if (error instanceof InsufficientCreditsError) {
    console.log(`Need ${error.required} credits, have ${error.available}`);
    // Service automatically routes to the billing top-up page
  } else if (error instanceof GenerationError) {
    console.error(`[${error.code}] ${error.message}`);
  }
}
Error CodeDescription
insufficient_creditsNot enough credits for the requested model
stream_errorHTTP error from fal-stream
no_bodyNo response body from provider
no_resultStream completed without a result
provider_errorProvider returned an error event
text_errorText generation failed
groq_errorGroq API error
audio_errorAudio generation failed
edge_function_errorEdge function invocation failed
gmi_errorGMI Cloud error
gmi_timeoutGMI generation timed out
unknown_routeUnrecognized generation route

Build docs developers (and LLMs) love