A live brush, not a prompt queue
potocolom turns an image model into a drawing partner. You sketch on a canvas and a diffusion model re-renders your strokes as a finished image while you draw, several times per second - not once, after a button press. The prompt sets the scene; your strokes decide the composition.
Around that loop sits a full studio: classic prompt-to-image generation with per-model controls, one-click upscaling, a history of everything you make, and a gallery to pin the keepers. This page explains the machinery underneath, in the order a stroke meets it.
The anatomy of the platform
Three moving parts. The studio runs in your browser. The platform API is a stateless relay and scheduler: it owns no GPU; it routes realtime frames, dispatches work and keeps the authoritative record of every job and asset in PostgreSQL. GPU workers hold the models and do the actual rendering.
Workers always dial out to the platform over one persistent WebSocket. Because the connection starts on the worker's side, a GPU machine needs no inbound ports, no public address and no firewall exceptions - any machine that can open a connection can serve, from a data-center card to the desktop under your desk.
On connect, a worker announces its models in a manifest: capabilities, parameter schema, VRAM needs. The platform validates every request against that schema, picks a worker with the model warm, and streams progress back live. Finished images never pass through the API: workers upload them straight to storage with signed URLs, and your browser loads them the same way. If the platform restarts, it rebuilds its queue from the database and carries on.
The realtime loop
While you draw, the canvas is snapshotted and sent as a compact binary frame - a small header plus WebP pixels - on the same WebSocket that brings results back. A distilled diffusion model re-renders it in a handful of denoising steps at 512 px, and generated frames stream back at 2 to 4 per second.
The loop never queues stale input: if a new stroke arrives while the GPU is busy, it replaces the pending frame rather than lining up behind it. Latest input wins; superseded frames are simply dropped. You always see the newest state of your drawing, never a replay of where it was.
Sessions are admitted against fixed per-worker slots and never oversubscribed. Go idle for about a minute and your slot is released - the canvas stays in the browser, and the next stroke reacquires one, usually instantly. If the machine under your session vanishes, the platform reassigns you, the canvas is re-sent, and drawing continues.
GPU scheduling
GPU seconds are the scarce resource, so scheduling is specified rather than improvised. Realtime sessions come first and are never oversubscribed. Queued generations fill whatever capacity is idle, and are preempted between denoising steps when a drawing session needs the slot; nothing ever preempts an active session.
How many sessions one GPU can hold is measured, not guessed: at warmup a worker benchmarks its models and advertises the concurrency it can sustain while keeping frame pacing above the bar.
Model placement follows demand. A hot set of fast models stays pinned in VRAM for instant sessions; everything else loads on demand, with load times measured and reported. When the pool is genuinely full, new sessions wait in an admission queue with a live position - and that queue is exactly the signal that brings more GPUs online.
Models as manifests
A model, to the platform, is a JSON manifest: what it can do, how much VRAM it needs, and a parameters block that is standard JSON Schema. That schema is the single source of truth - the studio renders its controls from it and the platform validates every request against it - so adding a model to a fleet makes it usable everywhere, with the right knobs, without touching a line of frontend code.
Manifests also carry the recipe: distilled fast models (the Turbo, Lightning and LCM class) for the drawing loop, heavier samplers for quality renders, optional scheduler overrides and fused acceleration LoRAs. On a single consumer 16 GB card, once warm, the fast class renders a 512 px image in about a third of a second, the Lightning class takes a few seconds at 1024 px, and the quality class about twenty seconds. The numbers are not marketing: they come from a benchmark harness anyone can run, and the results are published on the live benchmark page.
Models ship only after their licenses are vetted. Usage terms, attribution requirements and commercial limits are recorded in the manifest itself, and required attributions are honored in the product.
Images, privacy and safety
Transport and storage have different jobs, so they use different formats: canvas and generated frames travel as WebP, chosen for quality per byte at interactive speeds, while the stored master of every generation is lossless PNG - the archival copy of your work, with WebP thumbnails for fast browsing. Every generation stores its parameters and seed next to the image, so any result can be reproduced exactly, and provenance is recorded in the schema so an image can tell where it came from.
Assets are private by default and delivered through short-lived signed URLs; sharing is an explicit act. Signed-in state is an opaque server-side token in an HttpOnly cookie - invisible to page scripts, listable and instantly revocable. Nothing you create is used to train models.
The hosted service screens prompts through a layered pipeline - normalization, then rules, then a classifier - on every path a prompt can take, including live drawing. Enforcement works on strikes, without retaining prompt text.
The platform measures itself without watching you: no cookies, no trackers, not a line of client-side analytics. Usage statistics are rows the server already knows - which model ran, for how long, and a category label a CLIP pass assigns from the output image - never the prompt, the image, or your address. Self-hosted installs send one anonymous daily aggregate that can be previewed locally and disabled with a single switch.
Credits that cannot double-charge
The cloud meters usage in credits, and a credit corresponds to GPU time actually spent. Before any GPU second is spent, the platform reserves an estimate; when the work finishes, it commits the actual amount; failed work refunds automatically. Drawing sessions meter in small chunks only while active - an idle canvas costs nothing.
Every money path tolerates replay. Payment webhooks deduplicate on event ids, the credit ledger is append-only with unique source keys, and reservations are idempotent with a timeout that returns stranded credits on its own. Retries and redeliveries are no-ops by construction.
Payment surfaces are hosted by the payment provider, so card data never touches platform servers. If billing is ever unreachable, reserving fails closed - no GPU time is granted on credit - while finished work settles through a retry queue until it lands exactly once.
Built to fail safely
GPU machines vanish; the design treats that as normal. A worker dying mid-generation gets the job requeued exactly once before it fails visibly - an input that crashes workers cannot burn GPU time in a loop. A worker dying mid-session triggers a transparent resume: another machine takes over and your canvas is re-sent.
The platform restarting rebuilds its queue from the database. The database being down degrades the service instead of stopping it: live drawing keeps working while history waits. Failures refund, retries are bounded, and no failure mode produces a surprise bill.
Developed in the open
The product is AGPL 3.0 and complete on its own: the code that serves you - including this page - is the code in the repository, and you can run the entire platform on your own GPU.
The design is public too: the architecture documents, the wire protocol, the benchmark methodology, and a decision ledger that records not only every choice but the alternatives that were rejected and why.