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
17 changes: 10 additions & 7 deletions .agents/docs/website.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ The landing page includes one code-to-layout example below the default Home cont

- `@taffyjs/node` is the first direct binding and the default package used by current Guide examples.
- `@taffyjs/wasm` is the explicit WebAssembly binding for the same high-level direct JavaScript API. Its package documentation owns WebAssembly loading, initialization, runtime support and binding-specific performance or deployment differences; it must not duplicate or fork the shared API reference merely because the transport differs.
- `@taffyjs/yoga` is a planned Yoga-compatible API built on `@taffyjs/node`. It has a distinct consumer model and therefore owns its own compatibility, migration and API documentation.
- `@taffyjs/yoga` is the Yoga 3.2.1 compatibility facade built on `@taffyjs/node`. It has a distinct consumer model and therefore owns its own compatibility, migration and API documentation.
- `@taffyjs/yoga-wasm` builds that same compatibility facade over `@taffyjs/wasm`. It shares Yoga-facing source, declarations and compatibility classifications with `@taffyjs/yoga` while owning only its WebAssembly runtime and loading differences.

No planned package receives empty reference pages or documentation navigation that makes it look installable. The landing page may present the intended package family without progress labels, but a package receives a visible documentation section only when there is enough implementation and installation evidence to make that section useful. `@taffyjs/wasm` now meets that threshold; `@taffyjs/yoga` does not yet have a package section.
No planned package receives empty reference pages or documentation navigation that makes it look installable. The landing page may present the intended package family without progress labels, but a package receives a visible documentation section only when there is enough implementation and installation evidence to make that section useful. All four implemented packages now meet that threshold.

## Documentation structure

The documentation is arranged in three layers: Guide, Essentials, and package sections. Guide contains the Introduction and Getting Started. Essentials teaches the shared layout-engine model in learning order. Package sections hold complete runtime and platform support, initialization, binding-specific behavior, compatibility, migration, and exact public API details. One documentation sidebar lists Guide, Essentials, and every implemented package with its articles, so readers can see the complete documentation structure from any documentation page. The top navigation links to that documentation once as Guide rather than repeating packages in a separate menu. Empty package sections are not reserved in advance.
The documentation is arranged in three layers: Guide, Essentials, and package sections. Guide contains the Introduction and Getting Started. Essentials teaches the shared layout-engine model in learning order. Package sections hold complete runtime and platform support, initialization, binding-specific behavior, compatibility, migration, and exact public API details. Every package section begins with a short Design Philosophy article that explains the package's intended model, responsibility boundary and reasons for existing before the Overview explains setup and support. One documentation sidebar lists Guide, Essentials, and every implemented package with its articles, so readers can see the complete documentation structure from any documentation page. The top navigation links to that documentation once as Guide rather than repeating packages in a separate menu. Empty package sections are not reserved in advance.

Getting Started and Essentials use `@taffyjs/node` code by default. At points where runtime choice matters, a short callout sends browser or WebAssembly users to `@taffyjs/wasm` and users seeking Yoga compatibility to `@taffyjs/yoga`. Shared teaching is not repeated once per package.

Expand All @@ -36,15 +37,16 @@ Getting Started keeps the runnable Node example as the canonical code path and u

Essentials continues directly from that model. It explains what each shared concept is, the role it plays, how it affects a computation, and how to use it through focused `@taffyjs/node` examples. The sequence moves from the tree-compute-read lifecycle and styles and values into Block, Flexbox, Grid, and measuring text and images. The measurement page first establishes that Taffy only lays out boxes and relies on application-owned text and image systems for intrinsic sizes, then teaches the callback boundary. These pages teach the model rather than enumerate every method or field.

