e11

Studio · Visual production for IG and LinkedIn

The visual sibling of your editorial pipeline.

Studio is what we built when we wanted the discipline of our text editorial stack — typed templates, signed publish, audited posts — for Instagram carousels, reels, and LinkedIn. Remotion-powered render workers, our own S3, our own Meta Business Portfolio. Direct Graph API publish to @eleven11.pro and @dhara.security is live.

Own render workers. Own asset CDN. Own brand tokens. The corpus, the renders, and the publish ledger stay on the box you administer.

Surface signal

Status

LIVE

Publish

Graph API

Workspace

studio.eleven11.pro

Why this exists

Visual content shouldn't be where the brand collapses.

Most teams ship clean editorial in their blog and a Canva pastiche on Instagram. The reason isn't taste — it's that the production path for image and video work runs through a different stack, a different vendor, and a different person each week. Studio is what we built when we wanted the same discipline our text editorial pipeline already had — typed templates, signed publish, audited posts — for the visual surfaces that carry most of the impressions.

Studio is to visual content what pr is to text editorial. Sibling pipeline. Same signed-publish, operator-managed substrate — different format. The brand tokens are the same tokens. The publish ledger is one query away from the editorial one.

Self-sustained by design

Owned, not rented.

Visual production is where most teams quietly hand a vendor the keys to their brand — the renderer, the CDN, the publish API, the tokens. Studio is built so each of those is yours, and so a Meta token rotation or a SaaS pricing change is a Tuesday, not a fire drill.

01

Own render workers.

studio-render is a BullMQ worker we run on our own Hetzner box, with our own ffmpeg and our own Remotion 4 — not a SaaS render farm metered per second. The slow path of a complex carousel is bounded by our hardware, not by a queue we don't control.

02

Own asset CDN.

Renders land in an S3 bucket on AWS us-east-1 we administer, with a public-read policy we audited and a regional URL form we picked deliberately — the global form is silently rejected by Meta's IG content fetcher with error_subcode 2207052. The bucket is ours, the policy is ours, the URL shape is the one Meta actually accepts.

03

Own Meta Business Portfolio.

Direct Graph API publish runs on AilyakEleven Experiences LLP's verified Business Portfolio — our App, our Pages, our IG handles. No third-party scheduler standing between an approved post and the IG endpoint. When Meta rotates a token or trips a quality flag, we see the 190 in our own logs.

04

Own brand tokens.

render/tokens.ts mirrors the Launch Design system — the same Geist + Geist Mono, ink-on-cream, moss + sage palette dhara reports and architect proposals carry. Every template draws from the same tokens, so there is no drift between the audit PDF, the blog hero, and the IG slide.

05

Manual export stays first-class.

Both publish paths are real. Per-handle publish_kind_preference flips between Graph API and a downloadable export bundle — the manual route never rots into a placeholder. When a Meta App Review pause hits or a token revokes mid-week, the team posts manually from the same draft, against the same template, with no rebuild.

The primitive

Three records you can name. Typed.

Studio is built on a small, opinionated trio — a draft to compose, a template to render through, and a post to record what shipped. Adding a new surface is a new template row. Promotion between them is a server action, not a side effect.

S1 · Draft

Draft

drafts.*

A draft is a typed body_json + a chosen template + a target handle. Brain tab fills it from a paste-md or a steering hint; from-pr pulls a slot off an editorial run; the editor refines. Drafts never publish themselves — promotion to a render is a server action, not a side effect.

S2 · Template

Template

render/compositions/<slug>

A template is a Remotion composition + an editor.tsx + a row in the templates table — surface, aspect_w/h, output_format (jpeg/png/mp4/pdf), default slide count. Adding a new format is a registry entry, not a refactor of a central renderer.

S3 · Post

Post

publish_audit + posts.*

A post is the immutable record of a render that left the building. It carries the IG container ID, the Graph API response, and the publish_audit row. Drafts can be deleted; posts cannot — published artifacts are events, not content.

How it fits the fleet

Where the rest of the fleet becomes visible.

Studio is rarely the first tool a team meets — but it's the surface where the work the rest of the fleet does becomes a thing the world sees. A pr package becomes an IG carousel. A dhara finding becomes a finding-brief slide. An architect decision becomes a post.

pr

Studio's from-pr tab pulls a recent editorial run's social_slots array (≤280-char strings, hashtags inline) and binds slot[i] to a template+handle. Same Discover→Write→Curate output — one path goes to the blog, another to the IG carousel.

architect

POST /api/v1/drafts/from-architect (HMAC) lets an architect canvas tile turn a decision into a visual draft. The matter that recorded the decision is the matter that authored the post.

dhara

Dhara findings flow into the finding-brief template — headline, evidence, impact, CTA, severity badge — under the @dhara.security voice. The audit PDF and the IG slide cite the same finding, drawn from the same Launch Design palette.

ollama (dhara)

LLM-assist routes through https://dhara.eleven11.pro/ollama with gemma4:e2b by default, BYOK to anthropic / openai / google / openrouter when a workspace prefers. workspace_ai_settings beats env; env beats null; nothing silently defaults to Claude.

alerts

studio.* events publish into the alerts hub — render.failed, publish.succeeded, publish.token_revoked. The same operator console that watches dhara scans and pr packages watches the studio queue.

operator

Per-handle publish_kind_preference, workspace_ai_settings, S3 credentials, and at-rest keys are operator-managed. Studio reads the rows; nothing about the runtime configuration lives in source.

