tokengolf 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md CHANGED
@@ -38,10 +38,10 @@ A Node.js CLI tool that wraps Claude Code sessions with game mechanics. Users de
38
38
  ### Model as Character Class
39
39
  | Class | Model | Difficulty | Feel |
40
40
  |-------|-------|------------|------|
41
- | 🏹 Rogue | Haiku | Hard | Glass cannon. Must prompt precisely. |
42
- | ⚔️ Fighter | Sonnet | Normal | Balanced. The default run. |
43
- | 🧙 Warlock | Opus | Easy | Powerful but expensive. |
44
- | ⚜️ Paladin | Opus (plan mode) | Calculated | Strategic planner. Thinks before acting. |
41
+ | 🏹 Rogue | Haiku | Nightmare | Glass cannon. Must prompt precisely. |
42
+ | ⚔️ Fighter | Sonnet | Standard | Balanced. The default run. |
43
+ | 🧙 Warlock | Opus | Casual | Powerful but expensive. |
44
+ | ⚜️ Paladin | Opus (plan mode) | Tactical | Strategic planner. Thinks before acting. |
45
45
 
46
46
  ### Budget Tiers
47
47
  | Tier | Spend | Emoji |
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Josh Eche
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/cli.js CHANGED
@@ -575,28 +575,28 @@ var init_score = __esm({
575
575
  name: "Haiku",
576
576
  label: "Rogue",
577
577
  emoji: "\u{1F3F9}",
578
- difficulty: "Hard",
578
+ difficulty: "Nightmare",
579
579
  color: "red"
580
580
  },
581
581
  sonnet: {
582
582
  name: "Sonnet",
583
583
  label: "Fighter",
584
584
  emoji: "\u2694\uFE0F",
585
- difficulty: "Normal",
585
+ difficulty: "Standard",
586
586
  color: "cyan"
587
587
  },
588
588
  opusplan: {
589
589
  name: "Paladin",
590
590
  label: "Paladin",
591
591
  emoji: "\u269C\uFE0F",
592
- difficulty: "Calculated",
592
+ difficulty: "Tactical",
593
593
  color: "yellow"
594
594
  },
595
595
  opus: {
596
596
  name: "Opus",
597
597
  label: "Warlock",
598
598
  emoji: "\u{1F9D9}",
599
- difficulty: "Easy",
599
+ difficulty: "Casual",
600
600
  color: "magenta"
601
601
  }
602
602
  };
@@ -2024,10 +2024,13 @@ import React, { useState } from "react";
2024
2024
  import { Box, Text, useApp } from "ink";
2025
2025
  import { TextInput, Select, ConfirmInput } from "@inkjs/ui";
2026
2026
  var MODEL_OPTIONS = [
2027
- { label: "\u2694\uFE0F Sonnet \u2014 Balanced. The default run. [Normal]", value: "claude-sonnet-4-6" },
2028
- { label: "\u{1F3F9} Haiku \u2014 Glass cannon. Hard mode. [Hard]", value: "claude-haiku-4-5-20251001" },
2029
- { label: "\u269C\uFE0F Paladin \u2014 Opus plans, Sonnet executes. [Calculated]", value: "opusplan" },
2030
- { label: "\u{1F9D9} Opus \u2014 Powerful but expensive. [Easy]", value: "claude-opus-4-6" }
2027
+ { label: "\u2694\uFE0F Sonnet \u2014 Balanced. The default run. [Standard]", value: "claude-sonnet-4-6" },
2028
+ {
2029
+ label: "\u{1F3F9} Haiku \u2014 Glass cannon. Hard mode. [Nightmare]",
2030
+ value: "claude-haiku-4-5-20251001"
2031
+ },
2032
+ { label: "\u269C\uFE0F Paladin \u2014 Opus plans, Sonnet executes. [Tactical]", value: "opusplan" },
2033
+ { label: "\u{1F9D9} Opus \u2014 Powerful but expensive. [Casual]", value: "claude-opus-4-6" }
2031
2034
  ];
