Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .agents/docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This repository is a small Rust and JavaScript monorepo with one shared napi-rs
- `crates/taffyjs_binding` owns the napi-rs adapter and depends directly on Taffy. A shared Rust crate is justified only when a second Rust consumer needs it.
- `packages/taffyjs-node` owns the public ESM wrapper and declarations, the private napi-rs loader and declarations, and npm metadata. The wrapper owns JavaScript-only NodeId validity data and context; Taffy owns topology, Style, Layout, cache, and computation state.
- `packages/taffyjs-wasm` compiles the same authored source from `packages/taffyjs-node/src` against generated private Node and browser adapters that share one inline payload. It owns package metadata, generated artifacts, and build-time binding redirection; its package-specific typed generator lives under `tools/taffy-wasm`. It has no authored public wrapper source or separate initialization API.
- `packages/taffyjs-yoga` owns the Node-only ESM Yoga 3.2.1 compatibility facade, Yoga declarations and visible state, input translation, and Yoga-shaped output projection. It depends only on the public `@taffyjs/node` package boundary and does not modify Taffy or the native binding.
- `packages/taffyjs-yoga` owns the native ESM Yoga 3.2.1 compatibility facade, Yoga declarations and visible state, input translation, and Yoga-shaped output projection. It depends only on the public `@taffyjs/node` package boundary and does not modify Taffy or the native binding.
- `packages/taffyjs-yoga-wasm` builds the exact facade source owned by `packages/taffyjs-yoga/src` against the public `@taffyjs/wasm` backend. It owns only its package metadata and build-time backend redirection; it has no copied facade source or second compatibility policy.
- `benchmarks` owns the Node-only end-to-end public JavaScript benchmark cases, their TypeScript coordinator, ignored local results, and the retained dataset consumed by the public website. Each scenario owns a direct child directory; the complete boundary is recorded in [Benchmark Design](benchmark.md).
- `tests/taffyjs-node` is a private consumer package that tests `@taffyjs/node` through its package boundary.
Expand All @@ -18,7 +18,7 @@ This repository is a small Rust and JavaScript monorepo with one shared napi-rs

The `@taffyjs/node` public entry bundles the private napi-rs root loader, which selects the matching optional platform package. Its generated loader and declaration remain repository build inputs rather than published package files. The `@taffyjs/wasm` default entry reaches a no-TLA ESM bridge that imports the shared payload and immediately invokes a synchronous CommonJS factory mechanically derived from napi-rs's eager Node loader; its browser entry reaches a TLA adapter and the unmodified deferred loader. Neither direct runtime package exposes an intermediate binding package, JavaScript shadow tree, separate core crate, public binding, or public initialization API.

`@taffyjs/yoga` is a Node-only TypeScript compatibility layer over `@taffyjs/node`; browser and WASM backends never live in that package. It performs bounded input normalization and output processing, but it does not modify or fork Taffy core, add a Yoga-specific native algorithm, or reimplement Flex layout in JavaScript; behavior that cannot cross that boundary is documented as Different or Unsupported as recorded in [@taffyjs/yoga decisions](taffyjs-yoga-decisions.md).
`@taffyjs/yoga` is a native TypeScript compatibility layer over `@taffyjs/node` for Node.js, Bun, and Deno; browser and WASM backends never live in that package. It performs bounded input normalization and output processing, but it does not modify or fork Taffy core, add a Yoga-specific native algorithm, or reimplement Flex layout in JavaScript; behavior that cannot cross that boundary is documented as Different or Unsupported as recorded in [@taffyjs/yoga decisions](taffyjs-yoga-decisions.md).

`@taffyjs/yoga-wasm` is a separate transport over `@taffyjs/wasm`, selected at build time by replacing only the exact bare `@taffyjs/node` dependency. The eager root entry and lazy `/load` entry keep Yoga's public shapes; `/load` dynamically imports the facade so a browser compiles no WebAssembly until `loadYoga()` is called. Compatibility semantics stay owned by the shared Yoga source and documentation.

Expand Down
4 changes: 2 additions & 2 deletions .agents/docs/intent.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ TaffyJS is intended to bring Taffy, a high-performance layout engine written in

