Jack Claude Code into the Matrix: digital rain above the prompt, phosphor-green transcript, and messages from Zion.

A Claude Code mod: a live pane showing the session's token usage — totals, cache hit rate, cost, context window fill, rate limits, a per-request sparkline and a per-model breakdown.
Open it with /tokens.
The repository is private: you need access to it on GitHub, and GitHub set up on your computer.
/plugin install token-dashboard --marketplace mulbrix/claude-mods
Answer y to add the marketplace, then pick a scope.
hooks/register.tsx 278 lines1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4const isOn = atom({ plugin: 'matrix', key: 'isOn' } as const, true)
5
6const GREEN = '#00ff41'
7const DIM_GREEN = '#008f11'
8const BLACK = 0x000000
9const HEAD = 0xd8ffd8
10const DEFAULT = 0x01000000
11
12// Halfwidth katakana, digits and a few symbols: every one a single cell wide.
13const GLYPHS: number[] = []
14for (let c = 0xff66; c <= 0xff9d; c++) GLYPHS.push(c)
15for (const ch of '0123456789Z:."=*+-<>|') GLYPHS.push(ch.charCodeAt(0))
16
17const INTRO = [
18 'Wake up, Neo...',
19 'The Matrix has you...',
20 'Follow the white rabbit.',
21 'Knock, knock, Neo.',
22]
23
24const SPINNER_WORDS = [
25 'Following the white rabbit',
26 'Jacking in',
27 'Bending the spoon',
28 'Dodging bullets',
29 'Downloading kung fu',
30 'Decoding the Matrix',
31 'Tracing the call',
32 'Hacking the mainframe',
33 'Searching for the Oracle',
34 'Taking the red pill',
35 'Rewriting the code',
36 'Evading Agents',
37]
38
39const DONE_WORDS = [
40 'Jacked out after',
41 'Decoded in',
42 'Escaped the Agents in',
43 'Bent the spoon in',
44 'Rebooted reality in',
45 'Freed your mind in',
46]
47
48const pick = (list: string[], seed: string) => {
49 let hash = 0
50 for (let i = 0; i < seed.length; i++) hash = (hash * 31 + seed.charCodeAt(i)) | 0
51 return list[Math.abs(hash) % list.length]!
52}
53
54const randomGlyph = () => GLYPHS[Math.floor(Math.random() * GLYPHS.length)]!
55
56const B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
57const toBase64 = (bytes: Uint8Array) => {
58 let out = ''
59 for (let i = 0; i < bytes.length; i += 3) {
60 const n = (bytes[i]! << 16) | ((bytes[i + 1] ?? 0) << 8) | (bytes[i + 2] ?? 0)
61 out += B64[(n >> 18) & 63]! + B64[(n >> 12) & 63]!
62 out += i + 1 < bytes.length ? B64[(n >> 6) & 63]! : '='
63 out += i + 2 < bytes.length ? B64[n & 63]! : '='
64 }
65 return out
66}
67
68const fade = (t: number) => {
69 // t: 0 at the head, 1 at the tail's end.
70 const g = Math.round(255 - t * 210)
71 const r = Math.round(Math.max(0, 40 - t * 60))
72
73 return (r << 16) | (g << 8) | Math.round(Math.max(0, 65 - t * 80))
74}
75
76type Drop = { head: number; speed: number; length: number }
77
78/** The digital rain: a grid of glyphs and one falling drop per column. */
79class Rain {
80 columns = 0
81 rows = 0
82 glyphs = new Uint32Array(0)
83 drops: Drop[] = []
84 frame = 0
85
86 resize(columns: number, rows: number) {
87 if (columns === this.columns && rows === this.rows) return
88 this.columns = columns
89 this.rows = rows
90 this.glyphs = Uint32Array.from({ length: columns * rows }, randomGlyph)
91 this.drops = Array.from({ length: columns }, () => this.newDrop(true))
92 }
93
94 newDrop(anywhere: boolean): Drop {
95 const length = 3 + Math.floor(Math.random() * Math.max(4, this.rows * 1.5))
96
97 return {
98 head: anywhere ? Math.random() * (this.rows + length) : -Math.random() * this.rows * 2,
99 speed: 0.15 + Math.random() * 0.45,
100 length,
101 }
102 }
103
104 step() {
105 this.frame += 1
106 for (let c = 0; c < this.columns; c++) {
107 const drop = this.drops[c]!
108 drop.head += drop.speed
109 if (drop.head - drop.length > this.rows) this.drops[c] = this.newDrop(false)
110 }
111 for (let i = 0; i < this.glyphs.length; i++) {
112 if (Math.random() < 0.03) this.glyphs[i] = randomGlyph()
113 }
114 }
115
116 /** The current frame as Raster cells, with an optional line of text overlaid. */
117 cells(message?: string) {
118 const words = new Uint32Array(this.columns * this.rows * 3)
119 for (let r = 0; r < this.rows; r++) {
120 for (let c = 0; c < this.columns; c++) {
121 const i = r * this.columns + c
122 const drop = this.drops[c]!
123 const d = drop.head - r
124 let glyph = 0x20
125 let fg = DEFAULT
126 if (d >= 0 && d < 1) {
127 glyph = this.glyphs[i]!
128 fg = HEAD
129 } else if (d >= 1 && d < drop.length) {
130 glyph = this.glyphs[i]!
131 fg = fade(d / drop.length)
132 }
133 words[i * 3] = glyph
134 words[i * 3 + 1] = fg
135 words[i * 3 + 2] = BLACK
136 }
137 }
138 if (message) {
139 const row = Math.floor((this.rows - 1) / 2)
140 const start = Math.max(0, Math.floor((this.columns - message.length) / 2) - 1)
141 const padded = ` ${message} `.slice(0, this.columns)
142 for (let k = 0; k < padded.length; k++) {
143 const i = row * this.columns + start + k
144 words[i * 3] = padded.charCodeAt(k)
145 words[i * 3 + 1] = 0x00ff41
146 words[i * 3 + 2] = BLACK
147 }
148 }
149
150 return toBase64(new Uint8Array(words.buffer))
151 }
152}
153
154/** Light markdown flattening so prose can be drawn as one green Text. */
155const flatten = (text: string) =>
156 text
157 .replace(/^#{1,6}\s+/gm, '')
158 .replace(/\*\*(.+?)\*\*/g, '$1')
159 .replace(/__(.+?)__/g, '$1')
160 .replace(/`([^`]+)`/g, '$1')
161 .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1 <$2>')
162
163const isPlainProse = (text: string) => !/^\s*(```|~~~|\||>|\d+\.\s|[-*]\s\[)/m.test(text)
164
165export const register: Register = on => {
166 const rain = new Rain()
167 let bandId: string | null = null
168 let isEnabled = true
169 let introStartedAt = 0
170 let now = 0
171
172 const introText = () => {
173 const elapsed = now - introStartedAt
174 let at = 0
175 for (const line of INTRO) {
176 const typing = line.length * 90
177 const hold = 1400
178 if (elapsed < at + typing) return line.slice(0, Math.floor((elapsed - at) / 90) + 1) + '█'
179 if (elapsed < at + typing + hold) return line
180 at += typing + hold
181 }
182
183 return undefined
184 }
185
186 on('session.start', async ($, e, next) => {
187 await $.command.register({
188 name: 'matrix',
189 description: 'Toggle the Matrix look (digital rain, green transcript)',
190 })
191 isEnabled = await read($, isOn)
192 introStartedAt = now = await $.clock.now()
193 if (isEnabled) $.ui.status('◉ connected to the Matrix')
194
195 $.clock.every(70, () => {
196 now += 70
197 if (!isEnabled || bandId === null || rain.columns === 0) return
198 rain.step()
199 void $.ui.blit({ requestId: bandId, key: 'rain', cells: rain.cells(introText()) })
200 })
201
202 return next(e)
203 })
204
205 on('command.run', { command: 'matrix' }, async $ => {
206 const value = await update($, isOn, was => !was)
207 isEnabled = value
208 $.ui.status(value ? '◉ connected to the Matrix' : undefined)
209 if (value) introStartedAt = now
210
211 return { text: value ? 'Welcome back to the Matrix.' : 'You took the blue pill. The story ends.' }
212 })
213
214 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
215 if (e.props.hasSurvey || !(await read($, isOn)) || e.surface !== 'terminal') {
216 bandId = null
217 return next(e)
218 }
219 const { Raster } = $.ui.resolve(e)
220 const columns = Math.max(1, Math.min(512, e.props.bodyColumns))
221 const rows = Math.max(1, Math.min(e.props.maxRows - 1, e.props.isWorking ? 6 : 3))
222 rain.resize(columns, rows)
223 bandId = e.requestId
224
225 return <Raster key="rain" columns={columns} rows={rows} cells={rain.cells(introText())} />
226 })
227
228 on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
229 if (!(await read($, isOn)) || e.props.message !== null) return next(e)
230
231 return next({ ...e, props: { ...e.props, word: pick(SPINNER_WORDS, e.props.word) } })
232 })
233
234 on('ui.render', { component: 'TurnDuration' }, async ($, e, next) => {
235 if (!(await read($, isOn))) return next(e)
236 const { Text } = $.ui.resolve(e)
237 const seconds = Math.max(1, Math.round(e.props.durationMs / 1000))
238 const time = seconds >= 60 ? `${Math.floor(seconds / 60)}m ${seconds % 60}s` : `${seconds}s`
239
240 return (
241 <Text color={DIM_GREEN}>
242 ⌁ {pick(DONE_WORDS, e.props.word)} {time}
243 </Text>
244 )
245 })
246
247 on('ui.render', { component: 'UserMessage' }, async ($, e, next) => {
248 if (!(await read($, isOn)) || e.props.isExpanded || e.props.origin.kind !== 'composer') {
249 return next(e)
250 }
251 const { Text } = $.ui.resolve(e)
252
253 return (
254 <Text color={GREEN}>
255 <Text bold>neo@nebuchadnezzar</Text>
256 <Text color={DIM_GREEN}>:~$ </Text>
257 {e.props.text}
258 </Text>
259 )
260 })
261
262 on('ui.render', { component: 'AssistantMessage' }, async ($, e, next) => {
263 if (!(await read($, isOn)) || e.props.isSummary || !isPlainProse(e.props.text)) {
264 return next(e)
265 }
266 const { Box, Text } = $.ui.resolve(e)
267
268 return (
269 <Box flexDirection="row">
270 <Text color={GREEN}>{e.props.isFirstOfReply ? '▸ ' : ' '}</Text>
271 <Box flexDirection="column" flexShrink={1}>
272 <Text color={GREEN}>{flatten(e.props.text.trim())}</Text>
273 </Box>
274 </Box>
275 )
276 })
277}
278types/index.d.ts 8 lines1export type Toggle = boolean
2
3declare module 'claude-code' {
4 interface PluginState {
5 matrix: { isOn: Toggle }
6 }
7}
8