Ever made a trade and wondered if it was actually smart or just lucky? I built The Market Witness, a pixel-art courtroom where your real trades get judged. A shark prosecutor, a defense attorney, and a judge argue over your trade using live blockchain oracle data as evidence. Think Ace Attorney, but for your portfolio.
Live demo: market-witness.vercel.app
Source code: GitHub
Here's what it looks like
Wait, What's Oracle Data?
If you're not into crypto, no worries. Quick version.
Blockchains can't check the price of Bitcoin, gold, or Tesla stock on their own. They're isolated. Oracles are services that feed real-world data into blockchains: prices, timestamps, confidence levels.
Pyth Network is one of the biggest oracle networks out there. It covers 500+ assets (crypto, forex, equities, commodities) with sub-second updates. But here's what makes it interesting for devs: Pyth doesn't just give you a price number. Each update includes:
- Price - the actual asset price
- Confidence interval - how certain the market is (tight = stable, wide = volatile)
- EMA price - exponential moving average, showing the trend
- EMA confidence - trend stability over time
On top of that, Pyth Benchmarks gives you historical OHLC (open-high-low-close) candle data.
Most projects just slap these numbers into a dashboard. I wanted to turn them into a game mechanic.
The Concept: Your Trade Goes to Court
You enter a real trade. Pick any asset from 500+ Pyth feeds, choose BUY or SELL, set the dates. Then the trial begins.
Three original pixel-art characters run the courtroom:
- Chop the Shark (Prosecutor) - a ruthless red shark out to prove your trade was reckless
- Planck (Defense Attorney) - calm green guy who argues your trade was well-reasoned
- Judge PIRB - the purple judge who delivers the final verdict
Each round of the trial is tied to a specific Pyth data point. The prosecution and defense don't throw generic insults. They argue with real numbers from your actual trade.
How Pyth Data Becomes Courtroom Evidence
This is the core of the project. Each Pyth data field maps to a distinct piece of evidence:
Round 1: Price & P&L
The most basic question: did you make money?
const pricePctChange = ((exitPrice - entryPrice) / entryPrice) * 100;
Prosecution uses a loss as proof of guilt. Defense argues a profit shows good judgment.
Round 2: Confidence Interval
This is where it gets fun. Pyth's conf field tells you how uncertain the market was when you entered.
const confPctOfPrice = (conf / price) * 100;
Wide confidence (say, >0.5% of price)? The prosecutor goes: "The market couldn't even agree on a price, and you still hit Buy?"
Tight confidence? Defense fires back: "Tight spread, clean entry. This trader knew what they were doing."
Round 3: EMA Divergence
Were you trading with or against the trend?
const emaDivergence = ((price - emaPrice) / emaPrice) * 100;
Positive divergence on a BUY means price is above EMA, you bought into momentum. Negative means you went against the trend. The prosecution loves counter-trend entries.
Round 4: EMA Confidence Ratio
The sneakiest metric. Comparing EMA confidence to spot confidence shows if market stability is getting better or worse.
const emaConfRatio = emaConf / conf;
Ratio > 1 means the EMA is less certain than spot. Conditions are deteriorating. The prosecution uses this to argue you ignored warning signs.
Round 5: Benchmarks Volatility
Using Pyth Benchmarks API, I fetch 5-minute OHLC candles in a 2-hour window around the trade:
const volatilityPct = ((periodHigh - periodLow) / periodOpen) * 100;
High volatility + counter-trend entry = the prosecutor's dream argument.
The Tech Stack
- Next.js 14 (App Router, TypeScript)
- Tailwind CSS v4 with Pyth brand colors
- Framer Motion for character animations, verdict stamps, slide-ins
- Web Audio API for all sound effects (synthesized in code, zero audio files)
- OpenRouter API for server-side AI dialogue generation
- Pyth Hermes API for real-time and historical price feeds
- Pyth Pro Benchmarks for historical OHLC data
- Vercel for deployment
Sound Design Without Audio Files
Every sound in the game is generated with the Web Audio API. No MP3s, no WAVs, nothing imported.
The gavel hit is a 150Hz square wave mixed with a noise burst. The "OBJECTION!" sting is a 600Hz sawtooth layered with an 800Hz square wave and 100Hz bass. The victory fanfare is a C-E-G-C arpeggio on triangle oscillators.
// Gavel sound: square wave + noise burst
const osc = ctx.createOscillator();
osc.type = 'square';
osc.frequency.value = 150;
// mixed with white noise for the "crack"
Tiny bundle, full control over timing.
AI Dialogue With Real Data
Each trial is unique. AI generates dialogue based on actual evidence. The prompt includes all Pyth metrics, and the AI returns structured JSON:
{
rounds: [{
type: "prosecution",
text: "The confidence interval was 0.8% of price. The market was screaming uncertainty and you still pulled the trigger!",
evidence: {
source: "Pyth Price Feeds",
value: "+-0.8%",
label: "Confidence Interval"
}
}, ...],
verdict: "GUILTY",
score: 72
}
If AI is unavailable, a deterministic mock trial kicks in. Same UI, same evidence cards, just calculated from heuristics instead. The app always works.
Server-Side API Protection
All API keys live behind Next.js API routes. The frontend never touches them:
/api/trial -> proxies to OpenRouter (AI generation)
/api/benchmark -> proxies to Pyth Pro Benchmarks (OHLC data)
Data Flow
User enters trade (asset, BUY/SELL, dates)
|
Fetch Pyth data in parallel:
|-- Hermes API -> historical prices at open/close
|-- Hermes API -> current price
|-- /api/benchmark -> Pyth Pro OHLC candles
|
Calculate 6 evidence metrics
|
Generate trial (AI or mock fallback)
|
Interactive courtroom with character animations
|
Verdict + guilt score (0-100)
What I Learned
Oracle data is way richer than most people think. Before this project, I assumed price feeds were just... prices. The confidence interval and EMA fields turned out to be the most interesting parts. They tell a story about market conditions that raw price alone can't.
Gamification makes data click. Nobody wants to stare at a table of oracle metrics. But when a pixel-art shark screams "OBJECTION!" and waves your confidence interval in your face, suddenly everyone gets what it means.
Build the fallback first. The mock trial system gave me a working demo from day one, even while I was still iterating on AI prompts. Both paths share the same TypeScript interface, so the UI doesn't know or care which one generated the trial.
Try It
Pick any trade you've made (or make one up) and see if the courtroom finds you guilty:
Also posted about this on X/Twitter
Built for the Pyth Playground Community Hackathon. Source code on GitHub under Apache 2.0.
Pro tip: try a meme coin trade during a crash. Chop the Shark will have a field day.



Top comments (0)