- `@taffyjs/node` is the first entry point and provides native Node-API bindings built with napi-rs.
- `@taffyjs/wasm` is the explicit WebAssembly entry point for Node.js and bundled browsers. It reuses the `@taffyjs/node` public API over a threadless napi-rs WASIP binding rather than acting as an automatic fallback; its vouched contract is in [@taffyjs/wasm package design](taffyjs-wasm-package.md).
- `@taffyjs/yoga` is the Node-only Yoga 3.2.1 compatibility package built on top of `@taffyjs/node`; browser and WASM backends remain outside that package.
- `@taffyjs/yoga-wasm` is the separate Node.js and bundled-browser transport for that same compatibility facade. It builds the same source over `@taffyjs/wasm` so the two packages cannot drift into separate Yoga implementations.
- `@taffyjs/yoga` is the native Yoga 3.2.1 compatibility package built on top of `@taffyjs/node` for Node.js, Bun, and Deno; browser and WASM backends remain outside that package.
- `@taffyjs/yoga-wasm` is the separate Node.js, Bun, Deno, and bundled-browser transport for that same compatibility facade. It builds the same source over `@taffyjs/wasm` so the two packages cannot drift into separate Yoga implementations.
- The package family should support real consumers such as terminal UI frameworks without forcing those consumers to own their own Taffy bindings.

## Bun and Deno runtime support
Expand Down
5 changes: 3 additions & 2 deletions .agents/docs/taffyjs-yoga-wasm-package.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## Public contract

- The package is ESM-only and exposes the same root and `/load` shapes, declarations, constants, and Yoga compatibility classifications as `@taffyjs/yoga`.
- The package supports Node.js `>=22.18` and modern bundled browsers within the existing `@taffyjs/wasm` contract. It does not claim direct CDN, legacy-browser, Bun, Deno, workerd, or other edge-runtime support without separate evidence.
- The package supports Node.js `>=22.18`, Bun 1.2+ within major 1, Deno 2.2+ within major 2, and modern bundled browsers within the existing `@taffyjs/wasm` contract. Deno requires no permission flags. It does not claim direct CDN, legacy-browser, workerd, or other edge-runtime support without separate evidence.
- Consumers may install it under Yoga's original name with the registry alias `"yoga-layout": "npm:@taffyjs/yoga-wasm@<version>"`; supported application imports remain unchanged.
- `PositionType.Static` and every other Unsupported capability stay unsupported. Replacing the runtime transport does not create missing Taffy layout semantics.

Expand Down Expand Up @@ -36,5 +36,6 @@ Expected validation, callback, and Taffy errors retain the compatibility facade'
- Pack both `@taffyjs/wasm` and `@taffyjs/yoga-wasm`; install the latter under the bare `yoga-layout` dependency name in fresh npm and pnpm consumers; run both Node entries.
- From the installed tarballs, build bare `yoga-layout` and `yoga-layout/load` imports with Vite. Each browser bundle must select the `@taffyjs/wasm` browser condition, contain one inline payload and one `WebAssembly.compile`, emit no `.wasm` asset, and contain no `node:wasi` path.
- Run both installed browser entries in real Chromium without cross-origin isolation or `SharedArrayBuffer`. Importing `/load` must compile zero Wasm modules; the first `loadYoga()` call must compile exactly one.
- Run one fixed-layout smoke through both public entries on Bun 1.2.0 and Deno 2.2.0, the first releases of the supported minimum minors. The Deno smoke uses no permission flags, matching the underlying `@taffyjs/wasm` runtime.

The Yoga Wasm checks live in the existing Linux-only `check:wasm` graph because they require the WASIP Rust target and Chromium. Native cross-platform checks continue to own `@taffyjs/yoga`.
The Yoga Wasm build, package, Node.js, and browser checks live in the existing Linux-only `check:wasm` graph because they require the WASIP Rust target and Chromium. CI runs the alternate-runtime smokes immediately afterward using the packages produced by that graph. Native cross-platform checks continue to own `@taffyjs/yoga`.
2 changes: 1 addition & 1 deletion .agents/docs/technology-stack.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ For `packages/taffyjs-yoga-wasm`, Vite+ builds those same sibling source entries

`tools/api-codegen` owns source generation that must keep Rust and TypeScript API facts aligned. Its first maintained input is `api/numeric-families.json`; `vp run codegen` updates both language outputs. CI runs `vp run check:codegen`, which regenerates and rejects any resulting Git diff.

CI has six jobs. Ubuntu x64, Windows x64, and macOS arm64 each build the native addon and run all Rust, JavaScript, and type tests with Node.js 22.18.0; Ubuntu and Windows then smoke-test the public `@taffyjs/node` and `@taffyjs/yoga` entries with Bun 1.2.0 and Deno 2.2.0. Ubuntu also rejects stale committed package JavaScript and declarations after the build. A separate Ubuntu WASIP job installs the Rust target and Playwright Chromium, builds `@taffyjs/wasm`, reruns the complete Node public API suite against it, runs type, package-content, packed-consumer, bundled-consumer, and browser-runtime checks against the generated package, and applies the same Bun 1.2.0 and Deno 2.2.0 smoke checks to the public entry. That job also builds `@taffyjs/yoga-wasm`, reruns the complete maintained Yoga behavior and declaration suites, inspects and installs the packed package with npm and pnpm, and exercises both public entries in bundled Chromium. Alternate-runtime smoke checks perform one fixed layout rather than copying the complete behavior suite. A Node-only job checks formatting, JavaScript and repository TypeScript including maintained tools through Vite+'s type-aware lint path, and generated-source drift. A Rust-only job checks formatting and Clippy. Publication workflows are not configured.
CI has six jobs. Ubuntu x64, Windows x64, and macOS arm64 each build the native addon and run all Rust, JavaScript, and type tests with Node.js 22.18.0; Ubuntu and Windows then smoke-test the public `@taffyjs/node` and `@taffyjs/yoga` entries with Bun 1.2.0 and Deno 2.2.0. Ubuntu also rejects stale committed package JavaScript and declarations after the build. A separate Ubuntu WASIP job installs the Rust target and Playwright Chromium, builds `@taffyjs/wasm`, reruns the complete Node public API suite against it, runs type, package-content, packed-consumer, bundled-consumer, and browser-runtime checks against the generated package, and applies the same Bun 1.2.0 and Deno 2.2.0 smoke checks to the public entry. That job also builds `@taffyjs/yoga-wasm`, reruns the complete maintained Yoga behavior and declaration suites, inspects and installs the packed package with npm and pnpm, exercises both public entries in bundled Chromium, and smoke-tests both entries with Bun 1.2.0 and Deno 2.2.0. Alternate-runtime smoke checks perform one fixed layout rather than copying the complete behavior suite. A Node-only job checks formatting, JavaScript and repository TypeScript including maintained tools through Vite+'s type-aware lint path, and generated-source drift. A Rust-only job checks formatting and Clippy. Publication workflows are not configured.

## Public website

Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ jobs:
run: pnpm dlx bun@1.2.0 packages/taffyjs-wasm/tests/runtime-smoke.mjs
- name: Smoke test @taffyjs/wasm with Deno 2.2
run: pnpm dlx deno@2.2.0 run --node-modules-dir=manual packages/taffyjs-wasm/tests/runtime-smoke.mjs
- name: Smoke test @taffyjs/yoga-wasm with Bun 1.2
run: pnpm dlx bun@1.2.0 tests/taffyjs-yoga-wasm/runtime-smoke.mjs
- name: Smoke test @taffyjs/yoga-wasm with Deno 2.2
run: pnpm dlx deno@2.2.0 run --node-modules-dir=manual tests/taffyjs-yoga-wasm/runtime-smoke.mjs

check-node:
name: Node checks
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ npm install @taffyjs/node

TaffyJS supports Node.js 22.18+, Bun 1.2+ within the Bun 1 major, and Deno 2.2+ within the Deno 2 major. CI runs the complete test suite on Node.js 22.18.0 and smoke-tests Bun 1.2.0 and Deno 2.2.0 by importing each implemented public package, computing a minimal layout, and verifying the result. Bun and Deno support follows one current major per runtime rather than spanning runtime majors.

| Package | Node.js 22.18+ | Bun 1.2+ | Deno 2.2+ |
| -------------------- | ------------------ | ------------------ | --------------------------------------------------------------------------- |
| `@taffyjs/node` | ✅ | ✅ | ✅ (local `node_modules`; `--allow-env`, `--allow-read`, and `--allow-ffi`) |
| `@taffyjs/wasm` | ✅ | ✅ | ✅ (without permission flags) |
| `@taffyjs/yoga` | ✅ | ✅ | ✅ (local `node_modules`; `--allow-env`, `--allow-read`, and `--allow-ffi`) |
| `@taffyjs/yoga-wasm` | ⚠️ Not implemented | ⚠️ Not implemented | ⚠️ Not implemented |
| Package | Node.js 22.18+ | Bun 1.2+ | Deno 2.2+ |
| -------------------- | -------------- | -------- | --------------------------------------------------------------------------- |
| `@taffyjs/node` | ✅ | ✅ | ✅ (local `node_modules`; `--allow-env`, `--allow-read`, and `--allow-ffi`) |
| `@taffyjs/wasm` | ✅ | ✅ | ✅ (without permission flags) |
| `@taffyjs/yoga` | ✅ | ✅ | ✅ (local `node_modules`; `--allow-env`, `--allow-read`, and `--allow-ffi`) |
| `@taffyjs/yoga-wasm` | ✅ | ✅ | ✅ (without permission flags) |

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion apps/website/yoga-wasm/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ const Yoga = await loadYoga();

## Runtime and compatibility

The package supports Node.js 22.18 or newer and modern bundled browsers within the [`@taffyjs/wasm` runtime boundary](../wasm/index.md). Direct CDN imports, legacy browsers, and non-browser edge runtimes are not currently supported.
The package supports Node.js 22.18 or newer, Bun 1.2+ within the Bun 1 major, Deno 2.2+ within the Deno 2 major without permission flags, and modern bundled browsers within the [`@taffyjs/wasm` runtime boundary](../wasm/index.md). Direct CDN imports, legacy browsers, and non-browser edge runtimes are not currently supported.