The `@taffyjs/node` overview owns supported Node.js and platform combinations, native import rules, and package scope. The rest of that section is the canonical human-written reference for the direct `TaffyTree`, `Style`, layout result, value helper, and error APIs shared by Node and Wasm. The `@taffyjs/wasm` section owns availability, setup and observable runtime differences and links back to that shared reference instead of duplicating it. The `@taffyjs/yoga` section will own its Yoga-compatible surface, migration guidance, compatibility scope, and behavioral differences from the direct API.
The `@taffyjs/node` overview owns supported Node.js and platform combinations, native import rules, and package scope. The rest of that section is the canonical human-written reference for the direct `TaffyTree`, `Style`, layout result, value helper, and error APIs shared by Node and Wasm. The `@taffyjs/wasm` section owns availability, setup and observable runtime differences and links back to that shared reference instead of duplicating it. The `@taffyjs/yoga` section owns its Yoga-compatible surface, migration guidance, compatibility scope, and behavioral differences from the direct API. The `@taffyjs/yoga-wasm` section owns only the runtime and loading differences introduced by putting that same facade over Wasm; it links to the shared Yoga compatibility material instead of copying it.

The target page groups are:

- Guide: Introduction and Getting Started only.
- Essentials: the tree-compute-read workflow, styles and values, Block, Flexbox, Grid, and measuring text and images.
- `@taffyjs/node`: package overview and supported targets; `TaffyTree` node and topology operations, styles and context, the detailed `setStyle` versus `updateStyle` choice, computation and dirty state, and layout results; the grouped `Style` data model; value helpers; and errors.
- `@taffyjs/wasm`: package overview and setup, supported environments, initialization and deployment, observable differences from Node, and a link to the shared direct API reference.
- `@taffyjs/yoga`: package overview and installation, compatibility scope, migration from Yoga, Yoga-facing API reference, and documented differences from the direct Taffy API.
- `@taffyjs/node`: design philosophy; package overview and supported targets; `TaffyTree` node and topology operations, styles and context, the detailed `setStyle` versus `updateStyle` choice, computation and dirty state, and layout results; the grouped `Style` data model; value helpers; and errors.
- `@taffyjs/wasm`: design philosophy; package overview and setup, supported environments, initialization and deployment, observable differences from Node, and a link to the shared direct API reference.
- `@taffyjs/yoga`: design philosophy; package overview and installation, compatibility scope, migration from Yoga, Yoga-facing API reference, and documented differences from the direct Taffy API.
- `@taffyjs/yoga-wasm`: design philosophy; package overview and installation, WebAssembly loading and supported environments, and links to the shared Yoga compatibility material.

The global site navigation and the documentation sidebar serve different purposes. The landing page and later real Blog or Showcase sections are site-level content; Guide, Essentials, and package sections all belong to the same documentation sidebar. Do not create empty Blog, Showcase, version switcher or package pages merely to make the site appear complete.

