> Aperture 0.1.0 — experimental, unpublished. [Package archive](/downloads/bolted-aperture-0.1.0.tgz).

# Vanilla and framework-neutral integration

Read [the shared guide](guide.md) first. The vanilla starter includes a modal, image gallery, product details, and in-page navigation. Adapt the relevant lifecycle to your project; do not copy the showcase's art or styles unless requested.

```html
<div class="frame"><div class="scene">Revealed content</div></div>
<button type="button" id="toggle">Open / close</button>
```

```css
.frame {
  position: relative;
  height: 480px;
  overflow: hidden;
  padding: 0;
}
```

```ts
import { createAperture } from "@bolted/aperture";
import { parseRecipe, recipeToOptions } from "@bolted/aperture/recipes";

const recipe = parseRecipe(recipeJSON, { strict: true });
const host = document.querySelector<HTMLElement>(".frame")!;
const content = host.querySelector<HTMLElement>(":scope > .scene")!;
const button = document.querySelector<HTMLButtonElement>("#toggle")!;
const reveal = createAperture({ host, content, ...recipeToOptions(recipe) });
const toggle = () => {
  void reveal.toggle();
};
button.addEventListener("click", toggle);

// Call from the application's unmount/teardown lifecycle.
function cleanup() {
  button.removeEventListener("click", toggle);
  reveal.destroy();
}
```

This is a primitive example, not a complete modal. For a modal, open the native dialog first, create the reveal after layout, and await `open()` before focusing its content. Keep a close control outside the clipped child. Close/Escape must await `close()` before closing the dialog, then destroy, restore scrolling, and return focus. Guard rapid repeated requests so interrupted promises cannot move focus or navigate.

For gallery changes, close the old scene, decode the new image, update its caption/alt text, then open. Preserve controls and announce meaningful slide changes. Do not move focus into a slide automatically. For Vue or Svelte, use their mount/unmount lifecycle; the core API is framework-independent.

For real navigation, preserve ordinary links, modified clicks, new tabs and no-JS behavior. Check `status === 'completed'` before invoking the app's navigation function. `onUpdate` runs on every draw: avoid framework state updates there unless the UI needs them.