Its public API, declarations, and compatibility classifications come from the same source as `@taffyjs/yoga`. Changing to WebAssembly does not add missing Yoga semantics; consult the same [Yoga 3.2.1 compatibility guide](https://github.com/hyfdev/taffyjs/blob/main/packages/taffyjs-yoga/COMPATIBILITY.md).
4 changes: 2 additions & 2 deletions apps/website/yoga/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `@taffyjs/yoga`

`@taffyjs/yoga` is a Yoga 3.2.1 compatibility facade backed by native TaffyJS. It is for Node.js applications that want to replace `yoga-layout` while keeping the supported Yoga API and import shape.
`@taffyjs/yoga` is a Yoga 3.2.1 compatibility facade backed by native TaffyJS. It is for Node.js, Bun, and Deno applications that want to replace `yoga-layout` while keeping the supported Yoga API and import shape.

Read the [Design Philosophy](./design-philosophy.md) to understand what the package preserves, where Taffy remains visible, and how unsupported behavior is reported.

Expand Down Expand Up @@ -37,6 +37,6 @@ The asynchronous `yoga-layout/load` entry is also preserved.

## Runtime and compatibility

The package is ESM-only and requires Node.js 22.18 or newer. Native target support follows [`@taffyjs/node`](../node/index.md). It does not run in browsers; use [`@taffyjs/yoga-wasm`](../yoga-wasm/index.md) for the same facade over WebAssembly.
The package is ESM-only and supports Node.js 22.18 or newer, Bun 1.2+ within the Bun 1 major, and Deno 2.2+ within the Deno 2 major. Deno requires local `node_modules` plus `--allow-env`, `--allow-read`, and `--allow-ffi`. Native target support follows [`@taffyjs/node`](../node/index.md). It does not run in browsers; use [`@taffyjs/yoga-wasm`](../yoga-wasm/index.md) for the same facade over WebAssembly.

Compatibility is pinned to Yoga 3.2.1. Supported calls preserve Yoga's source shape, while known behavioral differences and unsupported features are explicit. See the [complete compatibility guide](https://github.com/hyfdev/taffyjs/blob/main/packages/taffyjs-yoga/COMPATIBILITY.md) before migrating an existing application.
2 changes: 1 addition & 1 deletion packages/taffyjs-yoga-wasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

The [design philosophy](../../apps/website/yoga-wasm/design-philosophy.md) explains why the Yoga-facing model and runtime transport remain separate choices.

The package supports Node.js `>=22.18` and modern bundled browsers within the [documented `@taffyjs/wasm` runtime boundary](https://github.com/hyfdev/taffyjs/blob/main/packages/taffyjs-wasm/README.md). Browser consumers need a bundler that honors package export conditions and top-level await. Direct CDN scripts, legacy browsers, and non-browser edge runtimes are not currently supported.
The package supports Node.js `>=22.18`, Bun 1.2+ within the Bun 1 major, Deno 2.2+ within the Deno 2 major, and modern bundled browsers within the [documented `@taffyjs/wasm` runtime boundary](https://github.com/hyfdev/taffyjs/blob/main/packages/taffyjs-wasm/README.md). Deno requires no permission flags. Browser consumers need a bundler that honors package export conditions and top-level await. Direct CDN scripts, legacy browsers, and non-browser edge runtimes are not currently supported.

This package is still private and unpublished. The installation form below describes the intended registry substitution after publication.

Expand Down
22 changes: 22 additions & 0 deletions tests/taffyjs-yoga-wasm/runtime-smoke.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Keep this runtime-only harness as JavaScript so clean type-aware checks do not resolve
// the build-only package entries before the WASIP job produces them.
import Yoga from "@taffyjs/yoga-wasm";
import { loadYoga } from "@taffyjs/yoga-wasm/load";

import { runYogaRuntimeSmoke } from "../runtime-smoke.ts";

const packageName = "@taffyjs/yoga-wasm";
const loadEntryName = "@taffyjs/yoga-wasm/load";
const resolvedEntry = import.meta.resolve(packageName);
const resolvedLoadEntry = import.meta.resolve(loadEntryName);

if (!resolvedEntry.endsWith("/packages/taffyjs-yoga-wasm/dist/index.js")) {
throw new Error(`${packageName} resolved to an unexpected entry: ${resolvedEntry}`);
}

if (!resolvedLoadEntry.endsWith("/packages/taffyjs-yoga-wasm/dist/load.js")) {
throw new Error(`${loadEntryName} resolved to an unexpected entry: ${resolvedLoadEntry}`);
}
Comment on lines +10 to +19

runYogaRuntimeSmoke(packageName, Yoga);
runYogaRuntimeSmoke(loadEntryName, await loadYoga());