Expand All @@ -56,6 +58,7 @@ The benchmark page is a site-level view of retained Node.js results rather than
- Guide introduces the product and establishes the minimum layout-engine mental model.
- Essentials teaches shared concepts and layout tasks in a deliberate learning sequence through `@taffyjs/node` code.
- Package sections explain package-specific runtime requirements or initialization, observable binding behavior, compatibility or migration needs, and exact public APIs.
- Design Philosophy articles explain why a package has its particular public model and boundary. They may mention future work only to state the rule that would govern it; they do not present unshipped APIs or unmeasured performance claims as current features.
- Getting Started and each relevant layout or measurement page own one complete example. There is no separate example collection that repeats those programs, and package pages and README files link to the Guide rather than copying them.
- Package README files remain short installation and orientation pages that link to the website.
- Source declarations and JSDoc remain the exhaustive editor-facing type and field reference. The website explains high-level APIs in human-written prose; its `Style` page groups related fields without reproducing a generated declaration dump or creating one page per field.
Expand Down
24 changes: 22 additions & 2 deletions apps/website/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const documentationSidebar = [
{
text: "@taffyjs/node",
items: [
{ text: "Design Philosophy", link: "/node/design-philosophy" },
{ text: "Overview", link: "/node/" },
{ text: "Nodes and Topology", link: "/node/nodes-and-topology" },
{ text: "Styles and Context", link: "/node/styles-and-context" },
Expand All @@ -38,7 +39,24 @@ const documentationSidebar = [
},
{
text: "@taffyjs/wasm",
items: [{ text: "Overview", link: "/wasm/" }],
items: [
{ text: "Design Philosophy", link: "/wasm/design-philosophy" },
{ text: "Overview", link: "/wasm/" },
],
},
{
text: "@taffyjs/yoga",
items: [
{ text: "Design Philosophy", link: "/yoga/design-philosophy" },
{ text: "Overview", link: "/yoga/" },
],
},
{
text: "@taffyjs/yoga-wasm",
items: [
{ text: "Design Philosophy", link: "/yoga-wasm/design-philosophy" },
{ text: "Overview", link: "/yoga-wasm/" },
],
},
{
text: "Benchmarks",
Expand All @@ -55,13 +73,15 @@ export default defineConfig({
{
text: "Guide",
link: "/guide/getting-started",
activeMatch: "^/(guide|node|wasm)/",
activeMatch: "^/(guide|node|wasm|yoga|yoga-wasm|benchmarks)/",
},
],
sidebar: {
"/guide/": documentationSidebar,
"/node/": documentationSidebar,
"/wasm/": documentationSidebar,
"/yoga/": documentationSidebar,
"/yoga-wasm/": documentationSidebar,
"/benchmarks/": documentationSidebar,
},
socialLinks: [{ icon: "github", link: "https://github.com/hyfdev/taffyjs" }],
Expand Down
8 changes: 6 additions & 2 deletions apps/website/guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ The WebAssembly package for Node.js and bundled browsers. It provides the same h

### `@taffyjs/yoga`

A planned Yoga-compatible API built on `@taffyjs/node`. It is intended for projects that already use Yoga's node and style model or need a straightforward migration path. It will be a compatibility layer rather than another form of the direct `TaffyTree` API.
A Yoga 3.2.1 compatibility facade built on `@taffyjs/node`. It is for projects that already use Yoga's node and style model or need a migration path that keeps supported Yoga imports and calls intact.

This guide uses `@taffyjs/node` by default. The same direct API also applies to `@taffyjs/wasm`; `@taffyjs/yoga` will have a separate consumer-facing model.
### `@taffyjs/yoga-wasm`

The same Yoga compatibility facade built on `@taffyjs/wasm`. It keeps the Yoga-facing source and compatibility rules shared with `@taffyjs/yoga` while making WebAssembly an explicit runtime choice.

This guide uses `@taffyjs/node` by default. The same direct API also applies to `@taffyjs/wasm`. The two Yoga packages preserve Yoga's separate consumer-facing model over the corresponding native and WebAssembly runtimes.

## Credits

Expand Down
31 changes: 31 additions & 0 deletions apps/website/node/design-philosophy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Design Philosophy

A binding can hide its Rust library behind a new JavaScript model. That may make the first call look familiar, but it also gives users two systems to understand: the wrapper and the engine underneath it.

`@taffyjs/node` takes the other route. Taffy is the model.

## Keep Taffy visible

The public API follows Taffy's `TaffyTree` workflow: create nodes, connect them into a tree, compute a layout, and read the stored results. Computation stays explicit. Styles, layouts, and available space keep their Taffy meanings.

This also means that some behavior may not match assumptions borrowed from the DOM or from a JavaScript state library. For example, `setStyle` replaces the complete Taffy style; it does not merge an object into the existing style. That behavior is intentional, not an accident of the binding. When it is the operation you need, the direct method remains available.

The benefit is that a Taffy concept has one meaning. Reading Taffy's documentation, source, or issue discussions does not require translating through another layout abstraction first.

## Keep one owner for layout state

Taffy owns the tree topology, styles, layout cache, computation state, and results. JavaScript receives readable inputs, safe node IDs, and detached result objects, but it does not maintain a second copy of the native tree.

That boundary matters when an application grows. A JavaScript shadow tree would need to stay synchronized after every mutation and failure. It could also disagree with the state that Taffy actually used. With one owner, a layout result always comes from the native tree that performed the calculation.

JavaScript still owns values that are naturally application data, such as node context. The division follows responsibility rather than forcing everything into Rust.

## Improve the crossing, not the layout model

A direct binding does not need to be deliberately inconvenient. It should solve problems created by the JavaScript-to-Rust boundary without replacing Taffy's API.

`updateStyle` is one example. It preserves fields that were not supplied and applies the change against the stored style in Rust. This is friendlier for ordinary updates and avoids reading or cloning a complete style in JavaScript only to change one field. [`setStyle` and `updateStyle`](./set-style-vs-update-style.md) remain separate because they express different operations.

The same rule applies to future performance work. A selective read API may be useful when a measured workload needs one field but a complete snapshot is expensive. If it ships, it should sit beside the complete getter, not turn the direct API into a query language that everyone must adopt.

Use Taffy's operations when the problem is layout. Add a binding-specific operation only when it makes the crossing safer, clearer, or measurably cheaper.
2 changes: 2 additions & 0 deletions apps/website/node/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

Follow [Getting Started](../guide/getting-started.md) to install the package and compute a first layout.

Read the [Design Philosophy](./design-philosophy.md) to understand why the API follows Taffy's model and where the binding deliberately adds JavaScript-specific operations.

## Runtime support

The package requires Node.js 22.18.0 or newer and currently provides native binaries for these targets:
Expand Down
33 changes: 33 additions & 0 deletions apps/website/wasm/design-philosophy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Design Philosophy

Choosing WebAssembly should change where Taffy runs, not how an application describes layout.

That is the central rule behind `@taffyjs/wasm`. It exposes the same public API as `@taffyjs/node`, built from the same authored JavaScript and TypeScript source. A program can choose the native or WebAssembly package without learning a second tree, style, or measurement model.

## Change the runtime, not the program

The two direct packages are not separate implementations kept similar by convention. The Wasm build compiles the source owned by `@taffyjs/node` against a different private binding. The public type and behavior suites then run against both packages.

In ordinary code, the runtime choice is visible in one place:

```ts
import { TaffyTree } from "@taffyjs/wasm";
```

The rest of the direct TaffyJS API stays the same. This is why the Guide and the detailed API pages can use `@taffyjs/node` without maintaining a second Wasm edition of every example.

## Make the choice explicit

`@taffyjs/node` is the native-addon choice on supported platforms. `@taffyjs/wasm` is the WebAssembly choice for bundled browsers and other supported runtimes. The package name records which one the application selected.

There is no automatic fallback from native code to WebAssembly. A silent fallback would make deployment failures harder to see and make performance depend on the machine that happened to load the package. An explicit import keeps the runtime predictable and lets applications make the tradeoff deliberately.

Comparative performance claims should come from end-to-end benchmarks that include JavaScript conversion costs. The architecture makes that comparison useful: either result can guide a package choice without requiring an API rewrite.

## Package the binary with the code

The Wasm binary is stored once inside a private JavaScript module. A bundled browser application does not need to copy a `.wasm` asset, construct its URL, or fetch it at runtime. This is especially useful when the output must be one self-contained JavaScript file or executable.

Initialization belongs to module loading rather than a second TaffyJS lifecycle. That keeps layout code independent of the runtime choice and lets applications use JavaScript's existing loading controls. The [Overview](./index.md#loading) shows the static and lazy forms.

Inlining increases the uncompressed JavaScript payload, and bundled browsers must support the package's module requirements. Those are visible deployment tradeoffs, not costs hidden behind a second public API.
2 changes: 2 additions & 0 deletions apps/website/wasm/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

`@taffyjs/wasm` runs the same TaffyJS API through WebAssembly. Choose it for a bundled browser application, or when you want to use WebAssembly explicitly in Node.js instead of loading a native addon.

Read the [Design Philosophy](./design-philosophy.md) to understand how the package keeps one direct API across native and WebAssembly runtimes.

## Install

```sh
Expand Down
Loading
Loading