Skip to content

Valiera00/SPITE

SPITE

Built out of spite. Made for control.

An open-source, node-based visual canvas for AI filmmaking. Bring your own API keys. Pay providers directly. Own your workflow.

SPITE was built because every AI filmmaking tool either traps you in a credit system you can't audit, or assumes you're an ML engineer who enjoys wiring up diffusion models by hand. This is neither. It's a production canvas for people who think in shots and scenes — characters, prompts, references, generated images, generated video, all on one infinite plane, all owned by you.


What it does

  • Node canvas. Drag prompts, references, image generators, and video generators onto an infinite plane. Connect them. Hit Generate on any node and SPITE orchestrates the right model call.
  • Character consistency. Tag images to a named folder (Character / Prop / Location), use @FolderName in any prompt, and SPITE wires the reference into every generation that mentions it.
  • Multi-model. Nano Banana Pro, FLUX, Kling, Seedance, Luma Ray2, MiniMax Hailuo, Wan — all in one canvas, switchable per node, all routed through fal.ai with your own key.
  • Scenes and shots. First-class production primitives. Tag a node as Shot 1 of Scene A; the scene strip at the top of the canvas keeps the structure visible.
  • Asset library. Every generation persists, organised by date, model, and project. Protected from cleanup if used on a canvas.
  • Generation recovery. When fal.ai stalls or the page reloads mid-generation, the recovery system pulls completed jobs back from fal within their 24h retention window. No other tool does this.
  • Cost-aware UX. Estimated cost on every Generate button. Live fal.ai balance badge. $25 confirmation threshold. Staggered batch submission. All built after a real $200-in-24-hours incident.
  • Export. Storyboard zip with one folder per scene, files named by shot order. Drop it straight into Premiere or Resolve.
  • Snapshots. Canvas state saves every three seconds. Point-in-time snapshots kept separately for recovery.
  • Auth. Single-user password gate. The internet does not need to see your work.

What it deliberately doesn't do

  • No video editing — SPITE is pre-production.
  • No real-time multi-user collaboration — single-user by design.
  • No automation that makes creative decisions for you.
  • No credit system, no markup, no subscription.

Self-host

Prerequisites

  • Node 20+ and pnpm (or npm/yarn — pnpm is what we develop against)
  • A free Neon account (Postgres)
  • A Cloudflare account with R2 enabled (S3-compatible storage; free tier covers most personal use)
  • A fal.ai account with a funded key (the generation provider — you pay them directly per generation)

Install

git clone <your-fork-url>
cd spite
pnpm install

Configure

Copy the template and fill in real values:

cp .env.example .env.local

Every field is required except the ones marked optional. SPITE refuses to boot with missing variables — it will route every request to a /setup page listing what's missing, with hints. You won't be guessing.

Where to find each value:

Variable Source
DATABASE_URL neon.tech → your project → Connection string
R2_ACCOUNT_ID Cloudflare dashboard → R2 (right sidebar)
R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY Cloudflare R2 → Manage API tokens → Create API token
R2_BUCKET_NAME Whatever you named the bucket you created
FAL_KEY fal.ai → Dashboard → Keys
APP_PASSWORD You pick — strong, your responsibility

Database

Open your Neon project's SQL editor and paste the contents of database-setup.sql. Hit Run. The script is idempotent — re-running it is safe and won't touch existing data.

R2 bucket CORS (do this once, or uploads fail)

The browser uploads media files directly to R2 via a presigned URL. R2 ships CORS-locked — without a CORS rule the browser's PUT dies with Failed to fetch, and assets never reach the bucket. Set this once in the Cloudflare dashboard:

  1. Cloudflare → R2 → click your bucket
  2. Settings tab → CORS PolicyEdit CORS policy
  3. Paste this and save — replace the placeholder with YOUR deployment's exact origin(s):
