v1.5.0 ← Examples GitHub
Advanced reactive interface Architecture & Next-gen Node Assets
AriannA
Fine-grain Reactive UI Framework · TypeScript · Zero dependencies
♡ Dedicated with love to my daughter Arianna
A TypeScript UI framework for the web — built around Real DOM, Virtual DOM, fine-grain Signals, reactive State, and a complete 50-control library. Includes 2D/3D renderers, AI/ML engine, quantitative finance (Bachelier, Heston), document generation, data structures (DAG, FSM, Trie), audio/video, and I/O — all with zero dependencies and a dual MIT + Commercial license.
Riccardo-Angeli/AriannA-Js MIT + Commercial · 2012–2026
TypeScript Signal+Sink Zero dependencies 600+ tests 50 controls 11 finance components 20 modifiers 11 additionals MIT + Commercial 2012 – 2026
Core
Global registry, plugin system, namespace management.
Signals
signal() · effect() · computed() · SignalMono · batch
Real DOM
Fluent chainable DOM + Signal+Sink fine-grain API.
Virtual DOM
Declarative tree, lazy mount, pending Sink queue.
State
Deep reactive proxy. Mutate directly, auto-notify.
Rule / Sheet
CSS-in-JS: JSON objects, @media, @keyframes, Less parser.
Two — 2D
SVG + Canvas engine, PathBuilder, Tween, D3 scales.
Three — 3D
WebGPU + WebGL2, PBR, CSG, STL/OBJ/GLB, OrbitControls.
AI / ML
Tensor, Transformer, Tokenizer, WebGPU matmul.
Finance
Indicators, Black-Scholes, Monte Carlo GPU, Backtest.
Docs
DOCX, XLSX, PPTX, PDF, CSV, SVG — read & write.
Video
Screen/camera capture, compositor, GIF encoder.
Audio
AudioEngine, Oscillator, Reverb, Sequencer, MIDI.
IO
FileIO, Http, SSE, WebSocket, LocalStore, IndexedDB.
50 Controls
Button, Table, TreeView, Modal, DatePicker and 45 more.
Finance Components
Candlestick, OrderBook, Heatmap, Donut, Screener…
Modifiers 2D
Resizer · Rotator · Skewer · Rounder · Reflector · Mover
Modifiers 3D
15 geometry + transform modifiers for Three.ts meshes.
4 Syntaxes
Real · Virtual · Decorators · JSX
600+ Tests
All passing. Core, DOM, CSS, AI, Finance, 3D, Modifiers.
Try it live
Edit the code in your head, hit Reload to bring it back. The preview runs in a sandboxed iframe with the AriannA runtime injected from the parent page.
Installation
AriannA is distributed as TypeScript source. No build step required for modern browsers with ES module support — or use Vite / Tauri for production builds.
Install
npm install arianna
# or scaffold a new project
npx arianna new my-app                    # browser
npx arianna new my-app --template tauri   # Tauri desktop
Repository structure
arianna/
├── core/                 // Core, Real, Virtual, Observable, State,// Rule, Sheet, Stylesheet, Namespace,// Context, Directive, Component
├── additionals/          // Domain modules
│   ├── AI.ts             // Tensor, Layers, Transformer, Tokenizer, MarkovChain
│   ├── Animation.ts      // Tween, Timeline, easings
│   ├── Audio.ts          // AudioEngine, Oscillator, effects
│   ├── Data.ts           // FSM, DAG, Trie, PriorityQueue, LRUCache
│   ├── Docs.ts           // In-repo doc-page generator
│   ├── Finance.ts        // BlackScholes, Bachelier, Heston, MonteCarlo,
│   │                     //   Indicators, Portfolio, Backtest
│   ├── Geometry.ts       // AABB, Ray, intersections, hulls
│   ├── IO.ts             // FileIO, Http, SSE, WebSocketIO, LocalStore
│   ├── Latex.ts          // LaTeX → SVG / MathML
│   ├── Math.ts           // Vectors, matrices, noise
│   ├── Network.ts        // Fetch wrappers, retry/backoff
│   ├── SSR.ts            // renderToString, renderToStream, hydrate
│   ├── Three.ts          // 3D scene graph, WebGL renderer
│   ├── Two.ts            // 2D scene graph, SVG/Canvas renderer
│   ├── Video.ts          // VideoPlayer, GIFEncoder
│   └── Workers.ts        // WorkerPool, message passing
├── components/
│   ├── inputs/           // Button, Checkbox, ColorPicker, DatePicker,
│   │                     //   Dropdown, FileUpload, Radio, RangeSlider,
│   │                     //   Rating, SearchBar, Switch, TextField, ...
│   ├── display/          // Avatar, Badge, Banner, Card, Chip, Divider,
│   │                     //   Icon, Modal, ProgressBar, Skeleton, Tooltip, ...
│   ├── layout/           // Accordion, Drawer, Header, Panel, Splitter,
│   │                     //   Stepper, Tabs, Tag, List, Sidebar
│   ├── navigation/       // Breadcrumb, Menu, NavRail, Pagination
│   ├── charts/           // BarChart, LineChart, PieChart
│   ├── data/             // Table, TreeView
│   ├── finance/          // CandlestickChart, LineChart, DepthChart,
│   │                     //   HeatmapChart, PortfolioDonut, PnLChart,
│   │                     //   RiskGauge, OrderBook, Screener,
│   │                     //   Sparkline, AlertBadge
│   └── modifiers/
│       ├── 2D/           // Resizer, Rotator, Skewer, Rounder, Reflector, Mover
│       └── 3D/           // Subdivision, Decimate, Bevel, Mirror, Array,//   Bend, Twist, Wave, Inflate, Smooth, Drag,//   Snap, LOD, Fade, Billboard
├── cli/                  // `arianna` command (new, generate, serve, build)
├── projects/             // Browser / Tauri / iOS / Android templates
├── release/              // Built bundles (arianna.js, arianna.min.js)
└── types/                // Shared type declarations + jsx-runtime
Import
// Bundle entry point — recommended
import { Core, Real, State, signal, effect, computed, batch } from 'arianna';

// Domain additionals
import { Finance, BlackScholes }   from 'arianna/additionals/Finance.ts';
import { AI, MarkovChain }        from 'arianna/additionals/AI.ts';
import { Two, Vec2D, Circle }     from 'arianna/additionals/Two.ts';

// UI controls — tree-shakeable per-file imports
import { Button }                 from 'arianna/components/inputs/Button.ts';
import { Table, TreeView }        from 'arianna/components/data';

// Finance components
import { CandlestickChart, RiskGauge } from 'arianna/components/finance';

// Modifiers
import { Resizer, Rotator }       from 'arianna/components/modifiers/2D';
import { BendModifier }            from 'arianna/components/modifiers/3D';
tsconfig.json (for JSX)
{
  "compilerOptions": {
    "target":            "ES2022",
    "module":            "ESNext",
    "moduleResolution":  "bundler",
    "jsx":               "react-jsx",
    "jsxImportSource":   "arianna",
    "strict":            true
  }
}
Architecture
AriannA is built around fine-grain reactivity: only the exact DOM node that depends on a signal updates when that signal changes — no component re-render, no VDOM diffing. The library is organized in five layers that build on top of each other.
5 · COMPONENTS 50 controls · 11 finance · 20 modifiers (2D/3D) 4 · ADDITIONALS AI · Finance · Two · Three · Animation · Audio · Video · IO · Data · Math · Geometry · Network · Workers · Latex · SSR 3 · DOM Real · Virtual · Rule · Sheet · Stylesheet · Directive · Namespace · Context 2 · REACTIVE PRIMITIVES signal · signalMono · effect · computed · batch · sinkText · sinkClass · untrack 1 · CORE Core · Observable · State · global registry · event bus · plugin system RUNTIME · BROWSER · NODE · TAURI
Signal+Sink — the reactivity core
A signal holds a value plus a list of subscribers. Reading signal.get() inside an effect() registers the effect as a dependency. Writing signal.set(v) triggers every dependent effect synchronously. No reconciliation, no diffing, no microtask queue.
const count = signal(0);
const doubled = computed(() => count.get() * 2);

effect(() => console.log('doubled is', doubled.get()));
// → "doubled is 0"

count.set(5);
// → "doubled is 10"  (synchronous, single dependency walk)

batch(() => {
  count.set(10);
  count.set(20);
});
// → "doubled is 40"  (one effect run, not two)
signal value + subs .get() effect callback sink TextNode or attribute .set() — notify subscribers 1 KB · zero alloc getter/setter pair tracks deps via current-effect stack isolated update no parent re-render
Compiled Hint — static templates with dynamic slots
When you build a tree with Real, AriannA compiles the static skeleton once and inserts subscription points (sinks) only at the dynamic positions. The DOM is created once; future updates touch only the sinks.
const name = signal('Arianna');

new Real('div')
  .child(new Real('h1').text('Hello'))            // static — compiled once
  .child(new Real('span').text(() => name.get()))   // dynamic — sink installed
  .child(new Real('p').text('How are you?'))         // static — compiled once
  .append(document.body);

name.set('World');   // → only the <span> TextNode mutates. h1 and p are untouched.
Core + Addons — the bundle model
AriannA splits responsibilities cleanly: a tiny core that you always need, plus optional addons that you import only where you use them. The core is ~1.5 KB gz; the rest of the library is opt-in.
This matters because most JavaScript frameworks ship one monolithic bundle whether you use 5% or 95% of it. AriannA does the opposite: every addon is a separate module, loadable statically (tree-shaken) or dynamically (code-split by your bundler).
LayerStatusSize (gz)Loaded by
Core — Real, Virtual, State, Observable, Rule, Sheet, signal, effect, computed, batchrequired~1.5 KBStatic import { ... } from 'arianna'
Addon — Two (2D scene graph)optional~8 KBimport { Two } from 'arianna/addons/Two'
Addon — Three (3D + WebGL)optional~12 KBimport { Three } from 'arianna/addons/Three'
Addon — Finance (BlackScholes, Heston, ...)optional~6 KBimport { Finance } from 'arianna/addons/Finance'
Addon — AI (Tensor, Transformer, ...)optional~10 KBimport { AI } from 'arianna/addons/AI'
Addon — Audio · Video · IO · Animation · Data · Geometry · Math · Latex · Network · Workers · SSRoptionalvariesPer-addon paths under arianna/addons/
Components — 50+ UI controls, 11 finance components, 20 modifiersopt-inper-componentarianna/components/<category>/<Name>
Loading addons — three patterns
1. Static import — addon code joins your main bundle. Use this when the addon is needed at boot.
import { Real, signal } from 'arianna';
import { Finance }       from 'arianna/addons/Finance';