2032
2035
  var EFFORT_OPTIONS_BASE = [
2033
2036
  { label: "\u2696\uFE0F Medium \u2014 Balanced (Anthropic recommended for Sonnet)", value: "medium" },
package/docs/index.html CHANGED
@@ -3,12 +3,17 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <script>
7
+ const stored = localStorage.getItem('tg-theme');
8
+ const theme = stored || (matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');
9
+ document.documentElement.setAttribute('data-theme', theme);
10
+ </script>
6
11
  <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⛳</text></svg>">
7
- <title>TokenGolf: Every token matters.</title>
12
+ <title>TokenGolf | Every token matters.</title>
8
13
  <link rel="preconnect" href="https://fonts.googleapis.com" />
9
14
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
15
  <link
11
- href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@700&display=swap"
16
+ href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,600;0,700;1,600&family=Source+Sans+3:wght@400;600;700&display=swap"
12
17
  rel="stylesheet"
13
18
  />
14
19
  <meta
@@ -19,13 +24,13 @@
19
24
  <!-- Open Graph -->
20
25
  <meta property="og:type" content="website" />
21
26
  <meta property="og:url" content="https://josheche.github.io/tokengolf/" />
22
- <meta property="og:title" content="TokenGolf: Every token matters." />
27
+ <meta property="og:title" content="TokenGolf | Every token matters." />
23
28
  <meta property="og:description" content="TokenGolf turns Claude Code sessions into a game. Track token efficiency, earn achievements, and level up your prompting skills." />
24
29
  <meta property="og:image" content="https://josheche.github.io/tokengolf/assets/tokengolf-bg-min.jpg" />
25
30
 
26
31
  <!-- Twitter Card -->
27
32
  <meta name="twitter:card" content="summary_large_image" />
28
- <meta name="twitter:title" content="TokenGolf: Every token matters." />
33
+ <meta name="twitter:title" content="TokenGolf | Every token matters." />
29
34
  <meta name="twitter:description" content="TokenGolf turns Claude Code sessions into a game. Track token efficiency, earn achievements, and level up your prompting skills." />
30
35
  <meta name="twitter:image" content="https://josheche.github.io/tokengolf/assets/tokengolf-bg-min.jpg" />
31
36
 
@@ -61,26 +66,69 @@
61
66
  padding: 0;
62
67
  }
63
68
 
69
+ /* ── Dark: painting at dusk — warm charcoal, not cold blue ── */
64
70
  :root {
65
- --bg: #0d1117;
66
- --card: #161b22;
67
- --border: #30363d;
68
- --text: #e6edf3;
69
- --muted: #8b949e;
70
- --green: #3fb950;
71
- --green-dim: #238636;
72
- --cyan: #79c0ff;
73
- --magenta: #d2a8ff;
74
- --yellow: #e3b341;
75
- --red: #f85149;
76
- --orange: #ffa657;
71
+ --bg: #1a1812;
72
+ --card: #23211a;
73
+ --border: #3d3828;
74
+ --text: #e8dcc4;
75
+ --muted: #9a9180;
76
+ --green: #6bb54a;
77
+ --green-dim: #4a8a32;
78
+ --cyan: #7cb8d4;
79
+ --magenta: #c8a0e0;
80
+ --yellow: #d4a840;
81
+ --red: #e05848;
82
+ --orange: #d4884a;
83
+ --hero-overlay-top: rgba(26,24,18,0.5);
84
+ --hero-overlay-mid: rgba(26,24,18,0.4);
85
+ --hero-overlay-bot: rgba(26,24,18,0.95);
86
+ --hero-text: #f2ead6;
87
+ --hero-eyebrow-color: #6bb54a;
88
+ --install-bg: rgba(26,24,18,0.5);
89
+ --install-border: rgba(232,220,196,0.18);
90
+ --term-bg: #161410;
91
+ --term-header-bg: #1e1c16;
92
+ --tab-bar-bg: #141210;
93
+ --badge-flow-bg: #1e2e1a;
94
+ --badge-rogue-bg: #2c1c30;
95
+ --death-border: #3d2020;
96
+ }
97
+
98
+ /* ── Light: golden hour — warm cream, ochre, sage ── */
99
+ [data-theme="light"] {
100
+ --bg: #f2ead6;
101
+ --card: #f8f4e8;
102
+ --border: #d4c8a8;
103
+ --text: #2a2618;
104
+ --muted: #6e6450;
105
+ --green: #4a7a2a;
106
+ --green-dim: #5a8a38;
107
+ --cyan: #2a6e9a;
108
+ --magenta: #7a4a9a;
109
+ --yellow: #8a6a10;
110
+ --red: #b03020;
111
+ --orange: #9a5a18;
112
+ --hero-overlay-top: rgba(242,234,214,0.15);
113
+ --hero-overlay-mid: rgba(242,234,214,0.08);
114
+ --hero-overlay-bot: rgba(242,234,214,0.93);
115
+ --hero-text: #2a2618;
116
+ --hero-eyebrow-color: #4a7a2a;
117
+ --install-bg: rgba(248,244,232,0.8);
118
+ --install-border: rgba(42,38,24,0.12);
119
+ --term-bg: #ece4d0;
120
+ --term-header-bg: #e2dac4;
121
+ --tab-bar-bg: #e2dac4;
122
+ --badge-flow-bg: #d4e8c8;
123
+ --badge-rogue-bg: #e4d4f0;
124
+ --death-border: #e8c0b8;
77
125
  }
78
126
 
79
127
  body {
80
128
  background: var(--bg);
81
129
  color: var(--text);
82
130
  font-family:
83
- -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
131
+ "Source Sans 3", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
84
132
  line-height: 1.6;
85
133
  }
86
134
 
@@ -166,9 +214,9 @@
166
214
  inset: 0;
167
215
  background: linear-gradient(
168
216
  to bottom,
169
- rgba(0, 0, 0, 0.55) 0%,
170
- rgba(0, 0, 0, 0.45) 40%,
171
- rgba(13, 17, 23, 0.95) 100%
217
+ var(--hero-overlay-top) 0%,
218
+ var(--hero-overlay-mid) 40%,
219
+ var(--hero-overlay-bot) 100%
172
220
  );
173
221
  }