[
  {
    "AllowedOrigins": ["https://your-app.vercel.app", "http://localhost:3000"],
    "AllowedMethods": ["PUT", "GET", "HEAD"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3600
  }
]

Pin AllowedOrigins to the precise origins you actually deploy from (your production domain and http://localhost:3000 for local dev). Do not use a broad wildcard like https://*.vercel.app — that would let a page on any Vercel-hosted site drive a browser request against your bucket if it ever gets hold of a presigned URL. If you use a custom domain, list that instead, e.g. "https://your-app.example.com". If you genuinely need preview deploys to upload, add each specific preview origin rather than the whole *.vercel.app space.

Run

pnpm dev

Open http://localhost:3000, type the APP_PASSWORD you set, and you're in.


Deploy to Vercel

  1. Push your fork to GitHub.
  2. Import the repo on vercel.com/new.
  3. Vercel → Project → Settings → Environment Variables. Add every name from .env.example with its real value. (Don't commit .env.local to git — .gitignore should already block it. The included scripts/check-no-secrets.sh will catch you if you try.)
  4. Trigger a deploy. The first deploy will route to /setup if anything is missing.

Cron cleanup

There's a scheduled cleanup endpoint at /api/assets/cleanup that deletes old, unprotected generated assets after 30 days and sweeps the auth / spend bookkeeping tables so they don't grow unbounded. A daily schedule is already defined in vercel.json (04:00 UTC). To activate it, just set CRON_SECRET to a long random string in your Vercel env — Vercel automatically sends it as Authorization: Bearer <CRON_SECRET> on each cron run, and the endpoint refuses to do anything without a matching secret.

If CRON_SECRET is unset the cron simply no-ops (returns 500 and logs), so nothing breaks — but the cleanup won't run. On non-Vercel hosts, point any external scheduler (GitHub Actions, etc.) at the same path with that Authorization header; both GET and POST work.


Project structure

app/                  Next.js App Router pages + API routes
  api/                Server-side endpoints (auth, generate, assets, R2 proxy)
  login/              The password gate
  setup/              Shown when required env vars are missing
  project/[id]/       The canvas for one project
components/
  canvas/             The node-based workspace (nodes, edges, toolbars)
  ui/                 shadcn/ui primitives
lib/
  env-check.ts        Refuse-to-boot env validation
  r2-upload.ts        R2 SDK wrapper + HMAC URL signing for the proxy
  fal-models.ts       Per-model config: endpoint, input shape, cost
  fal-cost.ts         Cost estimation + confirmation threshold
  mention-prompt.ts   Model-aware reference grammar compilation
scripts/              Tooling (secret check, etc.)
database-setup.sql    Idempotent schema for first-time setup
middleware.ts         Auth gate + env-check redirect

Contributing

Contributions are welcome — especially from people using AI tools in real production workflows. See CONTRIBUTING.md for how, what's useful, and what isn't.

If something is broken, file an issue with reproduction steps. If you added a feature, explain what production problem it solves, not just what it does.

The bar isn't perfection. It's honesty and usefulness.

Disclaimer

SPITE is provided as-is, with no warranty of any kind (see LICENSE for the legal version — AGPL §15 and §16). You're responsible for:

  • Your fal.ai bill. The cost gates (per-button estimates, $25 confirm dialog, live balance badge, server-side per-hour ceiling, kill switch) are best-effort. A bug, a misconfiguration, or a bypass we haven't anticipated could still result in unexpected charges. The hourly ceiling defaults to $100 and can be tuned via SPEND_LIMIT_USD_PER_HOUR.
  • The content you generate. SPITE doesn't filter prompts or outputs. Whatever your chosen models do, you've made.
  • Your data. Your assets live in your R2 bucket; your projects and metadata live in your Neon database. Nobody else has access. If SPITE breaks, the worst case is you redeploy and possibly drop a couple of tables. There's no central service that can lose your work — it's already in your storage.

If you find a security issue, report it via GitHub Security Advisories, not a public issue. See CONTRIBUTING.md for the rest of the disclosure flow.

License

AGPL-3.0-only. If you fork SPITE and run it as a service, your modified source must be available to your users. Self-hosting for yourself or your team has no such obligation.

This license exists because the whole point of SPITE is that creative infrastructure shouldn't disappear behind closed doors. Forking SPITE and making it closed-source would defeat the project's reason for existing.


SPITE is not finished. That is the point. But it should always be getting more useful, not more complicated.

About

AI-powered pre-production canvas for filmmakers. Flagship models, infinite canvas, auto-export.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages