A Next.js app that forges stylized 1024×1024 profile cards for avatars (X, Discord, etc.). The forge UI, ritual sequence, and canvas compositing run in the browser; portrait bytes are loaded from same-origin API routes (no third-party image API or remote model).
- Home — Landing with a single CTA into the forge.
- Forge (
/forge) — Two independent flows side by side:- Binding parameters — Pick archetype, element, intensity, mood, optional visual style, frame, and optional X handle. A deterministic seed maps your choices to one of 147 ritual portraits (metadata in
data/images.ts, files underprivate-assets/ritual/) and generates a ritual name + rarity. - Realm generator — Optional handle, pick one of eight worlds (ocean, volcanic, …). Each world reads
.pngor.webprasters fromprivate-assets/ritual/<world>/on the server (safe basenames, no public directory listing). A protected API returns one random file per forge; if a folder is empty, it falls back to the main portrait pool.
- Binding parameters — Pick archetype, element, intensity, mood, optional visual style, frame, and optional X handle. A deterministic seed maps your choices to one of 147 ritual portraits (metadata in
- Exports — Download raw portrait PNG, full card PNG, tweak glitch/contrast on the result, optional post to X.
- On-chain mint (Ritual) — Mint from the forge result screen as ERC-721 (
RitualPFP). To keep fees low, mint uses compact on-chain metadata (data URI) with a lightweight SVG + card fingerprint, and prefetches gas estimate before pressing Mint.
- Next.js 16 (App Router) · React 19 · TypeScript
- Tailwind CSS v4
- Canvas-based card renderer in
src/lib/ritual-canvas.ts
npm install
npm run devOpen http://localhost:3000. Production build:
npm run build
npm startSet these in .env.local:
NEXT_PUBLIC_RITUAL_PFP_ADDRESS=0x...
NEXT_PUBLIC_RITUAL_RPC_URL=https://rpc.ritualfoundation.org
NEXT_PUBLIC_RITUAL_EXPLORER_URL=https://explorer.ritualfoundation.org
PRIVATE_KEY=0x...
RITUAL_RPC_URL=https://rpc.ritualfoundation.orgNEXT_PUBLIC_RITUAL_PFP_ADDRESSis required to enable the mint panel.PRIVATE_KEY+RITUAL_RPC_URLare used by the Hardhat deploy script.- Never put
PRIVATE_KEYin Vercel env vars, and never commit real keys. - Keep
.env.localprivate (.gitignorealready excludes it).
npm run deploy:pfpCopy the deployed address into NEXT_PUBLIC_RITUAL_PFP_ADDRESS, then restart the app.
- Mint is free at contract level; users pay network gas in RITUAL.
- The gas number is from RPC simulation of the real
mint(tokenURI)call (not random). - Compact metadata mode is enabled by default to keep mint fees low.
- Wallet-confirmed final fee can differ slightly from the estimate.
private-assets/ritual/ is tracked in Git (WebP for shipped art). Clone + npm install + npm run build is enough; no separate asset sync.
- Main pool —
ritual-001…ritual-147as.webpor.png. Defaults assume.webp(data/images.tsviasrc/lib/ritual-main-ext.ts). For a PNG-only tree, setNEXT_PUBLIC_RITUAL_IMAGE_EXT=pngand rebuild. The image route accepts either extension and can fall back if only one exists on disk. - Realm folders —
private-assets/ritual/<world>/with safe*.pngor*.webpbasenames (src/lib/realm-raster-filename.ts). Worlds:ocean,volcanic,clockwork,glass,ancient,energy,mystical,cosmic.
npm run convert-webp -- --quality=92 --delete-pngSee private-assets/README.md. Other options: --lossless, --quality=N. oxipng helps if you stay on PNG only.
Ignore (already in .gitignore) |
Why |
|---|---|
node_modules/, .next/, out/ |
Generated |
.env* |
Secrets / local overrides |
.vercel |
Local link to Vercel |
Do not commit OS junk if it appears (.DS_Store is ignored). Optional: add *.psd, *.zip at repo root if you keep sources next to the app.
Tiny placeholder main pool only (not realm art):
node scripts/write-ritual-pngs.mjs| Route | Role |
|---|---|
GET /api/ritual-image/[filename] |
Serves ritual-NNN.png or .webp from private-assets/ritual/ |
GET /api/ritual-image/[filename]/[realmImage] |
Serves a realm raster; first segment is world slug |
POST /api/ritual-realm-pick |
Returns one chosen filename (never lists the folder) |
GET /api/ritual-cooldown |
Opaque blocked keys for global cooldown |
POST /api/ritual-assignment |
Registers a pick for cooldown (file, optional world for realm) |
There is no endpoint that enumerates all images.
- Push this repo to GitHub and import the project in Vercel.
- Framework preset: Next.js. Build:
npm run build, output: default. private-assets/ships with the repo — API routes read it from the deployment filesystem at runtime. Watch your plan’s total deployment / uncompressed size limits if the asset tree grows large again.- PNG-only deploy: set
NEXT_PUBLIC_RITUAL_IMAGE_EXT=pngin the Vercel environment and redeploy. - Cooldown store is in-memory per server instance (
src/lib/ritual-cooldown-server.ts). For many edge instances, replace with Redis / Upstash if you need a single global map.
Self-hosted (next start on a VPS) is also fine; same repo layout.
| Command | Description |
|---|---|
npm run dev |
Development server |
npm run build |
Production build |
npm run start |
Start production server |
npm run lint |
ESLint |
npm run deploy:pfp |
Deploy RitualPFP contract to Ritual network |
npm run convert-webp |
PNG → WebP under private-assets/ritual/ (see script header for flags) |
Private / all rights reserved unless you add a LICENSE file.