174
222
 
@@ -179,7 +227,7 @@
179
227
 
180
228
  .hero-eyebrow {
181
229
  font-family: "SF Mono", "Cascadia Mono", monospace;
182
- color: #6ee87a;
230
+ color: var(--hero-eyebrow-color);
183
231
  font-size: 2.5rem;
184
232
  letter-spacing: 0.1em;
185
233
  text-transform: uppercase;
@@ -187,7 +235,7 @@
187
235
  }
188
236
 
189
237
  .hero h1 {
190
- font-family: "Libre Baskerville", Georgia, serif;
238
+ font-family: "Cormorant Garamond", Georgia, serif;
191
239
  font-size: clamp(3rem, 10vw, 6rem);
192
240
  font-weight: 700;
193
241
  letter-spacing: 0.02em;
@@ -199,13 +247,13 @@
199
247
  }
200
248
 
201
249
  .hero h1 span {
202
- color: #ffffff;
203
- -webkit-text-fill-color: #ffffff;
250
+ color: var(--hero-text);
251
+ -webkit-text-fill-color: var(--hero-text);
204
252
  }
205
253
 
206
254
  .hero-tagline {
207
255
  font-size: clamp(1rem, 3vw, 1.4rem);
208
- color: rgba(255, 255, 255, 0.92);
256
+ color: var(--hero-text);
209
257
  font-style: italic;
210
258
  margin-bottom: 1.25rem;
211
259
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.8);
@@ -213,7 +261,7 @@
213
261
 
214
262
  .hero-sub {
215
263
  font-size: 1.05rem;
216
- color: rgba(255, 255, 255, 0.85);
264
+ color: var(--hero-text);
217
265
  max-width: 540px;
218
266
  margin-bottom: 2.5rem;
219
267
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.7);
@@ -224,10 +272,10 @@
224
272
  display: flex;
225
273
  align-items: center;
226
274
  gap: 0;
227
- background: rgba(13, 17, 23, 0.45);
275
+ background: var(--install-bg);
228
276
  backdrop-filter: blur(12px) saturate(1.2);
229
277
  -webkit-backdrop-filter: blur(12px) saturate(1.2);
230
- border: 1px solid rgba(255, 255, 255, 0.18);
278
+ border: 1px solid var(--install-border);
231
279
  border-radius: 9999px;
232
280
  padding: 0.4rem 0.4rem 0.4rem 1.25rem;
233
281
  max-width: 420px;
@@ -253,7 +301,7 @@
253
301
 
254
302
  .copy-btn {
255
303
  background: var(--green);
256
- color: #0d1117;
304
+ color: var(--bg);
257
305
  border: none;
258
306
  border-radius: 9999px;
259
307
  padding: 0.45rem 1rem;
@@ -267,14 +315,14 @@
267
315
  }
268
316
 
