diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 306957b7..c0efb76c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -38,7 +38,7 @@ jobs:
publish:
needs: build
runs-on: ubuntu-latest
- if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
@@ -53,9 +53,14 @@ jobs:
run: npm ci
- name: Build packages
- run: npm run build
+ run: npm run build:packages
+
+ - name: Publish @computekit/core
+ run: cd packages/core && npm publish --access public || echo "Already published or failed"
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- - name: Publish to npm
- run: npm publish --workspaces --access public
+ - name: Publish @computekit/react
+ run: cd packages/react && npm publish --access public || echo "Already published or failed"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 00000000..ed54dde4
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,45 @@
+name: Deploy Documentation to GitHub Pages
+
+on:
+ push:
+ branches: [main]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: 'pages'
+ cancel-in-progress: false
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v4
+
+ - name: Build with Jekyll
+ uses: actions/jekyll-build-pages@v1
+ with:
+ source: ./docs
+ destination: ./_site
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ permissions:
+ pages: write
+ id-token: write
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 00000000..79990136
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,43 @@
+name: Publish to npm
+
+on:
+ workflow_dispatch:
+ push:
+ branches: [main]
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Use Node.js 22.x
+ uses: actions/setup-node@v4
+ with:
+ node-version: 22.x
+ registry-url: 'https://registry.npmjs.org'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build packages
+ run: npm run build:packages
+
+ - name: Publish @computekit/core
+ run: cd packages/core && npm publish --access public
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ continue-on-error: true
+
+ - name: Publish @computekit/react
+ run: cd packages/react && npm publish --access public
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ continue-on-error: true
+
+ - name: Publish @computekit/react-query
+ run: cd packages/react-query && npm publish --access public
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ continue-on-error: true
diff --git a/.gitignore b/.gitignore
index 07a84104..6b2d1c36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,9 @@ build/
*.wasm
*.wasm.map
+# But include the demo WASM file for StackBlitz
+!examples/react-demo/public/compute.wasm
+
# IDE
.idea/
.vscode/
@@ -30,6 +33,9 @@ yarn-error.log*
.env.local
.env.*.local
+# npm tokens - NEVER commit these!
+.npmrc
+
# Temporary files
*.tmp
*.temp
diff --git a/README.md b/README.md
index 30f3f7e6..3c6d4e50 100644
--- a/README.md
+++ b/README.md
@@ -3,16 +3,18 @@
# ComputeKit
- **The React-first toolkit for WASM and Web Workers**
+ **A tiny toolkit for heavy computations using Web Workers**
- *Run heavy computations with React hooks. Use WASM for native-speed performance. Keep your UI at 60fps.*
+ *Integration with React hooks and WASM*
[](https://www.npmjs.com/package/@computekit/core)
-[](https://bundlephobia.com/package/@computekit/core)
+[](https://bundlephobia.com/package/@computekit/core)
+[](https://bundlephobia.com/package/@computekit/react)
[](https://opensource.org/licenses/MIT)
[](https://www.typescriptlang.org/)
+[](https://stackblitz.com/edit/compute-kit?file=README.md)
-[Getting Started](#-getting-started) • [Examples](#-examples) • [API](#-api) • [React Hooks](#-react-hooks) • [WASM](#-webassembly-support)
+[📚 Documentation](https://tapava.github.io/compute-kit) • [Live Demo](https://computekit-demo.vercel.app/) • [Getting Started](#-getting-started) • [Examples](#-examples) • [API](#-api) • [React Hooks](#-react-hooks) • [WASM](#-webassembly-support)
@@ -20,14 +22,14 @@
## ✨ Features
-- ⚛️ **React-first** — Purpose-built hooks like `useCompute` with loading, error, and progress states
-- 🦀 **WASM integration** — Load and call AssemblyScript/Rust WASM modules with zero boilerplate
-- 🚀 **Non-blocking** — Everything runs in Web Workers, keeping your UI at 60fps
-- 🔧 **Zero config** — No manual worker files, postMessage handlers, or WASM glue code
-- 📦 **Tiny** — Core library is ~3KB gzipped
-- 🎯 **TypeScript** — Full type safety for your compute functions and WASM bindings
-- 🔄 **Worker pool** — Automatic load balancing across CPU cores
-- 📊 **Progress tracking** — Built-in progress reporting for long-running tasks
+- 🔄 **Worker pool** : Automatic load balancing across CPU cores
+- ⚛️ **React-first** : Provides hooks like `useCompute` with loading, error, and progress states
+- 🦀 **WASM integration** : Easily load and call AssemblyScript/Rust WASM modules
+- 🚀 **Non-blocking** : Everything runs in Web Workers
+- 🔧 **Zero config** : No manual worker files or postMessage handlers
+- 📦 **Tiny** : Core library is ~5KB gzipped
+- 🎯 **TypeScript** : Full type safety for your compute functions and WASM bindings
+- 📊 **Progress tracking** : Built-in progress reporting for long-running tasks
---
@@ -48,7 +50,7 @@ You _can_ use Web Workers and WASM without a library. But here's the reality:
---
-## 🎯 When to use ComputeKit
+## 🎯 When to use this toolkit (And when not to use it)
| ✅ Use ComputeKit | ❌ Don't use ComputeKit |
| ---------------------------------- | ---------------------------- |
@@ -102,7 +104,7 @@ kit.register('fibonacci', (n: number) => {
// 3. Run it (non-blocking!)
const result = await kit.run('fibonacci', 50);
-console.log(result); // 12586269025 — UI never froze!
+console.log(result); // 12586269025 : UI never froze!
```
### React Usage
@@ -158,7 +160,7 @@ function Calculator() {
### React + WASM (Full Example)
-This is where ComputeKit shines — combining `useCompute` with WASM for native-speed performance:
+This is where ComputeKit shines : combining `useCompute` with WASM for native-speed performance:
```tsx
import { ComputeKitProvider, useComputeKit, useCompute } from '@computekit/react';
@@ -252,7 +254,7 @@ function ImageProcessor() {
**Key benefits:**
-- WASM runs in a Web Worker via `useCompute` — UI stays responsive
+- WASM runs in a Web Worker via `useCompute` : UI stays responsive
- Same familiar `loading`, `data`, `error` pattern as other compute functions
- WASM memory management encapsulated in the registered function
- Can easily add progress reporting, cancellation, etc.
@@ -323,11 +325,29 @@ const kit = new ComputeKit(options?: ComputeKitOptions);
#### Options
-| Option | Type | Default | Description |
-| ------------ | --------- | ------------------------------- | ----------------------- |
-| `maxWorkers` | `number` | `navigator.hardwareConcurrency` | Max workers in the pool |
-| `timeout` | `number` | `30000` | Default timeout in ms |
-| `debug` | `boolean` | `false` | Enable debug logging |
+| Option | Type | Default | Description |
+| -------------------- | ---------- | ------------------------------- | ----------------------------------- |
+| `maxWorkers` | `number` | `navigator.hardwareConcurrency` | Max workers in the pool |
+| `timeout` | `number` | `30000` | Default timeout in ms |
+| `debug` | `boolean` | `false` | Enable debug logging |
+| `remoteDependencies` | `string[]` | `[]` | External scripts to load in workers |
+
+### Remote Dependencies
+
+Load external libraries inside your workers:
+
+```typescript
+const kit = new ComputeKit({
+ remoteDependencies: [
+ 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js',
+ ],
+});
+
+kit.register('processData', (data: number[]) => {
+ // @ts-ignore - lodash loaded via importScripts
+ return _.chunk(data, 3);
+});
+```
#### Methods
@@ -363,12 +383,15 @@ const {
loading, // Boolean loading state
error, // Error if failed
progress, // Progress info
+ status, // 'idle' | 'running' | 'success' | 'error' | 'cancelled'
run, // Function to execute
reset, // Reset state
cancel, // Cancel current operation
} = useCompute(functionName, options?);
```
+````
+
### `useComputeCallback`
Returns a memoized async function (similar to `useCallback`).
@@ -376,7 +399,7 @@ Returns a memoized async function (similar to `useCallback`).
```typescript
const calculate = useComputeCallback('sum');
const result = await calculate([1, 2, 3, 4, 5]);
-```
+````
### `usePoolStats`
@@ -433,13 +456,13 @@ const wasmModule = await loadWasmModule('/compute/sum.wasm');
## ⚡ Performance Tips
-1. **Transfer large data** — Use typed arrays (Uint8Array, Float64Array) for automatic transfer optimization
+1. **Transfer large data** : Use typed arrays (Uint8Array, Float64Array) for automatic transfer optimization
-2. **Batch small operations** — Combine many small tasks into one larger task
+2. **Batch small operations** : Combine many small tasks into one larger task
-3. **Right-size your pool** — More workers ≠ better. Match to CPU cores.
+3. **Right-size your pool** : More workers ≠ better. Match to CPU cores.
-4. **Use WASM for math** — AssemblyScript functions can be 10-100x faster for numeric work
+4. **Use WASM for math** : AssemblyScript functions can be 10-100x faster for numeric work
```typescript
// ❌ Slow: Many small calls
@@ -500,13 +523,14 @@ computekit/
│ └── package.json
│
├── compute/ # AssemblyScript functions
+│ ├── blur.ts
│ ├── fibonacci.ts
│ ├── mandelbrot.ts
-│ └── matrix.ts
+│ ├── matrix.ts
+│ └── sum.ts
│
├── examples/
-│ ├── react-demo/ # React example app
-│ └── vanilla-demo/ # Vanilla JS example
+│ └── react-demo/ # React example app
│
└── docs/ # Documentation
```
@@ -519,8 +543,8 @@ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md)
```bash
# Clone the repo
-git clone https://github.com/your-username/computekit.git
-cd computekit
+git clone https://github.com/tapava/compute-kit.git
+cd compute-kit
# Install dependencies
npm install
@@ -539,7 +563,7 @@ npm test
## 📄 License
-MIT © [Your Name](https://github.com/your-username)
+MIT © [Ghassen Lassoued](https://github.com/tapava)
---
@@ -548,6 +572,7 @@ MIT © [Your Name](https://github.com/your-username)
Built with ❤️ for the web platform
- ⭐ Star on GitHub
+ 📚 Read the Docs •
+ ⭐ Star on GitHub
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 00000000..c806272a
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,26 @@
+# ComputeKit TODO
+
+## Features
+
+- [ ] **Progress throttling** - Add optional `progressThrottle` option to prevent state flooding when compute functions fire progress updates in tight loops. Should throttle/debounce progress callbacks to avoid choking the main thread with re-renders.
+ - Add `progressThrottle?: number` option (ms) to `ComputeOptions`
+ - Throttle `onProgress` calls in the React hook
+ - Consider both throttle (regular intervals) and debounce (wait for pause) strategies
+
+- [ ] **Typed registry** - Add TypeScript support to narrow function names to only registered functions for autocomplete and type safety.
+ - Make `useCompute('functionName')` autocomplete only registered function names
+ - Type safety on input/output based on registered function signatures
+ - Consider using TypeScript's string literal types or const assertions
+
+## Improvements
+
+- [ ] Add more WASM examples (Rust, C++)
+- [ ] Benchmark suite for comparing JS vs WASM performance
+- [ ] Documentation site (Docusaurus or similar)
+
+## Ideas
+
+- [ ] `useComputeMultiple` hook for managing multiple parallel tasks
+- [ ] `useComputeFile` hook for loading functions from separate files
+- [ ] Built-in caching for compute results
+- [ ] Streaming results for very large outputs
diff --git a/packages/wasm/assembly/index.ts b/compute/blur.ts
similarity index 100%
rename from packages/wasm/assembly/index.ts
rename to compute/blur.ts
diff --git a/compute/index.ts b/compute/index.ts
index 9bfc9f17..8a25f047 100644
--- a/compute/index.ts
+++ b/compute/index.ts
@@ -15,3 +15,4 @@ export {
vectorMagnitude,
vectorNormalize,
} from './matrix';
+export { getBufferPtr, blurImage } from './blur';
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000..e913d3b1
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,6 @@
+# Ignore Jekyll build output
+_site/
+.sass-cache/
+.jekyll-cache/
+.jekyll-metadata
+vendor/
diff --git a/docs/Gemfile b/docs/Gemfile
new file mode 100644
index 00000000..23ecc604
--- /dev/null
+++ b/docs/Gemfile
@@ -0,0 +1,6 @@
+source "https://rubygems.org"
+
+gem "jekyll", "~> 4.3"
+gem "just-the-docs", "~> 0.8"
+gem "jekyll-seo-tag"
+gem "jekyll-include-cache"
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 00000000..62f77d1c
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,67 @@
+title: ComputeKit
+description: The React-first toolkit for WASM and Web Workers
+url: 'https://tapava.github.io'
+baseurl: '/compute-kit'
+
+remote_theme: just-the-docs/just-the-docs@v0.8.2
+
+color_scheme: light
+
+logo: '/assets/logo.svg'
+
+aux_links:
+ GitHub: https://github.com/tapava/compute-kit
+ npm: https://www.npmjs.com/package/@computekit/core
+
+aux_links_new_tab: true
+
+heading_anchors: true
+
+search_enabled: true
+search:
+ heading_level: 2
+ previews: 3
+ preview_words_before: 5
+ preview_words_after: 10
+ tokenizer_separator: /[\s/]+/
+ rel_url: true
+ button: false
+
+nav_enabled: true
+nav_sort: case_insensitive
+
+back_to_top: true
+back_to_top_text: 'Back to top'
+
+footer_content: 'Copyright © 2024-2025 Ghassen Lassoued. Distributed under the MIT license.'
+
+ga_tracking:
+ga_tracking_anonymize_ip: true
+
+callouts:
+ warning:
+ title: Warning
+ color: yellow
+ note:
+ title: Note
+ color: blue
+ tip:
+ title: Tip
+ color: green
+
+plugins:
+ - jekyll-seo-tag
+ - jekyll-include-cache
+
+kramdown:
+ syntax_highlighter_opts:
+ block:
+ line_numbers: false
+
+compress_html:
+ clippings: all
+ comments: all
+ endings: all
+ startings: []
+ blanklines: false
+ profile: false
diff --git a/docs/_sass/custom/custom.scss b/docs/_sass/custom/custom.scss
new file mode 100644
index 00000000..952f62a1
--- /dev/null
+++ b/docs/_sass/custom/custom.scss
@@ -0,0 +1,612 @@
+// Modern ComputeKit Theme - Inspired by TanStack
+// Clean, professional, and readable
+
+// Import Inter font for modern typography
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
+
+// Root variables
+:root {
+ // Colors - Modern purple/blue accent like TanStack
+ --color-primary: #7c3aed;
+ --color-primary-light: #a78bfa;
+ --color-primary-dark: #5b21b6;
+ --color-accent: #06b6d4;
+
+ // Background
+ --color-bg: #ffffff;
+ --color-bg-secondary: #f8fafc;
+ --color-bg-tertiary: #f1f5f9;
+
+ // Text
+ --color-text: #1e293b;
+ --color-text-secondary: #64748b;
+ --color-text-muted: #94a3b8;
+
+ // Borders
+ --color-border: #e2e8f0;
+ --color-border-light: #f1f5f9;
+
+ // Code
+ --color-code-bg: #f8fafc;
+ --color-code-border: #e2e8f0;
+
+ // Shadows
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
+
+ // Fonts
+ --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+ --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', monospace;
+}
+
+// Base typography
+body {
+ font-family: var(--font-body) !important;
+ font-size: 16px;
+ line-height: 1.7;
+ color: var(--color-text);
+ background-color: var(--color-bg);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+// Headings
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.site-title {
+ font-family: var(--font-body) !important;
+ font-weight: 700;
+ color: var(--color-text);
+ letter-spacing: -0.02em;
+}
+
+h1 {
+ font-size: 2.5rem !important;
+ margin-bottom: 1rem;
+}
+
+h2 {
+ font-size: 1.75rem !important;
+ margin-top: 2.5rem;
+ padding-bottom: 0.5rem;
+ border-bottom: 1px solid var(--color-border);
+}
+
+h3 {
+ font-size: 1.35rem !important;
+ margin-top: 2rem;
+}
+
+// Sidebar styles
+.side-bar {
+ background-color: var(--color-bg-secondary) !important;
+ border-right: 1px solid var(--color-border);
+}
+
+.site-title {
+ font-size: 1.25rem !important;
+ font-weight: 700 !important;
+ color: var(--color-primary) !important;
+}
+
+.site-logo {
+ max-height: 2.5rem;
+}
+
+// Navigation
+.nav-list {
+ font-size: 0.9rem;
+
+ .nav-list-item {
+ margin: 0;
+
+ .nav-list-link {
+ padding: 0.5rem 1rem;
+ border-radius: 0.5rem;
+ margin: 0.125rem 0.5rem;
+ color: var(--color-text-secondary);
+ font-weight: 500;
+ transition: all 0.15s ease;
+
+ &:hover {
+ background-color: var(--color-bg-tertiary);
+ color: var(--color-primary);
+ }
+
+ &.active {
+ background-color: rgba(124, 58, 237, 0.1);
+ color: var(--color-primary);
+ font-weight: 600;
+ }
+ }
+ }
+}
+
+// Main content
+.main {
+ background-color: var(--color-bg);
+}
+
+.main-content {
+ max-width: 52rem;
+ padding: 2rem 3rem;
+
+ p {
+ margin-bottom: 1.25rem;
+ color: var(--color-text);
+ }
+
+ a {
+ color: var(--color-primary);
+ text-decoration: none;
+ font-weight: 500;
+
+ &:hover {
+ text-decoration: underline;
+ color: var(--color-primary-dark);
+ }
+ }
+}
+
+// Code blocks
+code {
+ font-family: var(--font-mono) !important;
+ font-size: 0.875em;
+ background-color: var(--color-code-bg);
+ padding: 0.2em 0.4em;
+ border-radius: 0.375rem;
+ color: var(--color-primary-dark);
+}
+
+pre {
+ background-color: #0d1117 !important;
+ border: none !important;
+ border-radius: 0.75rem !important;
+ padding: 1.25rem !important;
+ margin: 1.5rem 0 !important;
+ box-shadow: var(--shadow-md);
+ overflow-x: auto;
+
+ code {
+ background-color: transparent !important;
+ color: #e6edf3 !important;
+ padding: 0;
+ font-size: 0.875rem;
+ line-height: 1.6;
+ }
+}
+
+// Syntax highlighting - GitHub Dark theme (high contrast)
+.highlight {
+ background-color: #0d1117 !important;
+ border-radius: 0.75rem;
+
+ // Plain text
+ .p,
+ .w {
+ color: #e6edf3;
+ }
+
+ // Comments
+ .c,
+ .c1,
+ .cm,
+ .cs,
+ .cp {
+ color: #8b949e;
+ font-style: italic;
+ }
+
+ // Keywords (import, from, const, function, async, await, return)
+ .k,
+ .kd,
+ .kn,
+ .kp,
+ .kr,
+ .kc,
+ .kt {
+ color: #ff7b72;
+ }
+
+ // Strings
+ .s,
+ .s1,
+ .s2,
+ .sb,
+ .sc,
+ .sd,
+ .se,
+ .sh,
+ .si,
+ .sx,
+ .sr,
+ .ss {
+ color: #a5d6ff;
+ }
+
+ // Function names and method calls
+ .nf,
+ .fm {
+ color: #d2a8ff;
+ }
+
+ // Class names and types
+ .nc,
+ .nn,
+ .nx {
+ color: #ffa657;
+ }
+
+ // Variables and identifiers
+ .n,
+ .na,
+ .nb,
+ .ni,
+ .nl,
+ .no,
+ .nv,
+ .ne,
+ .nd {
+ color: #e6edf3;
+ }
+
+ // HTML/JSX tags
+ .nt {
+ color: #7ee787;
+ }
+
+ // Numbers
+ .m,
+ .mf,
+ .mh,
+ .mi,
+ .mo,
+ .il {
+ color: #79c0ff;
+ }
+
+ // Operators
+ .o,
+ .ow {
+ color: #ff7b72;
+ }
+
+ // Punctuation (braces, parentheses, etc)
+ .p {
+ color: #e6edf3;
+ }
+
+ // Property names
+ .py,
+ .na {
+ color: #79c0ff;
+ }
+
+ // Special - imports and exports
+ .kn {
+ color: #ff7b72;
+ }
+
+ // Decorators
+ .nd {
+ color: #d2a8ff;
+ }
+
+ // Built-in functions
+ .nb {
+ color: #ffa657;
+ }
+
+ // Error
+ .err {
+ color: #ffa198;
+ background-color: transparent;
+ }
+}
+
+// Tables
+table {
+ border-collapse: collapse;
+ width: 100%;
+ margin: 1.5rem 0;
+ font-size: 0.9rem;
+ border-radius: 0.5rem;
+ overflow: hidden;
+ box-shadow: var(--shadow-sm);
+ border: 1px solid var(--color-border);
+}
+
+th {
+ background-color: var(--color-bg-tertiary);
+ font-weight: 600;
+ text-align: left;
+ padding: 0.75rem 1rem;
+ border-bottom: 2px solid var(--color-border);
+}
+
+td {
+ padding: 0.75rem 1rem;
+ border-bottom: 1px solid var(--color-border-light);
+}
+
+tr:last-child td {
+ border-bottom: none;
+}
+
+tr:hover {
+ background-color: var(--color-bg-secondary);
+}
+
+// Buttons
+.btn {
+ font-family: var(--font-body);
+ font-weight: 600;
+ font-size: 0.9rem;
+ padding: 0.625rem 1.25rem;
+ border-radius: 0.5rem;
+ transition: all 0.15s ease;
+ text-decoration: none !important;
+}
+
+.btn-primary {
+ background-color: var(--color-primary) !important;
+ color: white !important;
+ border: none;
+ box-shadow: var(--shadow-sm);
+
+ &:hover {
+ background-color: var(--color-primary-dark) !important;
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-md);
+ }
+}
+
+// Callouts
+.warning,
+.note,
+.tip {
+ border-radius: 0.75rem;
+ padding: 1rem 1.25rem;
+ margin: 1.5rem 0;
+ border-left: 4px solid;
+
+ p:last-child {
+ margin-bottom: 0;
+ }
+}
+
+.note {
+ background-color: #eff6ff;
+ border-left-color: #3b82f6;
+}
+
+.warning {
+ background-color: #fef3c7;
+ border-left-color: #f59e0b;
+}
+
+.tip {
+ background-color: #ecfdf5;
+ border-left-color: #10b981;
+}
+
+// Search
+.search {
+ position: relative;
+ margin-bottom: 1rem;
+ padding: 0 1rem;
+}
+
+.search-input-wrap {
+ display: flex;
+ align-items: center;
+ position: relative;
+}
+
+.search-input {
+ font-family: var(--font-body);
+ width: 100%;
+ padding: 0.625rem 1rem 0.625rem 2.5rem;
+ font-size: 0.9rem;
+ background-color: var(--color-bg);
+ border: 1px solid var(--color-border);
+ border-radius: 0.5rem;
+ color: var(--color-text);
+ transition: all 0.15s ease;
+
+ &::placeholder {
+ color: var(--color-text-muted);
+ }
+
+ &:focus {
+ border-color: var(--color-primary);
+ box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
+ outline: none;
+ }
+}
+
+.search-label {
+ position: absolute;
+ left: 0.75rem;
+ top: 50%;
+ transform: translateY(-50%);
+ color: var(--color-text-muted);
+ pointer-events: none;
+
+ .search-icon {
+ width: 1rem;
+ height: 1rem;
+ }
+}
+
+.search-results {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ right: 0;
+ margin-top: 0.5rem;
+ background-color: var(--color-bg);
+ border: 1px solid var(--color-border);
+ border-radius: 0.5rem;
+ box-shadow: var(--shadow-md);
+ max-height: 20rem;
+ overflow-y: auto;
+ z-index: 100;
+}
+
+.search-results-list {
+ list-style: none;
+ padding: 0.5rem;
+ margin: 0;
+}
+
+.search-results-list-item {
+ padding: 0.5rem 0.75rem;
+ border-radius: 0.375rem;
+ cursor: pointer;
+
+ &:hover,
+ &.active {
+ background-color: var(--color-bg-tertiary);
+ }
+}
+
+.search-result-title {
+ font-weight: 600;
+ color: var(--color-text);
+ font-size: 0.9rem;
+}
+
+.search-result-doc {
+ font-size: 0.8rem;
+ color: var(--color-text-secondary);
+ margin-top: 0.125rem;
+
+ .search-result-doc-title {
+ font-weight: 500;
+ }
+}
+
+.search-result-previews {
+ font-size: 0.8rem;
+ color: var(--color-text-muted);
+ margin-top: 0.25rem;
+}
+
+.search-result-preview + .search-result-preview {
+ margin-top: 0.125rem;
+}
+
+.search-result-highlight {
+ background-color: rgba(124, 58, 237, 0.15);
+ color: var(--color-primary-dark);
+ padding: 0.125em 0.25em;
+ border-radius: 0.25rem;
+}
+
+.search-no-result {
+ padding: 1rem;
+ text-align: center;
+ color: var(--color-text-muted);
+ font-size: 0.9rem;
+}
+
+// TOC
+.toc {
+ background-color: var(--color-bg-secondary);
+ border-radius: 0.75rem;
+ padding: 1rem 1.25rem;
+ border: 1px solid var(--color-border);
+}
+
+// Footer
+.site-footer {
+ border-top: 1px solid var(--color-border);
+ color: var(--color-text-muted);
+ font-size: 0.875rem;
+}
+
+// Aux links (GitHub, npm)
+.aux-nav {
+ .aux-nav-list-item {
+ a {
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: var(--color-text-secondary);
+
+ &:hover {
+ color: var(--color-primary);
+ }
+ }
+ }
+}
+
+// Home page hero adjustments
+.fs-9 {
+ font-size: 3rem !important;
+ font-weight: 800 !important;
+ background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-accent) 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.fs-6 {
+ font-size: 1.35rem !important;
+ color: var(--color-text-secondary) !important;
+}
+
+// Lists
+ul,
+ol {
+ margin-bottom: 1.25rem;
+
+ li {
+ margin-bottom: 0.5rem;
+
+ &::marker {
+ color: var(--color-primary);
+ }
+ }
+}
+
+// Blockquotes
+blockquote {
+ border-left: 3px solid var(--color-primary);
+ padding-left: 1rem;
+ color: var(--color-text-secondary);
+ font-style: italic;
+}
+
+// Back to top button
+.back-to-top {
+ background-color: var(--color-primary);
+ color: white;
+ border-radius: 9999px;
+ padding: 0.5rem 1rem;
+ font-size: 0.875rem;
+ font-weight: 500;
+
+ &:hover {
+ background-color: var(--color-primary-dark);
+ }
+}
+
+// Responsive
+@media (max-width: 800px) {
+ .main-content {
+ padding: 1.5rem;
+ }
+
+ h1 {
+ font-size: 2rem !important;
+ }
+
+ .fs-9 {
+ font-size: 2.25rem !important;
+ }
+}
diff --git a/docs/api-reference.md b/docs/api-reference.md
new file mode 100644
index 00000000..5635d46f
--- /dev/null
+++ b/docs/api-reference.md
@@ -0,0 +1,333 @@
+---
+layout: default
+title: API Reference
+nav_order: 4
+description: 'Complete API reference for ComputeKit'
+permalink: /api-reference
+---
+
+# API Reference
+
+{: .no_toc }
+
+Complete API documentation for the ComputeKit core library.
+{: .fs-6 .fw-300 }
+
+
+
+ Table of contents
+ {: .text-delta }
+- TOC
+{:toc}
+
+
+---
+
+## ComputeKit Class
+
+The main entry point for using ComputeKit.
+
+### Constructor
+
+```typescript
+new ComputeKit(options?: ComputeKitOptions)
+```
+
+### ComputeKitOptions
+
+| Property | Type | Default | Description |
+| -------------------- | ---------- | -------------------------------------- | ------------------------------------- |
+| `maxWorkers` | `number` | `navigator.hardwareConcurrency \|\| 4` | Maximum number of workers in the pool |
+| `timeout` | `number` | `30000` | Default timeout for operations (ms) |
+| `debug` | `boolean` | `false` | Enable debug logging |
+| `workerPath` | `string` | `''` | Custom path to worker script |
+| `useSharedMemory` | `boolean` | `true` | Use SharedArrayBuffer when available |
+| `remoteDependencies` | `string[]` | `[]` | External scripts to load in workers |
+
+---
+
+## Methods
+
+### initialize()
+
+Manually initialize the worker pool. Called automatically on first `run()`.
+
+```typescript
+const kit = new ComputeKit();
+await kit.initialize(); // Optional: eager initialization
+```
+
+### register()
+
+Register a compute function.
+
+```typescript
+register(
+ name: string,
+ fn: (input: TInput, context: ComputeContext) => TOutput | Promise
+): this
+```
+
+**Parameters:**
+
+- `name` - Unique identifier for the function
+- `fn` - The function to execute (runs in a Web Worker)
+
+**Returns:** `this` (for chaining)
+
+```typescript
+kit.register('double', (n: number) => n * 2);
+
+kit.register('asyncTask', async (data, { reportProgress }) => {
+ // Report progress during long operations
+ reportProgress({ percent: 50 });
+ return await processData(data);
+});
+
+// Chaining
+kit.register('add', (a, b) => a + b).register('multiply', (a, b) => a * b);
+```
+
+### run()
+
+Execute a registered function.
+
+```typescript
+run(
+ name: string,
+ input: TInput,
+ options?: ComputeOptions
+): Promise
+```
+
+**Parameters:**
+
+- `name` - Name of the registered function
+- `input` - Input data (will be serialized)
+- `options` - Optional execution options
+
+```typescript
+const result = await kit.run('double', 21);
+console.log(result); // 42
+```
+
+### runWithMetadata()
+
+Execute a function and receive metadata about the execution.
+
+```typescript
+runWithMetadata(
+ name: string,
+ input: TInput,
+ options?: ComputeOptions
+): Promise>
+```
+
+```typescript
+const result = await kit.runWithMetadata('heavy', data);
+console.log(`Took ${result.duration}ms on worker ${result.workerId}`);
+```
+
+### getStats()
+
+Get current worker pool statistics.
+
+```typescript
+const stats = kit.getStats();
+console.log(`Active workers: ${stats.activeWorkers}`);
+console.log(`Queue length: ${stats.queueLength}`);
+```
+
+### isWasmSupported()
+
+Check if WebAssembly is supported in the current environment.
+
+```typescript
+if (kit.isWasmSupported()) {
+ // Load WASM module
+}
+```
+
+### terminate()
+
+Terminate all workers and clean up resources.
+
+```typescript
+await kit.terminate();
+```
+
+---
+
+## ComputeOptions
+
+Options for individual compute operations.
+
+| Property | Type | Description |
+| ------------ | ------------------------------------- | ------------------------------------- |
+| `timeout` | `number` | Operation timeout in ms |
+| `transfer` | `ArrayBuffer[]` | ArrayBuffers to transfer (not copy) |
+| `priority` | `number` | Priority level (0-10, higher = first) |
+| `signal` | `AbortSignal` | Abort signal for cancellation |
+| `onProgress` | `(progress: ComputeProgress) => void` | Progress callback |
+
+```typescript
+const controller = new AbortController();
+
+await kit.run('task', data, {
+ timeout: 5000,
+ priority: 10,
+ signal: controller.signal,
+ onProgress: (p) => console.log(`${p.percent}%`),
+});
+
+// Cancel the operation
+controller.abort();
+```
+
+---
+
+## ComputeProgress
+
+Progress information for long-running tasks.
+
+| Property | Type | Description |
+| ------------------------ | ---------- | --------------------------- |
+| `percent` | `number` | Progress percentage (0-100) |
+| `phase` | `string?` | Current phase name |
+| `estimatedTimeRemaining` | `number?` | Estimated ms remaining |
+| `data` | `unknown?` | Additional custom data |
+
+---
+
+## ComputeResult
+
+Result wrapper with execution metadata.
+
+| Property | Type | Description |
+| ---------- | --------- | ------------------------------------ |
+| `data` | `T` | The computed result |
+| `duration` | `number` | Execution time in ms |
+| `cached` | `boolean` | Whether result was cached |
+| `workerId` | `string` | ID of the worker that processed this |
+
+---
+
+## PoolStats
+
+Worker pool statistics.
+
+| Property | Type | Description |
+| --------------------- | -------------- | -------------------------- |
+| `workers` | `WorkerInfo[]` | Info about each worker |
+| `totalWorkers` | `number` | Total worker count |
+| `activeWorkers` | `number` | Currently busy workers |
+| `idleWorkers` | `number` | Currently idle workers |
+| `queueLength` | `number` | Tasks waiting in queue |
+| `tasksCompleted` | `number` | Total completed tasks |
+| `tasksFailed` | `number` | Total failed tasks |
+| `averageTaskDuration` | `number` | Average task duration (ms) |
+
+---
+
+## Event Handling
+
+ComputeKit extends EventEmitter and emits events:
+
+```typescript
+kit.on('worker:created', (info) => {
+ console.log('New worker:', info.id);
+});
+
+kit.on('worker:terminated', (info) => {
+ console.log('Worker terminated:', info.id);
+});
+
+kit.on('task:start', (taskId, name) => {
+ console.log(`Starting ${name}`);
+});
+
+kit.on('task:complete', (taskId, duration) => {
+ console.log(`Done in ${duration}ms`);
+});
+
+kit.on('task:error', (taskId, error) => {
+ console.error('Task failed:', error);
+});
+
+kit.on('task:progress', (taskId, progress) => {
+ console.log(`${progress.percent}%`);
+});
+```
+
+---
+
+## Utility Functions
+
+### isWasmSupported()
+
+Check if WebAssembly is available.
+
+```typescript
+import { isWasmSupported } from '@computekit/core';
+
+if (isWasmSupported()) {
+ // Use WASM
+}
+```
+
+### isSharedArrayBufferAvailable()
+
+Check if SharedArrayBuffer is available.
+
+```typescript
+import { isSharedArrayBufferAvailable } from '@computekit/core';
+
+if (isSharedArrayBufferAvailable()) {
+ // Use shared memory
+}
+```
+
+### getHardwareConcurrency()
+
+Get the number of logical CPU cores.
+
+```typescript
+import { getHardwareConcurrency } from '@computekit/core';
+
+const cores = getHardwareConcurrency();
+console.log(`${cores} CPU cores available`);
+```
+
+### findTransferables()
+
+Detect transferable objects in data for efficient worker communication.
+
+```typescript
+import { findTransferables } from '@computekit/core';
+
+const data = { buffer: new ArrayBuffer(1024), values: [1, 2, 3] };
+const transferables = findTransferables(data);
+// [ArrayBuffer(1024)]
+```
+
+---
+
+## Error Handling
+
+ComputeKit throws errors in these cases:
+
+```typescript
+try {
+ await kit.run('unknown', data);
+} catch (error) {
+ if (error.message.includes('not registered')) {
+ // Function not registered
+ } else if (error.message.includes('timed out')) {
+ // Timeout
+ } else if (error.message.includes('aborted')) {
+ // Cancelled via AbortSignal
+ } else {
+ // Worker error
+ }
+}
+```
diff --git a/docs/api.md b/docs/api.md
index a9814dad..ab2a40c1 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -1,3 +1,11 @@
+---
+layout: default
+title: Core API (Detailed)
+nav_order: 8
+description: 'Detailed API reference for @computekit/core'
+permalink: /core-api
+---
+
# @computekit/core API Reference
Complete API documentation for the ComputeKit core library.
@@ -24,13 +32,13 @@ new ComputeKit(options?: ComputeKitOptions)
#### ComputeKitOptions
-| Property | Type | Default | Description |
-|----------|------|---------|-------------|
-| `maxWorkers` | `number` | `navigator.hardwareConcurrency \|\| 4` | Maximum number of workers in the pool |
-| `timeout` | `number` | `30000` | Default timeout for operations (ms) |
-| `debug` | `boolean` | `false` | Enable debug logging |
-| `workerPath` | `string` | `''` | Custom path to worker script |
-| `useSharedMemory` | `boolean` | `true` | Use SharedArrayBuffer when available |
+| Property | Type | Default | Description |
+| ----------------- | --------- | -------------------------------------- | ------------------------------------- |
+| `maxWorkers` | `number` | `navigator.hardwareConcurrency \|\| 4` | Maximum number of workers in the pool |
+| `timeout` | `number` | `30000` | Default timeout for operations (ms) |
+| `debug` | `boolean` | `false` | Enable debug logging |
+| `workerPath` | `string` | `''` | Custom path to worker script |
+| `useSharedMemory` | `boolean` | `true` | Use SharedArrayBuffer when available |
### Methods
@@ -56,6 +64,7 @@ kit.register('asyncTask', async (data) => {
```
**Parameters:**
+
- `name` - Unique identifier for the function
- `fn` - The function to execute (runs in a Web Worker)
@@ -71,6 +80,7 @@ console.log(result); // 42
```
**Parameters:**
+
- `name` - Name of the registered function
- `input` - Input data (will be serialized)
- `options` - Optional execution options
@@ -115,13 +125,13 @@ await kit.terminate();
Options for individual compute operations.
-| Property | Type | Description |
-|----------|------|-------------|
-| `timeout` | `number` | Operation timeout in ms |
-| `transfer` | `ArrayBuffer[]` | ArrayBuffers to transfer (not copy) |
-| `priority` | `number` | Priority level (0-10, higher = first) |
-| `signal` | `AbortSignal` | Abort signal for cancellation |
-| `onProgress` | `(progress: ComputeProgress) => void` | Progress callback |
+| Property | Type | Description |
+| ------------ | ------------------------------------- | ------------------------------------- |
+| `timeout` | `number` | Operation timeout in ms |
+| `transfer` | `ArrayBuffer[]` | ArrayBuffers to transfer (not copy) |
+| `priority` | `number` | Priority level (0-10, higher = first) |
+| `signal` | `AbortSignal` | Abort signal for cancellation |
+| `onProgress` | `(progress: ComputeProgress) => void` | Progress callback |
```typescript
const controller = new AbortController();
@@ -140,12 +150,12 @@ await kit.run('task', data, {
Progress information for long-running tasks.
-| Property | Type | Description |
-|----------|------|-------------|
-| `percent` | `number` | Progress percentage (0-100) |
-| `phase` | `string?` | Current phase name |
-| `estimatedTimeRemaining` | `number?` | Estimated ms remaining |
-| `data` | `unknown?` | Additional data |
+| Property | Type | Description |
+| ------------------------ | ---------- | --------------------------- |
+| `percent` | `number` | Progress percentage (0-100) |
+| `phase` | `string?` | Current phase name |
+| `estimatedTimeRemaining` | `number?` | Estimated ms remaining |
+| `data` | `unknown?` | Additional data |
---
@@ -153,12 +163,12 @@ Progress information for long-running tasks.
Result wrapper with execution metadata.
-| Property | Type | Description |
-|----------|------|-------------|
-| `data` | `T` | The computed result |
-| `duration` | `number` | Execution time in ms |
-| `cached` | `boolean` | Whether result was cached |
-| `workerId` | `string` | ID of the worker that processed this |
+| Property | Type | Description |
+| ---------- | --------- | ------------------------------------ |
+| `data` | `T` | The computed result |
+| `duration` | `number` | Execution time in ms |
+| `cached` | `boolean` | Whether result was cached |
+| `workerId` | `string` | ID of the worker that processed this |
---
@@ -166,16 +176,16 @@ Result wrapper with execution metadata.
Worker pool statistics.
-| Property | Type | Description |
-|----------|------|-------------|
-| `workers` | `WorkerInfo[]` | Info about each worker |
-| `totalWorkers` | `number` | Total worker count |
-| `activeWorkers` | `number` | Currently busy workers |
-| `idleWorkers` | `number` | Currently idle workers |
-| `queueLength` | `number` | Tasks waiting in queue |
-| `tasksCompleted` | `number` | Total completed tasks |
-| `tasksFailed` | `number` | Total failed tasks |
-| `averageTaskDuration` | `number` | Average task duration (ms) |
+| Property | Type | Description |
+| --------------------- | -------------- | -------------------------- |
+| `workers` | `WorkerInfo[]` | Info about each worker |
+| `totalWorkers` | `number` | Total worker count |
+| `activeWorkers` | `number` | Currently busy workers |
+| `idleWorkers` | `number` | Currently idle workers |
+| `queueLength` | `number` | Tasks waiting in queue |
+| `tasksCompleted` | `number` | Total completed tasks |
+| `tasksFailed` | `number` | Total failed tasks |
+| `averageTaskDuration` | `number` | Average task duration (ms) |
---
@@ -192,7 +202,7 @@ Load a WASM module from various sources.
const module = await loadWasmModule('/path/to/module.wasm');
// From ArrayBuffer
-const bytes = await fetch('/module.wasm').then(r => r.arrayBuffer());
+const bytes = await fetch('/module.wasm').then((r) => r.arrayBuffer());
const module = await loadWasmModule(bytes);
// From base64
@@ -207,7 +217,7 @@ Load and instantiate a WASM module.
const { module, instance } = await loadAndInstantiate({
source: '/module.wasm',
imports: {
- env: { log: console.log }
+ env: { log: console.log },
},
memory: {
initial: 256,
diff --git a/docs/assets/logo.svg b/docs/assets/logo.svg
new file mode 100644
index 00000000..da53943e
--- /dev/null
+++ b/docs/assets/logo.svg
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/debugging.md b/docs/debugging.md
new file mode 100644
index 00000000..aa840181
--- /dev/null
+++ b/docs/debugging.md
@@ -0,0 +1,462 @@
+---
+layout: default
+title: Debugging
+nav_order: 8
+---
+
+# Debugging ComputeKit
+
+{: .no_toc }
+
+Learn how to debug worker code, understand errors, and troubleshoot issues in ComputeKit.
+{: .fs-6 .fw-300 }
+
+
+
+ Table of contents
+ {: .text-delta }
+- TOC
+{:toc}
+
+
+---
+
+## Overview
+
+Debugging Web Workers can be tricky because they run in a separate thread with their own global scope. ComputeKit provides several tools to make debugging easier:
+
+- Enhanced error messages with context
+- Debug mode with verbose logging
+- Console forwarding from workers
+- Chrome DevTools integration
+- Validation mode for main-thread debugging
+
+---
+
+## Enable Debug Mode
+
+The simplest way to start debugging is to enable debug mode:
+
+```typescript
+import { ComputeKit } from '@computekit/core';
+
+const kit = new ComputeKit({
+ debug: true, // Enable verbose logging
+});
+```
+
+With React:
+
+```tsx
+
+
+
+```
+
+Debug mode logs:
+
+- Worker creation and termination
+- Function registration
+- Task execution (start, complete, error)
+- Message passing between main thread and workers
+- Payload sizes for data transfer
+
+---
+
+## Understanding Error Messages
+
+When a compute function throws an error, ComputeKit captures and enriches it with context:
+
+```typescript
+kit.register('riskyFunction', (input: number) => {
+ if (input < 0) {
+ throw new Error('Input must be non-negative');
+ }
+ return Math.sqrt(input);
+});
+
+try {
+ await kit.run('riskyFunction', -5);
+} catch (error) {
+ console.error(error);
+ // ComputeError: Input must be non-negative
+ // Function: riskyFunction
+ // Worker: worker-abc123
+ // Duration: 2ms
+ // Stack: ...original stack trace...
+}
+```
+
+### Error Properties
+
+All errors from ComputeKit include:
+
+| Property | Description |
+| -------------- | ---------------------------------------- |
+| `message` | The original error message |
+| `functionName` | Name of the compute function that failed |
+| `workerId` | ID of the worker that processed the task |
+| `duration` | Time elapsed before the error occurred |
+| `stack` | Full stack trace from the worker |
+| `inputSize` | Size of the input data (in debug mode) |
+
+---
+
+## Chrome DevTools Integration
+
+### Debugging Workers Directly
+
+Chrome DevTools supports debugging Web Workers:
+
+1. Open DevTools (F12)
+2. Go to **Sources** tab
+3. In the left panel, find **Threads** section
+4. Click on a worker thread to debug it
+
+### Setting Breakpoints
+
+To set breakpoints in your compute functions:
+
+1. Enable source maps in your bundler (see below)
+2. In DevTools Sources, find your worker code
+3. Set breakpoints as normal
+4. Use the worker thread selector to switch contexts
+
+### Console Output
+
+Worker `console.log()` calls appear in the main DevTools console, prefixed with the worker context. Enable **Verbose** log level to see all worker output:
+
+```typescript
+kit.register('debugMe', (input: number[]) => {
+ console.log('Processing', input.length, 'items'); // Visible in DevTools
+ console.time('processing');
+
+ const result = input.map((x) => x * 2);
+
+ console.timeEnd('processing');
+ console.log('Result:', result.slice(0, 5), '...');
+
+ return result;
+});
+```
+
+---
+
+## Source Maps
+
+For the best debugging experience, configure your bundler to generate source maps for workers.
+
+### Vite
+
+```typescript
+// vite.config.ts
+export default defineConfig({
+ build: {
+ sourcemap: true,
+ },
+ worker: {
+ format: 'es',
+ rollupOptions: {
+ output: {
+ sourcemap: true,
+ },
+ },
+ },
+});
+```
+
+### Webpack
+
+```javascript
+// webpack.config.js
+module.exports = {
+ devtool: 'source-map',
+ module: {
+ rules: [
+ {
+ test: /\.worker\.ts$/,
+ use: {
+ loader: 'worker-loader',
+ options: {
+ inline: 'fallback',
+ },
+ },
+ },
+ ],
+ },
+};
+```
+
+### esbuild
+
+```typescript
+import * as esbuild from 'esbuild';
+
+await esbuild.build({
+ entryPoints: ['src/index.ts'],
+ bundle: true,
+ sourcemap: true,
+ outfile: 'dist/bundle.js',
+});
+```
+
+---
+
+## Validation Mode (Main Thread Execution)
+
+For difficult bugs, run your compute function on the main thread to use standard debugging tools:
+
+```typescript
+import { ComputeKit } from '@computekit/core';
+
+const kit = new ComputeKit({
+ // Force main thread execution (bypasses workers)
+ forceMainThread: true,
+});
+
+// Now you can set breakpoints directly in your compute functions
+kit.register('myFunction', (input) => {
+ debugger; // This will pause execution in DevTools
+ return processData(input);
+});
+```
+
+{: .warning }
+
+> **forceMainThread** should only be used for debugging. It defeats the purpose of using workers and will block the UI thread.
+
+---
+
+## Common Issues
+
+### "Function not found in worker"
+
+This error occurs when a compute function isn't registered before calling `run()`:
+
+```typescript
+// ❌ Wrong - function not registered
+await kit.run('myFunction', data);
+
+// ✅ Correct - register first
+kit.register('myFunction', (data) => processData(data));
+await kit.run('myFunction', data);
+```
+
+**In React**, ensure registration happens before the component that uses the function mounts:
+
+```tsx
+// ❌ Wrong - might race with child components
+function App() {
+ const kit = useComputeKit();
+
+ useEffect(() => {
+ kit.register('myFunction', fn);
+ }, [kit]);
+
+ return ;
+}
+
+// ✅ Correct - use a registration component or context
+function App() {
+ return (
+
+
+
+
+ );
+}
+
+function RegisterFunctions() {
+ const kit = useComputeKit();
+
+ useEffect(() => {
+ kit.register('myFunction', fn);
+ }, [kit]);
+
+ return null;
+}
+```
+
+### "DataCloneError: Failed to execute 'postMessage'"
+
+This error occurs when trying to transfer non-cloneable data:
+
+```typescript
+// ❌ Wrong - functions can't be cloned
+kit.register('bad', () => {
+ return {
+ data: [1, 2, 3],
+ callback: () => console.log('hi'), // Can't clone functions!
+ };
+});
+
+// ✅ Correct - return only cloneable data
+kit.register('good', () => {
+ return {
+ data: [1, 2, 3],
+ callbackName: 'logHi', // Return a reference instead
+ };
+});
+```
+
+**Non-cloneable types include:**
+
+- Functions
+- DOM nodes
+- Error objects (use `{ message, stack }` instead)
+- Symbols
+- WeakMap/WeakSet
+
+### Timeout Errors
+
+If tasks are timing out unexpectedly:
+
+```typescript
+// Increase timeout for long-running operations
+const result = await kit.run('heavyComputation', data, {
+ timeout: 120000, // 2 minutes
+});
+
+// Or set a global default
+const kit = new ComputeKit({
+ timeout: 60000, // 1 minute default
+});
+```
+
+### Worker Creation Failures
+
+If workers fail to create, check:
+
+1. **Content Security Policy** - Ensure your CSP allows `worker-src 'self' blob:`
+2. **Cross-origin issues** - Workers must be same-origin
+3. **Memory limits** - Each worker uses ~2-5MB of memory
+
+---
+
+## Logging Events
+
+Subscribe to ComputeKit events for detailed logging:
+
+```typescript
+const kit = new ComputeKit();
+
+kit.on('worker:created', ({ info }) => {
+ console.log(`Worker ${info.id} created`);
+});
+
+kit.on('worker:error', ({ error, info }) => {
+ console.error(`Worker ${info.id} error:`, error);
+});
+
+kit.on('task:start', ({ taskId, functionName }) => {
+ console.log(`Task ${taskId} started: ${functionName}`);
+});
+
+kit.on('task:complete', ({ taskId, duration }) => {
+ console.log(`Task ${taskId} completed in ${duration}ms`);
+});
+
+kit.on('task:error', ({ taskId, error }) => {
+ console.error(`Task ${taskId} failed:`, error);
+});
+
+kit.on('task:progress', ({ taskId, progress }) => {
+ console.log(`Task ${taskId}: ${progress.percent}%`);
+});
+```
+
+---
+
+## Pool Statistics
+
+Monitor worker pool health:
+
+```typescript
+const stats = kit.getStats();
+
+console.log(stats);
+// {
+// workers: [
+// { id: 'w1', state: 'idle', tasksCompleted: 42, errors: 0 },
+// { id: 'w2', state: 'busy', tasksCompleted: 38, errors: 1 },
+// ],
+// totalWorkers: 2,
+// activeWorkers: 1,
+// idleWorkers: 1,
+// queueLength: 0,
+// tasksCompleted: 80,
+// tasksFailed: 1,
+// averageTaskDuration: 145,
+// }
+```
+
+In React, use the `usePoolStats` hook:
+
+```tsx
+function PoolMonitor() {
+ const stats = usePoolStats();
+
+ return (
+
+
+ Workers: {stats.activeWorkers}/{stats.totalWorkers} active
+
+
Queue: {stats.queueLength} pending
+
Completed: {stats.tasksCompleted}
+
Failed: {stats.tasksFailed}
+
+ );
+}
+```
+
+---
+
+## Debugging Pipelines
+
+For multi-stage pipelines, use the built-in debugging features:
+
+```tsx
+const pipeline = usePipeline(stages);
+
+// Get a detailed report
+const report = pipeline.getReport();
+console.log(report.summary);
+console.log(report.timeline);
+console.log(report.insights);
+
+// Access metrics
+console.log(pipeline.metrics);
+// {
+// totalStages: 4,
+// completedStages: 3,
+// failedStages: 1,
+// slowestStage: { id: 'process', duration: 2340 },
+// timeline: [...]
+// }
+
+// Check individual stage status
+pipeline.stages.forEach((stage) => {
+ console.log(`${stage.name}: ${stage.status}`);
+ if (stage.error) {
+ console.error(` Error: ${stage.error.message}`);
+ }
+ if (stage.duration) {
+ console.log(` Duration: ${stage.duration}ms`);
+ }
+});
+```
+
+---
+
+## Getting Help
+
+If you're stuck:
+
+1. Enable `debug: true` and check the console
+2. Check the [Common Issues](#common-issues) section
+3. Use `forceMainThread: true` to debug on the main thread
+4. [Open an issue](https://github.com/pzaino/compute-kit/issues) with:
+ - ComputeKit version
+ - Browser and version
+ - Minimal reproduction code
+ - Console output with debug mode enabled
diff --git a/docs/demo.html b/docs/demo.html
index 45ff747a..f85b473d 100644
--- a/docs/demo.html
+++ b/docs/demo.html
@@ -1,459 +1,594 @@
-
+
-
-
-
+
+
+
ComputeKit | WASM + Worker Toolkit
+
+
+
+
+
+
+
+
+ ComputeKit
Demo
+
+
+ Documentation
+
+
+
+
+
+
+
- .modal-header {
- padding: 15px 20px;
- border-bottom: 1px solid var(--border);
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .modal-body {
- padding: 20px;
- overflow-y: auto;
- line-height: 1.6;
- font-size: 0.95rem;
- }
- .modal-body code { background: rgba(110,118,129,0.2); padding: 2px 4px; border-radius: 4px; font-family: var(--font-code); }
- .modal-body h3 { margin-top: 0; color: var(--text-main); }
-
- .close-btn {
- background: none; border: none; color: var(--text-muted);
- font-size: 1.5rem; cursor: pointer;
- }
+
+
- /* Responsive */
- @media (max-width: 800px) {
- main { grid-template-columns: 1fr; grid-template-rows: 1fr 1fr; }
- .sidebar { border-right: none; border-bottom: 1px solid var(--border); }
- }
-
-
-
+
+
-
-
-
- ComputeKit
Demo
+
-
- Documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Time: 0ms
-
-
- Mode: Idle
-
-
- Resolution: 0x0
-
-
-
+
+
+ Time: 0ms
+
+
+ Mode: Idle
+
+
+ Resolution: 0x0
+
+
+
-
-
-
-
What is ComputeKit?
-
ComputeKit is a tiny toolkit that allows frontend developers to run heavy computations using WebAssembly + Web Workers with a simple async API.
-
-
Why use it?
-
- No Rust required: Write compute functions in TypeScript-like AssemblyScript.
- Non-blocking: Calculations run in a Web Worker, keeping the UI buttery smooth (60fps).
- Automatic Workers: No need to manually manage `postMessage` or `worker.js` files.
-
-
-
Example Usage
-
import { compute } from '@computekit/core' ;
+
+
+
+
What is ComputeKit?
+
+ ComputeKit is a tiny toolkit that allows frontend developers to run heavy
+ computations using WebAssembly + Web Workers with a simple
+ async API.
+
+
+
Why use it?
+
+
+ No Rust required: Write compute functions in
+ TypeScript-like AssemblyScript.
+
+
+ Non-blocking: Calculations run in a Web Worker, keeping the
+ UI buttery smooth.
+
+
+ Automatic Workers: No need to manually manage `postMessage`
+ or `worker.js` files.
+
+
+
+
Example Usage
+
import { compute } from '@computekit/core' ;
// Define function in ./compute/fib.as
const result = await compute.fibonacci(1000 );
console.log(result); // UI never froze!
-
Performance
-
WebAssembly (WASM) runs at near-native speed. Combined with parallel processing via Workers, you can unlock performance previously impossible in the browser.
-
+
Performance
+
+ WebAssembly (WASM) runs at near-native speed. Combined with parallel
+ processing via Workers, you can unlock performance previously impossible in
+ the browser.
+
+
-
-
\ No newline at end of file
+
+