🎭 Theater & Live Performance · set design

StageLedger · x402

A real-time coordination layer for stage craft where every design revision, lighting plot, and prop manifest is a metered unlock. Production crews pay 0.01 USDC to pull the latest 3D scene data or prop list, ensuring that every seat in the house—and Every hand on the crew—is working off the most valuable, paid-for version of the vision. No more outdated physical prints; just pay-per-pull precision.

Optimism + x402 paywall· x402 native
Section · Onchain

The primitive.

full primer →

The onchain primitive runs at the right moment in the flow and surfaces a clear, verifiable result that directors can act on without web3 jargon.

Why this primitiveBy shifting from a static storage model to a pay-per-access manifest, we turn technical documentation into a micro-revenue stream for set designers. It prevents 'leaked' designs and ensures production houses value every iteration of the creative process while automating royalty splits for design reuse.

Kernel
an x402 pay-per-use paywall on Optimism Sepolia — Privy embedded wallet signs EIP-3009 USDC authorizations, a same-origin proxy relays PAYMENT-SIGNATURE to a facilitator (self-hosted facilitator) that settles 0.01 USDC and returns an Optimism tx hash in PAYMENT-RESPONSE
Drives the UI as
a 4-step flow log (Challenge → Sign → Retry → Settle) that ends with a live Optimism Etherscan tx link proving the micropayment cleared
Appendix · Secrets

Required keys.

