Skip to main content

Straight from the Chain

The site renders cats from on-chain data at request time. The browser never fetches a pre-baked CDN image for the core gallery or wallet views.

Render pipeline

  1. The app calls tokenURI(uint256 upegId, uint256 seed) on the RENDERER contract 0x2fE5bf2aB284bc71B261Ea6d32aaadfcA987Eeb8.
  2. The returned data:application/json;base64,... payload is decoded, then the embedded image field is decoded into raw SVG.
  3. Any embedded PNG fragments inside the SVG are upscaled with nearest-neighbor resampling so pixel edges stay crisp.
  4. The SVG is rasterized with @resvg/resvg-js.
  5. The PNG is resized with sharp using kernel: "nearest" for pixel-preserving output.

Cat render endpoint

GET /api/cat-render?id=<upegId>&seed=<seed>
GET /api/cat-render?id=<upegId>&seed=<seed>&thumb=1
Query paramRequiredMeaning
idYesUnsigned integer cat ID
seedYesUnsigned integer seed returned by OwnerUpegsPage
thumbNoSet to 1 for gallery thumbnails

Behavior:

  • Default output is a 456x336 PNG.
  • thumb=1 returns a 285x210 PNG.
  • Invalid id or seed returns 400.
  • The route is rate-limited to 60 requests per minute per IP.
  • Successful responses are cached as public, max-age=31536000, immutable.

Showcase data

GET /api/showcase-cats

This endpoint feeds the homepage "Straight from the Chain" section. It returns eight { id, seed } pairs.

Current behavior:

  • The route first tries OwnerUpegsPage against a known holder address.
  • If that live read fails or returns too few cats, it falls back to a hardcoded static pool.
  • Responses are cached with max-age=120 and stale-while-revalidate=600.

Why the seed matters

The app treats (id, seed) as the full render key. Given the same pair, the site will always resolve the same on-chain art output.