From d05d67e4e692b2c18dbb6987b273e9554e8764b5 Mon Sep 17 00:00:00 2001 From: Brian M Hunt Date: Wed, 15 Apr 2026 18:43:37 -0400 Subject: [PATCH 1/8] Add browser script tabs (ESM / Classic) to landing page Co-Authored-By: Claude Opus 4.6 (1M context) --- tko.io/src/content/docs/index.mdx | 37 +++++++++++++++++-------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/tko.io/src/content/docs/index.mdx b/tko.io/src/content/docs/index.mdx index fc9b3498..ab600f12 100644 --- a/tko.io/src/content/docs/index.mdx +++ b/tko.io/src/content/docs/index.mdx @@ -17,23 +17,26 @@ import { Tabs, TabItem } from '@astrojs/starlight/components'; ## Quick start -### Script tag (global) - -```html - - -``` - -### ES module (browser) - -```html - -``` +### Browser + + + + ```html + + ``` + + + ```html + + + ``` + + ### Package manager From 578deb2dcae3120536f478f68e468bff1f8383e9 Mon Sep 17 00:00:00 2001 From: Brian M Hunt Date: Thu, 16 Apr 2026 05:35:10 -0400 Subject: [PATCH 2/8] Fix mobile sidebar, add examples to What's Next - Fix transparent sidebar on mobile (unreadable over content) - Add Examples card to What to Read Next section Co-Authored-By: Claude Opus 4.6 (1M context) --- tko.io/src/content/docs/index.mdx | 5 +++++ tko.io/src/styles/tko.css | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/tko.io/src/content/docs/index.mdx b/tko.io/src/content/docs/index.mdx index ab600f12..a97e9551 100644 --- a/tko.io/src/content/docs/index.mdx +++ b/tko.io/src/content/docs/index.mdx @@ -121,6 +121,11 @@ For the modern TSX / `ko-*` path, use `@tko/build.reference` instead.

Components

Reusable UI, loading strategies, and component architecture.

+ + See it in action +

Examples

+

Interactive demos: todo app, spreadsheet, animated transitions, and more.

+
## Community diff --git a/tko.io/src/styles/tko.css b/tko.io/src/styles/tko.css index 10faa4c0..34ed3db3 100644 --- a/tko.io/src/styles/tko.css +++ b/tko.io/src/styles/tko.css @@ -487,6 +487,10 @@ header { } @media (max-width: 50rem) { + .sidebar-pane { + background: var(--sl-color-black); + } + .content-panel .sl-container, .right-sidebar-panel .sl-container { border-radius: 1rem; From df0f9e04570c8e83735ef7a40cdbabc5f9d3cbdf Mon Sep 17 00:00:00 2001 From: Brian M Hunt Date: Thu, 16 Apr 2026 05:38:34 -0400 Subject: [PATCH 3/8] Fix mobile sidebar: stop overriding Starlight's background The transparent background rule was applied to .sidebar-pane, overriding Starlight's built-in solid background on mobile. Remove .sidebar-pane from the transparent rule so the mobile overlay sidebar is readable. Co-Authored-By: Claude Opus 4.6 (1M context) --- tko.io/src/styles/tko.css | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tko.io/src/styles/tko.css b/tko.io/src/styles/tko.css index 34ed3db3..399b2197 100644 --- a/tko.io/src/styles/tko.css +++ b/tko.io/src/styles/tko.css @@ -128,8 +128,7 @@ header { .sidebar, .right-sidebar-panel, -.content-panel, -.sidebar-pane { +.content-panel { background: transparent; } @@ -487,10 +486,6 @@ header { } @media (max-width: 50rem) { - .sidebar-pane { - background: var(--sl-color-black); - } - .content-panel .sl-container, .right-sidebar-panel .sl-container { border-radius: 1rem; From 77afe3baac8280cbf134e7062ddca4556b8c4386 Mon Sep 17 00:00:00 2001 From: Brian M Hunt Date: Thu, 16 Apr 2026 08:44:32 -0400 Subject: [PATCH 4/8] Make version the hero heading on landing page Co-Authored-By: Claude Opus 4.6 (1M context) --- tko.io/src/content/docs/index.mdx | 4 ++-- tko.io/src/styles/tko.css | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tko.io/src/content/docs/index.mdx b/tko.io/src/content/docs/index.mdx index a97e9551..14f84cdd 100644 --- a/tko.io/src/content/docs/index.mdx +++ b/tko.io/src/content/docs/index.mdx @@ -6,8 +6,8 @@ description: Modern Knockout — reactive data binding and UI templating with ze import { Tabs, TabItem } from '@astrojs/starlight/components';
-

TKO v4.0.1

-

Modern Knockout, clarified

+

TKO v4.0.1

+

Modern Knockout, clarified

