A minimal r/place-inspired pixel canvas with MCP tools, built on Next.js. Uses Upstash Redis for storage and event logging.
- Install deps
bun install- Set Upstash Redis env vars (create a
.env.local)
UPSTASH_REDIS_REST_URL=...
UPSTASH_REDIS_REST_TOKEN=...If using Vercel, add the Upstash Redis integration and vercel link + vercel env pull to populate these automatically.
- Start dev server
bun run devOpen http://localhost:3001 and paint.
- GET
/api/canvas→ returns full canvas state{ meta, pixelsBase64 }. - GET
/api/canvas/events?limit=100→ returns{ events: CanvasEvent[] }for replay/analytics.
Write operations happen exclusively through MCP tools (no POST writer route). On first access, the canvas is initialized automatically if no state exists.
The server exposes tools in app/mcp/route.ts:
get_canvas: returns the current state, optionally as an embedded UIset_pixel: set one pixel by coordinates using a color string (e.g.#ff0000)get_events: fetch recent event log entries
All MCP tool invocations are recorded in the event log for auditing/replay.
- Canvas state is stored as
{ meta, pixelsBase64 }in Redis atcanvas:v1. - Pixels are stored as base64-encoded
Uint8Arrayof palette indices for compactness. - Event log is an append-only Redis list at
canvas:events:v1with two event kinds:tool_used→{ type, toolName, argsJson, timestampMs }pixel_set→{ type, x, y, color, colorIndex, source, timestampMs }
- Default canvas is 64x64 with a small palette; adjust as needed.
Fetch latest 100 events:
curl "http://localhost:3001/api/canvas/events?limit=100"Set a pixel via MCP tool invocation (from an MCP client):
{"tool":"set_pixel","args":{"x":1,"y":2,"color":"#ff0000"}}