# Instance and lifecycle

The [`DiagramInstance`](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/grafloria-renderer-instance-diagraminstance#diagraminstance) is the renderer-level facade: use it for specs, pixels, events, and lifecycle; use its model for data queries and its engine for behavior.

```mermaid
flowchart TB
  Host["Mounted host element"] --> Instance["DiagramInstance"]
  Instance --> Model["DiagramModel\ndata: nodes, links, groups"]
  Instance --> Engine["DiagramEngine\nbehavior: layout, validation, history"]
  Instance --> Pixels["rendered pixels"]
```

## Create the mounted instance

Create the instance with a real DOM container. The container needs a resolved height; a zero-height parent produces a blank canvas. The browser-only factory returns the same instance that framework bindings expose through their initialization callback.

The sample uses the shipped [`LIGHT_THEME`](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/grafloria-renderer-themes-constants#light_theme) for the initial appearance.

```ts
import {
  createDiagram,
  LIGHT_THEME,
  type DiagramInstance,
} from '@grafloria/renderer';

const container = document.getElementById('diagram')!;
container.style.height = '400px';
const nodes = [
  { id: 'start', type: 'rect', position: { x: 40, y: 80 }, label: 'Start' },
  { id: 'finish', type: 'rect', position: { x: 260, y: 80 }, label: 'Finish' },
];

const instance: DiagramInstance = createDiagram(container, {
  nodes,
  theme: LIGHT_THEME,
});
```

The mounted diagram contains two boxes. Pass a different theme at creation or replace it later with `setTheme()`.

The model is the data layer. Read it through [`DiagramModel`](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/grafloria-engine-models-diagrammodel#diagrammodel) when you need live nodes, links, or groups:

```ts
import { createDiagram } from '@grafloria/renderer';

const container = document.getElementById('diagram')!;
container.style.height = '400px';
const instance = createDiagram(container, {
  nodes: [{ id: 'review', type: 'rect', position: { x: 40, y: 80 }, label: 'Review' }],
});
const model = instance.getModel();
const review = model.getNode('review');
const currentNodes = model.getNodes();
```

Use the [`DiagramEngine`](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/grafloria-engine-engine#diagramengine) for behavior that is not an instance method, such as layout, validation, and history:

```ts
import { createDiagram } from '@grafloria/renderer';

const container = document.getElementById('diagram')!;
container.style.height = '400px';
const instance = createDiagram(container, {
  nodes: [{ id: 'review', type: 'rect', position: { x: 40, y: 80 }, label: 'Review' }],
});
const engine = instance.getEngine();
const validation = engine.validateDiagram();
```

Do not call `undo()` on the instance. History belongs to the engine; call `instance.getEngine().undo()` instead. Layout also belongs to the engine, followed by `renderNow()` when you need the result painted before continuing.

## Subscribe to changes

Subscribe on the instance with `on()`. It returns an unsubscribe function, so keep that function with the mounted instance and invoke it during teardown.

```ts
import { createDiagram } from '@grafloria/renderer';

const container = document.getElementById('diagram')!;
container.style.height = '400px';
const instance = createDiagram(container, {
  nodes: [{ id: 'review', type: 'rect', position: { x: 40, y: 80 }, label: 'Review' }],
});
const stopSelection = instance.on('selection:change', ({ nodes: selectedNodes }) => {
  console.log('selected nodes:', selectedNodes.length);
});

const stopViewport = instance.on('viewport:change', ({ zoom }) => {
  console.log('zoom:', zoom);
});

function onUnmount(): void {
  stopSelection();
  stopViewport();
  instance.dispose();
}
```

The event map includes node and edge changes, selection, completed connections, reconnections, node and edge clicks, and viewport changes. The handlers receive live model objects where the event provides them; click events also include world coordinates. Use `off()` when you need to remove a handler by its original function instead of retaining the returned unsubscribe function.

Framework bindings dress the same event map in their own idiom: React uses callback props, Vue uses emits, Angular uses outputs for its component events, and the web element bubbles DOM events. Reach through to `instance.on()` when you need the common instance surface.

## Dispose at unmount

Call `dispose()` from the host's unmount or close path, not immediately after setup. It releases the instance's rendering and interaction resources; the host then no longer owns a live diagram. Dispose subscriptions you manage separately when their API returns an unsubscribe function.

## Related

- [How Grafloria works](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/how-grafloria-works)
- [Events and interaction](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/events-and-interaction)
- [Model and documents](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/model-and-documents)
- [Commands and shared history](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/commands-and-shared-history)
- [Export diagrams](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/export-diagrams)
