silvery 0.3.0 → 0.4.1

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.
Files changed (120) hide show
  1. package/README.md +41 -145
  2. package/dist/chalk.js +3 -0
  3. package/dist/chalk.js.map +11 -0
  4. package/dist/index.js +340 -0
  5. package/dist/index.js.map +282 -0
  6. package/dist/ink.js +129 -0
  7. package/dist/ink.js.map +140 -0
  8. package/dist/runtime.js +394 -0
  9. package/dist/runtime.js.map +286 -0
  10. package/dist/theme.js +343 -0
  11. package/dist/theme.js.map +286 -0
  12. package/dist/ui/animation.js +3 -0
  13. package/dist/ui/animation.js.map +15 -0
  14. package/dist/ui/ansi.js +3 -0
  15. package/dist/ui/ansi.js.map +10 -0
  16. package/dist/ui/cli.js +8 -0
  17. package/dist/ui/cli.js.map +14 -0
  18. package/dist/ui/display.js +4 -0
  19. package/dist/ui/display.js.map +10 -0
  20. package/dist/ui/image.js +4 -0
  21. package/dist/ui/image.js.map +15 -0
  22. package/dist/ui/input.js +3 -0
  23. package/dist/ui/input.js.map +11 -0
  24. package/dist/ui/progress.js +8 -0
  25. package/dist/ui/progress.js.map +20 -0
  26. package/dist/ui/react.js +3 -0
  27. package/dist/ui/react.js.map +15 -0
  28. package/dist/ui/utils.js +3 -0
  29. package/dist/ui/utils.js.map +10 -0
  30. package/dist/ui/wrappers.js +14 -0
  31. package/dist/ui/wrappers.js.map +19 -0
  32. package/dist/ui.js +17 -0
  33. package/dist/ui.js.map +20 -0
  34. package/package.json +67 -15
  35. package/src/index.ts +67 -1
  36. package/src/runtime.ts +4 -0
  37. package/src/theme.ts +4 -0
  38. package/src/ui/animation.ts +2 -0
  39. package/src/ui/ansi.ts +2 -0
  40. package/src/ui/cli.ts +2 -0
  41. package/src/ui/display.ts +2 -0
  42. package/src/ui/image.ts +2 -0
  43. package/src/ui/input.ts +2 -0
  44. package/src/ui/progress.ts +2 -0
  45. package/src/ui/react.ts +2 -0
  46. package/src/ui/utils.ts +2 -0
  47. package/src/ui/wrappers.ts +2 -0
  48. package/src/ui.ts +4 -0
  49. package/examples/CLAUDE.md +0 -75
  50. package/examples/_banner.tsx +0 -60
  51. package/examples/cli.ts +0 -228
  52. package/examples/index.md +0 -101
  53. package/examples/inline/inline-nontty.tsx +0 -98
  54. package/examples/inline/inline-progress.tsx +0 -79
  55. package/examples/inline/inline-simple.tsx +0 -63
  56. package/examples/inline/scrollback.tsx +0 -185
  57. package/examples/interactive/_input-debug.tsx +0 -110
  58. package/examples/interactive/_stdin-test.ts +0 -71
  59. package/examples/interactive/_textarea-bare.tsx +0 -45
  60. package/examples/interactive/aichat/components.tsx +0 -468
  61. package/examples/interactive/aichat/index.tsx +0 -207
  62. package/examples/interactive/aichat/script.ts +0 -460
  63. package/examples/interactive/aichat/state.ts +0 -326
  64. package/examples/interactive/aichat/types.ts +0 -19
  65. package/examples/interactive/app-todo.tsx +0 -198
  66. package/examples/interactive/async-data.tsx +0 -208
  67. package/examples/interactive/cli-wizard.tsx +0 -332
  68. package/examples/interactive/clipboard.tsx +0 -183
  69. package/examples/interactive/components.tsx +0 -463
  70. package/examples/interactive/data-explorer.tsx +0 -506
  71. package/examples/interactive/dev-tools.tsx +0 -379
  72. package/examples/interactive/explorer.tsx +0 -747
  73. package/examples/interactive/gallery.tsx +0 -652
  74. package/examples/interactive/inline-bench.tsx +0 -136
  75. package/examples/interactive/kanban.tsx +0 -267
  76. package/examples/interactive/layout-ref.tsx +0 -185
  77. package/examples/interactive/outline.tsx +0 -171
  78. package/examples/interactive/paste-demo.tsx +0 -198
  79. package/examples/interactive/scroll.tsx +0 -77
  80. package/examples/interactive/search-filter.tsx +0 -240
  81. package/examples/interactive/task-list.tsx +0 -279
  82. package/examples/interactive/terminal.tsx +0 -798
  83. package/examples/interactive/textarea.tsx +0 -103
  84. package/examples/interactive/theme.tsx +0 -336
  85. package/examples/interactive/transform.tsx +0 -256
  86. package/examples/interactive/virtual-10k.tsx +0 -413
  87. package/examples/kitty/canvas.tsx +0 -519
  88. package/examples/kitty/generate-samples.ts +0 -236
  89. package/examples/kitty/image-component.tsx +0 -273
  90. package/examples/kitty/images.tsx +0 -604
  91. package/examples/kitty/input.tsx +0 -371
  92. package/examples/kitty/keys.tsx +0 -378
  93. package/examples/kitty/paint.tsx +0 -1017
  94. package/examples/layout/dashboard.tsx +0 -551
  95. package/examples/layout/live-resize.tsx +0 -290
  96. package/examples/layout/overflow.tsx +0 -51
  97. package/examples/playground/README.md +0 -69
  98. package/examples/playground/build.ts +0 -61
  99. package/examples/playground/index.html +0 -420
  100. package/examples/playground/playground-app.tsx +0 -416
  101. package/examples/runtime/elm-counter.tsx +0 -206
  102. package/examples/runtime/hello-runtime.tsx +0 -73
  103. package/examples/runtime/pipe-composition.tsx +0 -184
  104. package/examples/runtime/run-counter.tsx +0 -78
  105. package/examples/runtime/runtime-counter.tsx +0 -197
  106. package/examples/screenshots/generate.tsx +0 -563
  107. package/examples/scrollback-perf.tsx +0 -230
  108. package/examples/viewer.tsx +0 -654
  109. package/examples/web/build.ts +0 -365
  110. package/examples/web/canvas-app.tsx +0 -80
  111. package/examples/web/canvas.html +0 -89
  112. package/examples/web/dom-app.tsx +0 -81
  113. package/examples/web/dom.html +0 -113
  114. package/examples/web/showcase-app.tsx +0 -107
  115. package/examples/web/showcase.html +0 -34
  116. package/examples/web/showcases/index.tsx +0 -56
  117. package/examples/web/viewer-app.tsx +0 -555
  118. package/examples/web/viewer.html +0 -30
  119. package/examples/web/xterm-app.tsx +0 -105
  120. package/examples/web/xterm.html +0 -118
