Ray Swan_

Canon Forge

2025 · Generative · Architect, Engineer & Technical Product Lead

Creative velocity without drift — identity, set, and shot locks that hold canon across providers, models, and cuts.

01 · Problem

The constraint

Image models drift. A headshot, a wardrobe turn, a library interior, and a medium shot of the same figure will not stay one canon unless identity, set, and camera are locked assets — not a prompt you hope the model remembers.

02 · Built

What shipped

Built a TypeScript/React/Vite suite (CharacterForge, SetForge, CompositorForge, SceneForge) with an Express proxy. Generations go through /api/generate (Gemini, xAI Grok Imagine, Venice, Bedrock Titan/SD, local SD). Default client provider is xAI. Canon stills attach as reference or init images where the provider allows it. SceneForge builds keyframe sequences and a flipbook; /api/generate-video calls Veo for 8-second clips. Profiles persist in localStorage. GitHub Actions lint and build; node:test covers identityLock and provider helpers.

03 · Decisions

The path

  1. 01
    Stop asking the model to remember the person

    Treated identity as an approved asset plus a written identity-lock block. The canon headshot is attached when the provider accepts a reference image.

  2. 02
    Lock the room the same way

    Sets declare spatial invariants, landmarks, forbidden changes, and a lighting-rig lock. Wide/medium stills become the set’s reference the same way the headshot does for a face.

  3. 03
    Compose, then generate

    CompositorForge only fires after character, set, action, lens, and landmark lock are specified. The model is a renderer inside a shot list.

  4. 04
    Four forges, one production grammar

    Character, Set, Compositor, and Scene tabs share CharacterProfile / SetProfile / CompositeConfig / KeyframeScene so a later frame cannot quietly become a different actor in a different room.

  5. 05
    Provider is a swap, not the product

    Moved keys server-side. Gemini, xAI, Venice, Bedrock, and local SD share one generate path. Veo is the video path.

04 · Architecture

How it is built

Canon headshot as identity kernel

Approved reference stills live on the character profile. Later prompts include an identity-lock block. This is not a face-embedding or InstantID model.

Set invariants and lighting lock

Indoor/outdoor sets declare spatial invariants, fixed landmarks, forbidden changes, and a lighting-rig lock in the prompt.

Shot grammar before pixels

Compositor specs encode shot type, camera angle, lens preset, subject distance, emotion, and landmark lock — production language, not a vibes prompt.

Multi-provider renderer

Express /api/generate routes Gemini, xAI Grok Imagine, Venice, Amazon Bedrock (Titan / SD), and local Stable Diffusion. Client default in source is xAI.

Veo clips and SceneForge keyframes

/api/generate-video calls Veo (default veo-3.0-fast-generate-001) for an 8-second 16:9 clip. SceneForge generates a timed still sequence and plays it as a flipbook. Not an NLE.

Vite app + Express, not this site

React 19 + Vite 6 + TypeScript + Express. Keys stay on the server. This portfolio cannot host it.

05 · Surfaces

What it looks like to operate

Production control plane
Plate
Production control plane

Face mesh, set wireframe, locked composite, and frame strip on one console — identity through the cut.

06 · Standing

What this proves

Proves: I can design a generative production pipeline that keeps identity, set, and shot canon locked across providers.

Public source at github.com/rubyrayjuntos/canon-forge. Needs provider keys on the Express server. This static portfolio cannot host it. Render.yaml and a GHCR Docker workflow exist; the Dockerfile in tree is a dev stage. Not a multi-tenant SaaS.

Four-forge architecture (Character, Set, Compositor, Scene) with identity-lock prompt contracts, multi-provider routing (Gemini, xAI, Bedrock, Venice, local SD), and Veo video.

01 / 06 · Problem