Surfaces & contracts

Six things you actually call.

Four routes a person opens; two contracts adjacent tools call. The smallest surface that produces a signed, audited, brand-conformant post.

/drafts

Drafts inbox

Every brief in flight — Brain, From-pr, From-architect — listed by template, handle, and last edit. Trash icon cascades renders, assets, exports, and audit rows; published posts hold a hard FK and refuse the delete.

/drafts/[id]

Editor

Per-template editor component + a Remotion Player wired to the registered Composition. Generate-brief, Pull-from-pr, render preview, export bundle, mark-published — the full lifecycle of a draft on one route.

/posts

Posts ledger

Immutable record of what shipped — IG container IDs, Graph API responses, the publish path that delivered each one. The audit trail the operator console reads from when a token revocation lands.

/settings/ai

Brain configuration

Five-provider BYOK select (anthropic / openai / google / ollama / openrouter), Test button with latency, Save that preserves the encrypted key blob when the field is blank. workspace_ai_settings is the source of truth; STUDIO_AT_REST_KEY is service-managed.

POST /api/v1/drafts/from-architect

Architect ingress (HMAC)

Signed contract for the canvas — an architect matter signs a draft payload and studio creates it under the same workspace. Same shape pr uses for its publish ingest; same discipline.

GET /api/v1/widgets/studio

Widget envelope

x-api-key-gated discovery + envelope, conformant to docs/WIDGET-CONTRACT.md. The architect canvas renders studio's recent posts and queue depth as a tile next to dhara findings and cal availability.

Senior engineering, visible

The proofs are in the substrate.

Five decisions visible in the Dockerfile, the migration journal, the publish helper, and the registry — not adjectives, design choices. Each one is a bug we've already paid for, written down so we don't pay for it again.

Two processes, one image.

studio-web (Next.js + Hono) and studio-render (BullMQ) ship from the same Dockerfile with different command:. MIGRATE_ON_START is true on web, false on the worker — web has run them. One image, two roles, no surprise drift between them.

Hand-authored idempotent migrations.

drizzle/ holds plain SQL with explicit IF NOT EXISTS guards; drizzle/meta/_journal.json is appended manually. No drizzle-kit generate. Same migration discipline as architect — every schema change is reviewable, replayable, and free of generator drift.

Container readiness, not just existence.

publishCarousel and publishReel poll the IG container's status_code until FINISHED before calling media_publish — otherwise Meta returns error_subcode 2207027 'Media is not ready.' Shared pollContainerUntilFinished() helper. The bug is documented because we hit it; the helper is shared because we won't hit it again.

Path-traversal closed at the registry.

lib/template-prompt-path.ts bounds template_slug to ^[a-z0-9-]+$ and asserts startsWith on the base directory. Closes a vector that existed in llm-assist from Plan-1 T17 — any session could have read arbitrary files via template_slug=../../etc/passwd.

Lazy db() and renderQueue().

Both are functions, not module-load-time consts. Avoids eager env access that crashed next build when STUDIO_REDIS_URL was unset at compile time. Every call site uses db().insert(...). Senior pattern, documented in the Plan-A deviations.

Who this is for

Teams whose surface area is the brand.

Studio earns its keep when the gap between your editorial taste and your visual output starts costing impressions, leads, or trust.

Founders publishing under their own face who are tired of their LinkedIn looking nothing like their blog.
Security and compliance teams whose findings deserve a publish path as auditable as the audit itself.
Operators running multiple brands on Meta who need real Business Portfolio sovereignty, not an aggregator's API key.
Editorial teams who already run pr and want the same Discover→Curate→Package muscle for their visual surfaces.
Agencies tired of explaining to a client why the Canva file drifted from the brand book — and the brand book drifted from the deck.

FAQ

Final friction, reduced.

Is this a Canva replacement?

It is not. Canva is a design canvas; studio is a render and publish pipeline. The output is what's signed, audited, and posted — not the editing surface. If your team enjoys Canva, keep Canva. If your team is tired of every IG slide drifting from the brand, studio is the substrate that stops it.

Direct Graph API or manual posting?

Both. Graph API is live for @eleven11.pro and @dhara.security since the S3 us-east-1 regional-URL unblock on 2026-04-28. Per-handle publish_kind_preference flips between them — and the manual export bundle path is always the fallback when a token rotates or a Meta App Review pause hits.

How many templates are live, and how do you add one?

14 templates across 7 surfaces — ig-carousel, ig-reel, ig-story, web-hero, email-banner, linkedin-single, linkedin-carousel — landed by Plan-1d on 2026-04-30. Adding one is a Remotion composition, an editor.tsx, a row in the templates table, and a registry entry. Not a refactor of a central renderer.

Do my drafts and brand tokens leave the box?

Drafts and assets live in your studio Postgres + your S3 bucket. The render workers run on hardware you administer. The Brain tab routes through your BYOK LLM — by default the Dhara Ollama endpoint with gemma4:e2b, never silently to Anthropic. The corpus, the renders, and the publish ledger stay yours.

Review Studio

The visual pipeline is live. Walk in.

Studio is partner-deployed today — bundled with the rest of the Eleven11 fleet or standalone. Talk to us about IG handles, Meta Business Portfolio onboarding, or how to plug it into an existing editorial workflow.

Direct line

Consultation requests stay owned. We reply from e11 after reviewing fit and timing.