@@ -1,420 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>silvery Canvas Playground</title>
7
- <style>
8
- :root {
9
- --bg-primary: #1a1a2e;
10
- --bg-secondary: #16213e;
11
- --bg-tertiary: #0f0f1a;
12
- --text-primary: #eee;
13
- --text-secondary: #808080;
14
- --accent-cyan: #4ec9b0;
15
- --accent-blue: #9cdcfe;
16
- --accent-yellow: #dcdcaa;
17
- --border: #333;
18
- }
19
-
20
- * {
21
- box-sizing: border-box;
22
- margin: 0;
23
- padding: 0;
24
- }
25
-
26
- body {
27
- background: var(--bg-primary);
28
- color: var(--text-primary);
29
- font-family:
30
- system-ui,
31
- -apple-system,
32
- "Segoe UI",
33
- sans-serif;
34
- min-height: 100vh;
35
- display: flex;
36
- flex-direction: column;
37
- }
38
-
39
- /* Header */
40
- header {
41
- padding: 16px 24px;
42
- border-bottom: 1px solid var(--border);
43
- display: flex;
44
- align-items: center;
45
- gap: 16px;
46
- flex-wrap: wrap;
47
- }
48
-
49
- header h1 {
50
- color: var(--accent-cyan);
51
- font-size: 1.4rem;
52
- font-weight: 600;
53
- white-space: nowrap;
54
- }
55
-
56
- header .subtitle {
57
- color: var(--text-secondary);
58
- font-size: 0.9rem;
59
- }
60
-
61
- /* Preset buttons */
62
- .preset-bar {
63
- display: flex;
64
- gap: 8px;
65
- padding: 12px 24px;
66
- border-bottom: 1px solid var(--border);
67
- background: var(--bg-secondary);
68
- flex-wrap: wrap;
69
- align-items: center;
70
- }
71
-
72
- .preset-bar label {
73
- color: var(--text-secondary);
74
- font-size: 0.85rem;
75
- margin-right: 4px;
76
- }
77
-
78
- .preset-btn {
79
- background: var(--bg-tertiary);
80
- color: var(--text-primary);
81
- border: 1px solid var(--border);
82
- border-radius: 4px;
83
- padding: 6px 14px;
84
- font-size: 0.85rem;
85
- cursor: pointer;
86
- transition: all 0.15s;
87
- font-family: inherit;
88
- }
89
-
90
- .preset-btn:hover {
91
- border-color: var(--accent-cyan);
92
- color: var(--accent-cyan);
93
- }
94
-
95
- .preset-btn.active {
96
- background: var(--accent-cyan);
97
- color: var(--bg-primary);
98
- border-color: var(--accent-cyan);
99
- font-weight: 600;
100
- }
101
-
102
- /* Main area */
103
- .main {
104
- display: flex;
105
- flex: 1;
106
- min-height: 0;
107
- }
108
-
109
- /* Canvas container */
110
- .canvas-container {
111
- flex: 1;
112
- position: relative;
113
- min-height: 400px;
114
- display: flex;
115
- align-items: stretch;
116
- }
117
-
118
- #canvas {
119
- display: block;
120
- width: 100%;
121
- height: 100%;
122
- }
123
-
124
- .canvas-size-label {
125
- position: absolute;
126
- bottom: 8px;
127
- right: 8px;
128
- background: rgba(0, 0, 0, 0.7);
129
- color: var(--text-secondary);
130
- font-size: 0.75rem;
131
- padding: 2px 8px;
132
- border-radius: 3px;
133
- font-family: monospace;
134
- pointer-events: none;
135
- }
136
-
137
- /* Sidebar */
138
- .sidebar {
139
- width: 320px;
140
- border-left: 1px solid var(--border);
141
- background: var(--bg-secondary);
142
- overflow-y: auto;
143
- padding: 20px;
144
- flex-shrink: 0;
145
- }
146
-
147
- .sidebar h3 {
148
- color: var(--accent-blue);
149
- font-size: 1rem;
150
- margin-bottom: 12px;
151
- }
152
-
153
- .sidebar p {
154
- color: var(--text-secondary);
155
- font-size: 0.85rem;
156
- line-height: 1.6;
157
- margin-bottom: 16px;
158
- }
159
-
160
- .sidebar code {
161
- background: var(--bg-tertiary);
162
- padding: 1px 5px;
163
- border-radius: 3px;
164
- font-family: "SF Mono", "Fira Code", "JetBrains Mono", monospace;
165
- font-size: 0.8rem;
166
- }
167
-
168
- .code-block {
169
- background: var(--bg-tertiary);
170
- border: 1px solid var(--border);
171
- border-radius: 4px;
172
- padding: 12px;
173
- font-family: "SF Mono", "Fira Code", "JetBrains Mono", monospace;
174
- font-size: 0.78rem;
175
- line-height: 1.5;
176
- overflow-x: auto;
177
- white-space: pre;
178
- color: var(--text-primary);
179
- margin-bottom: 16px;
180
- }
181
-
182
- .code-block .keyword {
183
- color: #c586c0;
184
- }
185
- .code-block .component {
186
- color: #4ec9b0;
187
- }
188
- .code-block .string {
189
- color: #ce9178;
190
- }
191
- .code-block .prop {
192
- color: #9cdcfe;
193
- }
194
- .code-block .comment {
195
- color: #6a9955;
196
- }
197
-
198
- .section {
199
- margin-bottom: 24px;
200
- padding-bottom: 20px;
201
- border-bottom: 1px solid var(--border);
202
- }
203
-
204
- .section:last-child {
205
- border-bottom: none;
206
- }
207
-
208
- .feature-list {
209
- list-style: none;
210
- padding: 0;
211
- }
212
-
213
- .feature-list li {
214
- color: var(--text-secondary);
215
- font-size: 0.85rem;
216
- padding: 4px 0;
217
- padding-left: 16px;
218
- position: relative;
219
- }
220
-
221
- .feature-list li::before {
222
- content: "\2022";
223
- color: var(--accent-cyan);
224
- position: absolute;
225
- left: 0;
226
- }
227
-
228
- /* Loading state */
229
- .loading {
230
- display: flex;
231
- align-items: center;
232
- justify-content: center;
233
- height: 100%;
234
- color: var(--text-secondary);
235
- font-size: 1.1rem;
236
- }
237
-
238
- .loading::after {
239
- content: "";
240
- display: inline-block;
241
- width: 20px;
242
- height: 20px;
243
- border: 2px solid var(--border);
244
- border-top-color: var(--accent-cyan);
245
- border-radius: 50%;
246
- margin-left: 12px;
247
- animation: spin 0.8s linear infinite;
248
- }
249
-
250
- @keyframes spin {
251
- to {
252
- transform: rotate(360deg);
253
- }
254
- }
255
-
256
- /* Responsive */
257
- @media (max-width: 900px) {
258
- .main {
259
- flex-direction: column;
260
- }
261
- .sidebar {
262
- width: 100%;
263
- border-left: none;
264
- border-top: 1px solid var(--border);
265
- max-height: 40vh;
266
- }
267
- }
268
- </style>
269
- </head>
270
- <body>
271
- <header>
272
- <h1>silvery Canvas Playground</h1>
273
- <span class="subtitle">React components rendered to HTML5 Canvas via the silvery rendering pipeline</span>
274
- </header>
275
-
276
- <div class="preset-bar">
277
- <label>Examples:</label>
278
- <button class="preset-btn active" data-preset="hello">Hello World</button>
279
- <button class="preset-btn" data-preset="text">Text Styles</button>
280
- <button class="preset-btn" data-preset="colors">Colors</button>
281
- <button class="preset-btn" data-preset="flexbox">Flexbox</button>
282
- <button class="preset-btn" data-preset="borders">Borders</button>
283
- <button class="preset-btn" data-preset="dashboard">Dashboard</button>
284
- <button class="preset-btn" data-preset="responsive">Responsive</button>
285
- </div>
286
-
287
- <div class="main">
288
- <div class="canvas-container">
289
- <canvas id="canvas"></canvas>
290
- <div class="canvas-size-label" id="size-label"></div>
291
- </div>
292
-
293
- <div class="sidebar">
294
- <div class="section">
295
- <h3>How It Works</h3>
296
- <p>
297
- silvery is a React renderer that computes layout
298
- <strong>before</strong> content rendering. Components know their size during render via
299
- <code>useContentRect()</code>, not after.
300
- </p>
301
- <ul class="feature-list">
302
- <li>React reconciler builds an <code>InkxNode</code> tree</li>
303
- <li>Flexx (pure JS flexbox) computes layout synchronously</li>
304
- <li>Content renders to an OffscreenCanvas buffer</li>
305
- <li>Buffer is drawn to the visible canvas element</li>
306
- <li><code>requestAnimationFrame</code> drives re-renders on state changes</li>
307
- </ul>
308
- </div>
309
-
310
- <div class="section">
311
- <h3>Canvas Adapter API</h3>
312
- <div class="code-block">
313
- <span class="keyword">import</span> { <span class="component">renderToCanvas</span>,
314
- <span class="component">Box</span>, <span class="component">Text</span>,
315
- <span class="component">useContentRect</span> }
316
- <span class="keyword">from</span>
317
- <span class="string">'silvery/canvas'</span>;
318
-
319
- <span class="keyword">function</span>
320
- <span class="component">App</span>() { <span class="keyword">const</span> { width, height } =
321
- <span class="component">useContentRect</span>(); <span class="keyword">return</span> ( &lt;<span
322
- class="component"
323
- >Box</span
324
- >
325
- <span class="prop">borderStyle</span>=<span class="string">"single"</span>&gt; &lt;<span class="component"
326
- >Text</span
327
- >&gt; {width}px x {height}px &lt;/<span class="component">Text</span>&gt; &lt;/<span class="component"
328
- >Box</span
329
- >&gt; ); }
330
-
331
- <span class="keyword">const</span> canvas = document.getElementById(<span class="string">'canvas'</span>);
332
- <span class="component">renderToCanvas</span>(&lt;<span class="component">App</span>
333
- /&gt;, canvas);
334
- </div>
335
- </div>
336
-
337
- <div class="section">
338
- <h3>Render Targets</h3>
339
- <p>
340
- silvery supports multiple render targets through its
341
- <code>RenderAdapter</code> interface:
342
- </p>
343
- <ul class="feature-list">
344
- <li><strong>Terminal</strong> &mdash; ANSI character grid (production)</li>
345
- <li><strong>Canvas 2D</strong> &mdash; pixel buffer (this demo)</li>
346
- <li><strong>DOM</strong> &mdash; accessible HTML elements</li>
347
- <li><strong>WebGL</strong> &mdash; GPU-accelerated (planned)</li>
348
- </ul>
349
- </div>
350
-
351
- <div class="section">
352
- <h3>Build &amp; Run</h3>
353
- <div class="code-block">
354
- <span class="comment"># Build the playground bundle</span>
355
- cd vendor/beorn-silvery bun run examples/playground/build.ts
356
-
357
- <span class="comment"># Open in browser</span>
358
- open examples/playground/index.html
359
- </div>
360
- <p>
361
- For a full live-editing playground with Monaco editor and hot reload, see
362
- <code>docs/playground-design.md</code>.
363
- </p>
364
- </div>
365
- </div>
366
- </div>
367
-
368
- <script>
369
- // Preset button handling
370
- const buttons = document.querySelectorAll(".preset-btn")
371
- const sizeLabel = document.getElementById("size-label")
372
- const canvas = document.getElementById("canvas")
373
- let currentPreset = "hello"
374
-
375
- function setPreset(preset) {
376
- currentPreset = preset
377
- buttons.forEach((btn) => {
378
- btn.classList.toggle("active", btn.dataset.preset === preset)
379
- })
380
- // Send message to the app (loaded via module script below)
381
- window.postMessage({ type: "set-preset", preset }, "*")
382
- }
383
-
384
- buttons.forEach((btn) => {
385
- btn.addEventListener("click", () => setPreset(btn.dataset.preset))
386
- })
387
-
388
- // Update size label
389
- function updateSizeLabel() {
390
- if (canvas && sizeLabel) {
391
- sizeLabel.textContent = canvas.width + " x " + canvas.height
392
- }
393
- }
394
-
395
- const resizeObserver = new ResizeObserver(() => {
396
- requestAnimationFrame(updateSizeLabel)
397
- })
398
- if (canvas) resizeObserver.observe(canvas)
399
- updateSizeLabel()
400
-
401
- // Keyboard shortcuts for switching presets
402
- const presetKeys = {
403
- 1: "hello",
404
- 2: "text",
405
- 3: "colors",
406
- 4: "flexbox",
407
- 5: "borders",
408
- 6: "dashboard",
409
- 7: "responsive",
410
- }
411
- document.addEventListener("keydown", (e) => {
412
- if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") return
413
- const preset = presetKeys[e.key]
414
- if (preset) setPreset(preset)
415
- })
416
- </script>
417
-
418
- <script type="module" src="./dist/playground-app.js"></script>
419
- </body>
420
- </html>