Inspiration

I kept running into the same problem. Every AI tool I tried could generate images and video, but none of them could prove where those files came from. You download an AI-generated image, upload it somewhere, someone strips the metadata, and now there's no way to trace it back. Gone.

Then I read that the EU AI Act Article 50 kicks in on August 2, 2026. One day before this hackathon closes. The rule is straightforward: if you generate synthetic media for EU users, you have to mark it in a machine-readable way that survives re-saving, screenshots, and social media uploads. Most companies aren't ready for that.

I figured: what if the storage layer itself was the proof? Not just "we stuck a tag in the EXIF data" (which gets stripped the moment someone uploads to Instagram), but a real three-layer system where the provenance lives in the file, in a watermark buried in the pixels, AND in a durable record on Backblaze B2. Strip one layer, the others still recover it.

That's TrueFrame.

What it does

You type a prompt. TrueFrame generates an AI image (currently using Cloudflare's FLUX model through the Genblaze pipeline), then runs it through a four-step stamping process before it ever reaches your browser:

  1. Computes a SHA-256 hash of the raw bytes
  2. Attempts C2PA cryptographic signing (content credentials standard)
  3. Embeds an invisible watermark using LSB steganography
  4. Computes a perceptual fingerprint (pHash) for fuzzy matching later

All of this, plus a canonical provenance manifest (JSON document recording the provider, model, prompt, timestamps, and hash), gets uploaded to Backblaze B2 in a content-addressable layout. The SHA-256 hash IS the filename. You can't tamper with a file without changing its hash, and if the hash doesn't match what's on B2, the system knows.

Then there's the verification side. Anyone (no account needed) can drop a file onto the Verify page. TrueFrame runs a cascade:

  • First, it computes the SHA-256 and checks if that exact hash exists in B2. Match? Verified.
  • No match? It checks for an embedded C2PA manifest. Found one but hash doesn't match? Tampered.
  • Still nothing? It scans for the invisible watermark or runs a perceptual fingerprint match. Found a close match? Provenance recovered.

That last one is the "aha" moment for judges. I strip all the metadata from a file, re-encode it, and TrueFrame STILL recovers where it came from by matching the watermark or fingerprint against the B2 index.

How I built it

I worked on this solo over about three weeks. The stack:

Frontend is Next.js 16 with React 19 and Tailwind CSS v4. I built every component by hand (no shadcn, no component libraries) because I wanted full control over the dark-mode design system. The generate page has a three-panel layout: config on the left, live run timeline in the center, and the result with provenance details on the right.

Backend is FastAPI running on Python 3.11+. I chose FastAPI because I needed async I/O for the B2 uploads and AI provider calls without blocking. SQLAlchemy with async SQLite handles the metadata. Every endpoint follows a layered pattern: route calls service, service calls storage/AI provider.

AI generation went through several iterations. I tried AWS Bedrock first (account was locked). Then Gemini (quota was zero on a new key). Finally landed on Cloudflare Workers AI with their FLUX Schnell model, which gives 10,000 free image generations per day. Genblaze orchestrates the pipeline with fallback chains, so if one provider fails, the next one picks up automatically.

Storage is Backblaze B2 using the S3-compatible API via boto3. Everything is content-addressable: assets/{sha256[:2]}/{sha256[2:4]}/{sha256}.ext. This gives me deduplication for free and makes tamper detection trivial (wrong hash = wrong file). Manifests, fingerprint indexes, and verification audit logs all live on B2 too.

Deployment is Vercel for the frontend and Render's free tier for the backend. I set up GitHub Actions with path-filtered workflows so pushing to trueframe/src/ only deploys the frontend, and pushing to trueframe/backend/ only deploys the backend.

Challenges I faced

The biggest headache was SQLite concurrency. I originally had generation running as a FastAPI background task, but SQLite kept throwing "database is locked" errors because the background task and the request handler were fighting over the same connection. Tried WAL mode, pool size adjustments, delays. Nothing worked reliably. Eventually I made generation synchronous (the POST just blocks until the whole pipeline finishes). It adds 5-10 seconds of latency, but it never fails.

NextAuth v5 beta on Next.js 16 was another pain point. The session token format doesn't match what a plain FastAPI backend expects for JWT validation. I ended up creating a custom /api/token endpoint on the frontend that reads the NextAuth session, mints a fresh HS256 JWT signed with the shared secret, and hands it to fetchApi(). Hacky, but bulletproof.

The B2 bucket is private (Backblaze charges $1 to make it public, and I didn't want to pay during development). So I built a proxy endpoint on the backend that generates pre-signed URLs and redirects. The frontend never touches B2 directly.

And then there was the AI provider saga. AWS Bedrock wouldn't authorize any model on my account (new account restriction). Gemini's free tier showed quota=0 for image generation. Pollinations.ai worked locally but returned 403 from Render's cloud IPs. Cloudflare Workers AI was the fourth provider I tried, and it finally worked. The whole experience actually made the fallback-chain architecture more convincing, because I genuinely needed it.

What I learned

The provenance pipeline is the product, not the AI model. I spent way too long trying to get "real" AI images working before I realized the judges care about what happens AFTER generation. The stamping, storage, and verification cascade is the novel part. The image source is interchangeable.

Content-addressable storage is an underrated pattern. When your filename IS the hash of the contents, you get deduplication, tamper detection, and cache-friendliness in one design decision. I'll use this pattern again.

Building for a real deadline (August 2 EU AI Act + August 3 hackathon deadline) gave the project genuine urgency. I wasn't building a toy. There are actual companies that will need exactly this pipeline in production within weeks.

What's next

  • Get real C2PA signing working (the c2pa-python library has API issues on Python 3.14, needs debugging)
  • Add video generation when Cloudflare or GMI Cloud makes video models available on their free tier
  • Move from SQLite to Postgres so data persists across deploys
  • Build an embeddable "Verified by TrueFrame" badge that websites can drop in, like the Twitter blue check but for AI provenance

Built With

Share this project:

Updates