const price = Finance.BlackScholes.price(100, 105, 0.25, 0.05, 0.20, 'call');
2. Dynamic import — addon loads in a separate chunk on demand. Use this for routes / lazy features.
async function openTradingPanel() {
  const { Finance } = await import('arianna/addons/Finance');
  const { CandlestickChart } = await import('arianna/components/finance/CandlestickChart');
  // ... build the panel
}
3. Plugin registration — register an addon (your own or one of AriannA's) on the global Core registry so the rest of your code can find it via Core.has('finance').
import { Core } from 'arianna';
import { Finance } from 'arianna/addons/Finance';

Core.use({
  name: 'finance',
  install(core) { (core as any).Finance = Finance; },
});

Core.plugins(); // → ['finance', ...]
Writing your own addon
An addon is just a module that exports a namespace and (optionally) registers itself on window. The convention used across AriannA's built-in addons:
// my-addon.ts
export const MyAddon = {
  greet(name: string) { return `hello, ${name}`; },
};

if (typeof window !== 'undefined')
  Object.defineProperty(window, 'MyAddon', {
    value: MyAddon, writable: false, configurable: false, enumerable: false,
  });

export default MyAddon;
That's the entire contract. A single named export, optional window registration with non-configurable property descriptor (so nothing else can shadow it), and a default export for ergonomic import MyAddon from .... The addon doesn't need to know anything about Core — it's standalone.
Layers in detail
LayerKey typesPurpose
CoreCore, Observable, StateGlobal module registry, typed event bus, Proxy-backed reactive state objects
Reactive primitivessignal, signalMono, effect, computed, batchFine-grain reactivity. signalMono is the zero-allocation variant for single-subscriber TextNode bindings.
DOMReal, Virtual, Rule, Sheet, Directive, Namespace, ContextImperative + declarative DOM trees, scoped CSS, custom elements, SVG/MathML namespaces, dependency injection
AdditionalsTwo, Three, Finance, AI, Animation, Audio, Video, IO, Data, …Domain-specific modules. Optional, tree-shakeable.
Components50+ UI controls, 11 finance components, 20 modifiersReady-to-use, themable, accessible
Immutable global registry
Every namespace registers itself on window via Object.defineProperty with writable: false, configurable: false. Once loaded, it cannot be tampered with. window.Core === Core, always.
Core.version              // → { major: 1, minor: 2, patch: 0 } — frozen
Core.use(myPlugin)
Core.plugins()            // → ['my-plugin']
window.Core === Core      // → true, always
Real vs Virtual
Use Real for imperative, chainable DOM control with fluent API. Use Virtual for declarative rendering — describe the tree, let AriannA mount it. Both produce identical Real DOM output and share the same reactive primitives.
4 Syntaxes
AriannA supports four authoring styles. All produce the same result. Choose based on your workflow and tooling preferences.
1. Creating a reactive counter
import { Real, State } from './arianna-ts/index.ts';

const state = new State({ count: 0 });
const btn   = new Real('button');
btn.render().textContent = 'Clicked 0 times';

btn.on('click', () => {
  state.State.count++;
  btn.render().textContent = `Clicked ${'{'}state.State.count{'}'} times`;
});

state.subscribe((key, val) => console.log(key, val));
document.body.appendChild(btn.render());
import { Virtual, State } from './arianna-ts/index.ts';

const state = new State({ count: 0 });
const btn   = Virtual.Create('button');
btn.set('textContent', 'Clicked 0 times');

btn.on('click', () => {
  state.State.count++;
  btn.set('textContent', `Clicked ${'{'}state.State.count{'}'} times`);
});

Virtual.Mount(btn, document.body);
import { Component, Prop, Watch } from './arianna-ts/index.ts';

@Component({ tag: 'click-counter' })
class ClickCounter extends HTMLElement {
  @Prop() count = 0;

  @Watch('count')
  onCountChange(next: number) {
    this.textContent = `Clicked ${'{'}next{'}'} times`;
  }

  connectedCallback() {
    this.textContent = 'Clicked 0 times';
    this.addEventListener('click', () => this.count++);
  }
}
// Usage: <click-counter></click-counter>
/* @jsxImportSource arianna */
import { useState } from './arianna-ts/index.ts';

function ClickCounter() {{
  const [count, setCount] = useState(0);
  return (
    <button onClick={{() => setCount(count + 1)}}>
      Clicked {{count}} times
    </button>
  );
}}
2. Rendering a reactive list
const state = new State({{ items: ['Alpha', 'Beta'] }});
const ul    = new Real('ul');

const render = () => {{
  ul.render().innerHTML = '';
  state.State.items.forEach(item => {{
    const li = new Real('li');
    li.render().textContent = item;
    ul.render().appendChild(li.render());
  }});
}};
state.subscribe(render);
render();
document.body.appendChild(ul.render());

// Mutate — auto re-renders
state.State.items.push('Gamma');
const buildList = () => {{
  const ul = Virtual.Create('ul');
  state.State.items.forEach(item => {{
    const li = Virtual.Create('li');
    li.set('textContent', item); ul.add(li);
  }});
  return ul;
}};
let root = Virtual.Mount(buildList(), document.body);
state.subscribe(() => {{ root.unmount(); root = Virtual.Mount(buildList(), document.body); }});
@Component({{ tag: 'item-list' }})
class ItemList extends HTMLElement {{
  @Prop() items: string[] = ['Alpha', 'Beta'];

  @Watch('items')
  onItemsChange() {{ this.innerHTML = this.items.map(i => `<li>${'{'}i{'}'}</li>`).join(''); }}

  add(item: string) {{ this.items = [...this.items, item]; }}
}}
function ItemList() {{
  const [items, setItems] = useState(['Alpha', 'Beta']);
  const add = () => setItems([...items, 'Item ' + (items.length + 1)]);
  return (
    <div>
      <ul>{{items.map(i => <li>{{i}}</li>)}}</ul>
      <button onClick={{add}}>Add item</button>
    </div>
  );
}}
3. Custom element with styles
import { Real, Rule, Sheet } from 'arianna';

// Scoped CSS via Rule + Sheet
const sheet = new Sheet()
  .add(new Rule('.my-card', {
    display: 'block',
    padding: '16px',
    border:  '1px solid #ddd',
    borderRadius: '6px',
  }))
  .add(new Rule('.my-card:hover', {
    boxShadow: '0 4px 12px rgba(0,0,0,.1)',
  }))
  .attach();

// Build the card
const card = new Real('div')
  .cls('my-card')
  .child(new Real('h2').text('Hello'))
  .child(new Real('p').text('A reusable card'))
  .append(document.body);
import { Virtual, Rule, Sheet } from 'arianna';

new Sheet()
  .add(new Rule('.my-card', { padding: '16px', border: '1px solid #ddd' }))
  .attach();

const card = Virtual.Create('div', { class: 'my-card' });
const title = Virtual.Create('h2'); title.set('textContent', 'Hello');
const body  = Virtual.Create('p');  body.set('textContent', 'A reusable card');
card.add(title, body);
Virtual.Mount(card, document.body);
import { Component, Prop } from 'arianna';

@Component({
  tag: 'my-card',
  styles: `
    :host         { display: block; padding: 16px; border: 1px solid #ddd; border-radius: 6px }
    :host(:hover) { box-shadow: 0 4px 12px rgba(0,0,0,.1) }
  `,
})
class MyCard extends HTMLElement {
  @Prop() title = '';
  @Prop() body  = '';

  render() {
    return `<h2>${this.title}</h2><p>${this.body}</p>`;
  }
}

// <my-card title="Hello" body="A reusable card"></my-card>
/* @jsxImportSource arianna */
import { Rule, Sheet } from 'arianna';

new Sheet()
  .add(new Rule('.my-card', { padding: '16px', border: '1px solid #ddd' }))
  .attach();

function MyCard({ title, children }: { title: string; children?: any }) {
  return (
    <div className="my-card">
      <h2>{title}</h2>
      <p>{children}</p>
    </div>
  );
}

// <MyCard title="Hello">A reusable card</MyCard>
Benchmark
Performance measured with the official js-framework-benchmark (Stefan Krause) — keyed mode, Chrome ×4 CPU throttle, Mac M-series. AriannA v1.2.0 vs Solid v1.9.3 and React 18.3.
Duration (ms) — lower is better
Benchmark AriannA Solid React vs Solid vs React
create 1,000 rows 82.5 80.6 91.2 +2% −9%
replace 1,000 rows 89.3 90.2 103.4 −1% −14%
update every 10th row (1k) 40.5 40.2 46.1 −12%
select row (SignalMono) 8.7 11.1 14.3 −22% ★ −39% ★★
swap rows (SignalMono) 30.5 48.8 62.1 −38% ★★ −51% ★★
remove row 37.1 38.1 41.8 −3% −11%
create 10,000 rows 874 839 912 +4% −4%
append 1,000 rows 93.7 96.2 108.5 −3% −14%
clear rows 30.4 34.7 38.2 −12% −20%
Script time (ms) — isolates JS execution cost
Benchmark AriannA Solid React vs Solid
update every 10th row 1.3 2.8 4.1 −54% ★
select row 0.2 2.2 3.8 −91% ★★
swap rows 0.1 3.3 5.7 −97% ★★
remove row 0.2 1.3 2.1 −85%
Memory & Bundle
Metric AriannA Solid React vs Solid
Memory after create 1k rows 2.06 MB 2.64 MB 3.41 MB −22% ★
Bundle size (gzipped) 1.5 KB 4.5 KB 45 KB 3× less ★★
Why swap-rows and select-row win by so much
These two tests are where SignalMono and the Signal+Sink architecture shine. Instead of re-rendering a component or diffing a VDOM tree, AriannA wires a signal directly to a single Text node via node.nodeValue = value. When the signal fires, only that node updates — no wrapper, no scheduler, no diff. The result: 0.1 ms script time on swap-rows vs 3.3 ms for Solid (−97% script) and 0.2 ms on select-row vs 2.2 ms (−91% script).
Conditions: Mac M-series · Chrome ×4 CPU throttle · js-framework-benchmark keyed mode · median of 5 runs. Solid v1.9.3 · React 18.3.1 · AriannA v1.2.0. Bundle size = core only (no components). React includes react-dom.
Core
The global registry. Registers itself on window as an immutable property. Provides versioning and a plugin system.
Property / MethodTypeDescription
Core.versionfrozen object{ major, minor, patch } — SemVer, never writable
Core.NamespacesobjectRegistered HTML / SVG / MathML / X3D namespaces
Core.ScopesobjectProperty descriptor presets: public, protected, private, static
Core.use(plugin, opts?)(CorePlugin,any?)→CoreRegister plugin idempotently — safe to call multiple times
Core.plugins()()→string[]List all registered plugin names
// Plugin interface
interface CorePlugin {
  name    : string;
  install : (core: typeof Core, opts?: unknown) => void;
}

Core.use({
  name   : 'my-plugin',
  install: (core) => { (core as any).myFeature = () => {}; }
});
Core.plugins();           // → ['my-plugin']
Core.use(myPlugin);       // second call → no-op (idempotent)
Core.version.major;       // → 1
Core.version
Frozen SemVer object. Reading is always safe. Mutation throws in strict mode (silently ignored otherwise) — Object.isFrozen(Core.version) === true.
Core.version
// → { major: 1, minor: 2, patch: 0 }

// Compare versions
if (Core.version.major >= 1 && Core.version.minor >= 2) {
  // safe to use signalMono / sinkText
}

// Frozen — these all fail silently or throw
Core.version.major = 99;          // no-op (or TypeError in strict)
delete Core.version.patch;       // no-op
Object.isFrozen(Core.version);    // → true
Core.Namespaces
Pre-registered XML namespaces for non-HTML elements. Used by Real / Virtual / Namespace when creating SVG, MathML, or X3D nodes (document.createElementNS). You can register custom namespaces too.
Core.Namespaces.HTML
// → 'http://www.w3.org/1999/xhtml'

Core.Namespaces.SVG
// → 'http://www.w3.org/2000/svg'

Core.Namespaces.MathML
// → 'http://www.w3.org/1998/Math/MathML'

Core.Namespaces.XLink
// → 'http://www.w3.org/1999/xlink'

// Used internally — Real picks the namespace by tag
new Real('svg')         // → SVG namespace
  .child(new Real('circle').attr('r', '40'));

// Register your own
Core.Namespaces.MyXML = 'https://example.com/ns/v1';
new Real('my-tag', { namespace: 'MyXML' });
Core.Scopes
Property descriptor presets for use with Object.defineProperty. Encodes the four common visibility/mutability combinations as named constants — clearer intent than ad-hoc descriptors, and consistent across the framework.
Core.Scopes.public
// → { writable: true,  enumerable: true,  configurable: true  }

Core.Scopes.protected
// → { writable: true,  enumerable: false, configurable: true  }

Core.Scopes.private
// → { writable: true,  enumerable: false, configurable: false }

Core.Scopes.static
// → { writable: false, enumerable: true,  configurable: false }

// Apply a scope when defining a property
Object.defineProperty(target, 'apiKey', {
  ...Core.Scopes.private,        // hidden + locked
  value: 'sk-...',
});

// Same pattern Core itself uses to register itself on window:
Object.defineProperty(window, 'Core', {
  ...Core.Scopes.static,         // read-only public global
  value: Core,
});
Signals & Fine-grain Reactivity
AriannA v1.2.0 ships a complete Signal+Sink system. Fine-grain reactivity means only the exact DOM node that depends on a signal updates — no component re-render, no diffing, no VDOM overhead.
Core primitives
FunctionReturnsDescription
signal(v)Signal<T>Atomic reactive value. .get() tracks, .set() notifies, .peek() reads without tracking.
signalMono(v)SignalMono<T>Single-slot signal — direct TextNode patching via sinkText(). Zero wrapper overhead.
effect(fn)() => voidRuns fn immediately, re-runs whenever any signal read inside changes. Returns cleanup.
computed(fn)ReadonlySignal<T>Derived signal — lazy, memoized, tracks dependencies automatically.
batch(fn)voidDefers all notifications until fn() completes. Prevents cascading updates.
untrack(fn)TReads signals inside fn without registering as dependencies.
sinkText(s, node)voidWires a SignalMono directly to a Text node — zero allocation per update.
sinkClass(s, el, cls)voidToggles a CSS class on an element when signal value changes.
signal() — atomic reactive value
import { signal, effect, computed, batch } from 'arianna';

const count = signal(0);
const doubled = computed(() => count.get() * 2);

effect(() => {
  console.log(`count=\${count.get()}, doubled=\${doubled.get()}`);
});

count.set(5);   // logs: count=5, doubled=10
count.set(10);  // logs: count=10, doubled=20

// batch — single flush
batch(() => {
  count.set(100);
  count.set(200);
}); // only one effect run: count=200

// peek — read without tracking dependency
effect(() => {
  const curr = count.get();  // tracked
  const prev = count.peek(); // NOT tracked — won't re-run
});
Signal+Sink on Real DOM
Real and VirtualNode both expose the full Signal+Sink API. Each sink creates a single isolated effect tied to exactly one DOM node/attribute.
import { Real, signal } from 'arianna';

const name    = signal('AriannA');
const loading = signal(false);
const color   = signal('#e40c88');

const el = new Real('div')
  // TextNode Sink — only the text node updates
  .text(() => `Hello, \${name.get()}!`)
  // Attribute Sink — updates disabled attr
  .attr('disabled', () => loading.get() ? '' : null)
  // Class Sink — toggles CSS class
  .cls('loading', () => loading.get())
  // Style Sink — updates inline style
  .style('color', () => color.get())
  // Property Sink — sets .value on input
  .prop('dataset.label', () => name.get())
  .append(document.body);

name.set('World');  // only the TextNode updates — nothing else re-renders
signalMono() + sinkText() — zero-overhead TextNode
SignalMono is a single-slot signal for direct TextNode patching. Used internally by the benchmark — achieves 97% script reduction on swap-rows vs Solid.
import { signalMono, sinkText } from 'arianna';

const label = signalMono('Initial');

// Wire signal directly to a TextNode — no wrapper allocation
const node = document.createTextNode(label.peek());
document.body.appendChild(node);
sinkText(label, node);

// Updates the TextNode's nodeValue directly — zero overhead
label.set('Updated');  // → node.nodeValue = 'Updated'

// Via Real.textMono() — creates + wires in one call
const price = signalMono('€ 0.00');
new Real('span').textMono(price).append(document.body);
price.set('€ 1.99');  // direct node.nodeValue write
Two-way binding
import { Real, signal } from 'arianna';

const val = signal('');

// .bind(getter, setter) — two-way
const input = new Real('input')
  .bind(() => val.get(), (v) => val.set(v))
  .append(document.body);

// Mirror elsewhere — auto-updates on every keystroke
new Real('p').text(() => `You typed: \${val.get()}`).append(document.body);
Observable pub/sub (instance API)
import { Observable } from 'arianna';

const bus = new Observable();

bus.on('data-ready', (e) => console.log(e));
bus.fire({ Type: 'data-ready', payload: [1, 2, 3] });

// DOM bus (static) — cross-component events
Observable.On(document, 'theme-changed', (e) => applyTheme(e.detail));
State
Proxy-based reactive state. Mutate State.State directly — subscribers notified automatically. Includes computed values, batching, and StateMachine.
Property / MethodTypeDescription
state.StateProxy<T>Reactive proxy — mutate directly
state.subscribe(cb)(fn) → unsub fnSubscribe to any state change
state.computed(key,fn)(string,fn) → thisDerived value — recomputed on dependency change
state.batch(fn)(fn) → thisGroup multiple mutations into one notification
state.reset()() → thisReset to initial values
state.snapshot()() → TPlain non-reactive copy of current state
import State from './arianna-ts/State.ts';

const state = new State({ count: 0, name: 'AriannA' });

const unsub = state.subscribe((key, value) => {
  console.log(key, '→', value);
});

state.State.count = 1;        // triggers subscriber

state.computed('doubled', s => s.count * 2);
state.State.doubled;              // → 2

state.batch(() => {
  state.State.count = 10;      // single notification for both
  state.State.name  = 'New';
});

unsub();                          // stop listening
Deeply nested objects + array indices
The Proxy is recursive — every plain object and array reachable from the root becomes reactive automatically. Mutating a single array index, or a property six levels deep, fires exactly one notification with the full path. No need to flatten your data, no need for set() / setIn() helpers like Immer or Redux.
import { State } from 'arianna';

const store = new State({
  user: {
    name: 'Riccardo',
    addresses: [
      { city: 'Zurich',  primary: true  },
      { city: 'Roma',    primary: false },
    ],
  },
  cart: {
    items: [
      { sku: 'A1', qty: 2, meta: { gift: false } },
      { sku: 'B2', qty: 1, meta: { gift: true  } },
    ],
    totals: { subtotal: 0, tax: 0 },
  },
});

store.subscribe((path, value) => console.log(path, '→', value));

// (1) Mutate a deep scalar — single notification with the full path
store.State.user.addresses[1].primary = true;
// → "user.addresses.1.primary" → true

// (2) Mutate inside a nested object inside an array
store.State.cart.items[0].meta.gift = true;
// → "cart.items.0.meta.gift" → true

// (3) Array methods are intercepted — push/splice/pop all notify
store.State.cart.items.push({ sku: 'C3', qty: 5, meta: { gift: false } });
// → "cart.items.2"      → { sku: 'C3', qty: 5, meta: {…} }
// → "cart.items.length" → 3

store.State.cart.items.splice(0, 1);
// → "cart.items.0"      → { sku: 'B2', … }   (shift)
// → "cart.items.1"      → { sku: 'C3', … }
// → "cart.items.length" → 2

// (4) Reassign an entire subtree — children are re-wrapped lazily
store.State.user.addresses = [{ city: 'Milan', primary: true }];
// → "user.addresses"     → [{ city: 'Milan', primary: true }]
store.State.user.addresses[0].city = 'Genoa';       // still reactive
// → "user.addresses.0.city" → "Genoa"

// (5) Path-targeted subscription — listen only to one branch
const off = store.subscribePath('cart.items', (path, value) => {
  console.log('cart changed:', path, value);
});

// (6) Computed over deep data — recomputes only when its deps change
store.computed('cart.totals.subtotal', s =>
  s.cart.items.reduce((acc, it) => acc + it.qty, 0)
);
store.State.cart.totals.subtotal;   // → 6
store.State.cart.items[0].qty = 10;
store.State.cart.totals.subtotal;   // → 15  (auto-recomputed)
Implementation note: each nested object/array is wrapped in its own Proxy lazily on first access. Array index mutations are detected via the set trap on numeric keys; length changes from push/pop/splice notify separately, so subscribers can rebuild lists efficiently.
Define a component
A component in AriannA is just a function that returns a piece of DOM. There are three ways to write that function (function declaration, class, JSX) and two ways to construct the DOM inside it (Real for fluent imperative, Virtual for declarative tree). All combinations interoperate — pick the style that fits each part of your app.
Quickest possible
A button that says hello.
Function · Real
Most common style. Pure function, returns a Real wrapper, fluent chain inside. No state, no class, no JSX — just function calls.
Function · Virtual
Same shape as above, but using Virtual.Create() for declarative tree construction. Virtual.Mount() commits the tree to the DOM.
Class · Real
Useful when the component owns local state or needs lifecycle. The constructor sets up signals and DOM; .mount(parent) attaches it.
Class · Define() — custom element
Register the class as a real Web Component with Real.Define('my-tag', MyClass, HTMLElement). From that point on you can use <my-tag></my-tag> in plain HTML, in any framework, anywhere. Lifecycle methods (connectedCallback, disconnectedCallback) work as in standard Web Components.
Function · Constructor — legacy / imperative
A plain function called with new acts as a constructor. Useful for migrating non-class codebases. this refers to the instance being created; signals work the same way.
Class · Inheritance — composing components
Components are plain JavaScript classes. They compose with standard extends — no framework-specific wiring. Override methods or call super.method() to augment behavior.
JSX · Real
Familiar React-like syntax compiled by AriannA's JSX runtime. Configure tsconfig.json with "jsxImportSource": "arianna". Each tag becomes a Real instance under the hood.
Composition
Components compose by returning DOM and accepting parameters. Pass signals down for shared state.
When to use what
StyleBest forTradeoffs
Function · RealMost components — buttons, cards, lists, formsImperative; reads top-to-bottom; no JSX tooling needed
Function · VirtualTrees built from data (lists, nested config)Slightly more verbose; mount step is explicit
Class · RealStateful widgets, modals, controllers with cleanupMore boilerplate; useful when lifecycle matters
Class · Define()Reusable custom elements consumable as HTML tags from any frameworkWeb Components lifecycle; cross-framework distribution
Function · ConstructorMigrating legacy non-class codebasesImperative; this binding requires care
Class · InheritanceBuilding component libraries; reusable base classesStandard JS class semantics; super() and overrides
JSX · RealTeams coming from ReactRequires tsconfig + JSX runtime; not zero-config
Real
Try it live
Edit the code, hit Reload, see the result update in the sandboxed preview below.
Constructor overloads
CallModeReturns
Real('div')Wrapper — no newThe tag class/constructor
Real('#my-id')WrapperReal wrapping that element
Real(domElement)WrapperReal wrapping that element
Real('tag', Ctor, Base)DefineRegisters custom element
new Real('div')InstanceReal instance with <div>
new Real('div', { css: {} })InstanceReal with styles applied
new Real('#my-id')InstanceReal wrapping existing element
new Real(domElement)InstanceReal wrapping live element
new Real(virtualNode)InstanceReal from Virtual's element
Fluent, chainable DOM wrapper. Two modes: wrapper (no new) returns constructor/element; instance (new Real(...)) creates a Real instance.
Constructor overloads
// Wrapper mode — no new
Real('div')                  // tag class wrapper
Real('#my-id')              // querySelector → Real of that element
Real(HTMLButtonElement)        // interface wrapper
Real(existingNode)             // wrap existing DOM node

// Instance mode — creates element
new Real('button')                          // <button>
new Real('button', {{ css: {{ color: 'red' }} }}) // with styles
new Real(HTMLButtonElement)                   // from interface
new Real(myVirtualNode)                       // from Virtual node

// Define custom element
Real('my-tag', MyConstructor, HTMLButtonElement);
Instance methods (fluent — all return this)
Property / MethodTypeDescription
.render()HTMLElementReturns the underlying live DOM element
.on(type, cb)thisaddEventListener
.off(type, cb)thisremoveEventListener
.fire(event)thisdispatchEvent
.append(parent)thisAttach to parent element
.add(...nodes)thisAppend children (optional index)
.remove(...nodes)thisRemove specific children
.get(name)anyGet attribute or property
.set(name, val)thisSet attribute or property
.show() / .hide()thisToggle display
.log()thisconsole.log the element
Virtual
Constructor overloads — identical to Real
CallModeReturns
Virtual('div')Wrapper — no newVirtualNode for tag
Virtual('#my-id')WrapperVirtualNode shadowing DOM element
Virtual(domElement)WrapperVirtualNode wrapping live element
Virtual(realInstance)WrapperVirtualNode from Real's element
Virtual(virtualNode)WrapperReturns the node itself
Virtual('tag', Ctor, Base)DefineRegisters custom element
new Virtual('div')InstanceVirtualNode, no DOM until mount
new Virtual('div', { class: 'x' }, 'text')InstanceVirtualNode with attrs + children
new Virtual('#my-id')InstanceVirtualNode shadowing DOM element
new Virtual(domElement)InstanceVirtualNode wrapping live element
new Virtual(realInstance)InstanceVirtualNode from Real's element
Declarative virtual DOM tree. Callable with or without new — mirrors Real's constructor overloads. Nodes are described without touching the live DOM until mounted.
Constructor overloads (mirrors Real)
// WRAPPER mode — no new (like Real)
Virtual('div')                   // → Virtual.Create('div')
Virtual('#my-id')              // → wraps existing DOM element
Virtual(domElement)             // → wraps live DOM element
Virtual(myRealInstance)         // → wraps Real's element
Virtual(existingVirtualNode)    // → returns the node itself

// INSTANCE mode — with new (identical behaviour)
new Virtual('div')                // → new VirtualNode('div')
new Virtual('div', {{ class: 'card' }}) // → with attrs
new Virtual('#my-id')           // → shadow existing element
new Virtual(domElement)          // → wrap live element
new Virtual(myRealInstance)      // → wrap Real's element
Instance methods added (parity with Real)
MethodReturnsDescription
.show()thisel.style.display = '' — mirrors Real.show()
.hide()thisel.style.display = 'none' — mirrors Real.hide()
.valueOf()ElementReturns underlying DOM element — mirrors Real.valueOf()
.css(prop, val)thisSet CSS style property on mounted element
.dom(type, cb)thisNative DOM addEventListener (distinct from internal .on() bus)
.domOff(type, cb)thisNative DOM removeEventListener
Static API
Property / MethodTypeDescription
Virtual.Create(tag, attrs?, ...children)→ VirtualNodeCreate a virtual node
Virtual.Mount(node, parent)→ VirtualNodeRender node to real DOM
Virtual.Parse(html)→ VirtualNodeParse HTML string into VirtualNode tree
Virtual.NodesMap<string,VirtualNode>Global registry of all live nodes
VirtualNode methods
Property / MethodTypeDescription
node.add(...children)thisAppend child nodes
node.remove(...children)thisRemove child nodes
node.get(name) / node.set(name,val)any / thisAttribute access — syncs to DOM if mounted
node.mount(parent)thisRender to real DOM
node.unmount()thisRemove from real DOM
node.clone()VirtualNodeDeep clone the virtual tree
node.on(type, cb)thisSubscribe to internal event bus
node.fire(event)thisDispatch on internal event bus
import { Virtual } from './arianna-ts/Virtual.ts';

const card  = Virtual.Create('div', {{ class: 'card' }});
const title = Virtual.Create('h2'); title.set('textContent', 'Hello');
card.add(title);

Virtual.Mount(card, document.body);
// later:
card.unmount();
card.set('class', 'card card--active'); // syncs if mounted

card.on('VNode-Changed', e => console.log(e));
card.fire({{ Type: 'VNode-Changed', node: card }});
Usage in all 4 syntaxes
The same result — a card with a title and a click handler — written in each AriannA style.
1. Simple card with click event
// Real — imperative, fluent, live DOM
import {{ Real }} from './arianna-ts/Real.ts';

const card  = new Real('div');
const title = new Real('h2');
const body  = new Real('p');

title.render().textContent = 'Hello from Real';
body.render().textContent  = 'Fluent, chainable DOM wrapper.';

card.render().appendChild(title.render());
card.render().appendChild(body.render());
card.on('click', () => console.log('Real card clicked'));
document.body.appendChild(card.render());
// new Virtual — declarative, tree-based
import {{ Virtual }} from './arianna-ts/Virtual.ts';

const card  = Virtual.Create('div',  {{ class: 'card' }});
const title = Virtual.Create('h2');
const body  = Virtual.Create('p');

title.set('textContent', 'Hello from Virtual');
body.set('textContent',  'Declarative, tree-based.');

card.add(title, body);
card.on('click', () => console.log('Virtual card clicked'));

// Nothing touches the DOM until Mount
Virtual.Mount(card, document.body);

// Later: update live DOM via set()
title.set('textContent', 'Updated!'); // syncs immediately
import {{ Component, Prop, Watch }} from './arianna-ts/index.ts';

@Component({{ tag: 'my-card' }})
class MyCard extends HTMLElement {{
  @Prop() title = 'Hello from Decorators';
  @Prop() body  = 'Class-based, reactive.';

  @Watch('title')
  onTitleChange(next: string) {{
    const el = this.querySelector('h2');
    if (el) el.textContent = next;
  }}

  connectedCallback() {{
    this.innerHTML = `
      <div class="card">
        <h2>${{'{'}this.title{'}'}</h2>
        <p>${{'{'}this.body{'}'}</p>
      </div>
    `;
    this.addEventListener('click', () => console.log('Decorator card clicked'));
  }}
}}
// <my-card></my-card>
/* @jsxImportSource arianna */
/* @dom-render: virtual */  ← outputs VirtualNode tree

function MyCard({{ title, body }}: {{ title: string; body: string }}) {{
  return (
    <div className="card"
         onClick={{() => console.log('JSX card clicked')}}>
      <h2>{{title}}</h2>
      <p>{{body}}</p>
    </div>
  );
}}

// With @dom-render: virtual — produces VirtualNode
// With @dom-render: real (default) — produces Real instance
const vnode = <MyCard
  title="Hello from JSX"
  body="Declarative, JSX-powered."
/>;
2. Reactive list with State
import {{ Real, State }} from './arianna-ts/index.ts';

const state = new State({{ items: ['Alpha', 'Beta'] }});
const ul    = new Real('ul');

const render = () => {{
  ul.render().innerHTML = '';
  state.State.items.forEach(item => {{
    const li = new Real('li');
    li.render().textContent = item;
    ul.render().appendChild(li.render());
  }});
}};
state.subscribe(render);
render();
document.body.appendChild(ul.render());
state.State.items.push('Gamma'); // auto re-renders
import {{ Virtual, State }} from './arianna-ts/index.ts';

const state = new State({{ items: ['Alpha', 'Beta'] }});

const buildList = () => {{
  const ul = Virtual.Create('ul');
  state.State.items.forEach(item => {{
    const li = Virtual.Create('li');
    li.set('textContent', item);
    ul.add(li);
  }});
  return ul;
}};

// Mount initial tree
let root = Virtual.Mount(buildList(), document.body);

// On state change: unmount old, mount new
state.subscribe(() => {{
  root.unmount();
  root = Virtual.Mount(buildList(), document.body);
}});

state.State.items.push('Gamma'); // triggers unmount + remount
@Component({{ tag: 'item-list' }})
class ItemList extends HTMLElement {{
  @Prop() items: string[] = ['Alpha', 'Beta'];

  @Watch('items')
  onItemsChange(next: string[]) {{
    this.innerHTML = next
      .map(i => `<li>${{i}}</li>`)
      .join('');
  }}

  connectedCallback() {{
    this.innerHTML = this.items.map(i => `<li>${{i}}</li>`).join('');
  }}

  add(item: string) {{
    this.items = [...this.items, item]; // @Watch triggers
  }}
}}
function ItemList() {{
  const [items, setItems] = useState(['Alpha', 'Beta']);

  const add = () => setItems([...items, 'Item ' + (items.length + 1)]);

  return (
    <div>
      <ul>
        {{items.map((item, i) => (
          <li key={{i}}>{{item}}</li>
        ))}}
      </ul>
      <button onClick={{add}}>Add item</button>
    </div>
  );
}}
3. Virtual-specific: parse, clone, event bus
These patterns are unique to Virtual — no equivalent in Real.
// Parse HTML string → VirtualNode tree
const tree = Virtual.Parse(`
  <ul>
    <li>Alpha</li>
    <li>Beta</li>
  </ul>
`);
Virtual.Mount(tree, document.body);

// Clone a subtree before mounting
const original = Virtual.Create('div', { class: 'card' });
const clone     = original.clone();
clone.set('class', 'card card--active');
Virtual.Mount(original, document.body);
Virtual.Mount(clone,    document.body);

// Virtual event bus — communicates without DOM
const vnode = Virtual.Create('section');
vnode.on('data-ready', e => console.log('Payload:', e.payload));
vnode.fire({ Type: 'data-ready', payload: { count: 42 } });

// Check children without touching live DOM
const child = Virtual.Create('p');
vnode.add(child);
vnode.contains(child); // → true

// Access global node registry
Virtual.Nodes.get(vnode.Id); // → vnode
Virtual.Nodes.size;          // → total mounted nodes
Rule & Stylesheet
CSS-in-JS. Rule is a single CSS ruleset. Sheet is an ordered collection of Rules injected as a <style> element.
Rule
import Rule from './arianna-ts/Rule.ts';

const rule = new Rule('.btn', {{ color: 'red', fontSize: '14px' }});
rule.selector;   // → '.btn'
rule.css;        // → { color: 'red', fontSize: '14px' }
rule.toString(); // → '.btn { color: red; font-size: 14px; }'
Stylesheet (Sheet)
Property / MethodTypeDescription
new Sheet(r1, r2, ...)constructorCreate from Rule instances
sheet.add(rule, index?)thisAppend (or insert at index)
sheet.remove(rule)thisRemove a rule
sheet.inject(target)HTMLStyleElementInject <style> into target (e.g. document.head)
import {{ Sheet }} from './arianna-ts/Stylesheet.ts';

const sheet = new Sheet(
  new Rule('.btn',       {{ padding: '8px 16px' }}),
  new Rule('.btn:hover', {{ opacity: '0.8' }}),
);
sheet.add(new Rule('.btn:active', {{ transform: 'scale(.98)' }}));
sheet.add(new Rule('.btn-primary', {{ background: 'blue' }}), 0); // insert at index 0
sheet.inject(document.head);
Namespace
Full namespace coverage for HTML, SVG, MathML, and X3D. Each namespace is a proxy mapping tag names and interface names to typed constructors.
NamespaceInterfacesTags
HTML56118
SVG34
MathML29
X3Dvia Define
import Namespace from './arianna-ts/Namespace.ts';

Namespace.HTML.div;               // → HTMLDivElement constructor
Namespace.HTML.button;            // → HTMLButtonElement
Namespace.HTML.HTMLAnchorElement; // → by interface name
Namespace.SVG.circle;             // → SVGCircleElement
Namespace.SVG.path;
Context
Scoped dependency injection. A Context carries a typed value consumable by any descendant in the component tree.
import Context from './arianna-ts/Context.ts';

const ThemeCtx = Context.create({{ theme: 'dark' }});
ThemeCtx.provide({{ theme: 'light' }});

const {{ theme }} = ThemeCtx.consume();
console.log(theme); // → 'light'
Directive
Directives are reusable behaviors attached to DOM elements — the AriannA equivalent of v-if, v-for, @event in Vue or Angular's structural directives. They work with plain HTML elements, Real nodes, and Virtual nodes equally. All directives return an update() function — call it whenever your state changes to re-render that directive's output.
All directives
DirectiveSignatureDescription
Directive.if(el, condition, then, else?)Conditional rendering — swaps content based on a boolean fn
Directive.for(el, items, template)Render an array of items as children
Directive.foreach(el, obj, template)Iterate an object's key/value pairs
Directive.while(el, condition, body)Render while condition is true (like a loop)
Directive.switch(el, value, cases)Show one of N case branches based on a value fn
Directive.bind(el, prop, source)One-way binding: element property ← source fn
Directive.model(el, state, key)Two-way binding: input ↔ State property
Directive.show(el, condition)Toggle display (no DOM removal)
Directive.on(el, types, handler, opts?)Attach DOM event listener(s)
Directive.template(el, scope)Interpolate {{ }} placeholders in innerHTML
Directive.register(name, { mounted, unmounted })Register a custom reusable directive
Directive.apply(name, el, value)Apply a registered directive to an element
Directive.bootstrap(root, scope)Scan DOM for a-* attributes and apply all directives
1. Directive.if — conditional rendering
Replaces the element's innerHTML with either the then or the else branch depending on the condition function. Returns an update() you call when state changes.
let loggedIn = false;

const update = Directive.if(
  document.getElementById('auth-area'),
  () => loggedIn,
  '<div class="welcome">Welcome back! <button id="logout">Logout</button></div>',
  '<div class="login"><input placeholder="email"><button id="login">Login</button></div>'
);

// Toggle and re-render
document.getElementById('login')?.addEventListener('click', () => { loggedIn = true;  update(); });
document.getElementById('logout')?.addEventListener('click', () => { loggedIn = false; update(); });

// document.getElementById and Real('#id') are identical — use either
const update1 = Directive.if(
  document.getElementById('auth-area'),   // ← native DOM
  () => loggedIn, thenHtml, elseHtml
);
const update2 = Directive.if(
  Real('#auth-area'),                     // ← Real wrapper — same element
  () => loggedIn, thenHtml, elseHtml
);
// Both work — Real('#id') calls querySelector internally

// With State (auto-update)
const state = new State({ visible: false });
const upd   = Directive.if(Real('#panel'), () => state.State.visible,
  '<p>Shown!</p>', '<p>Hidden</p>');
state.subscribe(() => upd());
Directive.if — live loggedIn = false
Click to switch between if / else branch
condition = false → else branch rendered
JSX equivalent
/* @jsxImportSource arianna */
function AuthArea() {
  const [loggedIn, setLoggedIn] = useState(false);
  return loggedIn
    ? <div className="welcome">
        Welcome back! <button onClick={() => setLoggedIn(false)}>Logout</button>
      </div>
    : <div className="login">
        <input placeholder="email"/>
        <button onClick={() => setLoggedIn(true)}>Login</button>
      </div>;
}
Performance Benchmarks vs Solid v1.9.3 — same Mac M-series, Chrome ×4 throttle
Benchmark AriannA v12 Script Solid v1.9.3 Script Δ Total Δ Script
01 create 1k 82.5 ms 8.1 80.6 ms 8.3 +2% −2%
02 replace 1k 89.3 ms 14.1 90.2 ms 15.8 −1% −11%
03 update 10th 40.5 ms 1.3 40.2 ms 2.8 −54% ★
04 select row 8.7 ms 0.2 11.1 ms 2.2 −22% ★ −91% ★★
05 swap rows 30.5 ms 0.1 48.8 ms 3.3 −38% ★★ −97% ★★
06 remove row 37.1 ms 0.2 38.1 ms 1.3 −3% −85%
07 create 10k 874 ms 117 839 ms 94.7 +4% +23%
08 append 1k 93.7 ms 8.4 96.2 ms 9.4 −3% −11%
09 clear 1k 30.4 ms 25.5 34.7 ms 30.4 −12% −16%
22 run memory 2.06 MB 2.64 MB −22% ★
Bundle (gz) 1.5 KB 4.5 KB 3× less ★★
★ SignalMono slot optimization  ·  ★★ Compiled Hint + direct nodeValue write  ·  Solid leads only on create 10k due to mature compiler batching
HTML attribute syntax
Use a-if on any element. Directive.bootstrap(root, scope) wires everything automatically — no JS per-element needed.
<!-- In your HTML -->
<div id="app">

  <!-- a-if: shown when scope.loggedIn is truthy -->
  <div a-if="loggedIn">
    Welcome back, {{ username }}!
    <button a-on="click:logout">Logout</button>
  </div>

  <!-- a-if with else via a-else sibling (same parent, next element) -->
  <div a-if="loggedIn">✓ Authenticated</div>
  <div a-else>✗ Please log in</div>

</div>

// In your script — one call wires everything
const scope = {
  loggedIn : false,
  username : 'Riccardo',
  logout   : () => { scope.loggedIn = false; Directive.bootstrap(app, scope); },
};
Directive.bootstrap(document.getElementById('app'), scope);
HTML a-if — live bootstrap demo
Welcome back, Riccardo!
✗ Not logged in.
HTML: <div a-if="loggedIn">...</div><div a-else>...</div>
a-if="loggedIn" → false → else shown
2. Directive.for — array rendering
Renders each item of an array as a child element. The template function receives (item, index).
let planets = ['Mercury', 'Venus', 'Earth', 'Mars'];

// Native DOM or Real wrapper — identical result
const update = Directive.for(
  document.getElementById('planet-list'),   // native
  () => planets,
  (item, i) => `<li data-i="${i}">${i + 1}. ${item}</li>`
);
// equivalent with Real:
const update = Directive.for(
  Real('#planet-list'),                     // Real wrapper
  () => planets,
  (item, i) => `<li data-i="${i}">${i + 1}. ${item}</li>`
);

// Add an item and re-render
planets.push('Jupiter');
update();

// Remove an item and re-render
planets = planets.filter(p => p !== 'Venus');
update();
Directive.for — live
    4 items rendered
    JSX equivalent
    function PlanetList() {
      const [planets, setPlanets] = useState(['Mercury', 'Venus', 'Earth']);
      const add    = () => setPlanets([...planets, 'Planet ' + (planets.length + 1)]);
      const remove = () => setPlanets(planets.slice(0, -1));
      return (
        <ul>
          {planets.map((p, i) => <li key={i}>{i + 1}. {p}</li>)}
        </ul>
      );
    }
    HTML attribute syntax
    <!-- a-for: renders the element once per item -->
    <ul id="app">
      <li a-for="planet in planets">
        {{ planet }}
      </li>
    </ul>
    
    // Script
    Directive.bootstrap(document.getElementById('app'), {
      planets: ['Mercury', 'Venus', 'Earth', 'Mars'],
    });
    
    <!-- With index -->
    <li a-for="item, i in items">{{ i }}. {{ item.name }}</li>
    
    <!-- Nested -->
    <div a-for="user in users">
      <h3>{{ user.name }}</h3>
      <ul><li a-for="tag in user.tags">{{ tag }}</li></ul>
    </div>
    HTML a-for — live bootstrap demo
      HTML: <li a-for="planet in planets">{ planet }</li>
      a-for renders one <li> per array item
      3. Directive.foreach — object iteration
      Iterates an object's key/value pairs. Template receives (key, value).
      const scores = { Alice: 95, Bob: 87, Carol: 92, Dan: 78 };
      
      Directive.foreach(
        document.getElementById('score-list'),
        () => scores,
        (name, score) => `<li><strong>${name}</strong>: ${score}/100</li>`
      );
      
      // Equivalent to the Golem template:
      // <ol a-foreach="var name in scores"><li>{{ name }}: {{ scores[name] }}</li></ol>
      4. Directive.switch — multi-branch rendering
      Shows one branch from a map of cases. The value function returns the current key. Supports a default fallback.
      let tab = 'home';
      
      // document.getElementById ←→ Real('#id') — pick your style
      const update = Directive.switch(
        document.getElementById('tab-content'),  // or: Real('#tab-content')
        () => tab,
        {
          home    : '<div><h3>🏠 Home</h3><p>Welcome to AriannA.</p></div>',
          docs    : '<div><h3>📖 Docs</h3><p>Read the documentation.</p></div>',
          settings: '<div><h3>⚙️ Settings</h3><p>Configure your app.</p></div>',
          default : '<div><h3>404</h3><p>Page not found.</p></div>',
        }
      );
      
      // Navigate to a tab
      tab = 'docs'; update();
      Directive.switch — live
      tab = home
      JSX equivalent
      function TabContent({ tab }: { tab: string }) {
        const pages: Record<string, JSX.Element> = {
          home    : <div><h3>🏠 Home</h3><p>Welcome to AriannA.</p></div>,
          docs    : <div><h3>📖 Docs</h3><p>Read the docs.</p></div>,
          settings: <div><h3>⚙️ Settings</h3><p>Configure app.</p></div>,
        };
        return pages[tab] ?? <div>404</div>;
      }
      HTML attribute syntax
      <!-- a-switch on the container, a-case on each branch -->
      <div a-switch="currentPage">
      
        <div a-case="home">
          <h2>🏠 Home</h2><p>Welcome!</p>
        </div>
      
        <div a-case="about">
          <h2>ℹ️ About</h2><p>About us.</p>
        </div>
      
        <div a-case="default">
          <h2>404</h2>
        </div>
      
      </div>
      
      <<!-- Nav buttons -->>
      <button a-on="click:goHome">Home</button>
      <button a-on="click:goAbout">About</button>
      
      // Script
      const scope = {
        currentPage : 'home',
        goHome      : () => { scope.currentPage = 'home';  reboot(); },
        goAbout     : () => { scope.currentPage = 'about'; reboot(); },
      };
      const reboot = () => Directive.bootstrap(document.getElementById('app'), scope);
      reboot();
      HTML a-switch / a-case — live bootstrap demo
      HTML: <div a-switch="page"><div a-case="home">...</div></div>
      a-switch="currentPage" → home
      5. Directive.while — loop rendering
      Calls the body function repeatedly while condition is true, collecting HTML. Useful for computed sequences.
      let n = 5;
      
      Directive.while(
        document.getElementById('fib-list'),
        () => n > 0,
        (() => {
          let [a, b, count] = [0, 1, 0];
          return () => {
            const val = a; [a, b] = [b, a + b]; count++; n--;
            return `<li>fib(${count}) = ${val}</li>`;
          };
        })()
      );
      // Renders: fib(1)=0, fib(2)=1, fib(3)=1, fib(4)=2, fib(5)=3
      Directive.while — generate N Fibonacci numbers
      7
        7 Fibonacci numbers
        HTML attribute syntax
        <!-- a-while: renders the template while count > 0 -->
        <ol id="app">
          <li a-while="count > 0">
            Item {{ count-- }}
          </li>
        </ol>
        
        // Script — scope variables are read-write during iteration
        Directive.bootstrap(document.getElementById('app'), { count: 5 });
        // → renders: Item 5, Item 4, Item 3, Item 2, Item 1
        6. Directive.bind — one-way binding
        Binds an element's property to a source function. One-way: element updates when you call update().
        const state = new State({ username: 'Riccardo', score: 0 });
        
        // document.getElementById and Real('#id') are the same — use either
        const upd = Directive.bind(
          document.getElementById('name-display'),  // native getElementById
          'textContent',
          () => state.State.username
        );
        
        // Same with Real wrapper — querySelector under the hood
        const upd2 = Directive.bind(
          Real('#score-display'),                   // Real('#id') wrapper
          'innerHTML',
          () => `Score: <strong>${state.State.score}</strong>`
        );
        
        state.subscribe(() => { upd(); upd2(); });
        state.State.username = 'Arianna';  // → both spans update
        HTML attribute syntax
        <!-- a-bind="property:scopeKey" — one-way: element ← scope -->
        <div id="app">
        
          <span  a-bind="textContent:username"></span>
          <img   a-bind="src:avatarUrl"    alt="Avatar">
          <input a-bind="value:email"      placeholder="Email">
          <div   a-bind="className:cssClass">Styled</div>
          <div   a-bind="innerHTML:richHtml"></div>
        
        </div>
        
        // Script
        Directive.bootstrap(document.getElementById('app'), {
          username  : 'Riccardo',
          avatarUrl : '/img/avatar.png',
          email     : 'r@example.com',
          cssClass  : 'card active',
          richHtml  : 'Score: <strong>42</strong>',
        });
        7. Directive.model — two-way binding
        Two-way: input value changes update the State, and State changes update the input. Zero glue code.
        const state = new State({ name: '', age: '', color: '#e40c88' });
        
        // Mix freely — both target the same DOM element
        Directive.model(document.getElementById('inp-name'),  state, 'name');  // native
        Directive.model(Real('#inp-age'),                    state, 'age');   // Real
        Directive.model(Real('#inp-color'),                   state, 'color'); // Real
        
        // Real('#id') === document.querySelector('#id') — same element, zero overhead
        state.subscribe((key, val) => console.log(key, '→', val));
        state.State.name = 'Arianna';  // programmatic write updates the input too
        Directive.model — two-way binding
        State mirrors input values in real time
        HTML attribute syntax
        <!-- a-model: two-way binding — input ↔ scope property -->
        <div id="app">
        
          <input    a-model="user.name"     placeholder="Name">
          <input    a-model="user.age"      type="number">
          <input    a-model="theme.color"   type="color">
          <select   a-model="settings.lang">
            <option value="en">English</option>
            <option value="it">Italiano</option>
          </select>
          <textarea a-model="post.body"></textarea>
        
          <!-- Live preview — updates as user types -->
          <p>Hello, <span a-bind="textContent:user.name"></span>!</p>
        
        </div>
        
        // Script
        Directive.bootstrap(document.getElementById('app'), {
          user     : { name: '', age: '' },
          theme    : { color: '#e40c88' },
          settings : { lang: 'en' },
          post     : { body: '' },
        });
        8. Directive.show — toggle visibility
        Toggles display:none without removing the element from DOM. Cheaper than Directive.if for frequent toggles.
        let open = false;
        // Both lines target the same element — use what reads better
        const panel  = document.getElementById('side-panel');  // native
        const toggle = Real('#toggle-btn');                      // Real wrapper
        
        const update = Directive.show(panel, () => open);
        
        Real('#toggle-btn').on('click', () => { open = !open; update(); });
        // or: toggle.addEventListener('click', ...) — same thing
        
        // Directive.show vs Directive.if:
        //   .show → display toggle — element stays in DOM, state preserved
        //   .if   → innerHTML swap — content recreated on each change
        HTML attribute syntax
        <!-- a-show: toggles display, element stays in DOM -->
        <div id="app">
        
          <button a-on="click:toggleMenu">☰ Menu</button>
        
          <nav a-show="menuOpen">
            <a href="/">Home</a>
            <a href="/docs">Docs</a>
          </nav>
        
          <!-- a-show vs a-if:
            a-show → display:none   (element kept, state preserved)
            a-if   → innerHTML swap (element recreated on change)  -->
        
        </div>
        
        // Script
        const scope = {
          menuOpen   : false,
          toggleMenu : () => { scope.menuOpen = !scope.menuOpen; reboot(); },
        };
        const reboot = () => Directive.bootstrap(document.getElementById('app'), scope);
        reboot();
        HTML a-show — toggle visibility
        HTML: <nav a-show="menuOpen">...</nav>
        a-show="menuOpen" → false → display:none
        9. Directive.on — event listener
        Attach one or more DOM event listeners. Space-separated types. Supports AddEventListenerOptions.
        // document.getElementById or Real('#id') — identical
        Directive.on(document.getElementById('save-btn'), 'click', e => save());   // native
        Directive.on(Real('#save-btn'),                   'click', e => save());   // Real
        
        // Real shines for chaining — attach listener and append in one expression
        Real('#save-btn').on('click', save).on('mouseenter', highlight);
        
        // Multiple events space-separated
        Directive.on(Real('#search'), 'focus blur', e => highlight(e.type === 'focus'));
        
        // With options (passive scroll)
        Directive.on(Real('#list'), 'scroll', onScroll, { passive: true });
        
        // Equivalent HTML attribute (via bootstrap):
        // <button a-on="click:handleClick">Click me</button>
        HTML attribute syntax
        <!-- a-on="event:handler" — attach DOM listener -->
        <div id="app">
        
          <button a-on="click:handleClick">Click me</button>
          <button a-on="click:save">Save</button>
        
          <!-- Multiple events space-separated -->
          <input a-on="focus blur:handleFocus" placeholder="Focus me">
        
          <!-- Keyboard shortcuts -->
          <div  a-on="keydown:handleKey" tabindex="0">Press a key</div>
        
        </div>
        
        // Script
        Directive.bootstrap(document.getElementById('app'), {
          handleClick : (e) => console.log('clicked', e.target),
          save        : ()  => alert('Saved!'),
          handleFocus : (e) => console.log(e.type),   // 'focus' or 'blur'
          handleKey   : (e) => console.log(e.key),
        });
        10. Directive.template — {{ }} interpolation
        Replaces {{ key }} placeholders in an element's innerHTML with values from a scope object. Supports dot-notation and bracket-notation paths.
        const scope = {
          username : 'Arianna',
          score    : 42,
          planet   : 'Earth',
          planets  : { Earth: '3rd from the Sun' },
        };
        
        // native getElementById
        Directive.template(document.getElementById('tpl-output'), scope);
        
        // Real wrapper — same result, shorter on repeated use
        Directive.template(Real('#tpl-output'), scope);
        
        // Real('#id') === querySelector('#id') — zero difference in output
        // Bracket notation:  {{ planets[planet] }}  → "3rd from the Sun"
        // Dot notation:      {{ planets.Earth }}     → "3rd from the Sun"
        HTML attribute syntax
        <!-- {{ }} interpolation — works anywhere in innerHTML -->
        <div id="app">
        
          <h1>Hello, {{ username }}!</h1>
          <p>Score: {{ score }} / {{ maxScore }}</p>
          <p>Planet: {{ planets[selected] }}</p>
          <p>Nested: {{ user.address.city }}</p>
          <p>Expr:    {{ score > 50 ? 'pass' : 'fail' }}</p>
        
        </div>
        
        // Script
        Directive.bootstrap(document.getElementById('app'), {
          username  : 'Arianna',
          score     : 72,
          maxScore  : 100,
          selected  : 2,
          planets   : ['Mercury', 'Venus', 'Earth'],
          user      : { address: { city: 'Zürich' } },
        });
        HTML { } template interpolation — live
        72
        { } placeholders replaced with scope values
        11. Directive.register — custom directives
        Create your own directives. They receive the element and an optional value. Register once, apply anywhere.
        // Register a tooltip directive
        Directive.register('tooltip', {
          mounted(el, value)   { el.title = value; el.style.cursor = 'help'; },
          unmounted(el)        { el.title = ''; },
        });
        
        // Register a highlight directive
        Directive.register('highlight', {
          mounted(el, color = '#fff3cd') { el.style.background = color; },
          unmounted(el)                   { el.style.background = ''; },
        });
        
        // Apply programmatically
        Directive.apply('tooltip',   myButton, 'Save the document');
        Directive.apply('highlight', myInput,  '#ffd6e8');
        
        // Apply via HTML attributes (after bootstrap):
        // <button data-directive="tooltip" data-tooltip="Save">Save</button>
        12. Directive.bootstrap — HTML-first declarative usage
        Scan an element's subtree for a-* attributes and automatically apply all directives. The closest thing to Vue/Angular template syntax.
        <!-- In your HTML -->
        <div a-if="user.loggedIn">Welcome, {{ user.name }}!</div>
        <ul  a-for="item in cart"><li>{{ item.name }} — €{{ item.price }}</li></ul>
        <div a-show="cart.length > 0">Checkout</div>
        <input a-model="user.name" placeholder="Your name">
        <span a-bind="textContent:user.name"></span>
        <button a-on="click:addToCart">Add</button>
        
        // In your script — one call wires everything
        const scope = { user, cart, addToCart };
        
        // Identical — choose what reads better in context
        Directive.bootstrap(document.getElementById('app'), scope);  // native
        Directive.bootstrap(Real('#app'), scope);                    // Real wrapper
        
        // Real('#app') calls querySelector('#app') internally — same element
        // Rule of thumb: use Real() when you're already in an AriannA codebase
        //               use getElementById() when integrating with plain DOM code
        Interactive playground
        All four structural directives together. Shows how they compose — the list feeds into the switch, the if guards the output.
        Structural directives — composed demo
        if (showList) → hides/shows the entire list
        switch (view)
        for (items) 3 items
        showList=true, view=grid, 3 items
        Annotations (Decorators)
        Class-based component authoring with TypeScript decorators. Reactive props, watchers, event emitters, and template refs.
        Property / MethodTypeDescription
        @Component(opts)class decoratorRegister as custom element. opts: { tag, extends? }
        @Prop()propertyReactive — change triggers render
        @Watch(key)methodCalled when named prop changes. Args: (newVal, oldVal)
        @Emit(event?)methodDispatch CustomEvent when method returns
        @Ref()propertyBind to DOM element inside the template
        import {{ Component, Prop, Watch, Emit, Ref }} from './arianna-ts/index.ts';
        
        @Component({{ tag: 'user-card' }})
        class UserCard extends HTMLElement {{
          @Prop() name = '';
          @Prop() role = '';
          @Ref()  nameEl!: HTMLSpanElement;
        
          @Watch('name')
          onNameChange(next: string) {{
            if (this.nameEl) this.nameEl.textContent = next;
          }}
        
          @Emit('card-click')
          handleClick() {{ return {{ name: this.name }}; }}
        
          render() {{
            return `<div><span data-ref="nameEl">${'{'}this.name{'}'}</span> — ${'{'}this.role{'}'}</div>`;
          }}
        }}
        JSX Runtime
        AriannA ships a full React-JSX compatible runtime. Every JSX element maps to either a Real instance or a VirtualNode — no virtual DOM overhead unless you opt in.
        tsconfig.json setup
        {
          "compilerOptions": {
            "jsx"             : "react-jsx",
            "jsxImportSource" : "arianna"
          }
        }
        Dual runtime — Real (default) vs Virtual
        // Real mode (default) — every element is a Real instance
        import { Real, signal } from 'arianna';
        
        const count = signal(0);
        
        function App() {
          return (
            <div id="app">
              <h1 class="title">AriannA</h1>
              <p>Count: <span>{count.get()}</span></p>
              <button onClick={() => count.set(count.get() + 1)}>
                Increment
              </button>
            </div>
          );
        }
        
        // Virtual mode — per-file pragma at top
        /* @dom-render: virtual */
        function SVGIcon() {
          return (
            <svg width="40" height="40" viewBox="0 0 40 40">
              <circle cx="20" cy="20" r="18" fill="#e40c88" />
            </svg>
          );
        }
        Event syntax — $event and onEvent
        // Both are equivalent — $ takes precedence if both present
        <button $click={fn}>Dollar syntax</button>
        <button onClick={fn}>On-prefix syntax</button>
        
        // Any event name works
        <input $input={(e) => val.set(e.target.value)} />
        <div $mouseenter={show} $mouseleave={hide}>Hover me</div>
        Fragment
        // <>...</> — Real mode: DocumentFragment | Virtual mode: Fragment
        function Pair() {
          return (
            <>
              <span>First</span>
              <span>Second</span>
            </>
          );
        }
        Custom elements
        // PascalCase → kebab-case tag resolution via Core.GetDescriptor()
        import { MyButton } from './MyButton.ts';
        
        const el = <MyButton label="Click me" $click={handleClick} />;
        // → new Real('my-button').set('label','Click me').on('click',handleClick)
        setDefaultRuntime() — global switch
        import { setDefaultRuntime } from 'arianna/jsx-runtime';
        
        // Set globally at app bootstrap
        setDefaultRuntime('virtual');  // all JSX → VirtualNode
        setDefaultRuntime('real');     // back to default
        h() factory — direct use
        import { h, Fragment } from 'arianna/jsx-runtime';
        
        // Without JSX transform
        const btn = h('button', { class: 'primary', '$click': fn }, 'Click');
        const frag = h(Fragment, null, btn, h('span', null, 'text'));
        Dev runtime (react-jsxdev)
        // tsconfig for dev mode
        {
          "compilerOptions": {
            "jsx"             : "react-jsxdev",
            "jsxImportSource" : "arianna"
          }
        }
        // Resolved to: arianna/jsx-dev-runtime → jsxDEV()
        // Same behavior as jsx() — extra debug args are ignored
        Controls
        50 TypeScript controls, one file each. All extend Control. React-like API: set a property → control re-renders via requestAnimationFrame.
        Unified API (all controls)
        // Every control follows the same pattern:
        const ctrl = new ControlName('#container', options);
        ctrl.propertyName = value;       // setter → schedules re-render via rAF
        ctrl.on('event', handler);      // typed event bus
        ctrl.destroy();                  // remove DOM + cleanup all listeners
        
        // Example:
        const btn = new Button('#root', {{ variant: 'primary' }});
        btn.label   = 'Save';           // reactive setter
        btn.loading = true;             // disables + shows spinner
        btn.on('click', () => save());
        CategoryControlsCount
        CoreControl, Theme, Animation3
        LayoutAccordion, Card, Drawer, Modal, Panel, Splitter, Tabs7
        NavigationBreadcrumb, Header, Menu, NavRail, Pagination, Stepper6
        InputsButton, Checkbox, Chip, ColorPicker, DatePicker, Dropdown, FileUpload, Radio, RangeSlider, Rating, SearchBar, Switch, TextField, TimePicker14
        DisplayAvatar, Badge, Banner, Chip, DataTable, Divider, Icon, List, ProgressBar, ProgressCircular, Skeleton, Snackbar, Tag, Tooltip14
        ChartsBarChart, LineChart, PieChart3
        DataTreeView, Table2
        Total50
        Theme & CSS Tokens
        All controls use CSS custom properties. Theme ships dark and light token sets.
        import {{ Theme }} from './arianna-controls/core/Theme.ts';
        
        Theme.apply('dark');               // set tokens on :root
        Theme.apply('light', container);    // scoped to element
        Theme.apply('auto');               // prefers-color-scheme
        Theme.extend({{ '--ar-primary': '#ff6b6b' }});
        Theme.inject();                     // inject base CSS (once)
        TokenDarkLight
        --ar-bg#0d0d0d#ffffff
        --ar-text#e0e0e0#1a1a1a
        --ar-primary#7eb8f7#1565c0
        --ar-success#4caf50#2e7d32
        --ar-warning#ff9800#e65100
        --ar-danger#f44336#c62828
        --ar-border#2a2a2a#d0d0d0
        --ar-radius5px
        Additionals
        Optional add-on modules that extend AriannA. Each is a standalone plugin registered via Core.use(). Import from arianna-additionals/.
        Math
        Extended mathematics — Fraction, Vector2/3/4, Matrix4, Quaternion, LinearFunction, Statistics. All original Golem.Math constants preserved.
        import { Math, MathConstants, Fraction, Vector3, Statistics } from 'arianna/additionals';
        
        // Fractions
        const f = new Fraction(3, 4);
        f.Sum(new Fraction(1, 4)).toString();  // "1/1"
        
        // 3D Vectors
        const v = new Vector3(1, 2, 3);
        const u = new Vector3(4, 5, 6);
        v.dot(u);     // 32
        v.cross(u);   // Vector3(-3, 6, -3)
        v.length();   // √14 ≈ 3.742
        
        // Constants
        MathConstants.PI;    // 3.14159…
        MathConstants.Phi;   // golden ratio 1.618…
        MathConstants.c;     // speed of light 299792458 m/s
        
        // Statistics
        const data = [2, 4, 4, 4, 5, 5, 7, 9];
        Statistics.mean(data);      // 5
        Statistics.variance(data);  // 4
        Statistics.stdDev(data);    // 2
        
        // Matrix4 — perspective projection
        const m = Matrix4.perspective(MathConstants.PI / 4, 16/9, 0.1, 1000);
        Geometry
        2D/3D geometry primitives — Point, Size, Angle, AABB, Ray, Rectangle, Circle, Triangle, Polygon, Sphere, Box, Cylinder, Torus, Cone. Imports from Math.ts for Vector/Matrix types.
        import { Geometry, Point, Circle, AABB } from 'arianna/additionals';
        
        const p1 = new Point(0, 0);
        const p2 = new Point(3, 4);
        p1.distanceTo(p2);   // 5
        
        const c = new Circle(p1, 10);
        c.area();            // π × 100 ≈ 314.16
        c.contains(p2);     // true (dist=5 < r=10)
        
        const box = new AABB(p1, new Point(100, 100));
        box.intersects(new AABB(new Point(50,50), new Point(150,150)));  // true
        Animation
        WAAPI helpers — animate(), timeline(), spring physics, stagger utilities. Integrates with Signal+Sink.
        import { Animation } from 'arianna/additionals';
        Core.use(Animation);
        
        // Animate an element with WAAPI
        Animation.animate(el, [
          { opacity: 0, transform: 'translateY(20px)' },
          { opacity: 1, transform: 'translateY(0)'    },
        ], { duration: 300, easing: 'ease-out', fill: 'forwards' });
        
        // Stagger multiple elements
        Animation.stagger(document.querySelectorAll('.card'),
          { opacity: [0, 1], transform: ['translateY(12px)', 'none'] },
          { duration: 250, delay: 40 }  // 40ms between each
        );
        Network
        fetch/SSE/WebSocket abstractions with retry, timeout, and Signal integration.
        import { Network } from 'arianna/additionals';
        Core.use(Network);
        
        // Typed fetch with auto-JSON parse
        const data = await Network.get<{ name: string }[]>('/api/users');
        
        // SSE stream → Signal
        const price = signal(0);
        Network.sse('/api/prices', (e) => price.set(JSON.parse(e.data)));
        // Any effect reading price() now auto-updates
        effect(() => priceEl.text(() => `€\${price.get().toFixed(2)}`));
        Audio
        Web Audio API toolkit — Oscillator, NoiseGenerator, Filter, Reverb, Delay, Analyser, Sequencer, AudioPlayer, AudioRecorder, MIDIEngine. Built on a shared AudioEngine singleton with master gain and compressor.
        import { Audio } from 'arianna/additionals';
        Core.use(Audio);
        
        // Oscillator — uses shared AudioEngine, no manual context needed
        const osc = new Audio.Oscillator(440, 'sine');
        osc.start(0.5);                // volume 0–1
        setTimeout(() => osc.stop(), 1000);
        
        // Effects chain — Reverb, Delay, Filter all share the engine
        const reverb = new Audio.Reverb({ duration: 2.5, decay: 2.0 });
        const delay  = new Audio.Delay({ time: 0.3, feedback: 0.4 });
        
        // Analyser — real-time FFT for visualizers
        const ana = new Audio.Analyser({ fftSize: 2048 });
        const bins = ana.getFrequencyData();   // Uint8Array
        
        // Sequencer — step sequencer with callback per step
        const seq = new Audio.Sequencer(120, 16);  // 120 BPM, 16 steps
        seq.on((step, time) => { /* trigger sample at step */ });
        seq.start();
        
        // MIDI input — listen for note/CC messages
        const midi = new Audio.MIDIEngine();
        await midi.connect();
        midi.on(msg => console.log(msg.type, msg.note, msg.velocity));
        Video
        Video toolkit — ScreenCapture, CameraCapture, VideoPlayer, VideoCompositor (multi-layer canvas overlay), GIFEncoder (LZW-compressed animated GIFs). All return MediaStream / HTMLCanvasElement / Uint8Array — works with any standard video pipeline.
        import { Video } from 'arianna/additionals';
        Core.use(Video);
        
        // Camera — request user media and attach to a video element
        const cam = new Video.CameraCapture();
        const stream = await cam.start({ width: 1280, height: 720, audio: false });
        document.querySelector('video').srcObject = stream;
        
        // Screen capture — getDisplayMedia wrapper
        const screen = new Video.ScreenCapture();
        await screen.start();
        screen.stop();
        
        // VideoPlayer — controlled HTMLVideoElement with events
        const player = new Video.VideoPlayer(document.querySelector('#wrap'));
        player.load('/movie.mp4');
        player.on('timeupdate', () => console.log(player.currentTime));
        
        // VideoCompositor — overlay multiple sources on a canvas
        const comp = new Video.VideoCompositor(1920, 1080);
        comp.addLayer({ source: stream, x: 0, y: 0 });
        comp.addLayer({ source: '/logo.png', x: 20, y: 20, w: 120, h: 40 });
        comp.start();   // composite is comp.canvas
        
        // GIFEncoder — record canvas frames into an animated GIF
        const enc = new Video.GIFEncoder({ width: 320, height: 240, fps: 12 });
        for (let i = 0; i < 24; i++) {
          enc.addFrame(canvas);
        }
        const bytes = enc.encode();   // Uint8Array → save as .gif
        IO
        File I/O — drag-drop, clipboard, file reader, file saver. All async with Promise/Signal bridge.
        import { IO } from 'arianna/additionals';
        Core.use(IO);
        
        // Drag-drop zone → Signal
        const dropped = signal<File | null>(null);
        IO.dropZone(document.getElementById('drop')!, (files) => {
          dropped.set(files[0] ?? null);
        });
        
        // Save file
        await IO.save('export.json', JSON.stringify(data, null, 2));
        LaTeX
        LaTeX → MathML renderer for inline math in HTML. Supports fractions, superscripts, Greek letters, operators.
        import { Latex } from 'arianna/additionals';
        Core.use(Latex);
        
        // Render LaTeX to MathML string
        const ml = Latex.render('\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}');
        document.getElementById('math')!.innerHTML = ml;
        Three.js Bridge
        Three.js integration — reactive camera, OrbitControls binding, scene/renderer lifecycle.
        import { Three } from 'arianna/additionals';
        Core.use(Three);
        
        const app = Three.scene(document.querySelector('canvas')!);
        app.scene.add(new THREE.Mesh(
          new THREE.BoxGeometry(),
          new THREE.MeshStandardMaterial({ color: '#e40c88' })
        ));
        app.start();  // requestAnimationFrame loop
        Changelog
        v1.2.0 — April 2026
        • Signal+Sink fine-grain reactivity: signal(), signalMono(), sinkText(), sinkClass(), effect(), computed(), batch(), untrack()
        • Real/VirtualNode fluent Signal API: .text(), .textMono(), .attr(), .cls(), .prop(), .style(), .bind(), .destroy()
        • Rule v2: SelectorObject constructor, nested @-rules, @keyframes, @page margin-box, CssState
        • Stylesheet v2: Sheet.Less() indentation-based Less/Stylus parser, SheetES5, PascalCase aliases, async URL fetch
        • JSX Runtime: dual Real/Virtual mode, $event + onEvent syntax, Fragment, jsxDEV(), setDefaultRuntime()
        • Additionals: AriannA.ts barrel, Math.ts, Geometry.ts (import fix), Animation, Network, Audio, Video, IO, Latex, Three bridges
        • CLI v1.2.0: new, generate, serve, build, typecheck, bench, info commands
        • Control v2: _state, _fire, _listen, _onDestroy, _mounted, get() public
        • Table v2: _expandedRows, _renderRows, Web Worker, LRU cache, column resize, export CSV
        • Types: arianna.d.ts, arianna-globals.d.ts global window declarations
        • Context: asSignal() method — reactive Signal from context value
        • tsconfig: ES2022 target, allowImportingTsExtensions, moduleResolution: bundler
        • Benchmark: swap-rows −38%, select-row −22%, script −97%, bundle 3× smaller vs Solid v1.9.3
        • 400+ tests across 21 panels
        v1.0.0 — April 2026
        • Initial TypeScript release. Complete migration from JavaScript (2012–2024).
        • Core: frozen SemVer version, idempotent plugin registration, full namespace registry
        • Real, Virtual, State, Observable, Rule, Stylesheet, Context, Directive, Component
        • 50 UI controls: TreeView, Table, Accordion, Sidebar, Charts, and more
        • Dual AGPL + Commercial license
        License
        AriannA is dual-licensed — choose the license that fits your use case.
        MIT License (open source)
        Free for any open source or commercial project. Attribution required. See LICENSES/MIT.txt.
        Commercial License
        For closed-source or enterprise products requiring no attribution or additional support terms. Contact the author for pricing.
        Author
        Riccardo Angeli — Senior Software Architect & UI TechLead
        Zurich, Switzerland  ·  riccardo.angeli@arianna.dev
        github.com/Riccardo-Angeli/AriannA-Js  ·  npmjs.com/package/arianna
        ♡ Dedication
        A mia figlia Arianna.
        Hai ispirato questo progetto dal primo giorno. Ti voglio bene. — Papà
        Thanks
        Alessandro De Rossi  ·  Simone Ricucci  ·  Alessandro Ligi  ·  Marco Ciurcina  ·  Aurora Castello  ·  Massimiliano Ceaglio  ·  Andrea Giammarchi  ·  Francesco Maria Turno
        Copyright
        © Riccardo Angeli 2012–2026. All rights reserved.
        TreeView
        Hierarchical tree with lazy loading, keyboard navigation, search, checkbox mode, and drag & drop.
        TreeView — Live Demo no selection
        click a node to see the event →
        Property / MethodTypeDescription
        tree.nodes = []TreeNode[]Set root nodes — reactive, auto-renders
        tree.on('select',cb)event{ node, selected } fired on click or keyboard
        tree.on('expand',cb)event{ node } fired when a node opens
        tree.on('load',cb)event{ node, resolve } fired for lazy nodes
        tree.on('drop',cb)event{ sourceId, targetId } drag & drop
        tree.expand(id)methodExpand a node
        tree.collapse(id)methodCollapse a node
        tree.select(id)methodSelect a node programmatically
        tree.search(q)methodFilter visible nodes
        tree.getSelected()methodReturns TreeNode[]
        tree.expandAll() / collapseAll()methodBulk expand/collapse
        tree.destroy()methodRemove and cleanup
        import {{ TreeView, TreeViewCSS }} from './arianna-controls/TreeView.ts';
        
        const s = document.createElement('style');
        s.textContent = TreeViewCSS; document.head.appendChild(s);
        
        const tree = new TreeView('#sidebar', {{
          selectable : 'single',  // 'none' | 'single' | 'multi'
          icons      : true,
          checkboxes : false,
          keyboard   : true,
          draggable  : false,
        }});
        
        tree.nodes = [
          {{ id: '1', label: 'Root', icon: '📁', children: [
            {{ id: '1.1', label: 'Child A', icon: '📄' }},
            {{ id: '1.2', label: 'Child B', lazy: true }},  // lazy
          ]}},
        ];
        
        tree.on('select', ({{ node }}) => console.log(node.label));
        tree.on('load',   ({{ node, resolve }}) => fetchChildren(node.id).then(resolve));
        tree.expand('1');
        tree.search('child');
        Table
        Data grid: sorting, filtering, pagination, Web Worker offloading, LRU cache. Everything optional — one class.
        Table — 200 rows, sortable, paginated (10/page)
        sort a column or click a row →
        Property / MethodTypeDescription
        table.rows = []Row[]Set client-side data — reactive setter
        table.append(rows)methodAppend rows without full reload
        table.reload()methodRe-run fetch or re-process local data
        table.clear()methodEmpty the table
        table.getSelected()methodReturns selected Row[]
        table.exportCsv(name)methodDownload current view as CSV
        table.on('select',cb)event{ rows, row }
        table.on('sort',cb)event{ column, sort }
        table.on('page',cb)event{ page, pageSize, total }
        Options
        OptionDefaultDescription
        columnsrequiredColumn definitions array
        pageSize25Rows per page. 0 = no paging (show all)
        selectable'none''none' | 'single' | 'multi'
        workerfalseOffload sort+filter to Web Worker (Blob URL)
        cachefalseLRU cache for remote pages (server-side mode)
        fetchundefinedAsync fn for server-side: (params) → { rows, total }
        searchabletrueGlobal search bar
        exportCsvfalseCSV export button
        // Client-side with Web Worker
        const table = new Table('#root', {{
          columns: [
            {{ key: 'name',   label: 'Name',   sortable: true, width: 200 }},
            {{ key: 'role',   label: 'Role',   sortable: true }},
            {{ key: 'status', label: 'Status',
              render: (v) => `<span style="color:${'{'}v==='active'?'green':'gray'{'}'}">${'{'}v{'}'}</span>` }},
          ],
          pageSize  : 25,
          selectable: 'multi',
          worker    : true,
          exportCsv : true,
        }});
        table.rows = myData;
        
        // Server-side with cache
        const table = new Table('#root', {{
          columns,
          cache: true,
          fetch: async ({{ page, pageSize, sort, filter }}) => {{
            const r = await api.get(`/data?page=${'{'}page{'}'}&size=${'{'}pageSize{'}'}`);
            return {{ rows: r.data, total: r.total }};
          }},
        }});
        Expandable rows
        Enable row expansion to show nested detail — like the Horizon Explorer pattern. Set expandable: true and provide a rowContent async function that returns HTML or an HTMLElement.
        OptionTypeDescription
        expandablebooleanEnable expandable rows. Default: false
        rowContentasync (row) → string | HTMLElementCalled on expand — return the nested content
        expandSinglebooleanOnly one row open at a time. Default: false
        const table = new Table('#root', {
          columns: [
            { key: 'name',   label: 'Name',   sortable: true },
            { key: 'capital', label: 'Capital' },
            { key: 'region',  label: 'Region' },
          ],
        
          // ── Expandable rows ─────────────────────────────────────
          expandable  : true,
          expandSingle: true,   // collapse others when one opens
        
          // Async — called when user clicks ▶ on a row
          rowContent: async (row) => {
            const res  = await fetch(`/api/provinces/${'{'}row.id{'}'}`);
            const data = await res.json();
            return `<div style="padding:10px 0 10px 32px;border-left:2px solid var(--ar-primary)">
              <strong>Provinces of ${'{'}row.name{'}'}</strong>
              <ul>${'{'}data.map(p => `<li>${'{'}p.name{'}'}</li>`).join(''){'}'}</ul>
            </div>`;
          },
        });
        
        table.rows = myData;
        
        // Programmatic control
        table.expandRow(0);    // expand row at index 0
        table.collapseRow(0);  // collapse
        table.collapseAll();    // collapse all
        
        table.on('expand',   ({ row, index }) => console.log('opened:', row));
        table.on('collapse', ({ row, index }) => {{}});
        Live demo — expandable rows
        Table with expandable rows — click ▶ on any row
        click ▶ to expand a row →
        Layout Controls
        7 layout controls: Accordion, Card, Drawer, Modal, Panel, Splitter, Tabs.
        Accordion
        Tabs
        Cards
        Modal & Drawer
        const acc = new Accordion('#root', {{ multiple: false }});
        acc.items = [
          {{ id: '1', label: 'Panel 1', content: '<p>Content A</p>', open: true }},
          {{ id: '2', label: 'Panel 2', content: '<p>Content B</p>' }},
        ];
        acc.on('change', ({{ id, open }}) => console.log(id, open));
        
        const tabs = new Tabs('#root', {{ variant: 'line' }});
        tabs.items = [
          {{ id: 'a', label: 'Tab A', content: '...' }},
          {{ id: 'b', label: 'Tab B', content: '...', badge: 3 }},
        ];
        tabs.on('change', ({{ id }}) => console.log(id));
        
        const modal = new Modal({{ size: 'md' }});
        modal.title   = 'Confirm';
        modal.content = '<p>Are you sure?</p>';
        modal.open();
        modal.on('close', () => {{}});
        Navigation Controls
        6 navigation controls: Breadcrumb, Header, Menu, NavRail, Pagination, Stepper.
        Breadcrumb
        Stepper
        Pagination
        Menu — click button
        const bc = new Breadcrumb('#root');
        bc.items = [{{ label: 'Home', href: '/' }}, {{ label: 'Products', href: '/p' }}, {{ label: 'Laptop' }}];
        bc.on('click', ({{ item }}) => navigate(item.href));
        
        const stepper = new Stepper('#root');
        stepper.steps   = ['Account', 'Profile', 'Review', 'Done'];
        stepper.current = 1;
        stepper.next();                   // advance
        stepper.on('change', ({{ step }}) => {{}});
        
        const pager = new Pagination('#root', {{ total: 200, pageSize: 20 }});
        pager.on('change', ({{ page }}) => loadPage(page));
        
        const menu = new Menu();
        menu.items = [{{ id: 'edit', label: 'Edit', icon: '✏️' }}, {{ id: 'del', label: 'Delete', danger: true }}];
        menu.openBelow(myButton);
        menu.on('select', ({{ id }}) => {{}});
        Input Controls
        14 input controls. All expose reactive setters and typed events.
        Buttons
        TextField
        Switch & Checkbox & Radio
        Dropdown
        Rating & RangeSlider
        SearchBar
        const btn = new Button('#r', {{ variant: 'primary' }});
        btn.label   = 'Save';
        btn.loading = true;
        btn.on('click', () => save());
        
        const tf = new TextField('#r', {{ label: 'Email', type: 'email' }});
        tf.value = '[email protected]';
        tf.error = 'Invalid format';
        tf.on('change', ({{ value }}) => validate(value));
        
        const sw = new Switch('#r', {{ label: 'Dark mode' }});
        sw.checked = true;
        sw.on('change', ({{ checked }}) => applyTheme(checked));
        
        const dd = new Dropdown('#r', {{ searchable: true }});
        dd.options = [{{ value: 'ch', label: 'Switzerland' }}];
        dd.value   = 'ch';
        dd.on('change', ({{ value }}) => {{}});
        Display Controls
        14 display controls: badges, avatars, progress, skeleton, snackbar, tooltip, and more.
        Badge & Tag
        Avatar
        ProgressBar
        Skeleton
        Snackbar — click to fire
        const badge = new Badge('#r', {{ variant: 'success' }});
        badge.label = 'Active';
        
        const av = new Avatar('#r', {{ size: 40, shape: 'circle' }});
        av.name   = 'Riccardo Angeli'; // → 'RA'
        av.status = 'online';
        
        const pb = new ProgressBar('#r', {{ label: 'Upload', showValue: true }});
        pb.value          = 65;
        pb.indeterminate  = true;    // animated
        
        Snackbar.show('File saved!', {{ variant: 'success', duration: 3000 }});
        Charts
        3 SVG charts that integrate with AriannA Observable for reactive data binding.
        BarChart
        LineChart
        PieChart (donut)
        const bar = new BarChart('#root', {{ label: 'Monthly Sales' }});
        bar.data = [{{ label: 'Jan', value: 120 }}, {{ label: 'Feb', value: 95 }}];
        bar.on('click', ({{ bar }}) => console.log(bar.label));
        
        const line = new LineChart('#root', {{ area: true, smooth: true }});
        line.data = [{{ label: '00:00', value: 12 }}, {{ label: '01:00', value: 34 }}];
        
        const pie = new PieChart('#root', {{ donut: true, legend: true }});
        pie.data = [{{ label: 'EU', value: 42 }}, {{ label: 'US', value: 35 }}, {{ label: 'APAC', value: 23 }}];
        pie.on('click', ({{ slice }}) => {{}});
        Sidebar
        Resizable, collapsible, accordion navigation panel. Supports orientation: 'left' | 'right' — controls which edge the border and resize handle sit on, and which direction the panel collapses toward.
        Constructor
        import { Sidebar, SidebarCSS } from './arianna-controls/Sidebar.ts';
        
        const style = document.createElement('style');
        style.textContent = SidebarCSS;
        document.head.appendChild(style);
        
        const sidebar = new Sidebar('#shell', {
          orientation   : 'left',   // 'left' | 'right'
          width         : 260,
          minWidth      : 160,
          maxWidth      : 480,
          resizable     : true,
          collapsible   : true,
          collapsed     : false,
          collapsedWidth: 48,
          searchable    : true,
          showToggle    : true,
          persist       : true,
          storageKey    : 'my-app-nav',
        });
        orientation: 'left' | 'right'
        ValueBorderResize handleActive indicatorCollapse direction
        'left'border-rightright edge of panelleft border of itemslides left
        'right'border-leftleft edge of panelright border of itemslides right
        Sections & items
        sidebar.sections = [
          {
            id: 'core', label: 'Core Modules', open: true,
            items: [
              { id: 'real',    label: 'Real',    icon: '🌐' },
              { id: 'virtual', label: 'Virtual', icon: '🧩', badge: 'new' },
              { id: 'state',   label: 'State',   icon: '⚡', disabled: false },
            ],
          },
        ];
        sidebar.active = 'real';
        API reference
        Property / MethodTypeDescription
        sidebar.sections = []SidebarSection[]Set all sections (replaces existing)
        sidebar.active = 'id'stringSet the active item by id
        sidebar.collapse()thisCollapse to icon-only mode
        sidebar.expand()thisRestore full width
        sidebar.toggle()thisToggle collapsed state
        sidebar.setWidth(n)thisSet width in px (clamped to minWidth/maxWidth)
        sidebar.openSection(id)thisOpen an accordion section
        sidebar.closeSection(id)thisClose an accordion section
        sidebar.toggleSection(id)thisToggle a section
        sidebar.search(q)thisFilter items by query string ('' to clear)
        sidebar.on('select', cb)event{ item, section } — item clicked
        sidebar.on('resize', cb)event{ width } — drag resize
        sidebar.on('collapse', cb)event{ collapsed: boolean }
        sidebar.destroy()voidRemove element and all listeners
        SidebarItem interface
        FieldTypeDescription
        idstringUnique identifier
        labelstringDisplay text
        icon?stringEmoji or text icon
        badge?string | numberBadge shown after label
        disabled?booleanWhether item is disabled
        class?stringExtra CSS class(es) on item button
        data?unknownArbitrary user data
        Two — 2D Vector Engine
        SVG and Canvas 2D renderer with scene graph, animation, D3-style scales. Zero dependencies.
        Interactive Demo
        Two.ts — SVG Renderer live
        Quick start
        import Two from './additionals/Two.ts';
        
        const two = Two.createRenderer('#app', { mode: 'svg', width: 600, height: 400 });
        const stage = two.stage;
        
        const c = new Two.Circle({ cx: 100, cy: 100, r: 60, style: { fill: '#e40c88' } });
        stage.add(c);
        two.render();
        
        // Animate
        new Two.Tween(c, { r: 100 }, 600).easing('easeOutBounce').start();
        const loop = new Two.AnimationLoop(dt => two.render()).start();
        API
        ClassDescription
        SVGRendererLive SVG DOM, gradients, pointer events
        CanvasRendererCanvas2D, pixel ratio, toPNG/toJPEG
        Circle · Rect · EllipseBasic shapes with style, transforms
        Line · Polygon · PathLine and path geometry
        Text · ImageText rendering, image embedding
        Group2D · Stage2DScene graph containers
        PathBuilderFluent path: moveTo · lineTo · spline · arc
        scaleLinear · scaleBandD3-style scales with ticks/invert
        Tween<T>Property interpolation, 18 easing functions
        TimelineSequenced tweens with delay
        Export2DtoSVG · downloadSVG · downloadPNG · toPDF
        Three — 3D Engine
        WebGPU-primary + WebGL2 fallback 3D engine. PBR shading, CSG, STL/OBJ/GLB import/export. Zero dependencies.
        Interactive Demo
        Three.ts — 3D live (Canvas fallback in docs)
        Quick start
        import Three from './additionals/Three.ts';
        
        const renderer = new Three.WebGPURenderer(canvas);
        await renderer.init();
        
        const scene  = new Three.Scene();
        const camera = new Three.PerspectiveCamera(60, canvas.width/canvas.height, 0.1, 1000);
        camera.position.set(0, 1, 3);
        
        const mesh = new Three.Mesh(
          new Three.Box(1, 1, 1),
          new Three.PBRMaterial({ color: '#e40c88', roughness: 0.3 })
        );
        scene.add(mesh);
        
        const orbit = new Three.OrbitControls(camera, canvas);
        new Three.AnimationLoop(dt => {
          mesh.rotation.y += dt * 0.001;
          renderer.render(scene, camera);
        }).start();
        API
        ModuleContents
        GeometryBox · Sphere · Cylinder · Plane · Cone · Torus · BufferGeometry
        MaterialsBasic · Lambert · Phong · PBR (GGX/Smith) · Wireframe
        LightsAmbient · Directional · Point · Spot (16-light GPU buffer)
        Scene graphObject3D · Mesh · Group · Camera · Scene
        RenderersWebGPURenderer (WGSL PBR) · WebGL2Renderer (fallback)
        CSGunion · subtract · intersect (BSP tree)
        ModifiersSubdivision · Decimate · Mirror · Array · Bend · Twist · Bevel
        I/OSTL (binary+ASCII) · OBJ · GLB (glTF 2.0)
        ControlsOrbitControls (mouse + touch + damping)
        AI — Machine Learning Engine
        WebGPU compute-accelerated tensor operations, neural network layers, Transformer, and Tokenizer. Zero dependencies.
        Interactive Demo — Markov chain text generation
        AI.ts — MarkovChain live
        Quick start
        import AI from './additionals/AI.ts';
        
        // Tensor operations
        const a = AI.Tensor.randn([64, 128]);
        const b = AI.Tensor.randn([128, 64]);
        const c = await a.matmulGPU(b); // WebGPU compute shader
        
        // Sequential model
        const model = new AI.Sequential()
          .add(new AI.Dense(64,  { activation: 'relu', inputDim: 10 }))
          .add(new AI.Dense(32,  { activation: 'relu' }))
          .add(new AI.Dense(1,   { activation: 'sigmoid' }));
        model.compile({ loss: 'binaryCrossEntropy', optimizer: 'adam', lr: 0.001 });
        
        const losses = await model.fit(xTrain, yTrain, { epochs: 20, batchSize: 32, verbose: true });
        API
        ClassDescription
        TensorN-dim Float32Array: add/sub/mul/matmul, relu/sigmoid/softmax/layerNorm, reshape/slice/concat
        Dense · Flatten · DropoutStandard fully-connected layers
        BatchNorm · LayerNormNormalization layers
        Embedding · Attention · GRUSequence model layers
        SequentialStack of layers with Adam optimizer + backprop
        TransformerEncoder-only, sinusoidal PE, causal mask, top-K sampling
        TokenizerBPE-like char/word vocab, encode/decode, special tokens
        MarkovChainn-gram text generation
        AIUtilsoneHot · normalize · standardize · shuffle · trainTestSplit · accuracy
        Finance — Quantitative Engine
        Technical indicators, portfolio analytics, Black-Scholes, Monte Carlo (WebGPU-accelerated), and event-driven backtesting. Zero dependencies.
        Interactive Demo
        Finance.ts — Black-Scholes pricer
        Quick start
        import Finance from './additionals/Finance.ts';
        
        // Technical indicators
        const prices  = [100, 102, 98, 105, 110, 108, 115];
        const sma14   = Finance.Indicators.sma(prices, 14);
        const rsi14   = Finance.Indicators.rsi(prices, 14);
        const { macd, signal, histogram } = Finance.Indicators.macd(prices);
        
        // Black-Scholes
        const price  = Finance.BlackScholes.price(100, 105, 0.25, 0.05, 0.2, 'call');
        const greeks = Finance.BlackScholes.greeks(100, 105, 0.25, 0.05, 0.2);
        
        // GPU Monte Carlo (1M paths)
        const { price: mcPrice, stdError } =
          await Finance.MonteCarlo.optionGPU(100, 105, 0.25, 0.05, 0.2, 1_000_000);
        API
        NamespaceContents
        Finance.IndicatorsSMA · EMA · WMA · DEMA · TEMA · RSI · MACD · Bollinger · ATR · Stochastic · VWAP · OBV · CCI · WilliamsR · ADX
        Finance.Portfolioreturns · logReturns · sharpe · sortino · maxDrawdown · calmar · minVariance · maxSharpe · covarianceMatrix
        Finance.BlackScholesprice · greeks · impliedVol · binomialTree
        Finance.MonteCarlooption (CPU) · optionGPU (WebGPU 1M+ paths) · gbmPaths
        Finance.BachelierNormal Black price · greeks · impliedVol · fromBlackVol (lognormal→normal vol conversion)
        Finance.HestonStochastic vol pricing · calibrate(surface) — semi-analytical characteristic function
        Finance.Backtestrun(bars, strategy, capital, commission) → trades · equity · sharpe · winRate
        Docs — Document Engine
        Read and write DOCX, XLSX, PPTX, PDF, CSV, SVG — pure TypeScript, zero dependencies, no server required.
        API
        MethodDescription
        Docs.read(src)Auto-detect format from File/URL/ArrayBuffer
        Docs.download(doc, name)Trigger browser download
        Docs.docx.create(opts)Create Word document with paragraphs, tables, images
        Docs.xlsx.create(opts)Create Excel workbook with sheets and formulas
        Docs.xlsx.fromArray(rows)Quick 2D array → XLSX
        Docs.pptx.create(opts)Create PowerPoint presentation with slides
        Docs.pdf.create(opts)Create PDF 1.4 with pages, text, images
        Docs.csv.parse(text)RFC 4180 CSV → string[][]
        Docs.svg.create(w,h)SVG document builder
        Video — Capture & Composition
        Screen and camera capture, multi-layer compositor, animated GIF encoder (pure LZW). Zero dependencies.
        API
        ClassDescription
        ScreenCapturegetDisplayMedia → MediaRecorder → WebM Blob
        CameraCapturegetUserMedia → record, mountPreview()
        VideoPlayerFluent <video> wrapper: src · play · seek · captureFrame()
        VideoCompositorCanvas2D multi-layer (video/image/text/color), record()
        GIFEncoderaddFrame(canvas, delay) → encode() → Uint8Array (LZW)
        VideoUtilsdownload · blobToDataURL · canvasToGIF
        Audio — Web Audio Engine
        AudioContext wrapper with synthesis, effects chain, step sequencer, MIDI. Zero dependencies.
        API
        ClassDescription
        AudioEngineAudioContext, master GainNode, compressor, resume/suspend
        AudioPlayerLoad URL/ArrayBuffer/Blob, play/stop, volume, loop, playbackRate
        AudioRecordergetUserMedia microphone → MediaRecorder → WebM Blob
        Oscillatorsine/square/sawtooth/triangle, frequency, detune, volume
        NoiseGeneratorwhite/pink/brown noise via ScriptProcessor
        Reverb · Delay · FilterConvolution reverb, feedback delay, BiquadFilter
        AnalyserFFT spectrum, waveform, peak, RMS
        Sequencer16-step, BPM clock, pattern scheduling
        MIDIEngineWeb MIDI API, noteOn/Off/CC, noteToFreq, noteToName
        IO — File, Network & Storage
        File open/download/drag-drop, HTTP client with retries, SSE, WebSocket with reconnect, reactive LocalStore, IndexedDB wrapper, Clipboard, Web Share. Zero dependencies.
        API
        ClassDescription
        FileIOopen(multi, accept) · readText/Binary/DataURL · download · dropZone
        FSAccessFile System Access API: readFile · writeFile · openDirectory
        Httpget/post/put/del with retries, timeout, interceptors
        SSEEventSource wrapper with on() handler
        WebSocketIOReconnect, message queue, JSON auto-parse
        LocalStore<T>Typed localStorage + reactive subscribe()
        IDBIOIndexedDB promise: open · put · get · delete · getAll
        ClipboardreadText/writeText · readImage/writeImage
        ShareWeb Share API: share(title, text, url, files)
        Math — Mathematical Library
        Migrated from Golem.Math (2012). All original classes preserved + Vector2/3/4, Quaternion, Matrix4, Statistics.
        Contents
        ClassDescription
        MathConstants32 mathematical + physical constants (Phi, Avogadro, Planck, c, G…)
        FractionExact rational arithmetic: Sum, Subtract, Multiply, Divide
        Vector2/3/4Full N-dim operations: add, cross, dot, normalize, lerp
        Matrix4perspective, lookAt, translate, rotate, scale, inverse
        Quaternion3D rotation, slerp, fromEuler, toMatrix4
        ComplexComplex numbers: add, mul, div, magnitude, conjugate, polar
        Statisticsmean, variance, stdDev, median, mode, correlation
        Geometry — Geometric Library
        Migrated from Golem.Geometry (2012). Full Angle/Rotation system, shapes, solids, collision detection, ray casting.
        Contents
        ClassDescription
        Angle10 unit systems: Radians, Degrees, Turns, Grads, Mils, Hours… + full trig
        MatrixNxN: LUP, QR, EigenValues, EigenVectors, Determinant
        TransformCSS/3D: Translate, Scale, Rotate, Skew, Reflect
        ShapesRectangle, Line, Curve, Path, Triangle, Circle, Plane, Polygon
        SolidsFrustum, TetraHedron, Box, Sphere, Octahedron, Torus, Cylinder, Tube
        AABBAxis-aligned bounding box, containsPoint, intersects
        RayRay casting, intersectAABB, intersectTriangle, intersectPlane
        Data — Structures & Models
        Essential data structures and abstract models. DAG, FSM, Trie, PriorityQueue, LRUCache, SegmentTree, DisjointSet, ObservableMap/Array. Zero dependencies.
        Interactive Demo — FSM
        FSM — Traffic light state machine
        red
        valid: —
        Interactive Demo — DAG
        DAG — topological sort
        Interactive Demo — Trie autocomplete
        Trie — autocomplete
        API
        ClassDescription
        DAG<T>Directed Acyclic Graph: addEdge (cycle detection) · topoSort · ancestors · descendants
        GraphWeighted directed/undirected: BFS · DFS · dijkstra · aStar
        FSM<S,E>Finite State Machine: guards · actions · history · undo · on(transition) · toDOT()
        Trie<V>Prefix tree: insert · get · autocomplete · delete · longestPrefix
        PriorityQueue<T>Binary min-heap with custom comparator: push · pop · peek · toSortedArray
        Deque<T>Double-ended queue O(1): pushFront/Back · popFront/Back
        LRUCache<K,V>Least-Recently-Used cache O(1) get/put
        SegmentTreeRange sum/min/max with lazy propagation: query(l,r) · update(i,v)
        DisjointSetUnion-Find with path compression: union · find · connected · componentCount
        ObservableMap<K,V>Map with reactive subscribe(fn) → unsubscribe
        ObservableArray<T>Array with reactive splice/push/pop events
        Quick start
        import Data from './additionals/Data.ts';
        
        // DAG
        const dag = new Data.DAG<string>();
        dag.addEdge('A', 'B').addEdge('B', 'C').addEdge('A', 'C');
        console.log(dag.topoSort()); // ['A','B','C']
        
        // FSM
        const fsm = new Data.FSM('idle', [
          { from: 'idle', event: 'start', to: 'running' },
          { from: 'running', event: 'pause', to: 'paused' },
          { from: 'paused', event: 'resume', to: 'running' },
          { from: '*', event: 'stop', to: 'idle' },
        ]);
        fsm.send('start'); console.log(fsm.state); // 'running'
        
        // Trie
        const trie = new Data.Trie<number>();
        ['apple','application','apply','banana'].forEach((w,i) => trie.insert(w,i));
        console.log(trie.autocomplete('app')); // ['apple','application','apply']
        
        // Priority Queue
        const pq = new Data.PriorityQueue<number>();
        [5,1,3,2,4].forEach(n => pq.push(n));
        console.log(pq.pop()); // 1  (min-heap)
        Finance Components — Overview
        11 pure-SVG/HTML financial widgets. Zero dependencies. Each is a standalone file in components/finance/.
        CandlestickChart
        LineChart
        DepthChart
        HeatmapChart
        PortfolioDonut
        PnLChart
        RiskGauge
        OrderBook
        Screener
        Sparkline
        AlertBadge
        Import
        // Individual (tree-shakeable)
        import { CandlestickChart } from './components/finance/CandlestickChart.ts';
        
        // Bundle
        import FinanceComponents from './components/finance/index.ts';
        const { CandlestickChart, OrderBook, RiskGauge } = FinanceComponents;
        CandlestickChart
        OHLCV candlestick + volume bars. Pure SVG.
        Live demo
        const chart = new CandlestickChart('#container', {
          width: 700, height: 400, showVolume: true,
          bullColor: '#26a69a', bearColor: '#ef5350'
        });
        chart.render(bars); // Bar[] = { open, high, low, close, volume }
        LineChart
        Multi-series line chart with legend. Pure SVG.
        Live demo
        const chart = new LineChart('#container', { width: 600, height: 300 });
        chart.render([
          { name: 'AAPL', data: [150, 158, 155, 162] },
          { name: 'MSFT', data: [280, 290, 285, 295] },
        ]);
        DepthChart
        Cumulative bid/ask order book depth chart. Pure SVG.
        Live demo
        const chart = new DepthChart('#container', { width: 600, height: 300 });
        chart.render(
          bids, // [price, size][]  — sorted descending by price
          asks  // [price, size][]  — sorted ascending  by price
        );
        HeatmapChart
        Correlation / sector heatmap with color interpolation. Pure SVG.
        Live demo
        const chart = new HeatmapChart('#container', { width: 600, height: 400 });
        chart.render(
          ['AAPL', 'MSFT', 'GOOG', 'AMZN'],
          // NxN correlation matrix (-1..1)
          [
            [1.0,  0.7,  0.6,  0.5],
            [0.7,  1.0,  0.8,  0.6],
            [0.6,  0.8,  1.0,  0.7],
            [0.5,  0.6,  0.7,  1.0],
          ]
        );
        PortfolioDonut
        Asset allocation donut chart with percentage labels. Pure SVG.
        Live demo
        const donut = new PortfolioDonut('#container', { size: 300 });
        donut.render([
          { label: 'Equities',    value: 45 },
          { label: 'Bonds',       value: 25 },
          { label: 'Real Estate', value: 15 },
          { label: 'Commodities', value: 10 },
          { label: 'Cash',        value: 5  },
        ]);
        PnLChart
        Profit & loss bar chart, green/red coloring. Pure SVG.
        Live demo
        const pnl = new PnLChart('#container', { width: 500, height: 250 });
        pnl.render([
          { label: 'Q1', pnl:  12500 },
          { label: 'Q2', pnl:  -3800 },
          { label: 'Q3', pnl:   8200 },
          { label: 'Q4', pnl:  15700 },
        ]);
        RiskGauge
        Semi-circular gauge with color-coded risk zones. Pure SVG.
        Live demo
        const gauge = new RiskGauge('#container', { size: 200 });
        gauge.render(
          25,                  // value
          0, 100,             // min, max
          'Volatility'         // label
        );
        // Auto color: green <33% · amber 33-66% · red >66%
        OrderBook
        Bid/ask ladder table with mid price and spread. Pure HTML.
        Live demo
        const book = new OrderBook('#container');
        book.render(
          bids,         // [price, size][] — descending
          asks,         // [price, size][] — ascending
          10            // depth (rows per side)
        );
        Screener
        Filterable instrument table with formatted columns. Pure HTML.
        Live demo
        const screen = new Screener('#container');
        screen.render(
          [
            { symbol: 'AAPL', price: 175.32, change:  2.4,  volume: 52_300_000 },
            { symbol: 'MSFT', price: 412.10, change: -0.8,  volume: 28_700_000 },
            { symbol: 'GOOG', price: 142.80, change:  1.1,  volume: 19_400_000 },
          ],
          ['symbol', 'price', 'change', 'volume']  // optional column order
        );
        Sparkline
        Mini inline price sparkline. Auto-colors by direction. Pure SVG.
        Live demo
        const spark = new Sparkline('#container');
        spark.render(
          [100, 102, 98, 105, 110, 108, 115],
          { width: 100, height: 30 }
        );
        // Auto-colored: green if last >= first, red otherwise.
        // Override with opts.color: '#e40c88'.
        AlertBadge
        Price alert badge: neutral / info / warning / danger. Pure HTML.
        Live demo
        const badge = new AlertBadge('#container');
        
        badge.render('AAPL +2.4%',    'info');
        badge.render('TSLA -8.1%',    'danger',  'stop-loss');
        badge.render('BTC volatility','warning', 'high');
        badge.render('Market closed', 'neutral');
        
        // Levels: 'neutral' | 'info' | 'warning' | 'danger'
        2D Modifiers
        Interactive wrapper behaviors for any HTML element. Accept Real | HTMLElement | string (CSS selector) | Array.
        Mover — drag-to-move (axis lock, snap, bounds)
        Drag any element with axis lock, independent snapX / snapY grid, custom bounds and pointer-event support (mouse + touch + pen). Public mass / damping / stiffness fields are reserved for the upcoming physics engine.
        Mover live demo
        Resizer — 8-handle drag resize
        Resizer live demo
        Rotator — drag-to-rotate (snap 15°)
        Rotator live demo
        Skewer — skewX / skewY
        Skewer live demo
        Rounder — border-radius control (uniform or per-corner)
        Single uniform handle with r / radius, or four independent handles when any of topLeft / topRight / bottomLeft / bottomRight is set.
        Rounder live demo
        Reflector — flipX / flipY
        Reflector live demo
        ClassBehaviorCallback
        Resizer8-direction resize handles, min/max sizeonResize(el, w, h)
        RotatorDrag-to-rotate handle + angle snaponRotate(el, angle)
        SkewerskewX/Y via drag, maxAngleonSkew(el, sx, sy)
        Rounderborder-radius drag control, uniform r or per-corner topLeft/topRight/bottomLeft/bottomRightonRound(el, r, corner)
        ReflectorflipX/flipY buttons, animated CSS scale
        Moverdrag-to-move with axis lock, snapX/snapY, bounds, mass/damping/stiffnessonStart, onMove, onSnap, onEnd
        import { Resizer, Rotator, Rounder, Mover } from './components/modifiers/2D/index.ts';
        
        const r = new Resizer('#my-box', { minWidth: 80, handleColor: '#e40c88' });
        r.onResize((el, w, h) => console.log(w, h));
        
        const t = new Rotator('#my-box', { snap: 15 }); // snap to 15°
        t.onRotate((el, angle) => console.log(angle));
        
        // Rounder: per-corner mode
        const ro = new Rounder('#my-box', { topLeft: 20, bottomRight: 40 });
        ro.onRound((el, radius, corner) => console.log(corner, radius));
        
        // Mover: drag with snap to 10×10 grid, bounded to parent
        const mv = new Mover('#my-box', { snapX: 10, snapY: 10, bounds: 'parent' });
        mv.onMove((el, x, y) => console.log(x, y));
        3D Modifiers
        Geometry and transform modifiers for Three.ts meshes. All implement .apply() + enable/disable/destroy.
        Geometry
        ClassDescription
        SubdivisionModifierMidpoint subdivision surface (n iterations)
        DecimateModifierTriangle decimation to a target ratio
        BevelModifierEdge bevel / chamfer along face normals
        MirrorModifierMirror on X/Y/Z + optional vertex weld
        ArrayModifierLinear or radial instance array
        BendModifierBend geometry along an axis
        TwistModifierTwist geometry around an axis
        WaveModifierSinusoidal displacement (animatable)
        InflateModifierExpand along vertex normals
        SmoothModifierLaplacian smoothing (n iterations)
        Transform / Scene
        ClassDescription
        DragModifierMouse drag on XZ/XY/YZ plane
        SnapModifierSnap position + rotation to grid
        LODModifierSwap geometry by camera distance
        FadeModifierOpacity fade by distance (update per frame)
        BillboardModifierAlways face camera, per-axis lock
        import { SubdivisionModifier, WaveModifier } from './components/modifiers/3D/index.ts';
        
        new SubdivisionModifier(mesh, 2).apply(); // 2 iterations
        
        const wave = new WaveModifier(mesh, { amplitude: 0.3, frequency: 3 });
        let t = 0;
        loop(() => { wave.apply(t += 0.016); }); // animate
        PianoRoll
        Full MIDI piano-roll editor with vertical keyboard, scrollable beat grid, draw/select/erase tools, snap-to-grid, velocity lane, and live MIDI event emission for external synths or audio engines. Note model is plain JSON — round-trippable.
        Live demo
        Switch tools with the toolbar (or D / S / E). Click on the grid to draw notes (drag to extend), click a note to select+move, drag the right edge to resize. Space toggles play. Delete removes selection. Click any keyboard key on the left to trigger a MIDI note manually.
        Note model (JSON)
        Every note is plain data. Round-trippable JSON for save/load, transfer to MIDI engines, or AI-generated sequences.
        interface PianoRollNote {
          pitch:    number;   // MIDI 0-127 (C-1 to G9)
          start:    number;   // in beats (1 beat = quarter note)
          duration: number;   // in beats
          velocity: number;   // 0-127
          channel?: number;   // MIDI channel 1-16
        }
        
        interface ExportedSequence {
          bpm:     number;
          bars:    number;
          timeSig: [number, number];
          notes:   PianoRollNote[];
        }
        Component usage
        import { PianoRoll } from 'ariannajs/components/audio/PianoRoll';
        
        const pr = new PianoRoll('#root', {
          bpm:       120,
          bars:      8,
          pitchLow:  36,    // C2
          pitchHigh: 96,    // C7
          snap:      0.25,  // 1/16th
        });
        
        // Listen to MIDI events during playback — connect to your synth here
        pr.on('midi', evt => {
          // evt = { type: 'note-on'|'note-off', pitch, velocity, channel, time }
          mySynth.send(evt);
        });
        
        // Programmatic note creation
        pr.addNote(60, 0, 1, 100);   // C4 at beat 0, 1 beat long
        pr.addNote(64, 1, 1, 100);   // E4
        pr.addNote(67, 2, 2, 90);    // G4 longer, softer
        
        pr.play();
        
        // Round-trippable JSON
        const json = pr.export();
        pr.load(json);
        Public API
        Method / EventTypeDescription
        addNote(pitch, start, dur, vel?, ch?)methodCreate a note, returns its id
        removeNote(id)methodDelete a note
        updateNote(id, patch)methodModify pitch/start/duration/velocity
        clear()methodRemove all notes
        setTool('draw'|'select'|'erase')methodSwitch active tool
        play() / pause() / stop()methodsTransport control
        triggerNote(pitch, vel?) / releaseNote(pitch)methodManual note-on/off (e.g. virtual keyboard)
        export()methodSerialize sequence to JSON
        load(seq)methodReplace current sequence with JSON
        on('midi', cb)eventFires for every note-on/note-off during playback or virtual keyboard click
        on('change', cb)eventFires on add/remove/update note
        on('run-state', cb)eventFires on play/pause/stop transitions
        Keyboard shortcuts
        KeyAction
        DSwitch to Draw tool
        SSwitch to Select tool
        ESwitch to Erase tool
        SpaceToggle play / pause
        Delete / BackspaceDelete selected notes
        AudioPlayer
        Audio playback component with full transport (play/pause/stop), seek bar, volume control, and time display. Output is a Web Audio GainNode that downstream components (ChannelStrip, AudioTrackEditor, etc.) can connect to via .connect().
        Live demo
        A working AudioPlayer instance. Click play to start; the output is routed to AudioComponent.context.destination by default.
        Component usage
        import { AudioPlayer } from 'ariannajs/components/audio';
        
        const p = new AudioPlayer('#root', {
          src:      'song.mp3',
          loop:     false,
          volume:   0.8,
          autoplay: false,
        });
        
        // Listen to playback events
        p.on('timeupdate', e => console.log(e.time, e.duration));
        p.on('ended',      ()  => console.log('done'));
        
        // Web Audio routing — chain into a ChannelStrip or any AudioNode
        p.connect(strip);
        
        // Programmatic control
        p.play();
        p.pause();
        p.seek(30);                 // jump to 30s
        p.setVolume(0.5);
        
        Public API
        Method / EventDescription
        load(src)Load a new audio source URL
        play() / pause() / stop()Transport control (returns Promise for play)
        seek(time)Jump to time in seconds
        setVolume(0..1)Set volume (also updates the GainNode)
        setLoop(boolean)Enable/disable loop
        connect(target)Connect output to a ChannelStrip, AudioComponent, or AudioNode
        on('play' / 'pause' / 'ended' / 'timeupdate' / 'loaded')Forwarded HTML media events
        VideoPlayer
        Video playback component with transport, seek bar, volume, fullscreen, and Web Audio routing on the audio track. Aspect-ratio configurable; default 16:9.
        Live demo
        Component usage
        import { VideoPlayer } from 'ariannajs/components/video';
        
        const v = new VideoPlayer('#root', {
          src:         'movie.mp4',
          poster:      'poster.jpg',
          loop:        false,
          aspectRatio: '16/9',
        });
        
        // Listen to events
        v.on('loaded',     e => console.log(e.width, e.height));
        v.on('timeupdate', e => updateSubtitles(e.time));
        
        // Web Audio routing on the audio track
        v.connect(strip);
        
        // Fullscreen
        v.fullscreen();
        
        Public API
        Method / EventDescription
        load(src, poster?)Load a new video source
        play() / pause() / stop()Transport control
        seek(time)Jump to time in seconds
        setVolume(0..1)Set audio volume
        fullscreen()Request fullscreen on the video element
        connect(target)Route audio output to a ChannelStrip / AudioNode
        getElement()Get the underlying HTMLVideoElement
        ChannelStrip
        Audio channel strip in DAW style (Luna / Nuendo / Pro Tools). Provides input gain, 3-band parametric EQ (low shelf / mid peak / high shelf), pan, mute/solo, fader (post-EQ), and a real-time peak meter. Built entirely on Web Audio API — chain instances together for full mixing.
        Signal chain
        Internal Web Audio routing inside a ChannelStrip:
        input → gain → EQ low → EQ mid → EQ high → pan → fader → output (analyser)
        Live demo
        A standalone ChannelStrip with all controls. The meter is wired to a synthetic test tone so you can see it react.
        Component usage
        import { ChannelStrip } from 'ariannajs/components/audio';
        
        const strip = new ChannelStrip('#strip', {
          name:  'Lead Vox',
          color: '#e40c88',
          fader: 0,             // dB
          pan:   0,             // -1..+1
        });
        
        // Route audio through it
        somePlayer.connect(strip);
        strip.connect(masterStrip);
        masterStrip.connect(AudioComponent.context.destination);
        
        // Programmatic control
        strip.setEQ('low',  { gain: 3, freq: 100 });
        strip.setEQ('mid',  { gain: -2, freq: 1500, q: 2 });
        strip.setEQ('high', { gain: 1.5, freq: 8000 });
        strip.setFader(-6);
        strip.setMute(true);
        
        strip.on('change', e => console.log(e.kind, e.value));
        
        Public API
        Method / EventDescription
        setGain(db)Input gain (-24/+24 dB)
        setEQ('low' | 'mid' | 'high', { gain, freq, q? })Set parametric EQ band
        setPan(-1..+1)Stereo pan
        setFader(db)Post-EQ fader (-60/+12 dB)
        setMute(boolean) / setSolo(boolean)Mute/solo state
        setName(string)Update the strip header label
        connect(target)Route output to next strip / AudioNode
        on('change')Fires on every parameter update with kind & value
        AudioEditor
        Single-clip audio editor in Audacity style. Loads an AudioBuffer, displays the full waveform, and supports drag selection, deep zoom (50x), cut/copy/paste/delete, fade-in / fade-out on selection, normalize, gain, reverse, insert silence, and full undo/redo (50-step stack).
        Live demo
        Click + Load to load an audio file from disk, or use the included tone seed. Click-drag on the waveform to select a range; then use Cut/Fade In/Normalize buttons. ⌘Z undo, ⌘⇧Z redo, Space play/stop.
        Component usage
        import { AudioEditor } from 'ariannajs/components/audio';
        
        const ed = new AudioEditor('#root');
        
        // Load a buffer
        const buf = await ed.loadFile(file);   // File or URL
        ed.setBuffer(buf);
        
        // Edit operations (all push undo)
        ed.setSelectionTime(1.5, 3.0);
        ed.fadeIn();                       // linear fade on selection
        ed.normalize(-3);                  // peak to -3 dBFS
        ed.gain(2);                        // +2 dB on selection
        ed.cut();
        ed.paste();
        
        // Get the post-edit AudioBuffer
        const out = ed.getBuffer();
        
        ed.on('change',    e => console.log(e.kind));
        ed.on('selection', e => console.log(e.start, e.end));
        
        Keyboard shortcuts
        KeyAction
        ⌘Z / ⌘⇧ZUndo / Redo
        ⌘C / ⌘X / ⌘VCopy / Cut / Paste
        ⌘ASelect all
        Delete / BackspaceDelete selection
        SpacePlay / Stop
        Public API
        Method / EventDescription
        loadFile(src)Decode audio from URL/File/ArrayBuffer to AudioBuffer
        setBuffer(buf) / getBuffer()Set/get the editing buffer
        setSelectionTime(start, end)Selection in seconds
        cut() / copy() / paste() / delete()Standard edit ops
        fadeIn() / fadeOut()Linear fades on selection
        normalize(targetDb?)Peak-normalize selection (default 0 dBFS)
        gain(db)Apply gain in dB
        reverse() / insertSilence(seconds)Common transforms
        undo() / redo()Stack-based undo (50-step)
        play() / stop()Playback from selection start
        AudioTrackEditor
        Multi-track audio timeline (DAW pool) — like the Audio panel of Logic / Pro Tools / Ableton. Each track contains clips with rendered waveforms; clips can be moved, resized (trim left/right), copied, pasted, split. Real Web Audio playback via BufferSource per clip.
        Live demo
        Click the + on any track header to upload an audio file. Drag clips horizontally to move; drag clip edges to trim. ⌘C/⌘V/⌘X/Del work. Space toggles playback.
        Component usage
        import { AudioTrackEditor } from 'ariannajs/components/audio';
        
        const ed = new AudioTrackEditor('#root', {
          tracks: 4,
          bpm:    120,
        });
        
        // Add a clip from a buffer
        const buf = await ed.loadFile('vocals.wav');
        ed.addClip('t1', { buffer: buf, start: 0, name: 'Take 1' });
        
        // Programmatic split
        ed.splitClip(clipId, 5.5);     // split at 5.5s on timeline
        
        // Track management
        ed.addTrack({ id: 'fx', name: 'FX', color: '#3b82f6' });
        ed.removeTrack('t3');
        
        // Playback honors mute/solo state per track
        ed.play();
        ed.pause();
        
        ed.on('change', e => console.log(e.kind));
        
        Public API
        MethodDescription
        addTrack({ id, name, color? })Add a new track
        removeTrack(id)Remove track + all its clips
        addClip(trackId, { buffer, start, offset?, duration?, name? })Add a clip on a track
        removeClip(id) / splitClip(id, atTime)Clip operations
        cut() / copy() / paste(atTime) / deleteSelection()Multi-clip edit ops
        setZoom(0.1..8)Horizontal zoom factor
        play() / pause() / stop()Mix all clips, honors mute/solo per track
        loadFile(src)Decode URL/File to AudioBuffer for use in addClip
        VideoTrackEditor
        Multi-track video timeline (DaVinci Resolve / Premiere style). Loads video sources, generates thumbnails for the timeline, supports drag move/resize/trim of clips, copy/paste, split. Pure UI/data layer — pair with FFmpeg (via Tauri command) for actual rendering and export.
        Live demo
        Click + Source to upload a video file. Thumbnails are generated automatically (8 sample frames). Drag clips to rearrange; drag edges to trim.
        Component usage
        import { VideoTrackEditor } from 'ariannajs/components/video';
        
        const ed = new VideoTrackEditor('#root', { tracks: 3 });
        
        // Load a source — generates thumbnails automatically
        const src = await ed.loadSource('clip.mp4');
        ed.addClip('v1', {
          source:   src,
          start:    0,            // timeline position in seconds
          sourceIn: 0,            // in-point inside source
          duration: 5,
        });
        
        // Split, trim, move
        ed.splitClip(clipId, 2.5);
        
        // Serialize the project (sources, tracks, clips)
        const project = ed.export();
        fs.writeFileSync('project.json', JSON.stringify(project, null, 2));
        
        ed.on('change', e => console.log(e.kind));
        
        Tauri integration pattern
        For final rendering, pair the UI with FFmpeg in Rust via a Tauri command. Export the project JSON, walk the clips, and emit FFmpeg concat + seek + trim filter chains.
        // Frontend
        import { invoke } from '@tauri-apps/api/tauri';
        const project = ed.export();
        const outFile = await invoke('render_project', { project });
        Public API
        MethodDescription
        loadSource(file, thumbCount = 8)Load video, auto-generate thumbnails
        addTrack({ id, name, type? })Add a video or audio track
        addClip(trackId, { source, start, sourceIn?, duration? })Place a clip
        splitClip(id, atTime)Split a clip at a timeline timestamp
        cut() / copy() / paste(atTime) / deleteSelection()Multi-clip edit ops
        export()Returns ExportedProject (sources + tracks + clips)
        setZoom(0.1..8) / setPlayhead(time)View/transport state
        NodeEditor
        Generic JSON-schema-driven node-graph editor. Domain-agnostic — works for dataflow, audio routing, AI agent orchestration, video pipelines, server-side workflow composition. Linguaggio-agnostico: every node is described by a portable JSON schema, the runtime is your choice.
        Live demo
        Drag any block from the palette to the canvas. Click a port (LED) and drag to another port to connect them. Right-click a wire to delete it. The graph is fully serializable — click Export JSON.
        Port LED states
        ColorMeaning
        RedIdle, not connected
        YellowHover target while dragging a wire
        GreenConnected, types compatible (ok)
        OrangeConnected, types convertible (warn)
        Red blinkingConnected, type mismatch or runtime error
        Node schema (JSON contract)
        Every node is just data. Define your domain by listing the schemas the editor should expose in its palette.
        import { NodeEditor } from 'ariannajs/components/composite/NodeEditor';
        
        const editor = new NodeEditor('#root', {
          schemas: [
            {
              type: 'source.timer',
              name: 'Timer',
              category: 'Source',
              color: '#3b82f6', icon: '⏱',
              inputs:  [],
              outputs: [{ id: 'tick', type: 'number', label: 'tick' }],
            },
            {
              type: 'ai.llm',
              name: 'LLM Agent',
              category: 'AI',
              color: '#10b981', icon: '🧠',
              inputs:  [
                { id: 'prompt', type: 'string', label: 'prompt' },
                { id: 'ctx',    type: 'json',   label: 'context' },
              ],
              outputs: [
                { id: 'reply', type: 'string', label: 'reply' },
                { id: 'usage', type: 'json',   label: 'usage' },
              ],
            },
            {
              type: 'sink.log',
              name: 'Console',
              category: 'Sink',
              color: '#64748b', icon: '▣',
              inputs:  [{ id: 'in', type: 'any', label: 'in' }],
              outputs: [],
            },
          ],
        });
        
        editor.on('graph-change', () => {
          console.log('graph:', editor.export());
        });
        Public API
        Method / EventTypeDescription
        addNode(type, x, y)methodSpawn a node by schema type at given coords
        removeNode(id)methodRemove a node and all its wires
        addWire(srcN, srcP, dstN, dstP)methodConnect output port to input port
        removeWire(id)methodDelete a single wire
        setWireStatus(id, status)methodUpdate wire status from runtime (ok / warn / error)
        clear()methodReset to empty graph
        export()methodSerialize graph to JSON
        load(graph)methodReplace current graph from JSON
        setRunState(s)methodSet 'idle' | 'running' | 'paused'
        on('graph-change', cb)eventFires on add/remove/move
        on('run-state', cb)eventFires when Play/Pause/Stop changes state
        Wire routing — Manhattan
        Wires use right-angle (Manhattan) routing in 5 segments — Unreal Blueprint style. The midpoint between source and destination is computed dynamically as nodes move, so wires re-route smoothly during drag.

        Test Suite

        Click any group's Run All button below to run that group only.
        0 tests0 passed
        UUID · Scopes · GetPrototypeChain · SetDescriptors · Namespaces · GetDescriptor · Define · Events
        Core Inspector
        // run tests
        0 tests0 passed
        Core.use() · idempotency · Core.plugins() · version
        Installed plugins
        none yet
        Core version:
        0 tests0 passed
        on / off / fire / once / all · multi-type · static bus
        Registry Inspector
        // run tests
        0 tests0 passed
        getter/setter · Changing/Changed order · property-scoped events · history · deep nesting
        State Visualizer
        0 tests0 passed
        Array · Map · Set · WeakMap — Proxy interception
        Collection Inspector
        // run tests
        0 tests0 passed
        derived values · Computed-Changed event · string concat · conditional
        Computed Live
        0 tests0 passed
        Named States · State-Reached · transition sequences · match()
        Transitions
        // run tests
        0 tests0 passed
        6 constructor overloads · render · on/off/fire · append/add/remove · get/set · show/hide
        Real DOM Inspector
        // run tests
        0 tests0 passed
        Create · Render · Mount · Unmount · Parse · Compare · Clone · add/remove/push/pop
        Virtual Tree Inspector
        // run tests
        0 tests0 passed
        6 constructor overloads · get/set/remove/merge/replace · Rule-Changed · clone · Rule.Parse
        Rule Inspector
        // run tests
        0 tests0 passed
        8 constructor overloads · add/insert/remove/shift/pop/clear · getIndex · contains · Observable
        Sheet Inspector
        // run tests
        0 tests0 passed
        provide · consume · update · Context-Changed · has · keys · multi-context
        Context Registry
        // run tests
        0 tests0 passed
        if · for · while · switch · bind · show · model · bootstrap
        Directive Sandbox
        Source — All Runtime Directives
        Directive.if — conditional rendering with update()
        const panel = document.querySelector('#my-panel'); let visible = true; const update = Directive.if(panel, () => visible, '<div class="content">Content visible</div>', '<div class="empty">Nothing to show</div>' ); // Toggle: visible = false; update(); // shows else branch visible = true; update(); // shows then branch
        Directive.for — list from array (reactive update)
        const ul = document.querySelector('ul'); let items = ['Mercury', 'Venus', 'Earth']; const update = Directive.for(ul, () => items, (item, i) => `<li data-i="${i}">${item}</li>` ); items = ['Mercury', 'Venus', 'Earth', 'Mars']; update(); // re-renders 4 items, removes old 3
        Directive.foreach — object iteration (Golem: foreach="var planet in object")
        const object = { Mercury : 'Mercury Value', Pluto : 'Pluto Value', Uranus : 'Uranus Value', Jupiter : 'Jupiter Value', Earth : 'Earth Value', }; const ol = document.querySelector('#ForeachComponent'); Directive.foreach(ol, () => object, (planet, value) => `<li class="Value">{{ planet }} : {{ object[planet] }}</li>` .replace('{{ planet }}', planet) .replace('{{ object[planet] }}', value) ); // Mirrors: <ol foreach="var planet in object"><li>{{ planet }} : {{ object[planet] }}</li></ol>
        Directive.while — render while condition is true
        const ul = document.querySelector('ul'); let i = 0; Directive.while(ul, () => i < 5, () => { const html = `<li>Item ${i}</li>`; i++; return html; }); // Renders: Item 0, Item 1, Item 2, Item 3, Item 4
        Directive.switch — render matching case (like <switch> in Solid)
        let tab = 'home'; const update = Directive.switch(container, () => tab, { home : '<div>🏠 Home</div>', about : '<div>ℹ About</div>', contact : '<div>✉ Contact</div>', default : '<div>404 Not Found</div>', }); tab = 'about'; update(); // switches to About panel
        Directive.bind — one-way binding: element property ← source
        const span = document.querySelector('#name-display'); const state = new State({ name: 'AriannA' }); const update = Directive.bind(span, 'textContent', () => state.State.name); state.on('State-name-Changed', update); state.State.name = 'Beta 1'; // span updates automatically
        Directive.show — toggle visibility (no DOM removal)
        const sidebar = document.querySelector('#sidebar'); let open = false; const update = Directive.show(sidebar, () => open); document.querySelector('#toggle-btn').addEventListener('click', () => { open = !open; update(); // sets display:'' or display:'none' });
        Directive.model — two-way binding: input ↔ State
        const state = new State({ name: '', email: '' }); Directive.model(document.querySelector('#name-input'), state, 'name'); Directive.model(document.querySelector('#email-input'), state, 'email'); // input.value ↔ state.State.name — both directions, zero glue code state.on('State-Changed', e => console.log(e.Property.Name, '→', e.Property.New) );
        Directive.template — {{ }} literal interpolation (Golem TemplateLiterals)
        // Matches Golem: <p>This is an {{ example }} of Template {{ literals }}</p> var example = 'EXAMPLE'; var literals = 'LITERALS'; var Level1A = { Level2A: 'Data Level2A Value' }; Directive.template(document.querySelector('#LiteralsComponent'), { example, literals, Level1A, }); // "This is an EXAMPLE of Template LITERALS" // "{{ Level1A.Level2A }}" → "Data Level2A Value" // Bracket notation: const planet = 'Mercury'; const object = { Mercury: 'Mercury Value' }; Directive.template(el, { planet, object }); // "{{ planet }}" → "Mercury" // "{{ object[planet] }}" → resolved via path lookup
        Directive.on — event listener (v-on / @event equivalent)
        // Single type Directive.on(button, 'click', handler); // Multi-type (space-separated) Directive.on(input, 'focus blur', e => toggleHighlight(e.type)); // With options Directive.on(scroller, 'scroll', onScroll, { passive: true });
        HTML attribute directives via Directive.bootstrap()
        <!-- HTML-first declarative usage --> <div a-if="user.loggedIn">Welcome!</div> <ul a-for="item in items"><li>{{ item }}</li></ul> <ol a-foreach="var planet in object"><li>{{ planet }}</li></ol> <div a-show="isVisible"></div> <input a-model="state.name"> <button a-on="click:submitForm">Submit</button> <span a-bind="textContent:user.name"></span> const scope = { user, items, object, state, isVisible, submitForm }; Directive.bootstrap(document.body, scope);
        0 tests0 passed
        HTML (56 ifaces · 118 tags) · SVG (34) · MathML (29) · X3D Define · SVG custom Define
        Registry Inspector
        // run tests
        0 tests0 passed
        Exhaustive Rule construction · all CSS properties · complex selectors · media queries · pseudo-classes
        Source — RuleDefinition object
        Full object literal with every CSS category
        const cssRule = { Selector : '.my-class-selector > div', Contents : { /* Layout */ display : 'flex', flexDirection : 'column', alignItems : 'center', justifyContent : 'space-between', gap : '1rem', width : '100%', minHeight : '48px', padding : '12px 16px', margin : '0 auto', boxSizing : 'border-box', /* Typography */ fontFamily : 'ui-monospace, monospace', fontSize : '14px', fontWeight : '600', lineHeight : '1.5', letterSpacing : '0.02em', textAlign : 'left', textTransform : 'none', textDecoration : 'none', whiteSpace : 'nowrap', overflow : 'hidden', textOverflow : 'ellipsis', /* Visual */ background : 'dodgerblue', color : 'white', border : '1px solid rgba(0,0,0,.15)', borderRadius : '6px', boxShadow : '0 2px 6px rgba(0,0,0,.3)', outline : 'none', opacity : '1', visibility : 'visible', cursor : 'pointer', /* Transition / Animation */ transition : 'background .2s ease, transform .15s ease', transform : 'translateY(0)', willChange : 'transform', /* Position */ position : 'relative', zIndex : '1', top : 'auto', left : 'auto', } }; const r = new Rule(cssRule); console.log(r.Text); // .my-class-selector > div { display: flex; background: dodgerblue; ... }
        Pseudo-class / pseudo-element selectors
        const hover = new Rule('.my-class-selector > div:hover', { background : 'royalblue', transform : 'translateY(-2px)', boxShadow : '0 4px 12px rgba(0,0,0,.4)', }); const before = new Rule('.my-class-selector > div::before', { content : '""', display : 'block', width : '4px', height : '100%', background : 'crimson', position : 'absolute', left : '0', top : '0', }); const nthChild = new Rule('.my-class-selector > div:nth-child(2n+1)', { background : 'rgba(30,144,255,.12)', }); const focus = new Rule('.my-class-selector > div:focus-within', { outline : '2px solid dodgerblue', outlineOffset : '2px', });
        Media queries — via Sheet with multiple rules
        // Media queries use the selector field as the full @media block, // with the inner rule as the Contents string. // This is the standard CSSStyleSheet pattern AriannA wraps. const sheet = new Sheet(); // Base rule sheet.add(new Rule('.responsive-card', { display : 'grid', gridTemplateColumns : '1fr 1fr', gap : '1rem', })); // Tablet breakpoint — parsed from raw CSS string sheet.add(new Rule( '@media (max-width: 768px)', '.responsive-card { grid-template-columns: 1fr; gap: .5rem; }' )); // Mobile breakpoint sheet.add(new Rule( '@media (max-width: 480px)', '.responsive-card { padding: 8px; font-size: 13px; }' )); // Prefer-reduced-motion sheet.add(new Rule( '@media (prefers-reduced-motion: reduce)', '.responsive-card * { transition: none !important; animation: none !important; }' )); // Dark mode sheet.add(new Rule( '@media (prefers-color-scheme: dark)', '.responsive-card { background: #1a1a2e; color: #eee; }' )); console.log(sheet.Length); // 5
        Live Sheet Output
        // run tests
        0 tests0 passed
        Fluent chains · add/set/append · selector targets · Real instances · event chains
        Source — Fluent chain patterns
        Pattern 1 — create → style → add children → append to parent
        // Build a card component entirely through chains const card = new Real('div') .set('id', 'my-card') .set('class', 'card-component') .add('<h2 class="card-title">Hello AriannA</h2>') .add('<p class="card-body">Reactive DOM without virtual DOM overhead.</p>') .add('<button id="card-btn">Click me</button>') .on('click', e => { if (e.target.id === 'card-btn') e.target.textContent = 'Clicked!'; }) .append(document.body);
        Pattern 2 — append to selector string
        // .append() accepts a CSS selector — no need to querySelector manually const badge = new Real('span') .set('class', 'badge') .add('New') .append('#my-card'); // CSS selector const footer = new Real('footer') .set('class', 'card-footer') .append('.card-component'); // class selector
        Pattern 3 — append to Real instance
        const container = new Real('section').set('id', 'container'); const item = new Real('article') .set('class', 'item') .add('<h3>Item</h3>') .append(container); // Real instance as parent container.contains(item); // true — Real instance check container.contains('.item'); // true — selector check
        Pattern 4 — unshift / push / pop / shift
        const list = new Real('ul'); list .push('<li>Item B</li>') // append to end .push('<li>Item C</li>') .unshift('<li>Item A</li>') // prepend .pop() // remove last → C gone .shift(); // remove first → A gone → only B remains list.render().childElementCount; // 1
        Pattern 5 — remove by selector / by Real / by index
        const nav = new Real('nav'); const homeLink = new Real('a').set('href', '/').set('class', 'home'); const aboutLink = new Real('a').set('href', '/about'); nav.add(homeLink.render(), aboutLink.render(), '<a href="/contact">Contact</a>'); nav.remove('.home'); // by CSS selector nav.remove(aboutLink); // by Real instance nav.remove(0); // by index
        Pattern 6 — event chain + fire
        const btn = new Real('button') .set('id', 'submit-btn') .add('Submit') .on('click', e => console.log('clicked', e)) .on('mouseenter', () => btn.set('class', 'hovered')) .on('mouseleave', () => btn.set('class', '')) .fire('custom-ready', { detail: { id: 'submit-btn' } });
        Pattern 7 — show/hide + get
        const panel = new Real('aside') .set('id', 'side-panel') .set('class', 'panel') .add('<div class="content">Sidebar content</div>') .hide(); // display: none panel.get('id'); // 'side-panel' panel.get('class'); // 'panel' // toggle const toggle = () => panel.render().style.display === 'none' ? panel.show() : panel.hide();
        Chain Step Visualizer
        // run tests to see chain steps
        0 tests 0 passed
        Function constructor · Class constructor · Real.Define · super() · this · State · Virtual SVG · Prototype chain
        Live Sandbox — Component Creation
        Prototype Chain Inspector
        Source — Function Constructor (ES5 style)
        Real.Define with a plain function — this = the element
        function CustomFunction() { this.style.width = '120px'; this.style.height = '120px'; this.style.background = 'dodgerblue'; this.style.display = 'flex'; this.style.alignItems = 'center'; this.style.justifyContent = 'center'; this.style.color = 'white'; this.style.margin = '2px'; this.style.borderRadius = '8px'; this.innerText = 'FUNCTION'; } Real.Define('custom-function', CustomFunction, HTMLButtonElement); // Instantiate via code const cf = new Real('custom-function').append('#comp-sandbox'); // Get prototype chain Core.GetPrototypeChain(cf.render()); // → ["CustomFunction","HTMLButtonElement","HTMLElement","Element","Node","EventTarget","Object"]
        Class constructor with super() — ES6+ style
        class CustomClass extends HTMLButtonElement { constructor() { super(); // mandatory — sets up HTMLButtonElement this.style.width = '120px'; this.style.height = '120px'; this.style.background = 'crimson'; this.style.display = 'flex'; this.style.alignItems = 'center'; this.style.justifyContent = 'center'; this.style.color = 'white'; this.style.margin = '2px'; this.style.borderRadius = '8px'; this.textContent = 'CLASS'; } } Real.Define('custom-class', CustomClass, HTMLButtonElement); // Instantiate via code — identical API to function style const cc = new Real('custom-class').append('#comp-sandbox'); Core.GetPrototypeChain(cc.render()); // → ["CustomClass","HTMLButtonElement","HTMLElement","Element","Node","EventTarget","Object"]
        Click handler — State mutation + Virtual SVG injection
        // Reactive state wired to a component click const state = new State({ step: 0, label: 'Click me' }); cf.on('click', () => { state.State.step++; state.State.label = 'Step ' + state.State.step; // Inject a Virtual SVG circle on each click const svg = Virtual.Create('svg', { xmlns: 'http://www.w3.org/2000/svg', width: '40', height: '40', viewBox: '0 0 40 40' }, Virtual.Create('circle', { cx:'20', cy:'20', r:'18', fill:'white', opacity:'0.8' }) ); cf.push(svg.render()); });
        0 tests0 passed
        Component · Prop · Watch · Emit · Ref
        0 tests0 passed
        h() · Fragment · Real mode · Virtual mode · $event · onEvent
        SSE — Axum Bridge
        Connecting...
        Fire → POST /events/fire
        Health — GET /health
        
            
        SSE Log
        Global Event Log
        CLI Reference arianna-cli v1.2.0
        The AriannA CLI scaffolds projects, generates components, runs a dev server, and builds for production. Install globally or use via npx.
        Install
        # Global install
        npm install -g arianna
        
        # Or use without installing
        npx arianna <command>
        Commands
        CommandOptionsDescription
        arianna new <n>--template browser|tauri|ios|androidScaffold a new project. Creates index.html, src/main.ts, tsconfig.json.
        arianna generate <type> <n>component | directive | state | testGenerate a file from template. Outputs to src/components/, src/, src/tests/.
        arianna serve--port <n> (default 3000)Start a dev server with static file serving. No bundler required.
        arianna build--minifyBundle arianna-core/index.ts → dist/arianna.js via esbuild.
        arianna typecheckRun tsc --noEmit. Alias: arianna tc
        arianna benchOpen the js-framework-benchmark harness.
        arianna infoPrint version, author, thanks.
        Scaffold a browser app
        arianna new my-app
        # Creates:
        #   my-app/
        #   ├── index.html
        #   ├── src/main.ts
        #   └── tsconfig.json
        
        cd my-app
        arianna serve      # http://localhost:3000
        Scaffold a Tauri app
        arianna new my-tauri-app --template tauri
        # Creates browser scaffold + src-tauri/ with Cargo.toml and tauri.conf.json
        
        cd my-tauri-app
        cargo tauri dev
        Generate a component
        arianna generate component MyCard
        # → src/components/MyCard.ts
        # Exports: class MyCard with el, signal, destroy()
        
        arianna generate state AppState
        # → src/AppState.ts
        # Exports: AppState with signal(), computed(), reset()
        
        arianna generate test MyCard
        # → src/tests/MyCard.ts
        # Basic test scaffold
        Build for production
        arianna build --minify
        # → dist/arianna.js  (ESM bundle, minified)
        # Uses esbuild — install separately: npm i -D esbuild
        
        # In your HTML:
        <script type="module">
          import { Real, signal } from './dist/arianna.js';
        </script>
        Create Component
        The CLI scaffolds a complete AriannA component with all 4 syntax variants, CSS-in-JS styles, and a test file.
        Usage
        node arianna-cli.mjs component <ComponentName> [--dir <dir>]
        
        # Examples
        node arianna-cli.mjs component MyButton
        node arianna-cli.mjs component UserCard    --dir src/ui/components
        node arianna-cli.mjs component DataWidget  --dir src/features/dashboard
        Generated files
        src/components/MyButton/
        ├── MyButton.ts        ← component (Decorators + commented Real/Virtual/JSX)
        ├── MyButton.css.ts    ← CSS-in-JS via Rule/Sheet
        ├── MyButton.test.ts   ← test file (AriannA test pattern)
        └── index.ts           ← barrel export
        What's inside MyButton.ts
        import {{ Component, Prop, Watch, Emit }} from '../arianna-ts/index.ts';
        
        @Component({{ tag: 'my-button' }})
        export class MyButton extends HTMLElement {{
          @Prop() label    = 'MyButton';
          @Prop() disabled = false;
        
          @Watch('label')
          onLabelChange(next: string) {{
            const el = this.querySelector('.my-button__label');
            if (el) el.textContent = next;
          }}
        
          @Emit('my-button-click')
          handleClick() {{ return {{ label: this.label }}; }}
        
          connectedCallback() {{
            this.innerHTML = `
              <div class="my-button">
                <span class="my-button__label">\${{this.label}}</span>
              </div>
            `;
            if (!this.disabled)
              this.addEventListener('click', () => this.handleClick());
          }}
        }}
        
        // Use: <my-button label="Save"></my-button>
        CSS-in-JS (MyButton.css.ts)
        import {{ Rule, Sheet }} from '../arianna-ts/index.ts';
        
        export const MyButtonSheet = new Sheet(
          new Rule('.my-button', {{ padding: '8px 16px', borderRadius: '5px', cursor: 'pointer' }}),
          new Rule('.my-button:hover', {{ background: 'var(--ar-bg4)' }}),
          new Rule('.my-button--disabled', {{ opacity: '0.45', cursor: 'not-allowed' }}),
        );
        export function injectMyButtonStyles() {{ MyButtonSheet.inject(document.head); }}
        Two.ts Tests
        Finance.ts Tests
        AI.ts Tests
        Video.ts Tests
        Audio.ts Tests
        IO.ts Tests
        Modifiers 2D Tests
        Modifiers 3D Tests
        Finance Components Tests
        🌐 Browser App
        Vanilla browser app. Vite for dev server and build. No framework — just AriannA, TypeScript, and ES modules. Works offline with no backend.
        Prerequisites
        # Node.js ≥ 20, npm or pnpm
        node arianna-cli.mjs create browser my-site
        Quick start
        cd arianna-projects/my-site
        npm install
        npm run dev      # → http://localhost:3000 (Vite HMR)
        npm run build    # → dist/ (ES modules bundle)
        npm run check    # TypeScript check
        Tools
        Vite (dev server + build) · TypeScript · ES modules · No bundler required in dev
        Project structure
        my-site/
        ├── index.html          ← entry point
        ├── src/
        │   ├── main.ts         ← AriannA app entry
        │   └── app.ts          ← components
        ├── tsconfig.json
        ├── vite.config.ts
        └── package.json
        🍎 Tauri macOS
        Rust Rover: open src-tauri/ as Cargo project. Set run config: cargo tauri dev. Xcode: required only for signing/notarization. Open Xcode → Preferences → Accounts → add Apple ID. Set bundle.macOS.signingIdentity in tauri.conf.json.
        Prerequisites
        # Install Rust
        curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
        
        # Install Tauri CLI
        cargo install tauri-cli
        
        # Create project
        node arianna-cli.mjs create tauri-macos my-desktop
        Quick start
        cd arianna-projects/my-desktop
        npm install
        npm run dev      # Tauri dev window (hot reload)
        npm run build    # → src-tauri/target/release/bundle/
                         #   dmg/ → macOS disk image
                         #   app/ → .app bundle
        Tools
        Rust Rover (Rust backend) · Xcode (signing, notarization, App Store) · Tauri 2 · Vite
        Project structure
        my-desktop/
        ├── index.html
        ├── src/main.ts         ← AriannA frontend
        ├── src-tauri/
        │   ├── src/lib.rs      ← #[tauri::command] handlers
        │   ├── src/main.rs     ← entry point
        │   ├── Cargo.toml
        │   ├── tauri.conf.json ← bundle config, signingIdentity
        │   └── capabilities/   ← permissions
        └── vite.config.ts
        📱 Tauri iOS
        Rust Rover: open src-tauri/ as Cargo project, cross-compile target: aarch64-apple-ios. Xcode: manages simulator, provisioning profiles, and device deployment. After first build, open src-tauri/gen/apple/my-iphone-app.xcodeproj. Apple Developer account required for device builds.
        Prerequisites
        # Add iOS Rust targets
        rustup target add aarch64-apple-ios x86_64-apple-ios
        
        # Install Tauri CLI
        cargo install tauri-cli
        
        # Create project
        node arianna-cli.mjs create tauri-ios my-iphone-app
        Quick start
        cd arianna-projects/my-iphone-app
        npm install
        npm run sim      # iOS Simulator
        npm run dev      # Connected iPhone (USB debugging)
        npm run build    # → .ipa
        Tools
        Rust Rover (Rust backend) · Xcode 15+ (simulator, device, signing, provisioning) · Tauri 2
        Project structure
        my-iphone-app/
        ├── index.html          ← viewport-fit=cover (notch + home indicator)
        ├── src/main.ts         ← AriannA UI
        ├── src-tauri/
        │   ├── src/lib.rs      ← Tauri commands
        │   ├── Cargo.toml      ← iOS target deps
        │   └── tauri.conf.json
        └── vite.config.ts      ← Safari 16 target
        🪟 Windows App
        Rust Rover: open src-tauri/ as Cargo project. WebView2: ships with Windows 10 1803+ (Edge). For older systems set webviewInstallMode: embedBootstrapper in tauri.conf.json. Code signing: set bundle.windows.certificateThumbprint. WiX Toolset must be on PATH.
        Prerequisites
        # Install Rust on Windows
        winget install Rustlang.Rustup
        rustup toolchain install stable
        
        # Install WiX Toolset (for MSI)
        winget install WixToolset.WixToolset
        
        # Install Tauri CLI
        cargo install tauri-cli
        
        node arianna-cli.mjs create windows my-win-app
        Quick start
        cd arianna-projects/my-win-app
        npm install
        npm run dev      # Dev window with HMR
        npm run build    # → src-tauri/target/release/bundle/
                         #   msi/  → Windows Installer
                         #   nsis/ → NSIS installer
        Tools
        Rust Rover or VS Code + rust-analyzer (Rust backend) · WiX Toolset (MSI installer) · WebView2 (bundled with Edge)
        Project structure
        my-win-app/
        ├── index.html
        ├── src/main.ts          ← AriannA frontend (auto dark/light)
        ├── src-tauri/
        │   ├── src/lib.rs       ← Tauri commands
        │   ├── src/main.rs      ← windows_subsystem = "windows"
        │   ├── Cargo.toml
        │   └── tauri.conf.json  ← bundle.targets: [msi, nsis]
        └── vite.config.ts       ← chrome105 target
        🤖 Android App
        Rust Rover: open src-tauri/ as Cargo project, set Android SDK path in Rust Rover settings. Android Studio: SDK Manager → install NDK + CMake. After first build, open src-tauri/gen/android/ in Android Studio for signing keystore and Play Store bundle.
        Prerequisites
        # Add Android Rust targets
        rustup target add aarch64-linux-android armv7-linux-androideabi
        rustup target add x86_64-linux-android i686-linux-android
        
        # Set environment variables
        export ANDROID_HOME=~/Android/Sdk
        export NDK_HOME=$ANDROID_HOME/ndk/26.x.x
        
        # Install Tauri CLI
        cargo install tauri-cli
        
        node arianna-cli.mjs create android my-android-app
        Quick start
        cd arianna-projects/my-android-app
        npm install
        npm run emulator   # Android Emulator
        npm run dev        # Connected device (USB debugging)
        npm run apk        # Debug APK
        npm run build      # Signed AAB → Play Store
        Tools
        Rust Rover (Rust backend) · Android Studio (SDK, NDK, emulator, signing, Play Store) · Java 17+
        Project structure
        my-android-app/
        ├── index.html          ← viewport user-scalable=no, safe-area
        ├── src/main.ts         ← AriannA UI (touch optimized)
        ├── src-tauri/
        │   ├── src/lib.rs      ← #[tauri::command] handlers
        │   ├── Cargo.toml      ← Android target deps (API 24+)
        │   └── tauri.conf.json ← minSdkVersion: 24
        └── vite.config.ts      ← chrome114 target (Android WebView)
        TransportBar
        DAW-style transport widget — Play / Stop / Pause buttons, dual-mode timecode display (Bars:Beats:Ticks or HH:MM:SS:FF SMPTE), and live tempo/loop indicators. Reusable across AudioTrackEditor, VideoTrackEditor, and the AudioEditor.
        Constructor
        import { TransportBar } from 'arianna/components/composite';
        
        const bar = new TransportBar('#mount', {
          bpm           : 120,
          timeSignature : '4/4',
          framerate     : 30,
          mode          : 'bars',    // or 'smpte'
        });
        bar.on('play',  () => engine.start());
        bar.on('pause', () => engine.pause());
        bar.on('stop',  () => engine.stop());
        Live demo
        API
        Property / MethodTypeDescription
        bar.bpm = nnumberSet tempo (bars-mode timecode)
        bar.framerate = nnumberSMPTE framerate (24 / 25 / 29.97 / 30)
        bar.mode = 'bars'|'smpte'stringSwitch timecode display
        bar.positionnumberCurrent position in beats (read/write)
        bar.on('play'|'stop'|'pause'|'seek', cb)eventLifecycle events
        Chat
        WhatsApp / Signal-style chat widget. Bubbles, timestamps, typing indicators, read receipts, message reactions, and threaded replies. Designed as a fully composable surface — the rendering can be themed and the message stream is reactive: feed it from any source and the UI follows.
        Constructor
        import { Chat } from 'arianna/components/composite';
        
        const chat = new Chat('#mount', {
          me   : { id: 'u1', name: 'Riccardo', avatar: '/me.png' },
          peers: [{ id: 'u2', name: 'Arianna' }],
          messages: [
            { id: 'm1', from: 'u2', text: 'Hey!', at: Date.now() - 3600e3 },
            { id: 'm2', from: 'u1', text: 'Doing great 🎉', at: Date.now(), status: 'read' },
          ],
          features: { reactions: true, threads: true, typing: true },
        });
        chat.on('send',    e => api.send(e.message));
        chat.on('react',   e => api.react(e.messageId, e.emoji));
        Live demo
        Message interface
        FieldTypeDescription
        idstringUnique message id
        fromstringUser id of sender
        textstringBody (markdown supported)
        atnumberTimestamp (epoch ms)
        status?'sending' | 'sent' | 'delivered' | 'read' | 'failed'Delivery status
        reactions?Reaction[]Emoji reactions
        replyTo?stringThread parent message id
        attachments?Attachment[]Files / images / audio
        Events
        EventDetail
        send{ message }
        react{ messageId, emoji }
        typing{ isTyping }
        scroll-top{} — load older messages
        Graphics · 2D — Overview
        The 2D graphics suite is the foundation of the Wires modeller and the Daedalus Visual Composer. Five components compose to rebuild an Illustrator-class workflow inside the browser.
        ComponentPurpose
        Canvas2DPannable / zoomable infinite canvas with grid, snap, and rulers
        BezierEditorVector path editor — anchors with smooth / corner / asymmetric handles, closed/open paths
        LayersPanelLayer stack — visibility, lock, groups, drag-reorder, multi-select
        ToolsPaletteIllustrator-style tool palette: select, pen, rect, ellipse, crop, magic-wand
        LinesPalette2DProfile / line tool palette for 2D paths (line, arc, spline, bezier, polyline)
        Colour pickers and gradient editors live in their own Colors namespace.
        Live demo
        Canvas2D
        Pannable / zoomable canvas surface that hosts vector paths, raster layers, and interactive widgets. Background grid is configurable; pan / zoom can be tuned per axis.
        Constructor
        import { Canvas2D } from 'arianna/components/graphics/2D';
        
        const c = new Canvas2D('#mount', {
          width  : 800,
          height : 500,
          pan    : true,
          zoom   : true,
          grid   : { size: 10, snap: true },
          rulers : true,
        });
        API
        MethodDescription
        c.zoomTo(level)Set zoom level (1 = 100%)
        c.panTo(x, y)Centre the viewport on (x, y)
        c.fit(bounds)Fit a bounding box in the viewport
        c.toDataURL()Export current view as PNG data URL
        BezierEditor
        Vector path editor. Each anchor can be Smooth, Corner, or Asymmetric. Handles are draggable; double-click on the path inserts an anchor; ⌫ deletes selection. Emits change events on every edit.
        Constructor
        import { BezierEditor } from 'arianna/components/graphics/2D';
        
        const ed = new BezierEditor('#mount', {
          width    : 600,
          height   : 300,
          closed   : true,
          initial  : [
            { x: 80,  y: 180, mode: 'corner' },
            { x: 300, y: 60,  mode: 'smooth' },
            { x: 520, y: 180, mode: 'corner' },
          ],
        });
        ed.on('change', () => save(ed.toPath()));
        Anchor mode
        ModeDescription
        'corner'Sharp corner — handles independent
        'smooth'Symmetric handles, equal length
        'asymmetric'Collinear handles with different lengths
        LayersPanel
        Layer stack with visibility, lock, groups, drag-reorder, and multi-select. Tree structure mirrors the SVG / scene-graph hierarchy.
        Constructor
        import { LayersPanel } from 'arianna/components/graphics/2D';
        
        const lp = new LayersPanel('#mount', {
          layers: [
            { id: 'bg',   name: 'Background', kind: 'shape' },
            { id: 'grp1', name: 'Logo', kind: 'group', children: [
              { id: 'icon', name: 'Icon',     kind: 'shape' },
              { id: 'text', name: 'Wordmark', kind: 'text'  },
            ]},
          ],
        });
        Layer kinds

        shape · path · text · image · group · adjustment

        ToolsPalette
        Illustrator-style tool palette: select, pen, rectangle, ellipse, crop, magic-wand. Emits tool events when a tool is picked.
        Constructor
        import { ToolsPalette } from 'arianna/components/graphics/2D';
        
        const p = new ToolsPalette('#mount', {
          tools: ['select', 'pen', 'rect', 'ellipse', 'crop', 'wand'],
        });
        p.on('tool', e => editor.setTool(e.tool));
        LinesPalette2D
        Companion palette for path / line tools — line, arc, spline, bezier, polyline. Used by BezierEditor and the Wires modeller for profile creation.
        Constructor
        import { LinesPalette2D } from 'arianna/components/graphics/2D';
        
        const p = new LinesPalette2D('#mount', {
          tools: ['line', 'arc', 'spline', 'bezier', 'polyline'],
        });
        Graphics · 3D — Overview
        UI chrome around any 3D renderer (Three.js, Babylon, WebGPU). The components are display-only and emit events; you wire them to your engine of choice.
        ComponentPurpose
        CameraViewer3DMaya-style 4-pane viewport (top / front / side / persp) with axes, gizmo, frame-fit
        MaterialsPalettePBR material library + drag-to-assign
        Modifiers3DPaletteModifier stack (bend, twist, mirror, array, subdivide) with reorderable list
        CameraViewer3D
        Maya-style four-pane viewport. Top / front / side panes are orthographic; perspective pane has axes (RGB = X/Y/Z), camera gizmo, and frame-fit shortcut.
        Constructor
        import { CameraViewer3D } from 'arianna/components/graphics/3D';
        
        const v = new CameraViewer3D('#mount', {
          width   : 800,
          height  : 600,
          showAxes: true,
          showGizmo: true,
          panes   : ['top', 'front', 'side', 'persp'],
        });
        v.on('pane-change', e => layout.set(e.pane, e.camera));
        MaterialsPalette
        PBR material browser — exports as { color, metallic, roughness, normal, emissive }. Drag a material onto a 3D object in the viewport to assign.
        Constructor
        import { PaletteMaterials } from 'arianna/components/graphics/3D';
        
        const mp = new PaletteMaterials('#mount', {
          materials: [
            { id: 'gold',   name: 'Gold',   kind: 'pbr-standard', color: '#ffd700', metallic: 1.0, roughness: 0.2 },
            { id: 'rubber', name: 'Rubber', kind: 'pbr-standard', color: '#1c1c1c', metallic: 0.0, roughness: 0.9 },
          ],
        });
        mp.on('pick', e => engine.assignMaterial(e.materialId));
        Material kinds

        pbr-standard · pbr-clearcoat · unlit · toon

        Modifiers3DPalette
        Non-destructive modifier stack — analogous to Blender's modifier stack. Each modifier wraps a parametric transformation (bend, twist, mirror, array, subdivide). Reorderable, toggleable, and serialisable.
        Constructor
        import { PaletteModifiers3D } from 'arianna/components/graphics/3D';
        
        const mp = new PaletteModifiers3D('#mount', {
          available: ['bend', 'twist', 'mirror', 'array', 'subdivide'],
          stack    : [
            { kind: 'twist',  amount: 45 },
            { kind: 'mirror', axis: 'x' },
          ],
        });
        mp.on('change', e => engine.applyStack(e.stack));
        Colors — Overview
        Eight components, all sharing the colour-space mathematics from the additionals/Colors addon. Every picker reads & writes RGB / HEX / HSL / HSV / CMYK / OKLCH / CIELUV / Cube equivalently — pick a colour anywhere, read it in any space.
        ComponentStyle
        ColorPickerCompact HSL+RGB picker (the original AriannA picker)
        ColorPickerWheelIllustrator-style hue wheel + SV square + 8-space readout
        ColorPickerSquarePhotoshop-style SV square + hue strip + editable readouts
        ColorPickerTileTile palette (Tailwind / Material / pastel / web-safe / Mac OS classic) + recents + hex input
        GradientEditor (base)Common stop / interpolation / preview machinery, used by the three editors below
        LinearGradientEditorAngle + stops + interpolation space (rgb / hsl / oklab)
        RadialGradientEditorShape (circle / ellipse) + size + draggable centre + stops
        ShapeGradientEditorIllustrator freeform mesh — arbitrary 2D control points with colours
        additionals/Colors — pure-math layer
        import * as Colors from 'arianna/additionals/Colors';
        
        Colors.parseHex('#e40c88');            // → { r:228, g:12, b:136, a:1 }
        Colors.rgbToOklch({ r:228, g:12, b:136, a:1 }); // → { L:0.62, C:0.24, h:4 }
        Colors.formatCss('oklch', oklch);     // → 'oklch(62.0% 0.240 4)'
        Live demo
        ColorPicker
        The original AriannA picker — compact, HSL + RGB readout, alpha slider. Kept for back-compat alongside the three new picker styles.
        import { ColorPicker } from 'arianna/components/graphics/colors';
        
        const cp = new ColorPicker('#mount', {
          color: '#e40c88',
          alpha: true,
        });
        cp.on('change', e => element.style.color = e.hex);
        ColorPickerWheel
        Illustrator-style hue wheel surrounding an SV square. Optional 8-space readout panel (RGB / HEX / HSL / HSV / CMYK / OKLCH / CIELUV / Cube).
        import { ColorPickerWheel } from 'arianna/components/graphics/colors';
        
        const cp = new ColorPickerWheel('#mount', {
          color  : '#e40c88',
          size   : 240,
          readout: true,
        });
        ColorPickerSquare
        Photoshop-style picker: SV square + vertical hue strip + editable readouts for every channel (R G B, H S L, H S V, hex, alpha).
        import { ColorPickerSquare } from 'arianna/components/graphics/colors';
        
        const cp = new ColorPickerSquare('#mount', {
          color: '#3b82f6',
          alpha: true,
          size : 220,
        });
        ColorPickerTile
        Tile palette with five built-in palettes (Tailwind / Material / pastel / web-safe / Mac OS classic), plus recents row and hex input.
        import { ColorPickerTile } from 'arianna/components/graphics/colors';
        
        const cp = new ColorPickerTile('#mount', {
          palette : 'tailwind',    // 'tailwind'|'material'|'pastel'|'web-safe'|'mac-os-classic'|RGB[][]
          columns : 8,
          tileSize: 28,
        });
        GradientEditor (base)
        Abstract base with the shared stop / interpolation / preview machinery — used by the three concrete editors below. Subclass to build your own gradient style.
        import { GradientEditorBase } from 'arianna/components/graphics/colors';
        
        // You normally extend this rather than instantiate it directly:
        class AngleSweepEditor extends GradientEditorBase { /* … */ }
        LinearGradientEditor
        Linear gradient with angle, stops (drag horizontally to reposition), and interpolation space (rgb / hsl / oklab). Outputs CSS / SVG / canvas string equivalents.
        import { LinearGradientEditor } from 'arianna/components/graphics/colors';
        
        const ed = new LinearGradientEditor('#mount', {
          angle : 45,
          interp: 'oklab',
          stops : [
            { t: 0,    color: { r:228, g:12,  b:136, a:1 } },
            { t: 0.5,  color: { r:147, g:51,  b:234, a:1 } },
            { t: 1,    color: { r:59,  g:130, b:246, a:1 } },
          ],
        });
        ed.on('change', () => element.style.background = ed.toCSS());
        RadialGradientEditor
        Radial gradient. Shape: circle / ellipse. Size: closest-side / closest-corner / farthest-side / farthest-corner. Centre is draggable.
        import { RadialGradientEditor } from 'arianna/components/graphics/colors';
        
        const ed = new RadialGradientEditor('#mount', {
          shape: 'circle',
          size : 'farthest-corner',
          cx   : 50, cy: 50,
        });
        ShapeGradientEditor
        Illustrator-style freeform mesh gradient. Place arbitrary control points on a 2D canvas; each carries a colour. Resolution is configurable via speed (resolution divisor for performance).
        import { ShapeGradientEditor } from 'arianna/components/graphics/colors';
        
        const ed = new ShapeGradientEditor('#mount', {
          width : 360,
          height: 240,
          speed : 2,    // 1 = full res, 2 = half, 4 = quarter
        });
        Payments — Overview
        Eight provider-specific payment buttons plus a compound PaymentGateway that orchestrates them in a single checkout UI. All buttons follow each provider's brand guidelines.
        ComponentProvider
        PaymentGatewayCompound — picks the best of the configured methods
        CreditCardVisa / Mastercard / Amex / Maestro — Luhn validation, brand auto-detect
        ApplePayApple Pay (HIG-compliant black button)
        GooglePayGoogle Pay (G-Pay multicolour mark)
        PayPalPayPal Smart Button
        StripeWraps Stripe Payment Element / hosted Checkout
        AliPayAlipay redirect / QR
        SatispayItalian mobile-first payments
        NexiItalian merchant gateway (XPay)
        Live demo
        PaymentGateway
        Compound widget that orchestrates every configured payment method in a single UI. Renders a method picker and the selected provider's button / form. Emits a unified success event regardless of method.
        Constructor
        import { PaymentGateway } from 'arianna/components/payments';
        
        const pg = new PaymentGateway('#mount', {
          amount  : 99.00,
          currency: 'EUR',
          methods : {
            applePay : { merchantId: 'merchant.com.example', countryCode: 'IT' },
            googlePay: { merchantId: '12345…', gateway: 'stripe', gatewayMerchantId: 'acct_1…' },
            card     : { saveOption: true, allowedBrands: ['visa', 'mastercard'] },
            paypal   : { clientId: 'AYxxx' },
            stripe   : { publishableKey: 'pk_test_…', clientSecret: '…', returnUrl: '…' },
            satispay : { redirectUrl: 'https://online.satispay.com/…' },
            nexi     : { redirectUrl: 'https://ecommerce.nexi.it/…' },
            alipay   : { mode: 'redirect', redirectUrl: '…' },
          },
        });
        pg.on('success', e => api.confirm(e.method, e.payload));
        pg.on('cancel',  e => api.log('cancelled', e.method));
        CreditCard
        Live card preview, brand auto-detection (Visa / Mastercard / Amex / Maestro), Luhn validation. Optional "save card for next time" checkbox.
        import { CreditCard, detectBrand, validateLuhn } from 'arianna/components/payments';
        
        const cc = new CreditCard('#mount', {
          amount       : 99.00,
          currency     : 'EUR',
          saveOption   : true,
          allowedBrands: ['visa', 'mastercard', 'amex', 'maestro'],
        });
        cc.on('submit', e => api.charge(e.card));
        Helpers
        FunctionDescription
        detectBrand(num)'visa' | 'mastercard' | 'amex' | 'maestro' | null
        validateLuhn(num)boolean
        formatCardNumber(num)'4242 4242 4242 4242' (brand-aware grouping)
        ApplePay
        Apple Pay button — black, plain, HIG-compliant. Calls window.ApplePaySession when available; falls back gracefully on unsupported browsers.
        import { ApplePay } from 'arianna/components/payments';
        
        new ApplePay('#mount', {
          merchantId : 'merchant.com.example.shop',
          countryCode: 'IT',
          currency   : 'EUR',
          amount     : 99.00,
          label      : 'Acme — 1 item',
          supportedNetworks: ['visa', 'masterCard', 'amex'],
        });
        GooglePay
        Google Pay button. Loads https://pay.google.com/gp/p/js/pay.js on demand and bridges to google.payments.api.PaymentsClient.
        import { GooglePay } from 'arianna/components/payments';
        
        new GooglePay('#mount', {
          merchantId       : '12345678901234567890',
          gateway          : 'stripe',
          gatewayMerchantId: 'acct_1ABCxyz',
          currency         : 'EUR',
          amount           : 99.00,
          cardNetworks     : ['VISA', 'MASTERCARD', 'AMEX'],
        });
        PayPal
        PayPal Smart Button — yellow, brand-conformant. Loads PayPal SDK on mount; emits approve when the buyer completes the flow.
        import { PayPal } from 'arianna/components/payments';
        
        new PayPal('#mount', {
          clientId: 'AYxxx-your-client-id',
          amount  : 99.00,
          currency: 'EUR',
        });
        Stripe
        Wraps Stripe's Payment Element / hosted Checkout. You provide the publishableKey and a clientSecret created server-side.
        import { Stripe } from 'arianna/components/payments';
        
        new Stripe('#mount', {
          publishableKey: 'pk_test_…',
          clientSecret  : '…',
          returnUrl     : 'https://shop.example.com/return',
        });
        AliPay
        Alipay button — Chinese super-app. Two modes: 'redirect' opens the Alipay payment page; 'qr' shows the QR inline for in-store / mobile pickup.
        import { AliPay } from 'arianna/components/payments';
        
        new AliPay('#mount', {
          mode       : 'redirect',    // or 'qr'
          redirectUrl: 'https://mapi.alipay.com/gateway.do?...',
          amount     : 99.00,
          currency   : 'EUR',
        });
        Satispay
        Satispay redirect button — Italian mobile-first payments.
        import { Satispay } from 'arianna/components/payments';
        
        new Satispay('#mount', {
          redirectUrl: 'https://online.satispay.com/…',
          amount     : 99.00,
          currency   : 'EUR',
        });
        Nexi
        Nexi XPay — Italian merchant gateway. Redirects to the Nexi-hosted payment page; webhook confirms payment server-side.
        import { Nexi } from 'arianna/components/payments';
        
        new Nexi('#mount', {
          redirectUrl: 'https://ecommerce.nexi.it/…',
          amount     : 99.00,
          currency   : 'EUR',
        });
        Shipments — Overview
        Tracker components for major couriers, plus a multi-carrier auto-detect widget that picks the right one from a tracking number.
        ComponentCarrier
        TrackerAbstract base — generic timeline UI, override fetch() for custom carriers
        DHLTrackerDHL Express (yellow / red)
        UPSTrackerUPS (brown shield)
        FedExTrackerFedEx (purple / orange wordmark)
        BRTTrackerBRT (Bartolini) — Italian express
        TrackingMultiAuto-detects the carrier from the tracking number; asks if ambiguous
        Tracking number formats
        CarrierPatternExample
        DHL10 digits1234567890
        UPS1Z + 16 alphanumerics1Z9999W99999999999
        FedEx12 / 15 / 20 digits012345678901234
        BRT13 digits1234567890123
        Live demo
        Tracker (base)
        Abstract base for all carrier trackers. Renders a canonical timeline (picked up → in transit → out for delivery → delivered) with carrier branding. Subclass and override fetch(trackingNumber) to plug a custom carrier.
        import { Tracker } from 'arianna/components/shipments';
        
        class CustomTracker extends Tracker {
          async fetch(num: string) {
            const r = await fetch(`/api/track/${num}`);
            return r.json();
          }
        }
        
        new CustomTracker('#mount', {
          trackingNumber: 'ABC123',
          config        : { name: 'Custom Co.', color: '#0066cc', logoUrl: '/custom.svg' },
        });
        DHLTracker
        DHL Express tracker — yellow / red brand, queries the DHL public tracking API with the supplied apiKey.
        import { DHLTracker } from 'arianna/components/shipments';
        
        new DHLTracker('#mount', {
          trackingNumber: '1234567890',
          apiKey        : 'demo-key',
        });
        UPSTracker
        UPS tracker — brown shield, OAuth-based UPS Tracking API.
        import { UPSTracker } from 'arianna/components/shipments';
        
        new UPSTracker('#mount', {
          trackingNumber: '1Z9999W99999999999',
          clientId      : '…',
          clientSecret  : '…',
        });
        FedExTracker
        FedEx tracker — purple / orange wordmark with the famous hidden arrow between E and x.
        import { FedExTracker } from 'arianna/components/shipments';
        
        new FedExTracker('#mount', {
          trackingNumber: '012345678901234',
          apiKey        : '…',
        });
        BRTTracker
        BRT (Bartolini) tracker — Italian express courier, red brand.
        import { BRTTracker } from 'arianna/components/shipments';
        
        new BRTTracker('#mount', {
          trackingNumber: '1234567890123',
        });
        TrackingMulti
        Multi-carrier auto-detect. Type a tracking number and the matching carrier is picked from the configured list. If multiple carriers match the same pattern, the user is asked to disambiguate.
        import { TrackingMulti } from 'arianna/components/shipments';
        
        const tm = new TrackingMulti('#mount', {
          carriers: ['dhl', 'ups', 'fedex', 'brt'],
        });
        tm.on('detect', e => analytics.track('tracking', e.carrier));
        Detection logic
        1. Match the tracking number against each carrier's regex.
        2. If exactly one carrier matches → auto-select.
        3. If multiple → render a picker, let the user choose.
        4. If none → emit no-match event, show a friendly error.
        GoogleMap
        Iframe embed of Google Maps using the public output=embed endpoint — no API key required for the basic map. Accepts a center (lat/lng), zoom, and an optional address string.
        import { GoogleMap } from 'arianna/components/maps';
        
        const map = new GoogleMap('#mount', {
          center : { lat: 45.4642, lng: 9.1900 },
          zoom   : 13,
          address: 'Milano, Italy',
        });
        map.setZoom(15);
        map.setLocation({ lat: 45.47, lng: 9.19 });
        OpenStreetMap
        Open data, no API key, no tracking. Uses the official openstreetmap.org/export/embed.html endpoint with a computed bounding box around the centre.
        import { OpenStreetMap } from 'arianna/components/maps';
        
        new OpenStreetMap('#mount', {
          center: { lat: 51.5074, lng: -0.1278 },
          zoom  : 12,
        });
        Dock
        Desktop launcher chrome with two switchable styles. Use setStyle('macos' | 'windows') to flip between a floating magnifying dock and a flat taskbar at runtime.
        import { Dock } from 'arianna/components/layout';
        
        const dock = new Dock('#mount', {
          style: 'macos',
          items: [
            { id: 'finder', label: 'Finder', icon: '🗂️', running: true, active: true },
            { id: 'mail',   label: 'Mail',   icon: '✉️',  badge: 3 },
          ],
        });
        dock.setStyle('windows');  // switch live
        dock.setBadge('mail', 7);
        dock.on('item-click', e => console.log('clicked', e.id));
        Window
        Desktop-style window with draggable title bar, resize handle, traffic-light (or Windows-style) controls, optional menu bar and arbitrary body content. Sits on the highest z-index when focused and falls behind peers when blurred.
        import { Window } from 'arianna/components/layout';
        
        const win = new Window(desktop, {
          style : 'macos',
          title : 'Finder',
          width : 420, height: 280,
          menu  : [
            { id: 'file', label: 'File' },
            { id: 'edit', label: 'Edit' },
          ],
          body  : '<p style="padding:16px">Drag the title bar to move.</p>',
        });
        win.on('close', () => console.log('closed'));
        win.moveTo(120, 80);
        win.resizeTo(600, 400);
        Desktop — Dock + Windows together
        A full desktop reconstruction: a wallpaper container hosts multiple Window instances; a single Dock at the bottom toggles them. Click a dock icon to open / focus the matching window; close a window and the dock badge updates.
        import { Dock, Window } from 'arianna/components/layout';
        
        const dock = new Dock(dockHost, { style: 'macos', items: [...] });
        const openWindows = new Map();
        
        dock.on('item-click', e => {
          if (openWindows.has(e.id)) { openWindows.get(e.id).focus(); return; }
          const win = new Window(desktop, { title: e.id, width: 360, height: 240 });
          openWindows.set(e.id, win);
          win.on('close', () => openWindows.delete(e.id));
        });
        Calendar — month view
        Month / week / day calendar with event placement, configurable week start, locale-aware labels and a built-in toolbar with prev / next / today + view switcher.
        import { Calendar } from 'arianna/components/inputs';
        
        const cal = new Calendar('#mount', {
          view     : 'month',
          weekStart: 1,  // 0 = Sunday, 1 = Monday
          events   : [
            { id: 'e1', title: 'Team standup', start: new Date(), color: '#3b82f6' },
          ],
        });
        cal.setView('week');
        cal.addEvent({ id: 'e2', title: 'Demo', start: new Date() });
        Calendar — date picker
        The same Calendar component as Layout, used here as a date picker: listen for day-click and wire the selected e.date into any field.
        import { Calendar } from 'arianna/components/inputs';
        
        const cal = new Calendar(calEl, { view: 'month' });
        cal.on('day-click', (e) => {
          field.value = e.date.toLocaleDateString(undefined, {
            weekday: 'long', day: 'numeric',
            month  : 'long',  year: 'numeric',
          });
        });
        Animations — Overview
        The components/animations module hosts UI widgets for hand-keyed animation. They drive any object that exposes a set(property, values) method via the IKeyframeTarget contract — Three.js nodes, DOM properties, Audio params, Two.ts shapes, even abstract numerical state.
        import { KeyframeEditor } from 'arianna/components/animations';
        
        const editor = new KeyframeEditor('#mount', {
          clips: [{
            id: 'a', name: 'anim', sampleRate: 60, duration: 0.75,
            nodes: [{ id: 'cube', label: 'Cube', properties: [
              { id: 'position', label: 'position', channels: ['x','y','z'],
                keyframes: [
                  { time: 0.00, values: [0,0,0] },
                  { time: 0.15, values: [1,0,0], easing: 'easeOutCubic' },
                  { time: 0.30, values: [1,1,0] },
                ] },
            ] }],
          }],
          wrapMode: 'loop', speed: 0.5,
        });
        
        editor.bind('cube', { set: (prop, vals) => { /* drive target */ } });
        editor.play();
        Module layout
        • components/animations/KeyframeEditor.ts — full timeline editor with track and property canvas lanes, mouse drag, dblclick to add keyframe, right-click context menu for easing
        • components/animations/index.ts — barrel
        • Marries additionals/Physics via World.attach() and World.bake()
        • Reuses the named easing table (linear, easeInQuad, easeOutCubic, easeOutBack, easeOutBounce, easeOutElastic, …) exported by additionals/Animation; custom curves via { type: 'cubic-bezier', p1x, p1y, p2x, p2y }
        KeyframeEditor
        3ds Max / Blender / After Effects style timeline editor. Extends Control<KeyframeEditorOptions>. Renders track and property canvas lanes inside a chrome of toolbar / footer.
        import { KeyframeEditor } from 'arianna/components/animations';
        import type { IKeyframeTarget, Keyframe, Clip, WrapMode, EasingName }
          from 'arianna/components/animations';
        
        interface KeyframeEditorOptions {
          class?      : string;
          theme?      : 'light' | 'dark' | 'auto';
          clips?      : Clip[];
          activeClip? : string;
          wrapMode?   : WrapMode;       // 'normal' | 'loop' | 'ping-pong' | 'clamp-forever'
          speed?      : number;       // playback multiplier
          view?       : 'time' | 'frames';
          spacing?    : number;
          onChange?   : (s: KeyframeEditorState) => void;
          onKeyframe? : (e: { nodeId, propertyId, keyframe }) => void;
          onPlay?     : () => void;
          onStop?     : () => void;
        }
        Public API
        editor.play()       editor.pause()      editor.stop()
        editor.seek(t)      editor.step(frames)
        editor.bind(nodeId, target)   // IKeyframeTarget
        editor.unbind(nodeId)
        editor.addClip(clip)          editor.setActiveClip(id)
        editor.addKeyframe(node, prop, { time, values, easing })
        editor.removeKeyframe(node, prop, index)
        editor.sample(node, prop, t?)   // → number[] | null
        editor.getState()
        
        // Events: 'play', 'pause', 'stop', 'seek', 'change'
        editor.on('change', state => ...)
        Clip / NodeTrack / Property / Keyframe
        interface Clip {
          id          : string;
          name        : string;
          sampleRate  : number;       // fps
          duration    : number;       // seconds
          defaultEase?: EasingDef;
          nodes       : NodeTrack[];
        }
        
        interface NodeTrack {
          id: string; label: string;
          properties: Property[];
        }
        
        interface Property {
          id        : string;
          label     : string;
          channels  : string[];      // ['x','y','z'] | ['value'] | ['r','g','b']
          keyframes : Keyframe[];
        }
        
        interface Keyframe {
          time   : number;
          values : number[];
          easing?: EasingDef;           // named curve, step, or cubic-bezier
          locked?: boolean;
          label? : string;
        }
        
        type EasingDef =
          | EasingName
          | { type: 'cubic-bezier', p1x, p1y, p2x, p2y };
        
        type EasingName =
          | 'linear' | 'step'
          | 'easeInQuad'  | 'easeOutQuad'  | 'easeInOutQuad'
          | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic'
          | 'easeInQuart' | 'easeOutQuart'
          | 'easeInExpo'  | 'easeOutExpo'  | 'easeInOutExpo'
          | 'easeOutBack' | 'easeOutBounce' | 'easeOutElastic';
        IKeyframeTarget
        interface IKeyframeTarget {
          set: (property: string, values: number[]) => void;
        }
        
        // Three.js node example
        editor.bind('cube', {
          set: (prop, [x, y, z]) => {
            if (prop === 'position') cube.position.set(x, y, z);
            if (prop === 'scale')    cube.scale.set(x, y, z);
          },
        });
        Physics — Overview
        Self-contained 2D / 3D physics additional. No DOM, pure math and scheduling. Lives next to AI, Math, Finance, Two, Three, Animation as a sibling addon. Plugin pattern identical to additionals/Animation: Core.use(Physics) mirrors all public classes onto window.
        import { Physics, World, Body, Box, Circle } from 'arianna/additionals/Physics';
        Core.use(Physics);
        
        const world = new World({ gravity: [0, -9.81], dimension: 2 });
        world.addBody(new Body({ shape: new Box(20, 0.5),
                                  static: true, position: [0, -3] }));
        world.addBody(new Body({ shape: new Circle(0.5), mass: 1,
                                  position: [0, 5], restitution: 0.7 }));
        world.start();
        Capabilities
        • Bodies — static / dynamic / kinematic with mass, inverse-mass, restitution, friction, damping, orientation
        • Shapes — Circle / Sphere, Box / AABB, Capsule, Polygon (convex 2D)
        • Constraints — Spring (Hooke + damping), DistanceConstraint, Pin, Rope
        • Fields — Drag (linear + quadratic), PointGravity, Wind (with turbulence)
        • Broadphase — uniform spatial hash (toggleable to naive)
        • Narrowphase — circle/sphere/box pair tests + AABB fallback
        • Integration — semi-implicit Euler (default) or Verlet, sub-stepping
        • Collision groups + masks — bitfield filtering; sensors (no impulse)
        • Keyframe marriageWorld.attach(), World.bake(), Body.followKeyframes()
        • Diagnosticson('contact-start' | 'contact-end' | 'step'), debugDraw(ctx)
        Live demo
        World
        The simulation container. Owns bodies, constraints, fields; drives a fixed-step loop or accepts manual .step(dt).
        interface WorldOptions {
          gravity?       : number[];                       // [0,-9.81] 2D · [0,-9.81,0] 3D
          dimension?     : 2 | 3;
          integrator?    : 'semi-implicit-euler' | 'verlet';
          timeScale?     : number;                         // global playback speed
          substeps?      : number;                         // stability: 4 is a good default
          broadphase?    : 'spatial-hash' | 'naive';
          cellSize?      : number;
          fixedStep?     : number;                         // 1/60
          onStep?        : (dt) => void;
          onContactStart?: (e: ContactEvent) => void;
          onContactEnd?  : (e: ContactEvent) => void;
        }
        
        const world = new World({ gravity: [0, -9.81], substeps: 4 });
        
        world.addBody(body);
        world.addConstraint(constraint);
        world.addField(new Drag(0.05, 0.01));
        
        world.start();             // requestAnimationFrame loop
        world.stop();
        world.step(1/60);          // manual stepping
        
        world.on('contact-start', e => ...);
        world.on('step', dt => ...);
        ContactEvent
        interface ContactEvent {
          a: Body; b: Body;
          point  : number[];
          normal : number[];
          depth  : number;
        }
        Body
        A physics body: shape + transform + dynamic state. Mass and inertia are derived from the shape. Static / kinematic flags freeze the body against impulses while letting kinematic bodies still move (e.g. driven by keyframes).
        interface BodyOptions {
          shape           : Shape;
          position?       : number[];
          velocity?       : number[];
          orientation?    : number | Quat;
          angularVelocity?: number | number[];
          mass?           : number;          // default 1
          static?         : boolean;
          kinematic?      : boolean;
          sensor?         : boolean;         // trigger only, no impulse
          restitution?    : number;          // 0..1
          friction?       : number;          // 0..1
          linearDamping?  : number;
          angularDamping? : number;
          gravityScale?   : number;
          group?          : number;          // bitfield, default 0x0001
          mask?           : number;          // bitfield, default 0xffff
          userData?       : unknown;
        }
        
        body.addForce(F);              // accumulated for this step
        body.addImpulse(J);            // instant Δv
        body.addTorque(t);             // 2D scalar / 3D vector
        body.followKeyframes(editor, 'cube');  // kinematic chase
        Shapes
        Geometry primitives. Each computes its own AABB and moment of inertia. Sphere is an alias of Circle for 3D readability.
        new Circle(radius);
        new Sphere(radius);                    // alias of Circle
        new Box(width, height);                // 2D
        new Box(width, height, depth);         // 3D
        new Capsule(radius, length);
        new Polygon([[0,0], [1,0], [0.5,1]]); // convex 2D
        Narrowphase pair coverage
        • Circle ↔ Circle — analytic SAT
        • Circle ↔ Box — closest-point clamp
        • Box ↔ Box — separating-axis
        • All others — AABB-only fallback (sufficient for sensors and gross overlap)
        Constraints
        Solved sequentially each substep. Position-based correction for distance / rope / pin; force-based for springs.
        // Hooke spring with damping
        world.addConstraint(new Spring(a, b, restLength=0.5,
                                               stiffness=200, damping=8));
        
        // Rigid distance — keep bodies exactly L apart
        world.addConstraint(new DistanceConstraint(a, b, L));
        
        // Pin to a world-space anchor (cancels velocity)
        world.addConstraint(new Pin(body, [0, 3]));
        
        // Rope — max distance, no compression
        world.addConstraint(new Rope(a, b, maxLength=2));
        Fields
        Environmental forces evaluated for every body each step.
        // Air resistance — linear + quadratic terms
        world.addField(new Drag(linear=0.05, quadratic=0.01));
        
        // Planet-like point gravity (inverse-square)
        world.addField(new PointGravity(origin=[0,0], strength=50, radius=10));
        
        // Wind with optional turbulence
        world.addField(new Wind(direction=[1,0], strength=2, turbulence=0.5));
        Keyframe marriage — attach & bake
        The Physics additional integrates with KeyframeEditor two ways, both first-class.
        1. World.attach() — live drive
        Every physics step writes resulting body positions into the editor's bound IKeyframeTarget so visuals reflect simulation live.
        const ball = world.addBody(new Body({ shape: new Circle(0.3), position: [0,3] }));
        
        editor.bind('ball', { set: (p, v) => threeBall.position.set(...v) });
        world.attach(editor, { 'ball': ball });
        world.start();
        2. World.bake() — physics → keyframes
        Runs the simulation forward and inserts keyframes into the editor at fixed intervals, producing a deterministic, editable animation clip from a physics run. Existing keyframes for tracked nodes are replaced. Body state is snapshotted and restored after baking.
        world.bake(editor, 'phys', {
          from : 0,
          to   : 2,        // seconds
          fps  : 60,
          nodes: { 'ball': ball, 'crate': crate },
        });
        
        // → Returns the raw samples; the editor's clip is updated in place.
        3. Body.followKeyframes() — kinematic chase
        Make a body track an animated value as kinematic input, so authored motion can collide with simulated objects.
        const paddle = world.addBody(new Body({
          shape: new Box(2, 0.3), kinematic: true,
        }));
        paddle.followKeyframes(editor, 'paddle');
        // physics-driven balls now bounce off the keyframed paddle
        Starter templates
        Twelve ready-to-run projects with full IDE configuration: six browser starters (vanilla HTML + the AriannA runtime, no build step) and six Tauri starters (Vite + a Rust backend, targeting macOS / Windows / Linux / iOS / Android plus a web preview).
        Each template ships in three flavours: bare, -vscode (.vscode/ preset), and either -webstorm or -rustrover (.idea/ preset). Browser starters pair with VSCode + WebStorm; Tauri starters pair with VSCode + RustRover. Unzip and open the folder in your editor of choice — the runtime, sample components, and sourcemaps are wired up already.
        All 36 ZIPs are committed to the arianna-projects repository and served directly via raw.githubusercontent.com — no GitHub Release tagging is needed. Rebuild locally with node scripts/build-zips.mjs and commit the refreshed ZIPs.
        VSCode preset
        Every -vscode variant ships a .vscode/ folder with the following files.
        .vscode/settings.json
        {
          "editor.formatOnSave": true,
          "editor.tabSize": 2,
          "editor.insertSpaces": true,
          "editor.defaultFormatter": "esbenp.prettier-vscode",
          "typescript.tsdk": "node_modules/typescript/lib",
          "typescript.preferences.importModuleSpecifier": "relative",
          "files.associations": { "*.arianna": "typescript" }
        }
        .vscode/extensions.json
        {
          "recommendations": [
            "esbenp.prettier-vscode",
            "dbaeumer.vscode-eslint",
            "streetsidesoftware.code-spell-checker"
          ]
        }
        .vscode/launch.json
        {
          "version": "0.2.0",
          "configurations": [{
            "type": "chrome",
            "request": "launch",
            "name": "AriannA — launch",
            "url": "http://localhost:5173",
            "webRoot": "${workspaceFolder}",
            "sourceMaps": true
          }]
        }
        WebStorm preset
        Every -webstorm variant ships a .idea/ folder with the run / debug configuration, project SDK reference, and code style preset matching the AriannA codebase.
        .idea/codeStyles/Project.xml
        <code_scheme name="Project">
          <option name="RIGHT_MARGIN" value="100"/>
          <TypeScriptCodeStyleSettings>
            <option name="USE_SINGLE_QUOTES" value="true"/>
            <option name="USE_SEMICOLON_AFTER_STATEMENT" value="true"/>
            <option name="INDENT_SIZE" value="2"/>
          </TypeScriptCodeStyleSettings>
        </code_scheme>
        .idea/runConfigurations/AriannA_dev.xml
        <component name="ProjectRunConfigurationManager">
          <configuration name="AriannA dev" type="NodeJSConfigurationType">
            <option name="workingDir" value="$PROJECT_DIR$" />
            <option name="jsFile"     value="node_modules/.bin/vite" />
            <option name="appParameters" value="dev" />
          </configuration>
        </component>
        Open in WebStorm / RustRover
        Each template's .idea/ folder also includes a matching misc.xml with WebStorm as the JavaScript-runtime IDE and (optionally) a Rust toolchain reference for Tauri-flavoured starters such as arianna-desktop — open them in RustRover and the frontend + backend run configurations show up pre-configured.
        RustRover preset
        The -rustrover variant is paired with every Tauri starter (six of them — Android, iOS, Linux, macOS, Web preview, and Windows). It ships a .idea/ folder pre-wired with both the Cargo build target and the Tauri-dev run configuration, so the Rust backend and the AriannA TS frontend launch together with one click.
        .idea/runConfigurations/Tauri_dev.xml
        <component name="ProjectRunConfigurationManager">
          <configuration name="Tauri dev" type="CargoCommandRunConfiguration">
            <option name="command"    value="tauri dev" />
            <option name="workingDirectory" value="$PROJECT_DIR$/src-tauri" />
          </configuration>
        </component>
        .idea/runConfigurations/Cargo_build.xml
        <component name="ProjectRunConfigurationManager">
          <configuration name="Cargo build" type="CargoCommandRunConfiguration">
            <option name="command"    value="build --release" />
            <option name="workingDirectory" value="$PROJECT_DIR$/src-tauri" />
          </configuration>
        </component>
        Bundled inside every Tauri ZIP
        When you grab arianna-tauri-macos-rustrover.zip (or the iOS / Android / Linux / Windows / Web variant), the archive already contains .idea/ with the two configurations above plus the shared TypeScript code style. Open the unzipped folder in RustRover and the run-configuration dropdown shows "Tauri dev" + "Cargo build" without any further setup.