269
317
  .copy-btn:hover {
270
- background: #52d765;
318
+ background: #7cc85a;
271
319
  }
272
320
  .copy-btn:active {
273
321
  transform: scale(0.97);
274
322
  }
275
323
  .copy-btn.copied {
276
324
  background: var(--green-dim);
277
- color: #e6edf3;
325
+ color: var(--hero-text);
278
326
  }
279
327
 
280
328
  .hero-links {
@@ -286,7 +334,7 @@
286
334
  }
287
335
 
288
336
  .hero-links a {
289
- color: rgba(255, 255, 255, 0.9);
337
+ color: var(--hero-text);
290
338
  display: flex;
291
339
  align-items: center;
292
340
  gap: 0.4rem;
@@ -372,11 +420,11 @@
372
420
  }
373
421
 
374
422
  .badge-flow {
375
- background: #1f3a2a;
423
+ background: var(--badge-flow-bg);
376
424
  color: var(--green);
377
425
  }
378
426
  .badge-rogue {
379
- background: #2d1b30;
427
+ background: var(--badge-rogue-bg);
380
428
  color: var(--magenta);
381
429
  }
382
430
 
@@ -424,19 +472,19 @@
424
472
  font-size: 1.4rem;
425
473
  }
426
474
 
427
- .difficulty-hard {
475
+ .difficulty-nightmare {
428
476
  color: var(--red);
429
477
  font-weight: 600;
430
478
  }
431
- .difficulty-normal {
479
+ .difficulty-standard {
432
480
  color: var(--yellow);
433
481
  font-weight: 600;
434
482
  }
435
- .difficulty-easy {
483
+ .difficulty-casual {
436
484
  color: var(--green);
437
485
  font-weight: 600;
438
486
  }
439
- .difficulty-calculated {
487
+ .difficulty-tactical {
440
488
  color: var(--magenta);
441
489
  font-weight: 600;
442
490
  }
@@ -474,38 +522,6 @@
474
522
  }
475
523
 
476
524
  /* ── CLI Commands ── */
477
- .cli-block {
478
- overflow: hidden;
479
- }
480
-
481
- .cli-block-header {
482
- background: #1c2128;
483
- padding: 0.6rem 1rem;
484
- font-size: 0.78rem;
485
- color: var(--muted);
486
- font-family: "SF Mono", monospace;
487
- border-bottom: 1px solid var(--border);
488
- display: flex;
489
- align-items: center;
490
- gap: 0.5rem;
491
- }
492
-
493
- .cli-block-header::before {
494
- content: "● ● ●";
495
- color: #30363d;
496
- font-size: 0.65rem;
497
- letter-spacing: 0.2em;
498
- }
499
-
500
- .cli-block pre {
501
- padding: 1.5rem;
502
- overflow-x: auto;
503
- font-family:
504
- "SF Mono", "Cascadia Mono", "Fira Code", "Consolas", monospace;
505
- font-size: 0.88rem;
506
- line-height: 1.8;
507
- }
508
-
509
525
  .cli-block .cmd {
510
526
  color: var(--cyan);
511
527
  }
@@ -542,19 +558,19 @@
542
558
  .tier-amount {
543
559
  color: var(--muted);
544
560
  font-size: 0.82rem;
545
- font-family: monospace;
546
561
  }
547
562
 
548
563
  .achievement-card.death {
549
- border-color: #3d1f1f;
564
+ border-color: var(--death-border);
550
565
  }
551
566
 
552
567
  .tab-btn[aria-selected="true"].tab-death {
553
568
  background: var(--red);
554
- box-shadow: 0 2px 16px rgba(248, 81, 73, 0.3);
569
+ color: #f2ead6;
570
+ box-shadow: 0 2px 16px rgba(224, 88, 72, 0.3);
555
571
  }
556
572
 
557
- .tab-btn.tab-death:hover {
573
+ .tab-btn.tab-death:not([aria-selected="true"]):hover {
558
574
  color: var(--red);
559
575
  }
560
576
 
@@ -583,7 +599,7 @@
583
599
  display: flex;
584
600
  gap: 0.25rem;
585
601
  margin-bottom: 2rem;
586
- background: #0a0e14;
602
+ background: var(--tab-bar-bg);
587
603
  border: 1px solid var(--border);
588
604
  border-radius: 10px;
589
605
  padding: 0.3rem;
@@ -601,20 +617,20 @@
601
617
  border-radius: 7px;
602
618
  cursor: pointer;
603
619
  transition: color 0.2s, background 0.2s, box-shadow 0.2s;
604
- font-family: "SF Mono", "Cascadia Mono", monospace;
605
620
  white-space: nowrap;
606
- letter-spacing: -0.01em;
621
+ letter-spacing: 0.02em;
622
+ text-transform: uppercase;
607
623
  }
608
624
 
609
625
  .tab-btn:hover {
610
626
  color: var(--text);
611
- background: rgba(48, 54, 61, 0.45);
627
+ background: rgba(61, 56, 40, 0.25);
612
628
  }
613
629
 
614
630
  .tab-btn[aria-selected="true"] {
615
- color: #0d1117;
631
+ color: #f2ead6;
616
632
  background: var(--cyan);
617
- box-shadow: 0 2px 16px rgba(121, 192, 255, 0.3);
633
+ box-shadow: 0 2px 16px rgba(124, 184, 212, 0.3);
618
634
  }
619
635
 
620
636
  .tab-panel {
@@ -668,7 +684,7 @@
668
684
  /* ── Terminal chrome ── */
669
685
  .term {
670
686
  position: relative;
671
- background: #0c1017;
687
+ background: var(--term-bg);
672
688
  border: 1px solid var(--border);
673
689
  border-radius: 10px;
674
690
  overflow: hidden;
@@ -696,42 +712,42 @@
696
712
 
697
713
  /* Glow variants */
698
714
  .term[data-glow="cyan"] {
699
- box-shadow: 0 4px 32px rgba(0,0,0,0.55), 0 0 48px rgba(121,192,255,0.06);
715
+ box-shadow: 0 4px 32px rgba(0,0,0,0.55), 0 0 48px rgba(124,184,212,0.06);
700
716
  }
701
717
  .term[data-glow="cyan"]:hover {
702
- border-color: rgba(121,192,255,0.35);
703
- box-shadow: 0 4px 40px rgba(0,0,0,0.5), 0 0 72px rgba(121,192,255,0.12);
718
+ border-color: rgba(124,184,212,0.35);
719
+ box-shadow: 0 4px 40px rgba(0,0,0,0.5), 0 0 72px rgba(124,184,212,0.12);
704
720
  }
705
721
  .term[data-glow="yellow"] {
706
- box-shadow: 0 4px 32px rgba(0,0,0,0.55), 0 0 48px rgba(227,179,65,0.06);
722
+ box-shadow: 0 4px 32px rgba(0,0,0,0.55), 0 0 48px rgba(212,168,64,0.06);
707
723
  }
708
724
  .term[data-glow="yellow"]:hover {
709
- border-color: rgba(227,179,65,0.35);
710
- box-shadow: 0 4px 40px rgba(0,0,0,0.5), 0 0 72px rgba(227,179,65,0.12);
725
+ border-color: rgba(212,168,64,0.35);
726
+ box-shadow: 0 4px 40px rgba(0,0,0,0.5), 0 0 72px rgba(212,168,64,0.12);
711
727
  }
712
728
  .term[data-glow="red"] {
713
- box-shadow: 0 4px 32px rgba(0,0,0,0.55), 0 0 48px rgba(248,81,73,0.06);
729
+ box-shadow: 0 4px 32px rgba(0,0,0,0.55), 0 0 48px rgba(224,88,72,0.06);
714
730
  }
715
731
  .term[data-glow="red"]:hover {
716
- border-color: rgba(248,81,73,0.35);
717
- box-shadow: 0 4px 40px rgba(0,0,0,0.5), 0 0 72px rgba(248,81,73,0.12);
732
+ border-color: rgba(224,88,72,0.35);
733
+ box-shadow: 0 4px 40px rgba(0,0,0,0.5), 0 0 72px rgba(224,88,72,0.12);
718
734
  }
719
735
  .term[data-glow="green"] {
720
- box-shadow: 0 4px 32px rgba(0,0,0,0.55), 0 0 48px rgba(63,185,80,0.06);
736
+ box-shadow: 0 4px 32px rgba(0,0,0,0.55), 0 0 48px rgba(107,181,74,0.06);
721
737
  }
722
738
  .term[data-glow="green"]:hover {
723
- border-color: rgba(63,185,80,0.35);
724
- box-shadow: 0 4px 40px rgba(0,0,0,0.5), 0 0 72px rgba(63,185,80,0.12);
739
+ border-color: rgba(107,181,74,0.35);
740
+ box-shadow: 0 4px 40px rgba(0,0,0,0.5), 0 0 72px rgba(107,181,74,0.12);
725
741
  }
726
742
 
727
743
  /* Header bar */
728
744
  .term-header {
729
- background: #13181f;
745
+ background: var(--term-header-bg);
730
746
  padding: 0.6rem 0.9rem;
731
747
  font-size: 0.75rem;
732
748
  color: var(--muted);
733
749
  font-family: "SF Mono", "Cascadia Mono", monospace;
734
- border-bottom: 1px solid rgba(48, 54, 61, 0.6);
750
+ border-bottom: 1px solid var(--border);
735
751
  display: flex;
736
752
  align-items: center;
737
753
  gap: 0.65rem;
@@ -807,9 +823,127 @@
807
823
  justify-content: center;
808
824
  margin-top: 0.75rem;
809
825
  }
826
+
827
+ /* ── Theme toggle ── */
828
+ .theme-toggle {
829
+ position: fixed;
830
+ top: 1rem;
831
+ right: 1rem;
832
+ z-index: 100;
833
+ width: 40px;
834
+ height: 40px;
835
+ border-radius: 50%;
836
+ border: 1px solid var(--border);
837
+ background: var(--card);
838
+ cursor: pointer;
839
+ display: flex;
840
+ align-items: center;
841
+ justify-content: center;
842
+ font-size: 1.1rem;
843
+ transition: background 0.2s, border-color 0.2s;
844
+ box-shadow: 0 2px 8px rgba(0,0,0,0.15);
845
+ line-height: 1;
846
+ padding: 0;
847
+ }
848
+
849
+ .theme-toggle:hover {
850
+ border-color: var(--muted);
851
+ }
852
+
853
+ /* Sun visible in dark mode (click to go light) */
854
+ .theme-icon-moon { display: none; }
855
+ .theme-icon-sun { display: inline; }
856
+ [data-theme="light"] .theme-icon-sun { display: none; }
857
+ [data-theme="light"] .theme-icon-moon { display: inline; }
858
+
859
+ /* ── Light mode targeted overrides ── */
860
+ [data-theme="light"] .card {
861
+ box-shadow: 0 1px 4px rgba(0,0,0,0.06);
862
+ }
863
+
864
+ [data-theme="light"] .term::after {
865
+ background: repeating-linear-gradient(
866
+ 0deg,
867
+ transparent 0px,
868
+ transparent 2px,
869
+ rgba(0,0,0,0.018) 2px,
870
+ rgba(0,0,0,0.018) 4px
871
+ );
872
+ }
873
+
874
+ [data-theme="light"] .term {
875
+ box-shadow: 0 2px 12px rgba(0,0,0,0.08);
876
+ }
877
+
878
+ [data-theme="light"] .term[data-glow="cyan"] {
879
+ box-shadow: 0 2px 12px rgba(42,38,24,0.06), 0 0 24px rgba(42,110,154,0.06);
880
+ }
881
+ [data-theme="light"] .term[data-glow="cyan"]:hover {
882
+ border-color: rgba(42,110,154,0.3);
883
+ box-shadow: 0 2px 16px rgba(42,38,24,0.06), 0 0 36px rgba(42,110,154,0.1);
884
+ }
885
+ [data-theme="light"] .term[data-glow="yellow"] {
886
+ box-shadow: 0 2px 12px rgba(42,38,24,0.06), 0 0 24px rgba(138,106,16,0.08);
887
+ }
888
+ [data-theme="light"] .term[data-glow="yellow"]:hover {
889
+ border-color: rgba(138,106,16,0.3);
890
+ box-shadow: 0 2px 16px rgba(42,38,24,0.06), 0 0 36px rgba(138,106,16,0.12);
891
+ }
892
+ [data-theme="light"] .term[data-glow="red"] {
893
+ box-shadow: 0 2px 12px rgba(42,38,24,0.06), 0 0 24px rgba(176,48,32,0.06);
894
+ }
895
+ [data-theme="light"] .term[data-glow="red"]:hover {
896
+ border-color: rgba(176,48,32,0.3);
897
+ box-shadow: 0 2px 16px rgba(42,38,24,0.06), 0 0 36px rgba(176,48,32,0.1);
898
+ }
899
+ [data-theme="light"] .term[data-glow="green"] {
900
+ box-shadow: 0 2px 12px rgba(42,38,24,0.06), 0 0 24px rgba(74,122,42,0.06);
901
+ }
902
+ [data-theme="light"] .term[data-glow="green"]:hover {
903
+ border-color: rgba(74,122,42,0.3);
904
+ box-shadow: 0 2px 16px rgba(42,38,24,0.06), 0 0 36px rgba(74,122,42,0.1);
905
+ }
906
+
907
+ [data-theme="light"] .hero h1 {
908
+ text-shadow:
909
+ 0 2px 16px rgba(242,234,214,0.5),
910
+ 0 1px 3px rgba(242,234,214,0.3);
911
+ }
912
+
913
+ [data-theme="light"] .hero-eyebrow {
914
+ text-shadow: 0 1px 8px rgba(242,234,214,0.6);
915
+ }
916
+
917
+ [data-theme="light"] .hero-tagline {
918
+ text-shadow: 0 1px 8px rgba(242,234,214,0.6);
919
+ }
920
+
921
+ [data-theme="light"] .hero-sub {
922
+ text-shadow: 0 1px 6px rgba(242,234,214,0.5);
923
+ }
924
+
925
+ [data-theme="light"] .copy-btn {
926
+ color: #f2ead6;
927
+ }
928
+ [data-theme="light"] .copy-btn:hover {
929
+ background: #5a8a38;
930
+ }
931
+
932
+ [data-theme="light"] .install-box {
933
+ box-shadow: 0 4px 24px rgba(0,0,0,0.08);
934
+ }
935
+
936
+ [data-theme="light"] .tab-btn[aria-selected="true"] {
937
+ color: #f2ead6;
938
+ }
810
939
  </style>
811
940
  </head>
812
941
  <body>
942
+ <button class="theme-toggle" id="theme-toggle" aria-label="Toggle theme">
943
+ <span class="theme-icon-sun">☀️</span>
944
+ <span class="theme-icon-moon">🌙</span>
945
+ </button>
946
+
813
947
  <!-- ── Hero ── -->
814
948
  <div class="hero">
815
949
  <div class="hero-eyebrow">⛳</div>
@@ -910,32 +1044,32 @@
910
1044
  <tbody>
911
1045
  <tr>
912
1046
  <td><span class="class-emoji">🏹</span> <strong>Rogue</strong></td>
913
- <td class="mono">claude-haiku-4-5</td>
914
- <td class="difficulty-hard">Hard</td>
1047
+ <td>Haiku</td>
1048
+ <td class="difficulty-nightmare">Nightmare</td>
915
1049
  <td>Glass cannon. Must prompt precisely.</td>
916
1050
  </tr>
917
1051
  <tr>
918
1052
  <td>
919
1053
  <span class="class-emoji">⚔️</span> <strong>Fighter</strong>
920
1054
  </td>
921
- <td class="mono">claude-sonnet-4-6</td>
922
- <td class="difficulty-normal">Normal</td>
1055
+ <td>Sonnet</td>
1056
+ <td class="difficulty-standard">Standard</td>
923
1057
  <td>Balanced. The default run.</td>
924
1058
  </tr>
925
1059
  <tr>
926
1060
  <td>
927
1061
  <span class="class-emoji">🧙</span> <strong>Warlock</strong>
928
1062
  </td>
929
- <td class="mono">claude-opus-4-6</td>
930
- <td class="difficulty-easy">Easy</td>
1063
+ <td>Opus</td>
1064
+ <td class="difficulty-casual">Casual</td>
931
1065
  <td>Powerful but expensive.</td>
932
1066
  </tr>
933
1067
  <tr>
934
1068
  <td>
935
1069
  <span class="class-emoji">⚜️</span> <strong>Paladin</strong>
936
1070
  </td>
937
- <td class="mono">claude-opus-4-6 (plan mode)</td>
938
- <td class="difficulty-calculated">Calculated</td>
1071
+ <td>Opusplan</td>
1072
+ <td class="difficulty-tactical">Tactical</td>
939
1073
  <td>Strategic planner. Thinks before acting.</td>
940
1074
  </tr>
941
1075
  </tbody>
@@ -1578,8 +1712,8 @@
1578
1712
  <!-- ── CLI Commands ── -->
1579
1713
  <section id="cli">
1580
1714
  <h2><span>⌨️</span>CLI Commands</h2>
1581
- <div class="card cli-block">
1582
- <div class="cli-block-header">terminal</div>
1715
+ <div class="term cli-block" data-glow="cyan">
1716
+ <div class="term-header">terminal</div>
1583
1717
  <pre>
1584
1718
  <span class="comment"># Install</span>
1585
1719
  <span class="dollar">$</span> <span class="cmd">npm install -g tokengolf</span>
@@ -1636,6 +1770,18 @@
1636
1770
  });
1637
1771
  });
1638
1772
 
1773
+ /* ── Theme toggle ── */
1774
+ document.getElementById('theme-toggle').addEventListener('click', () => {
1775
+ const next = document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light';
1776
+ document.documentElement.setAttribute('data-theme', next);
1777
+ localStorage.setItem('tg-theme', next);
1778
+ });
1779
+ matchMedia('(prefers-color-scheme: light)').addEventListener('change', e => {
1780
+ if (!localStorage.getItem('tg-theme')) {
1781
+ document.documentElement.setAttribute('data-theme', e.matches ? 'light' : 'dark');
1782
+ }
1783
+ });
1784
+
1639
1785
  function copyInstall() {
1640
1786
  const cmd = document.getElementById("install-cmd").value;
1641
1787
  const btn = document.getElementById("copy-btn");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokengolf",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "Gamify your Claude Code sessions. Flow mode tracks you. Roguelike mode trains you.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,5 +36,6 @@
36
36
  },
37
37
  "engines": {
38
38
  "node": ">=18.0.0"
39
- }
39
+ },
40
+ "license": "MIT"
40
41
  }