METAMASK_PRIVATE_KEY
Exported from MetaMask. Fund on Optimism Sepolia via the Optimism faucet.
open ↗
OPTIMISM_SEPOLIA_RPC_URL
Alchemy Optimism Sepolia HTTPS endpoint (or https://sepolia.optimism.io).
open ↗
ETHERSCAN_API_KEY
Single Etherscan v2 key — covers Optimism Etherscan (chainId 11155420) with no extra key.
open ↗
PRIVY_APP_ID
Enables Google sign-in and sponsored Optimism Sepolia transactions.
open ↗
PINATA_JWT
Pins images / JSON / manifests to IPFS.
open ↗

Add these in your Lovable project under Settings → Secrets before pasting the prompt below.

Appendix · Mega-prompt

The build prompt.

Paste into a fresh Lovable project. Make sure all five secrets above are set first. read the build strategy →

Build "StageLedger" in ONE Lovable message. Single-page x402-native paid app on Optimism Sepolia.

CONCEPT
A real-time coordination layer for stage craft where every design revision, lighting plot, and prop manifest is a metered unlock. Production crews pay 0.01 USDC to pull the latest 3D scene data or prop list, ensuring that every seat in the house—and Every hand on the crew—is working off the most valuable, paid-for version of the vision. No more outdated physical prints; just pay-per-pull precision.
Discipline: Theater & Live Performance (set design).
Onchain primitive: x402 micropayments on Optimism Sepolia (USDC via EIP-3009). Why: By shifting from a static storage model to a pay-per-access manifest, we turn technical documentation into a micro-revenue stream for set designers. It prevents 'leaked' designs and ensures production houses value every iteration of the creative process while automating royalty splits for design reuse.

5-CREDIT BUDGET (HARD LIMIT):
- ONE single-page app. No Lovable Cloud, no database, no auth flows beyond Privy drop-in.
- NO smart contract deploy. x402 settles USDC via EIP-3009 `transferWithAuthorization` — the USDC contract already exists at 0x5fd84259d66Cd46123540766Be93DFE6D43130D7 on Optimism Sepolia (chainId 11155420).
- Privy is the auth + signing layer (Google login + embedded wallet on Optimism Sepolia).
- At most ONE AI call per user action (Lovable AI Gateway with LOVABLE_API_KEY, only if AI is part of the idea).
- Skip tests, skip CI, skip docs. Ship the demo.

STACK
- React + Vite + TanStack Start (the template Lovable ships).
- Privy embedded wallet wraps <App /> in src/main.tsx:
    <PrivyProvider appId={import.meta.env.VITE_PRIVY_APP_ID}
      config={{ loginMethods:['google'], embeddedWallets:{createOnLogin:'users-without-wallets'},
                defaultChain:{ id: 11155420, name:'Optimism Sepolia' } }}>
- viem public client uses Alchemy Optimism Sepolia — put the URL in src/data/rpc.json as
  { "optimismSepolia": "https://opt-sepolia.g.alchemy.com/v2/<KEY>" } and use
  createPublicClient({ chain: optimismSepolia, transport: http(rpc.optimismSepolia) }).
  The default public RPC is rate-limited — Alchemy is required for USDC balanceOf.

TEN NON-OBVIOUS x402 RULES (get these wrong and it silently fails)
1. CORS: proxy the facilitator. Public x402 facilitators do NOT send
   Access-Control-Allow-Origin. A direct browser fetch throws "TypeError: Failed to fetch" BEFORE
   you see the 402. Wrap the upstream call in a same-origin TanStack server route at
   src/routes/api/public/x402-proxy.ts and forward PAYMENT-SIGNATURE (request) + PAYMENT-RESPONSE (response).
2. x402 v2 envelope shape. The base64-encoded PAYMENT-SIGNATURE payload is NOT
   { scheme, network, payload } at top level — that's v1 and the facilitator will reject it as invalid_payload.
   It MUST be:
     { "x402Version": 2,
       "accepted": { /* the full PaymentRequirement you picked, echoed back verbatim */ },
       "payload":  { "signature": "0x…",
                     "authorization": { from, to, value, validAfter, validBefore, nonce } } }
3. Network id is CAIP-2: "eip155:11155420" for Optimism Sepolia (NOT "optimism-sepolia"). Match on this
   when picking a requirement from accepts[].
4. Amount field renamed. v2 uses `amount` (atomic units, string), NOT v1's `maxAmountRequired`.
   USDC has 6 decimals — "10000" = 0.01 USDC.
5. Header names are literal-cased and non-standard: PAYMENT-SIGNATURE (request) and PAYMENT-RESPONSE (response).
6. EIP-3009 domain fields come from requirement.extra. Use extra.name ("USDC") and extra.version ("2")
   in the EIP-712 domain — NOT hardcoded. chainId is 11155420; verifyingContract is requirement.asset.
7. nonce is bytes32 random, generated client-side (crypto.getRandomValues(new Uint8Array(32)) → 0x-hex).
   Never reuse. validAfter = now-60s, validBefore = now + maxTimeoutSeconds (default 300).
8. Sign via Privy embedded wallet's provider, NOT React hooks: get the EIP-1193 provider
   (const provider = await embedded.getEthereumProvider()) and call
   provider.request({ method: "eth_signTypedData_v4", params: [address, JSON.stringify(typedData)] }).
9. Alchemy RPC in src/data/rpc.json (rule above). USDC balanceOf against the default public RPC will flake.
10. Fund flow uses Circle faucet (https://faucet.circle.com/, choose Optimism Sepolia). Show the user's
    Privy address prominently, link to the faucet, then a "Refresh balance" button. ~10s arrival.

FILE LAYOUT
  src/data/x402.json          { endpoint, proxy, usdcAddress: "0x5fd84259d66Cd46123540766Be93DFE6D43130D7",
                                chainId: 11155420, network: "eip155:11155420",
                                faucetUrl: "https://faucet.circle.com/",
                                explorer: "https://sepolia-optimism.etherscan.io" }
  src/data/rpc.json           { "optimismSepolia": "https://opt-sepolia.g.alchemy.com/v2/<KEY>" }
  src/lib/x402.ts             fetchChallenge / pickRequirement / signPayment / fetchPaid
  src/routes/api/public/x402-proxy.ts   same-origin GET proxy (below)
  src/routes/index.tsx        demo UI: sign-in → fund → 4-step flow log

PROXY ROUTE (drop-in — copy verbatim):
```ts
// src/routes/api/public/x402-proxy.ts
import { createFileRoute } from "@tanstack/react-router";
import x402Cfg from "@/data/x402.json";

export const Route = createFileRoute("/api/public/x402-proxy")({
  server: {
    handlers: {
      GET: async ({ request }) => {
        const sig = request.headers.get("PAYMENT-SIGNATURE");
        const upstream = await fetch(x402Cfg.endpoint, {
          method: "GET",
          headers: sig ? { "PAYMENT-SIGNATURE": sig } : {},
        });
        const body = await upstream.arrayBuffer();
        const out = new Headers();
        const ct = upstream.headers.get("content-type");
        if (ct) out.set("Content-Type", ct);
        const pr = upstream.headers.get("PAYMENT-RESPONSE");
        if (pr) out.set("PAYMENT-RESPONSE", pr);
        return new Response(body, { status: upstream.status, headers: out });
      },
    },
  },
});
```

The /api/public/* prefix bypasses Lovable's published-site auth — desired for a demo endpoint.

USER FLOW (log every step in the UI so the user sees what happened)
1. Land on page → "Sign in with Google" (Privy) → embedded wallet auto-provisioned on Optimism Sepolia.
2. Fund: show wallet address + "Get 0.01 USDC on Optimism Sepolia" → link to https://faucet.circle.com/
   → "Refresh balance" button reads USDC balanceOf via viem + Alchemy RPC.
3. Click the primary action button for this idea (set design). App runs:
   (a) Challenge — GET /api/public/x402-proxy → expect 402 → parse { x402Version:2, accepts:[…], error }.
       Pick accepts[] where network === "eip155:11155420" && scheme === "exact".
   (b) Sign — Build EIP-3009 typed data (see rules 6–8), call Privy signTypedData,
       wrap into the v2 envelope (rule 2), base64.
   (c) Retry — GET /api/public/x402-proxy with header PAYMENT-SIGNATURE: <base64>.
   (d) Settle — On 200, read PAYMENT-RESPONSE header, base64-decode →
       { success, transaction, network, payer }. Link tx to `${explorer}/tx/${transaction}`.
4. Footer renders: "Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14"

FACILITATOR
Default endpoint: /api/public/x402-endpoint (self-hosted, same-origin — code below) (returns 402 with an
accepts[] challenge, settles 0.01 USDC per successful call, returns the protected payload).

REQUIRED SECRETS (Lovable → Project Settings → Secrets):
- PRIVY_APP_ID                  Google sign-in + embedded wallet. Docs: https://docs.privy.io/llms-full.txt
- ALCHEMY_OPTIMISM_SEPOLIA_RPC_URL  Free at https://dashboard.alchemy.com/ (create app, Optimism Sepolia,
                                copy HTTPS URL). Also expose as VITE_ALCHEMY_OPTIMISM_SEPOLIA_RPC_URL
                                so the frontend viem client can read balances.

COMMON FAILURE MODES (fix these before shipping)
- "TypeError: Failed to fetch" at step (a): called the facilitator directly from the browser. Use the proxy.
- "invalid_payload" at step (c): sent v1 envelope. Wrap under `accepted` (rule 2).
- "invalid_signature": wrong domain — chainId mismatch, or extra.version hardcoded to "1".
  Use chainId 11155420 and extra.version from the requirement.
- "insufficient_funds": wallet has ETH but no USDC. Fund via Circle faucet, then Refresh balance.
- Balance stays at 0 after faucet: reading against default public RPC. Wire Alchemy via rpc.json.
- expires_at errors on retry: clock skew or reused nonce. Generate fresh nonce + timestamps per attempt.

CREDIT (must appear in UI footer):
Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
Appendix · Market

Market sizing.

TAM
$2.8B
Global live event production and theatre technology market seeking immutable, metered technical data standards.
SAM
$450M
Touring Broadway and West End technical production budgets, including high-frequency equipment manifest updates.
SOM
$12M
Specialized 3D set design firms and independent technical directors on Base seeking 'source of truth' synchronization.

Indicative figures for hackathon pitches — refine with your own research before raising.

See also

Adjacent entries.

set design
SetDesign Manifest
Store and share complex 3D set designs and manifests immutably on IPFS for production coordination.
playwright collaboration
DraftFlow · x402
Pay-per-contribution script evolution. Every time a playwright pushes a new scene, dialogue tweak, or stage direction, the production pays a $0.01 micro-royalty. This turns the script into a living, metered asset where writers are paid for the act of creation in real-time. Producers unlock specific drafts or 'forks' of a play for rehearsal by paying a settled $0.01 fee per actor access, ensuring the creative sweat equity is instantly monetized and timestamped on-chain.
casting marketplace
StageRead · x402
A high-frequency talent scout protocol where every audition tape submission and casting call 'side' download is a micro-settlement. Directors pay $0.01 to unlock a performer's reel, and actors pay $0.01 to commit their encrypted audition data to the chain. This replaces monthly subscription models with a 'pay-per-opportunity' architecture, preventing platform bloat and ensuring only high-intent interactions between talent and production.
lighting rights management
LumenSync · x402
A protocol for lighting designers to meter the 'burn' of their intellectual property. Lighting consoles ping the x402 endpoint to unlock specific DMX map frames or complex Chamsys/MA3 sequence macros. Venues pay 0.01 USDC per cue-trigger or per-minute of 'look' duration, ensuring designers are compensated for every performance without complex manual auditing.