# Renderer architecture v2

## Contract

Shared code receives one `AsukaRenderEngine`. Features are grouped by domain:

| Domain | Required service | Optional extension |
| --- | --- | --- |
| Lifecycle | `lifecycle` | - |
| Events | `events` | - |
| History | `history` | - |
| Scene/object editing | `scene`, `objects`, `selection` | - |
| Viewport/export | `viewport`, `exports` | - |
| Drawing surfaces | - | `areas`, `surface` |
| Product 3D | - | `products`, `models`, `parts`, `materials` |
| Native Fabric tooling | - | `canvas2d` |

Shared modules must branch on optional service availability or capabilities, not
on `engine.kind`. Native APIs belong only in engine-specific modules.

The old flat methods and the `.fabric` / `.threeD` namespaces are removed. No
compatibility facade is shipped.

The operation-level support and coordinate contract is maintained in
`RENDERER_FUNCTIONAL_MATRIX.md`. Its source of truth lives outside the runtime
bundle in `scripts/renderer-functional-matrix.cjs`; `npm run audit:renderer-matrix`
checks that every public service method remains classified.

## Loading boundaries

The standard product distribution deliberately exposes a small, stable set of
files instead of workflow microchunks:

1. `asukadesigner.min.js`: renderer-neutral shell and public API.
2. `asuka-fabric.min.js`: Fabric runtime, loaded only when a 2D view needs it.
3. `asuka-babylon.min.js`: Babylon runtime, loaded only when a 3D view needs it.
4. Licensed feature files: `studio-addon.js`, `pricing-addon.js`,
   `pricing-rules-addon.js`, `marker-addon.js`, `drawing-areas-addon.js`, and
   `model-optimizer-addon.js`. Each is loaded only after both license and file
   availability checks pass.

The renderer-neutral Studio 3D implementation is physically contained in
`studio-addon.js`; loading Babylon without the Studio entitlement does not ship
that UI implementation. The current Fabric Studio implementation remains in the
Fabric renderer because it directly depends on Fabric filters and controls. Its
registration and activation are still license-gated, and authorization never
relies on client-side chunk secrecy.

Built-in shell workflows stay grouped in the main file. The main bundle may
dynamically import only the two renderer files and the declared licensed
add-ons; the bundle audit rejects extra JavaScript files or cross-engine imports.

`product-single` intentionally inlines dynamic imports and is not the recommended
artifact when engine isolation matters. It remains an optional universal build
and is currently outside the renderer migration critical path.

## Budgets

- Main shell: 1,000,000-byte target, 1,100,000-byte hard limit.
- Fabric renderer: 700,000-byte target, 900,000-byte hard limit.
- Babylon renderer: 3,500,000-byte target, 4,200,000-byte hard limit.
- Licensed add-ons have individual target and hard limits in
  `scripts/audit-product-bundle.cjs`.
- Fabric, Babylon, and licensed add-ons must remain dynamic imports of the main
  shell and must not import optional sibling add-ons.

Run `npm run check:ci` before release. It type-checks, audits the renderer and 3D
contracts and functional matrix, runs tests, builds the standard product, and
verifies its exact file set and bundle boundaries.

## Validation gates

- `npm run audit:renderer-matrix` keeps all 126 public operations classified,
  including their coordinate spaces and units.
- `npm run test:e2e:renderer-contract` runs the same mounted editing workflow
  against the real Fabric and Babylon adapters. It also validates target-scoped
  3D view/area/layer ZIP exports and checks that export isolation restores the scene.
- `e2e/renderer-isolation.spec.ts` covers 2D-only, 3D-only and mixed network
  loading. The inactive renderer must never be requested before its first view.
- `npm run check:all` is the complete release gate: strict lint, type checking,
  contract audits, unit tests, distribution build/budgets and Chromium workflows.

The renderer migration is complete for the standard split distribution.
`product-single` remains deliberately frozen outside this scope, as documented
above; this is a product packaging choice rather than a Renderer v2 contract gap.