Reactive data binding and UI templating with zero runtime dependencies. Start with the package you need and move from overview to working bindings.

Start with bindings diff --git a/tko.io/src/styles/tko.css b/tko.io/src/styles/tko.css index 399b2197..10c8efd4 100644 --- a/tko.io/src/styles/tko.css +++ b/tko.io/src/styles/tko.css @@ -257,7 +257,15 @@ header { color: var(--sl-color-text-accent); } -.landing-hero h2 { +.landing-version { + margin: 0 0 0.3rem; + font-family: var(--tko-font-display); + font-size: clamp(2rem, 5vw, 3.2rem); + font-weight: 700; + color: var(--sl-color-white); +} + +.landing-hero h2:not(.landing-version) { margin: 0; max-width: 11ch; font-size: clamp(1.55rem, 3.7vw, 2.55rem); From 720a6bd6f816347f2d7bf7c5df81d1e71b3a3416 Mon Sep 17 00:00:00 2001 From: Brian M Hunt Date: Thu, 16 Apr 2026 08:45:14 -0400 Subject: [PATCH 5/8] Fix examples card copy to match actual demos Co-Authored-By: Claude Opus 4.6 (1M context) --- tko.io/src/content/docs/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tko.io/src/content/docs/index.mdx b/tko.io/src/content/docs/index.mdx index 14f84cdd..1b019639 100644 --- a/tko.io/src/content/docs/index.mdx +++ b/tko.io/src/content/docs/index.mdx @@ -124,7 +124,7 @@ For the modern TSX / `ko-*` path, use `@tko/build.reference` instead. See it in action

Examples

-

Interactive demos: todo app, spreadsheet, animated transitions, and more.

+

Interactive demos: spreadsheet, signal graph, form engine, and more.

From a022285d25fe95d5bdce28d8933143cbdaca8b9c Mon Sep 17 00:00:00 2001 From: Brian M Hunt Date: Thu, 16 Apr 2026 09:17:51 -0400 Subject: [PATCH 6/8] Default to build.reference on landing page Quick start, browser examples, and package manager tabs now use @tko/build.reference. Choose-a-build cards reordered: reference first (recommended), knockout second (migrations). Co-Authored-By: Claude Opus 4.6 (1M context) --- tko.io/src/content/docs/index.mdx | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/tko.io/src/content/docs/index.mdx b/tko.io/src/content/docs/index.mdx index 1b019639..9a9a9004 100644 --- a/tko.io/src/content/docs/index.mdx +++ b/tko.io/src/content/docs/index.mdx @@ -23,16 +23,16 @@ import { Tabs, TabItem } from '@astrojs/starlight/components'; ```html ``` ```html - + ``` @@ -43,27 +43,27 @@ import { Tabs, TabItem } from '@astrojs/starlight/components'; ```sh - npm install @tko/build.knockout + npm install @tko/build.reference ``` ```sh - bun add @tko/build.knockout + bun add @tko/build.reference ``` ```sh - pnpm add @tko/build.knockout + pnpm add @tko/build.reference ``` ```sh - yarn add @tko/build.knockout + yarn add @tko/build.reference ``` -For the modern TSX / `ko-*` path, use `@tko/build.reference` instead. +For Knockout 3.x compatibility, use `@tko/build.knockout` instead. ## First binding example @@ -76,8 +76,9 @@ For the modern TSX / `ko-*` path, use `@tko/build.reference` instead.

Hello, .

- + ``` @@ -85,16 +86,16 @@ For the modern TSX / `ko-*` path, use `@tko/build.reference` instead. ## Choose a build ## What stays familiar From bc9149bc12589e664dd7ffc36e543351f01831e5 Mon Sep 17 00:00:00 2001 From: Brian M Hunt Date: Thu, 16 Apr 2026 09:58:47 -0400 Subject: [PATCH 7/8] Address PR review feedback and improve honeycomb perf - Gitignore .dts-tmp/, .nx/, .vitest-attachments/ build artifacts - Use general wording for Examples card instead of naming specific demos - Scope .landing-version CSS to .landing-hero for tighter isolation - Throttle honeycomb hover to one update per animation frame - Cancel in-progress click waterfall before starting a new one Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 3 ++ tko.io/public/examples/honeycomb.html | 48 +++++++++++++++++++-------- tko.io/src/content/docs/index.mdx | 2 +- tko.io/src/styles/tko.css | 2 +- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 048fd577..2e2c2be6 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ builds/**/meta test-results/ .claude/worktrees/ __screenshots__ +.dts-tmp/ +.nx/ +.vitest-attachments/ diff --git a/tko.io/public/examples/honeycomb.html b/tko.io/public/examples/honeycomb.html index 3b22a442..875575f4 100644 --- a/tko.io/public/examples/honeycomb.html +++ b/tko.io/public/examples/honeycomb.html @@ -557,34 +557,54 @@

Honeycomb

lastKey: ko.observable(null), activeSource: null, activeNeighbors: [], + _pendingHover: null, + _hoverRaf: 0, + _clickRaf: 0, hoverCell(cell) { if (!cell.interactive || cell.key === viewModel.lastKey()) return true - if (viewModel.activeSource) { - viewModel.activeSource.source(false) - } - viewModel.activeNeighbors.forEach(neighbor => neighbor.neighbor(false)) + viewModel._pendingHover = cell + if (!viewModel._hoverRaf) { + viewModel._hoverRaf = requestAnimationFrame(() => { + viewModel._hoverRaf = 0 + const target = viewModel._pendingHover + if (!target) return + + if (viewModel.activeSource) { + viewModel.activeSource.source(false) + } + viewModel.activeNeighbors.forEach(neighbor => neighbor.neighbor(false)) - viewModel.lastKey(cell.key) - viewModel.activeSource = cell - viewModel.activeNeighbors = cell.neighbors + viewModel.lastKey(target.key) + viewModel.activeSource = target + viewModel.activeNeighbors = target.neighbors - cell.source(true) - cell.neighbors.forEach(neighbor => neighbor.neighbor(true)) + target.source(true) + target.neighbors.forEach(neighbor => neighbor.neighbor(true)) - viewModel.vdomCount(viewModel.vdomCount() + viewModel.totalVisible()) - viewModel.obsCount(viewModel.obsCount() + cell.neighbors.length) + viewModel.vdomCount(viewModel.vdomCount() + viewModel.totalVisible()) + viewModel.obsCount(viewModel.obsCount() + target.neighbors.length) + }) + } return true }, clickCell(cell) { if (!cell.interactive) return true + if (viewModel._clickRaf) { + cancelAnimationFrame(viewModel._clickRaf) + viewModel._clickRaf = 0 + } + const queue = buildWaterfallQueue(cell, cells) let index = 0 const batchSize = 24 function advanceBurst() { - if (index >= queue.length) return + if (index >= queue.length) { + viewModel._clickRaf = 0 + return + } let touched = 0 while (index < queue.length && touched < batchSize) { @@ -604,10 +624,10 @@

Honeycomb

viewModel.vdomCount(viewModel.vdomCount() + touched * viewModel.totalVisible()) viewModel.obsCount(viewModel.obsCount() + touched) - requestAnimationFrame(advanceBurst) + viewModel._clickRaf = requestAnimationFrame(advanceBurst) } - requestAnimationFrame(advanceBurst) + viewModel._clickRaf = requestAnimationFrame(advanceBurst) return true } } diff --git a/tko.io/src/content/docs/index.mdx b/tko.io/src/content/docs/index.mdx index 9a9a9004..70d85db8 100644 --- a/tko.io/src/content/docs/index.mdx +++ b/tko.io/src/content/docs/index.mdx @@ -125,7 +125,7 @@ For Knockout 3.x compatibility, use `@tko/build.knockout` instead. See it in action

Examples

-

Interactive demos: spreadsheet, signal graph, form engine, and more.

+

Interactive demos showing observable updates, dependency graphs, and reactive state.

diff --git a/tko.io/src/styles/tko.css b/tko.io/src/styles/tko.css index 10c8efd4..46c612d7 100644 --- a/tko.io/src/styles/tko.css +++ b/tko.io/src/styles/tko.css @@ -257,7 +257,7 @@ header { color: var(--sl-color-text-accent); } -.landing-version { +.landing-hero .landing-version { margin: 0 0 0.3rem; font-family: var(--tko-font-display); font-size: clamp(2rem, 5vw, 3.2rem); From 0e1e8de89d60b0ad03a75ece1c3e599ab43f8c9c Mon Sep 17 00:00:00 2001 From: Brian M Hunt Date: Thu, 16 Apr 2026 10:02:00 -0400 Subject: [PATCH 8/8] Parallelize browser tests across CI matrix jobs Run chromium, firefox, and webkit as separate concurrent jobs instead of sequentially in one job. Should cut wall time ~3x. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/test-headless.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-headless.yml b/.github/workflows/test-headless.yml index 0ada8bcd..0a77dfa1 100644 --- a/.github/workflows/test-headless.yml +++ b/.github/workflows/test-headless.yml @@ -8,6 +8,10 @@ on: jobs: test: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + browser: [chromium, firefox, webkit] container: image: mcr.microsoft.com/playwright:v1.59.1-noble @@ -36,4 +40,4 @@ jobs: run: bunx vitest run env: HOME: /root - VITEST_BROWSERS: chromium,firefox,webkit + VITEST_BROWSERS: ${{ matrix.browser }}