@@ -5,10 +5,13 @@ import { setCurrentRun } from '../lib/state.js';
5
5
  import { getModelClass, getEffortLevel, getModelBudgets, FLOORS } from '../lib/score.js';
6
6
 
7
7
  const MODEL_OPTIONS = [
8
- { label: '⚔️ Sonnet — Balanced. The default run. [Normal]', value: 'claude-sonnet-4-6' },
9
- { label: '🏹 Haiku — Glass cannon. Hard mode. [Hard]', value: 'claude-haiku-4-5-20251001' },
10
- { label: '⚜️ PaladinOpus plans, Sonnet executes. [Calculated]', value: 'opusplan' },
11
- { label: '🧙 Opus — Powerful but expensive. [Easy]', value: 'claude-opus-4-6' },
8
+ { label: '⚔️ Sonnet — Balanced. The default run. [Standard]', value: 'claude-sonnet-4-6' },
9
+ {
10
+ label: '🏹 Haiku Glass cannon. Hard mode. [Nightmare]',
11
+ value: 'claude-haiku-4-5-20251001',
12
+ },
13
+ { label: '⚜️ Paladin — Opus plans, Sonnet executes. [Tactical]', value: 'opusplan' },
14
+ { label: '🧙 Opus — Powerful but expensive. [Casual]', value: 'claude-opus-4-6' },
12
15
  ];
13
16
 
14
17
  const EFFORT_OPTIONS_BASE = [
package/src/lib/score.js CHANGED
@@ -37,28 +37,28 @@ export const MODEL_CLASSES = {
37
37
  name: 'Haiku',
38
38
  label: 'Rogue',
39
39
  emoji: '🏹',
40
- difficulty: 'Hard',
40
+ difficulty: 'Nightmare',
41
41
  color: 'red',
42
42
  },
43
43
  sonnet: {
44
44
  name: 'Sonnet',
45
45
  label: 'Fighter',
46
46
  emoji: '⚔️',
47
- difficulty: 'Normal',
47
+ difficulty: 'Standard',
48
48
  color: 'cyan',
49
49
  },
50
50
  opusplan: {
51
51
  name: 'Paladin',
52
52
  label: 'Paladin',
53
53
  emoji: '⚜️',
54
- difficulty: 'Calculated',
54
+ difficulty: 'Tactical',
55
55
  color: 'yellow',
56
56
  },
57
57
  opus: {
58
58
  name: 'Opus',
59
59
  label: 'Warlock',
60
60
  emoji: '🧙',
61
- difficulty: 'Easy',
61
+ difficulty: 'Casual',
62
62
  color: 'magenta',
63
63
  },
64
64
  };