feat: add render graph driven renderer architecture

Amp-Thread-ID: https://ampcode.com/threads/T-019f9d91-77c1-7206-a60f-ed6554ce92ab

Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
Amp
2026-07-27 02:53:44 +00:00
co-authored by heaust
parent 8a8369706b
commit d4e8634f67
290 changed files with 48804 additions and 1995 deletions
+47
View File
@@ -0,0 +1,47 @@
# Live composition
## What you will build
An editor that replaces a version-1 node definition with version 2 and migrates its graph instance atomically.
## Prerequisites and checkpoint
Understand [composition](../concepts/composition). Start with the v1 node visible and retain the receipt's `revision`.
## 1. Acquire the v1 revision
```ts
import type { FxNode, FxNodeView } from "fxnode";
const v1Receipt = await api.composeNode("example.live.parameter", liveNodeV1);
let revision = v1Receipt.revision;
```
This is an **excerpt**: await socket dependencies first, compose v1, call `setState`, attach a view, add its instance through that view, attach the host, and render. **Checkpoint:** v1 is visible and `revision` came from its receipt—not a guessed constant.
## 2. Replace it using the v2 receipt
```ts
async function upgrade(root: FxNode, view: FxNodeView) {
const v2Receipt = await root.composeNode("example.live.parameter", liveNodeV2, {
expectedRevision: revision,
});
revision = v2Receipt.revision;
await view.whenRendered();
return v2Receipt;
}
```
Invoke this on an explicit host action. **Checkpoint:** inspect `v2Receipt.status`, `graphChanged`, `graphVersion`, and updated `revision`; the migrated v2 node is visible. Clean up the button/page listeners, host, and API on teardown.
### Why?
Composition revision and graph version are separate concurrency domains. A committed rebind can advance both; a no-op advances neither. Compare-and-swap prevents two writers from assuming the same authority.
## Complete example
See the working [`examples/live-composition/main.ts`](https://github.com/Heaust-ops/fxnode/blob/main/examples/live-composition/main.ts) and its [definitions](https://github.com/Heaust-ops/fxnode/blob/main/examples/live-composition/definitions.ts).
## Related concepts / relevant API / next
Read [graph state and events](../concepts/graph-state-and-events) and [`CompositionReceipt`](/reference/generated/fxnode/type-aliases/CompositionReceipt), then plan [lifecycle cleanup](../guides/rendering-and-lifecycle).