silvery 0.11.3 → 0.15.0

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/CHANGELOG.md CHANGED
@@ -7,6 +7,54 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.15.0] - 2026-04-10
11
+
12
+ ### Performance
13
+
14
+ - **Lazy TextFrame** — defer buffer snapshot clone + 80K Cell object creation to first access. Eliminates the #1 per-frame cost that was misattributed to React reconciliation. **15–20× faster than Ink** (was 3–6×).
15
+ - **Skip syncPrevLayout** — O(N) tree walk skipped on cursor move when no layout changed.
16
+ - **No-op frame skip** — return prev buffer unchanged when no dirty flags set.
17
+
18
+ ### Added
19
+
20
+ - **Text layout: `width="snug-content"`** — tightest box width for same line count. Inspired by [Pretext shrinkwrap](https://chenglou.me/pretext/bubbles/).
21
+ - **Text layout: `wrap="even"`** — minimum-raggedness line breaking via dynamic programming. [Pretext Knuth-Plass](https://chenglou.me/pretext/).
22
+ - **Floating component defaults** — ModalDialog, Toast, Tooltip default to `snug-content`. All accept spread BoxProps.
23
+ - **Text layout demo** — `bunx @silvery/examples text layout`.
24
+ - **Benchmarks** — resize, scroll, large terminal (400×200), Pretext algorithms, reconciliation profiling.
25
+
26
+ ### Fixed
27
+
28
+ - **Wide char STRICT** — grapheme cluster handling in STRICT output verification parser.
29
+ - **Pretext correctness** — 5 bugs from GPT 5.4 Pro review.
30
+
31
+ ## [0.12.0] - 2026-04-10
32
+
33
+ ### Added
34
+
35
+ - **Pretext-inspired text layout** — `width="snug-content"` finds the tightest box width that keeps the same line count ([Pretext: "shrinkwrap"](https://chenglou.me/pretext/bubbles/)). `wrap="even"` uses minimum-raggedness dynamic programming for globally-optimal line breaks. See [Text Layout guide](/guide/layouts#text-layout).
36
+ - **PreparedText cache** — three-level per-node text analysis cache (plain text, collected styled text, formatted lines per width). 27-49% faster on resize workloads, zero regression on cursor move.
37
+ - **Floating component defaults** — ModalDialog, Toast, Tooltip default to `width="snug-content"` (tightest fit around content). All accept spread BoxProps for overriding.
38
+ - **Pretext demo** — `examples/pretext-demo.tsx` with interactive chat bubbles, even wrapping, and combined showcase.
39
+ - **Node.js 23.6+ CLI** — `bunx silvery examples` works on both Bun and Node.
40
+ - **Benchmarks** — resize/fold, scroll container, large terminal (400×200), Pretext algorithms, reconciliation profiling.
41
+
42
+ ### Fixed
43
+
44
+ - **Wide char STRICT** — grapheme cluster handling (CJK, emoji, ZWJ sequences) in STRICT output verification parser.
45
+ - **VT100 pending wrap** — STRICT_OUTPUT false positives on fold/collapse operations.
46
+ - **Pretext correctness** — 5 bugs fixed after GPT 5.4 Pro review: shrinkwrap lower bound, newline handling in Knuth-Plass DP, ANSI-aware trimming, L3 cache invalidation.
47
+
48
+ ### Changed
49
+
50
+ - **Reactive cascade is production path** — alien-signals computeds drive rendering by default. Imperative oracle runs only under `SILVERY_STRICT=1`.
51
+ - **Bit-packed dirty flags** — 7 epoch fields (56 bytes) → dirtyBits + dirtyEpoch (16 bytes per node).
52
+ - **Pipeline simplification** — -1,111 LOC (STRICT extraction to output-verify.ts, instrumentation consolidation, cascade dedup).
53
+
54
+ ### Performance
55
+
56
+ - Massive performance improvements across the rendering pipeline: reactive cascade, bit-packed dirty flags, PreparedText cache (27-49% faster resize), layout-on-demand gate, container-level layout skip, dirty-set rendering.
57
+
10
58
  ## [0.11.0] - 2026-04-09
11
59
 
12
60
  ### Added
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Powerful apps. Polished UIs. Proudly terminal.**
4
4
 
5
- Ink-compatible React renderer for interactive terminal apps. Same `Box`, `Text`, `useInput` API you know. 3–6× faster in mounted rerender benchmarks.
5
+ Ink-compatible React renderer for interactive terminal apps. Same `Box`, `Text`, `useInput` API you know. up to 20× faster in mounted rerender benchmarks.
6
6
 
7
7
  ```console
8
8
  $ npm install silvery react
@@ -35,7 +35,7 @@ await render(<Counter />).run()
35
35
 
36
36
  ### Shiny new stuff
37
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
38
+ - **[Best-in-class performance](https://silvery.dev/guide/silvery-vs-ink#performance-size)** — up to 20× 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
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
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
41
  - [Scroll containers](https://silvery.dev/guide/scrolling) — `overflow="scroll"` with virtualization
package/bin/silvery.ts CHANGED
@@ -18,7 +18,7 @@ function findPackageRoot(startDir: string): string {
18
18
  const pkg = join(dir, "package.json")
19
19
  if (existsSync(pkg)) {
20
20
  try {
21
- const json = JSON.parse(readFileSync(pkg, "utf8"))
21
+ const json = JSON.parse(readFileSync(pkg, "utf8")) as { name?: string }
22
22
  if (json.name === "silvery") return dir
23
23
  } catch {}
24
24
  }
@@ -37,7 +37,7 @@ const args = process.argv.slice(2)
37
37
  const examplesCli = resolve(root, "packages/examples/bin/cli.ts")
38
38
 
39
39
  if (args.includes("--version") || args.includes("-v")) {
40
- const pkg = JSON.parse(readFileSync(resolve(root, "package.json"), "utf8"))
40
+ const pkg = JSON.parse(readFileSync(resolve(root, "package.json"), "utf8")) as { version?: string }
41
41
  console.log(`silvery ${pkg.version}`)
42
42
  process.exit(0)
43
43
  }