Roulette band for Claude Code: a number per prompt, the wheel spins while Claude works, hit or miss when it lands.

Turn every Claude Code prompt into a spin of the wheel. 🎡
You get a number. Claude gets to work. The wheel spins above your prompt the whole time, and when Claude is done the ball drops. Did it land on your number? 🍀
🎰 [ 23 ] · your number 17 · 0J 3C 5M ← Claude is working, wheel spinning
🎰 landed 8 black · COLOR HIT · your number 27 · 0J 4C 5M
| Result | Meaning | Odds |
|---|---|---|
| 💎 JACKPOT | The ball landed on your number | 1 in 37 |
| 🔴⚫ COLOR HIT | Same color as your number | about 1 in 2 |
| 💸 MISS | The house wins again | the rest |
Zero is green 🟢, as on a real European wheel. Your score (J/C/M) is remembered between sessions, so the losing streak follows you around. 🃏
⚠️ Disclaimer: this is a toy. No money, no stakes, no real wagering. I do not support or encourage gambling, and neither should you. Gambling causes real harm; if it is affecting you or someone you know, please seek help, for example from your local gambling-support helpline. ❤️
git clone https://github.com/NedimKaravdic/claude-casino
claude --plugin-dir ./claude-casino
Or add the folder to CLAUDE_CODE_PLUGIN_DIRS. Requires Claude Code 2.1.287 or newer (function hooks, early access). 🚀
claude plugin validate . # 🔍 what the engine would refuse
claude plugin test . # 🧪 spins the wheel on terminal and desktop
hooks/register.tsx is the whole casino 🏛️:
turn.start deals your number and starts a 90 ms tickerui.render on AbovePrompt draws the spinning bandturn.complete stops the ticker, drops the ball and scoresUnlike a real casino, this one costs nothing and pays nothing. The only thing you can lose here is your focus. 🎩
GPL-3.0. Fork it, change it, share it, but keep it open. © 2026 Nedim Karavdic
hooks/register.tsx 76 lines1import { atom, read, update } from 'claude-code'
2import type { Register, Timer } from 'claude-code'
3
4import type { Game, Outcome } from '../types'
5
6const game = atom({ plugin: 'roulette', key: 'game' } as const, null)
7
8const RED = new Set([1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36])
9const spin = () => Math.floor(Math.random() * 37)
10const colorOf = (n: number) => (n === 0 ? 'green' : RED.has(n) ? 'red' : 'black')
11const judge = (bet: number, landed: number): Outcome =>
12 bet === landed ? 'jackpot' : colorOf(bet) === colorOf(landed) ? 'color' : 'miss'
13
14export const register: Register = on => {
15 let ticker: Timer | null = null
16
17 on('session.start', async ($, e, next) => {
18 const score = ((await $.store.get('score')) as Game['score'] | undefined) ?? { jackpot: 0, color: 0, miss: 0 }
19 await update($, game, () => ({ bet: spin(), wheel: 0, phase: 'idle', outcome: null, score }))
20 return next(e)
21 })
22
23 on('turn.start', async ($, e, next) => {
24 ticker?.cancel()
25 await update($, game, g => g && { ...g, phase: 'spinning', outcome: null })
26 ticker = $.clock.every(90, () => update($, game, g => g && { ...g, wheel: spin() }))
27 return next(e)
28 })
29
30 on('turn.complete', async ($, e, next) => {
31 ticker?.cancel()
32 ticker = null
33 const landed = spin()
34 const g = await read($, game)
35 if (g) {
36 const outcome = judge(g.bet, landed)
37 const score = { ...g.score, [outcome]: g.score[outcome] + 1 }
38 await update($, game, () => ({ bet: spin(), wheel: landed, phase: 'landed', outcome, score }))
39 await $.store.set('score', score)
40 $.ui.toast(
41 outcome === 'jackpot' ? `🎰 JACKPOT! ${landed} hit your number`
42 : outcome === 'color' ? `🎲 ${colorOf(landed)} hit, number missed`
43 : `💸 ${landed} ${colorOf(landed)}, miss`,
44 )
45 }
46 return next(e)
47 })
48
49 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
50 const g = await read($, game)
51 if (!g || e.props.hasSurvey) return next(e)
52
53 const { Box, Text } = $.ui.resolve(e)
54 const tint = (n: number) => (colorOf(n) === 'red' ? 'red' : colorOf(n) === 'green' ? 'green' : 'white')
55 const label: Record<Outcome, string> = { jackpot: 'JACKPOT', color: 'COLOR HIT', miss: 'MISS' }
56
57 return (
58 <Box>
59 <Text>🎰 </Text>
60 {g.phase === 'spinning' ? (
61 <Text color={tint(g.wheel)} bold>[ {String(g.wheel).padStart(2, ' ')} ]</Text>
62 ) : g.phase === 'landed' && g.outcome ? (
63 <Text color={g.outcome === 'miss' ? 'red' : 'green'} bold>
64 landed {g.wheel} {colorOf(g.wheel)} · {label[g.outcome]}
65 </Text>
66 ) : (
67 <Text dimColor>place your prompt</Text>
68 )}
69 <Text dimColor> · your number </Text>
70 <Text color={tint(g.bet)} bold>{g.bet}</Text>
71 <Text dimColor> · {g.score.jackpot}J {g.score.color}C {g.score.miss}M</Text>
72 </Box>
73 )
74 })
75}
76types/index.d.ts 15 lines1export type Outcome = 'jackpot' | 'color' | 'miss'
2export type Game = {
3 bet: number
4 wheel: number
5 phase: 'idle' | 'spinning' | 'landed'
6 outcome: Outcome | null
7 score: Record<Outcome, number>
8}
9
10declare module 'claude-code' {
11 interface PluginState {
12 'roulette': { game: Game | null }
13 }
14}
15