ChartGuessr

GeoGuessr for charts. Draw the next 60s of BTC price, closest sketch wins USDC.

ChartGuessr

Created At

ETHGlobal Cannes 2026

Project Description

ChartGuess is a real-time prediction game where two players compete to sketch the future price movement of Bitcoin. Think of it as GeoGuessr, but for financial charts.

Two players get matched together and watch a live Bitcoin price chart build itself on screen for 45 seconds. They study the rhythm, the momentum, the patterns. Then the chart freezes, and both players have exactly 15 seconds to draw, with their finger or mouse, the line they think the price will follow next. No buttons, no "up or down" choices. You literally sketch the shape of the future.

Once time runs out, both drawings lock in and the real price starts revealing itself right next to the players' sketches. The system mathematically measures how close each drawing was to reality, and the player whose line most closely matches the actual price movement wins.

The twist that makes it more than just a fun game: there's real money on the line. Each player puts in 1 USDC (a digital dollar) to enter a match. The funds are held in a smart contract, essentially a digital lockbox that neither player nor the platform can touch. The moment the winner is determined, the contract automatically pays out 1.90 USDC to the winner. No middleman, no delays, no "request withdrawal" buttons. The math decides, the code pays. That's it.

Why does this matter? Traditional prediction markets force you into boring yes-or-no bets. "Will Bitcoin go up?" That's a coin flip with extra steps. But real markets don't move in straight lines. They spike, dip, consolidate, and break out. If you genuinely have a feel for price action, a simple "up or down" button can't capture that. ChartGuess lets you express your full market intuition as a drawing, and then proves whether you were right or not.

It's part game, part skill test, part prediction market, built for anyone who's ever looked at a chart and thought, "I know exactly what's about to happen next."

How it's Made

The frontend is built with React 19 and Vite. The landing page uses Three.js for a 3D rotating Bitcoin model and GSAP for smooth state transitions and animations. For the core gameplay, we integrated TradingView's lightweight-charts library to render the live BTC price feed, then layered a raw HTML5 canvas directly on top of it. This canvas is where players draw their predictions. We captured every mouse or touch movement as an array of x/y coordinates with timestamps, so each sketch becomes a precise data structure we can compare against real price data.

For authentication and wallet connection, we used Dynamic Labs with Sign-In With Ethereum (SIWE). Dynamic handles the entire wallet flow, session management, and embedded wallet creation so players don't need to have a crypto wallet beforehand. This was critical for making the onboarding frictionless. A player can sign in, get a wallet, and enter a match in seconds.

The backend runs on Node.js with Express. Matchmaking works through Redis sorted sets. When a player clicks "Find Match," they get added to a Redis sorted set with their timestamp as the score. A background worker continuously runs ZPOPMIN to atomically pop two players at once, guaranteeing no race conditions or double-matching. Once a pair is formed, the entire game state, timers, and phase transitions are pushed to both clients via Server-Sent Events (SSE). We chose SSE over WebSockets intentionally because the data flow is strictly one-directional from server to client, SSE handles reconnects natively, and the payload stays lightweight.

For live price data, we integrated Chainlink Data Streams to get high-frequency, low-latency BTC/USD price feeds. Data Streams gives us access to institutional-grade pricing data that updates sub-second, which is exactly what we need for a game where the scoring happens on 1-second tick granularity. On top of that, we use Chainlink CRE (Compute Runtime Environment) to handle the off-chain computation logic. The RMSE scoring calculation, normalizing player drawings against real price curves, resampling both to equal data points, and running the deviation math, all of this gets processed through CRE. This keeps the scoring deterministic and verifiable without bloating on-chain gas costs. Chainlink CRE essentially acts as our trustless computation layer: it takes the raw input from both players and the real price buffer, runs the math off-chain, and delivers a verified result that triggers the on-chain settlement. This way, players don't have to trust our backend to be honest about who won. The math is reproducible and verifiable through Chainlink's infrastructure.

Settlement happens entirely on-chain through a Solidity escrow contract deployed on Circle's Arc Testnet. We chose Arc specifically because it supports Circle's Unified USDC Balance, meaning USDC moves natively across the network without bridging complexity. When a player enters a match, they sign an enterMatch transaction that locks 1 USDC into the contract. Both players' funds sit in escrow, untouchable by anyone, until the match resolves. Once Chainlink CRE delivers the scoring result, the backend calls settleMatch through Viem, and the smart contract automatically routes 1.90 USDC to the winner's wallet. No manual withdrawals, no custodial holding, no admin keys. The contract logic is simple: lock, compare, pay. Circle's Unified USDC Balance on Arc made this seamless because we didn't have to deal with wrapped tokens or cross-chain bridging. USDC is just USDC, native and instant.

One notably hacky thing: syncing the HTML5 canvas drawing layer pixel-perfectly with the TradingView chart underneath was a nightmare. The chart has its own coordinate system, scaling, and auto-adjusting price axis. We had to reverse-engineer the chart's internal price-to-pixel mapping so that when a player draws at a certain vertical position, we can accurately convert that back to an actual dollar value. Any misalignment and the entire RMSE scoring breaks. We ended up intercepting the chart's visible range on every render frame and dynamically recalculating the canvas coordinate transform to stay in sync.

background image mobile

Join the mailing list

Get the latest news and updates

ChartGuessr | ETHGlobal