silvery 0.11.0 → 0.11.2

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/README.md CHANGED
@@ -1,10 +1,8 @@
1
- # Silvery
1
+ # Silvery — React for modern terminal apps
2
2
 
3
- **React for modern terminal apps.**
3
+ **Powerful apps. Polished UIs. Proudly terminal.**
4
4
 
5
- Ink-compatible React renderer with an atomic rendering pipeline. Same `Box`, `Text`, `useInput` API you know. 99% Ink 7.0 compatible, 2.55.2× faster on mounted workloads, bundle-parity with Ink+Yoga. Plus everything you wish Ink had.
6
-
7
- > **Work in progress.** APIs may change. Feedback welcome.
5
+ Ink-compatible React renderer for interactive terminal apps. Same `Box`, `Text`, `useInput` API you know. 36× faster in mounted rerender benchmarks.
8
6
 
9
7
  ```console
10
8
  $ npm install silvery react
@@ -33,43 +31,75 @@ await render(<Counter />).run()
33
31
 
34
32
  - **React 18 + 19** — hooks, refs, effects, suspense — all works
35
33
  - **Flexbox layout** — `Box` with `flexDirection`, `padding`, `gap`, `flexGrow`, just like Ink
36
- - **Ink/Chalk compatible** — same component model, [`@silvery/ink`](https://github.com/beorn/silvery/tree/main/packages/ink) compatibility layer for migrating existing Ink applications
37
-
38
- ### Better
39
-
40
- - **Atomic rendering pipeline** — layout runs before render (no two-pass flash), cell-level buffer diff (no line redraws), synchronized frame output via DEC mode 2026 (no tearing). A class of rendering bugs architecturally impossible: no flicker, no component dropout on scroll, no half-updated frames
41
- - **2.5–5.2× faster than Ink 7.0 on mounted workloads** — wins all 16 benchmark scenarios. Only changed cells emit to the terminal; incremental output is 28–192× smaller than full redraw. Run `bun run bench` in the repo to reproduce
42
- - **Bundle parity with Ink+Yoga** — 114.9 KB gzipped runtime vs Ink+Yoga's 116.6 KB (0.99× tied). Pure TypeScript, no WASM, zero native deps — works on Alpine, CI, Docker, everywhere
43
- - **Responsive layout** — `useBoxRect()` returns actual dimensions synchronously during render
44
- - **Dynamic scrollback**live React zone at the bottom, completed items graduate to terminal-owned scrollback. Cmd+F works natively. The thing Claude Code spent six months trying to retrofit into Ink
45
- - **Scrollable containers**`overflow="scroll"` with automatic measurement and clipping
46
- - **99% Ink 7.0 compatible** — 918+/931 Ink tests pass on silvery's compat layer. Drop-in migration via `@silvery/ink`
47
- - **Theme system** 38 palettes, semantic design/color tokens (`$primary`, `$error`), auto-detects terminal colors
48
- - **30+ components**TextInput, TextArea, SelectList, ListView, Table, TreeView, Console, Tabs, CommandPalette, ModalDialog, Toast, and more
49
- - **Focus system**scoped focus, arrow-key directional nav, click-to-focus
50
- - **Text selection** — mouse drag, word/line selection, `userSelect` boundaries, Alt+drag override. Works out of the box with `withDomEvents()`
51
- - **Find** — `Ctrl+F` buffer search with match highlighting and `n`/`N` navigation. Works out of the box with `withFocus()`
52
- - **Copy-mode**`Esc, v` for vim-style keyboard-driven text selection and yanking
53
- - **Drag-and-drop**mouse drag with hit testing, automatic via `withDomEvents()`
54
- - **Extremely composable** use as just a renderer (`render`), add a runtime (`run`), or build full apps with any React state library (useState, Zustand, Jotai, Redux). Swap terminal backends (real TTY, headless, xterm.js emulator) for testing. Embed silvery components in existing CLIs. Use the layout engine standalone. Render to terminal, or (experimental) Canvas, or DOM
55
- - **Most complete terminal protocol support** — 100+ escape sequences, all auto-negotiated: 12 OSC (hyperlinks, clipboard, palette, text sizing, semantic prompts, notifications), 35+ CSI (cursor, mouse modes, paste, focus, sync output, device queries), 50+ SGR (6 underline styles, underline colors, truecolor, 256-color), full Kitty keyboard (5 flags), full SGR mouse (any-event, drag, wheel)
34
+ - **[Ink-compatible](https://silvery.dev/guide/silvery-vs-ink#compatibility)** — most code works with just an import change. 918/931 Ink 7.0 tests pass on silvery's compat layer. Drop-in migration via [`@silvery/ink`](https://silvery.dev/guide/silvery-vs-ink). See the [full feature comparison](https://silvery.dev/guide/silvery-vs-ink)
35
+
36
+ ### Shiny new stuff
37
+
38
+ - **[Best-in-class performance](https://silvery.dev/guide/silvery-vs-ink#performance-size)** — 3–6× faster than Ink in mounted rerender benchmarks, 10–20× less terminal output. Cell-level dirty tracking, only changed cells emit. Per-node skip for unchanged subtrees. Works in inline mode with native scrollback, not just fullscreen
39
+ - **Pure TypeScript, zero native deps** — no WASM, no build steps. [Layout via Flexily](https://silvery.dev/guide/layout-engine) (or Yoga). Works on Alpine, CI, Docker, everywhere
40
+ - **[Web-like responsive layout](https://silvery.dev/guide/silvery-vs-ink#responsive-layout)** — `useBoxRect()` returns actual dimensions during render. No post-render measurement, no two-pass layout cycle. Enables:
41
+ - [Scroll containers](https://silvery.dev/guide/scrolling) — `overflow="scroll"` with virtualization
42
+ - [Sticky positioning](https://silvery.dev/guide/layout-coordinates)`position="sticky"` for headers and footers
43
+ - [ANSI-aware compositing](https://silvery.dev/guide/ansi-layering)color blending with alpha across overlapping layers
44
+ - **[Inline, fullscreen, or both](https://silvery.dev/guide/runtime-layers)** — same components, one-line switch. All with incremental rendering:
45
+ - [Fullscreen](https://silvery.dev/guide/runtime-getting-started)alt screen, traditional TUI
46
+ - [Inline with dynamic scrollback](https://silvery.dev/examples/scrollback) live React zone at bottom, completed items graduate to terminal-owned scrollback. Native Cmd+F and text selection
47
+ - [Virtual inline](https://silvery.dev/design/dynamic-scrollback)alt screen + app-managed scrollback history, scrollable and searchable
48
+ - **[Web-like interaction](https://silvery.dev/guide/event-handling)** — full keyboard and mouse events that just work. Modifier keys, mouse buttons, and drag all combine seamlessly into a single event model. Enables:
49
+ - [Focus scopes](https://silvery.dev/guide/silvery-vs-ink#focus-system) spatial arrow-key nav, Tab/Escape, click-to-focus
50
+ - [Text selection](https://silvery.dev/guide/text-selection)mouse drag, word/line, `userSelect` boundaries, Alt+drag override
51
+ - [Find](https://silvery.dev/guide/find)`Ctrl+F` with match highlighting and `n`/`N` navigation
52
+ - [Copy-mode](https://silvery.dev/guide/clipboard) — `Esc, v` for vim-style keyboard selection and yanking
53
+ - [Drag-and-drop](https://silvery.dev/guide/event-handling) mouse drag with hit testing
54
+ - **[Rich component library](https://silvery.dev/guides/components)** — 45+ components: TextInput, SelectList, ListView, Table, TreeView, Tabs, CommandPalette, ModalDialog, Toast, and more. Every component automatically participates in focus, mouse, and keybindings (readline, vim) — no wiring needed. [38 theme palettes](https://silvery.dev/guide/styling) with semantic tokens (`$primary`, `$error`) and auto-detected terminal colors
55
+ - **[Playwright-style testing](https://silvery.dev/guide/testing)** — 3,000+ tests. Full access to terminal internals (scrollback buffer, cursor position, cell styles, window dimensions):
56
+ - `createRenderer` — fast unit tests with auto-refreshing CSS locators, cell-level color assertions, frame-by-frame inspection
57
+ - [Termless](https://termless.dev) — like Playwright for terminals. Full ANSI fidelity with [10 swappable backends](https://termless.dev/guide/backends) (xterm.js, Ghostty, Alacritty, WezTerm, Kitty, and more)
58
+ - [`SILVERY_STRICT`](https://silvery.dev/guide/debugging) — multi-level verification: buffer (incremental vs fresh), ANSI (internal parser), terminal (cross-backend), and accumulated replay
59
+ - **[Composable architecture](https://silvery.dev/guide/providers)** — every layer is independently swappable. [DI](https://silvery.dev/guide/providers) via `pipe()` providers:
60
+ - [Layout](https://silvery.dev/guide/layout-engine) — Flexily or Yoga
61
+ - [State](https://silvery.dev/guide/runtime-layers) — BYO (useState, Zustand, Jotai, Redux)
62
+ - [Term](https://silvery.dev/guide/runtime-layers) — real, headless, emulator
63
+ - [App](https://silvery.dev/guide/runtime-layers) — from stringify to rich app (withFocus, withDomEvents, withCommands). Render to terminal, Canvas, or DOM
64
+ - **[All modern terminal protocols](https://silvery.dev/guide/silvery-vs-ink#terminal-protocol-coverage)** — [60 years of terminal protocols](https://terminfo.dev/about), unified into clean APIs. 100+ escape sequences you'll never have to write — auto-negotiated and gracefully degraded: [Kitty keyboard](https://terminfo.dev) + [SGR mouse](https://terminfo.dev) become rich events with modifiers; [hyperlinks](https://terminfo.dev) are just props; [clipboard](https://terminfo.dev) is a function call. Truecolor, underline styles, synchronized output, bracketed paste, focus reporting, resize detection, inline images, and [more](https://silvery.dev/guide/silvery-vs-ink#terminal-protocol-coverage)
65
+
66
+ ### Why Silvery?
67
+
68
+ Silvery grew out of building a complex terminal app — a multi-pane workspace with thousands of nodes. Components needed to know their size during render. Updates needed to be fast. Scroll containers, mouse events, focus scopes, and Playwright-style testing needed to just work. What started as a renderer grew into a layout engine, then 45+ components, theming, testing infrastructure, and eventually a framework.
69
+
70
+ Along the way, three principles emerged. Take the best from the web, stay true to the terminal, and raise the bar for developer ergonomics, architecture composability, and performance.
71
+
72
+ [The Silvery Way](https://silvery.dev/guide/the-silvery-way) · [Silvery vs Ink](https://silvery.dev/guide/silvery-vs-ink) · [About](https://silvery.dev/about)
73
+
74
+ ### Next steps
75
+
76
+ - [Quick start](https://silvery.dev/getting-started/quick-start) — install, first app, deploy
77
+ - [Interactive examples](https://silvery.dev/examples) — `npx silvery examples` to try them locally
78
+ - [Silvery vs Ink](https://silvery.dev/guide/silvery-vs-ink) — feature comparison and migration guide
56
79
 
57
80
  ## Packages
58
81
 
59
- | Package | Description |
60
- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
61
- | [`silvery`](https://github.com/beorn/silvery) | Components, hooks, renderer — the one package you need |
62
- | [`@silvery/test`](https://github.com/beorn/silvery/tree/main/packages/test) | Testing utilities and locators |
63
- | [`@silvery/ink`](https://github.com/beorn/silvery/tree/main/packages/ink) | Ink compatibility layer migrate existing Ink apps with minimal changes |
82
+ | Package | Description |
83
+ | --------------------------------- | ----------------------------------------------------------------- |
84
+ | `silvery` | Components, hooks, renderer — the one package you need |
85
+ | `@silvery/ink` / `@silvery/chalk` | Ink compatibility 918/931 Ink 7.0 tests, 32/32 Chalk tests |
86
+ | `@silvery/test` | Playwright-style testinglocators, `press()`, buffer assertions |
87
+ | `@silvery/create` | Composable app builder — `pipe()` providers |
88
+ | `@silvery/theme` | 38 palettes, semantic tokens, auto-detect |
89
+ | `@silvery/commander` | **Beautiful CLIs for free** — help renders through Silvery itself |
90
+ | `@silvery/headless` | Pure state machines — portable, no React |
91
+ | `@silvery/ansi` | Terminal primitives — styling, SGR, detection |
64
92
 
65
93
  ## Ecosystem
66
94
 
67
- | Project | What |
68
- | ------------------------------------------ | ------------------------------------------------------------- |
69
- | [Termless](https://termless.dev) | Headless terminal testing — like Playwright for terminal apps |
70
- | [Flexily](https://beorn.github.io/flexily) | Pure JS flexbox layout engine (Yoga-compatible, zero WASM) |
71
- | [Loggily](https://beorn.github.io/loggily) | Debug + structured logging + tracing |
72
- | [terminfo.dev](https://terminfo.dev) | Terminal feature support database, powered by Termless |
95
+ Standalone projects Silvery builds on — each stands on its own:
96
+
97
+ | Project | What |
98
+ | -------------------------------------- | ----------------------------------------------------------------------- |
99
+ | [Flexily](https://beorn.codes/flexily) | Pure JS flexbox layout engine (Yoga-compatible, 2.5× faster, zero WASM) |
100
+ | [Termless](https://termless.dev) | Headless terminal testing like Playwright for terminal apps |
101
+ | [terminfo.dev](https://terminfo.dev) | Terminal feature compatibility database (161 features, 19 terminals) |
102
+ | [Loggily](https://beorn.codes/loggily) | Structured logging + tracing + metrics |
73
103
 
74
104
  ## Coming
75
105
 
@@ -77,7 +107,11 @@ await render(<Counter />).run()
77
107
  - **Frameworks** — Svelte, Solid.js, Vue adapters
78
108
  - **@silvery/create** — Structured state management with commands, keybindings, effects-as-data
79
109
 
80
- **Runtimes:** Bun >= 1.0 and Node.js >= 18. CLI (`silvery` command) requires Bun.
110
+ **Runtimes:** Bun >= 1.0 and Node.js >= 23.6. CLI (`silvery` command) requires Bun.
111
+
112
+ ## Inspirations
113
+
114
+ Silvery builds on ideas from [Ink](https://github.com/vadimdemedes/ink) (React for terminals), [Ratatui](https://ratatui.rs/) (cell-level buffer model), [shadcn/ui](https://ui.shadcn.com/) (polished defaults, semantic theming), [SlateJS](https://www.slatejs.org/) (plugin composition, operations-as-data), [The Elm Architecture](https://guide.elm-lang.org/architecture/) / [BubbleTea](https://github.com/charmbracelet/bubbletea) (TEA state machines), the CSS/Web platform (flexbox, container queries, DOM events, focus scopes), [VS Code](https://code.visualstudio.com/) (command palette, keybindings), [Playwright](https://playwright.dev/) (locator-based testing), [ProseMirror](https://prosemirror.net/) (selection model), [Blessed](https://github.com/chjj/blessed) (rich terminal UIs in JS), and [Textual](https://textual.textualize.io/) (CSS-like terminal theming).
81
115
 
82
116
  ## License
83
117
 
package/bin/silvery.ts ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * silvery CLI — delegates to @silvery/examples
4
+ * Works on both Node.js 23.6+ and Bun.
5
+ */
6
+ import { resolve, dirname, join } from "node:path"
7
+ import { readFileSync, existsSync } from "node:fs"
8
+ import { spawn } from "node:child_process"
9
+ import { fileURLToPath } from "node:url"
10
+
11
+ const __filename = fileURLToPath(import.meta.url)
12
+ const __dirname = dirname(__filename)
13
+
14
+ // Find package root by walking up looking for package.json with name "silvery"
15
+ function findPackageRoot(startDir: string): string {
16
+ let dir = startDir
17
+ for (let i = 0; i < 10; i++) {
18
+ const pkg = join(dir, "package.json")
19
+ if (existsSync(pkg)) {
20
+ try {
21
+ const json = JSON.parse(readFileSync(pkg, "utf8"))
22
+ if (json.name === "silvery") return dir
23
+ } catch {}
24
+ }
25
+ const parent = dirname(dir)
26
+ if (parent === dir) break
27
+ dir = parent
28
+ }
29
+ return dirname(startDir)
30
+ }
31
+
32
+ // Detect runtime for spawning child processes
33
+ const runtime = typeof globalThis.Bun !== "undefined" ? "bun" : "node"
34
+
35
+ const root = findPackageRoot(__dirname)
36
+ const args = process.argv.slice(2)
37
+ const examplesCli = resolve(root, "packages/examples/bin/cli.ts")
38
+
39
+ if (args.includes("--version") || args.includes("-v")) {
40
+ const pkg = JSON.parse(readFileSync(resolve(root, "package.json"), "utf8"))
41
+ console.log(`silvery ${pkg.version}`)
42
+ process.exit(0)
43
+ }
44
+
45
+ // Strip "examples" subcommand — the examples CLI handles bare args as example names
46
+ const delegateArgs = args[0] === "examples" ? args.slice(1) : args
47
+
48
+ const proc = spawn(runtime, ["run", examplesCli, ...delegateArgs], {
49
+ stdio: "inherit",
50
+ })
51
+ proc.on("exit", (code) => process.exit(code ?? 1))