Directives Guide
Live Demos HubDirectives Guide
Interactive production-grade hypermedia component for HTMXUI.
Interactive Preview
Community Directives & Extensions Guide
Learn how to connect external 3D viewports (Three.js), interactive maps (Leaflet), or custom canvas renderers to HTMXUI in under 15 lines of declarative code.
Why the Directive Model?
HTMXUI is strictly a foundational application runtime (~40KB). Rather than bundling heavy 3rd-party dependencies (like a 600KB Three.js bundle or 150KB Leaflet map engine), HTMXUI provides HTMXUI.directive() and HxBolt.ticker. This gives community developers full reactive signal bindings, lifecycle cleanup, and game-loop synchronization without bloating the core.
Example 1: Connecting a 3D WebGL Canvas (Three.js)
Define a custom directive hx-three-mesh and bind its rotation and position directly to local Bolt reactive state:
<div hx-state='{ "elevation": 1.5 }'>
<canvas hx-three-mesh class="w-full h-64 rounded-xl border"></canvas>
<input type="range" min="-3" max="3" step="0.1" hx-model.number="elevation" class="w-full mt-2">
</div>
Example 2: Connecting an Interactive Map (Leaflet)
Register an hx-leaflet-map directive that tracks coordinates and places pins:
HTML Source
<div class="space-y-10 max-w-4xl py-6 text-foreground">
<!-- Title & Intro -->
<div>
<div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/20 text-primary text-xs font-semibold mb-3">
<span>🔌</span> Extension Architecture
</div>
<h1 class="text-4xl font-extrabold tracking-tight">Community Directives & Extensions Guide</h1>
<p class="text-muted-foreground mt-2 text-sm leading-relaxed">
Learn how to connect external 3D viewports (Three.js), interactive maps (Leaflet), or custom canvas renderers to HTMXUI in under 15 lines of declarative code.
</p>
</div>
<!-- Section 1: Philosophy -->
<section class="space-y-3">
<h2 class="text-xl font-bold tracking-tight">Why the Directive Model?</h2>
<p class="text-sm text-muted-foreground leading-relaxed">
HTMXUI is strictly a foundational application runtime (~40KB). Rather than bundling heavy 3rd-party dependencies (like a 600KB Three.js bundle or 150KB Leaflet map engine), HTMXUI provides <code>HTMXUI.directive()</code> and <code>HxBolt.ticker</code>. This gives community developers full reactive signal bindings, lifecycle cleanup, and game-loop synchronization without bloating the core.
</p>
</section>
<!-- Section 2: 3D WebGL / Three.js Example -->
<section class="space-y-4">
<h3 class="text-lg font-bold tracking-tight">Example 1: Connecting a 3D WebGL Canvas (Three.js)</h3>
<p class="text-xs text-muted-foreground">Define a custom directive <code>hx-three-mesh</code> and bind its rotation and position directly to local Bolt reactive state:</p>
<div class="bg-[#1e293b] text-[#e2e8f0] rounded-xl p-5 font-mono text-xs overflow-x-auto space-y-2 border border-slate-700">
<span class="text-slate-400">// Register custom 3D directive</span>
<div><span class="text-purple-400">HTMXUI</span>.<span class="text-sky-400">directive</span>(<span class="text-emerald-400">'hx-three-mesh'</span>, (canvasEl, options, { state, onCleanup }) => {</div>
<div class="pl-4"><span class="text-slate-400">// Initialize Three.js WebGL scene</span></div>
<div class="pl-4"><span class="text-blue-400">const</span> renderer = <span class="text-blue-400">new</span> THREE.<span class="text-sky-400">WebGLRenderer</span>({ canvas: canvasEl, antialias: <span class="text-amber-400">true</span> });</div>
<div class="pl-4"><span class="text-blue-400">const</span> scene = <span class="text-blue-400">new</span> THREE.<span class="text-sky-400">Scene</span>();</div>
<div class="pl-4"><span class="text-blue-400">const</span> camera = <span class="text-blue-400">new</span> THREE.<span class="text-sky-400">PerspectiveCamera</span>(<span class="text-amber-400">60</span>, canvasEl.clientWidth / canvasEl.clientHeight, <span class="text-amber-400">0.1</span>, <span class="text-amber-400">1000</span>);</div>
<div class="pl-4"><span class="text-blue-400">const</span> cube = <span class="text-blue-400">new</span> THREE.<span class="text-sky-400">Mesh</span>(<span class="text-blue-400">new</span> THREE.<span class="text-sky-400">BoxGeometry</span>(), <span class="text-blue-400">new</span> THREE.<span class="text-sky-400">MeshNormalMaterial</span>());</div>
<div class="pl-4">scene.<span class="text-sky-400">add</span>(cube);</div>
<br>
<div class="pl-4"><span class="text-slate-400">// Hook into HTMXUI 120 FPS game ticker</span></div>
<div class="pl-4"><span class="text-blue-400">const</span> unsub = <span class="text-purple-400">HxBolt</span>.<span class="text-sky-400">ticker</span>.<span class="text-sky-400">subscribe</span>((dt) => {</div>
<div class="pl-8">cube.rotation.y += <span class="text-amber-400">0.02</span>;</div>
<div class="pl-8">cube.position.y = state.elevation || <span class="text-amber-400">0</span>; <span class="text-slate-400">// 2-way reactive sync</span></div>
<div class="pl-8">renderer.<span class="text-sky-400">render</span>(scene, camera);</div>
<div class="pl-4">});</div>
<br>
<div class="pl-4"><span class="text-slate-400">// Clean up WebGL resources when element is unmounted</span></div>
<div class="pl-4"><span class="text-sky-400">onCleanup</span>(() => {</div>
<div class="pl-8"><span class="text-sky-400">unsub</span>();</div>
<div class="pl-8">renderer.<span class="text-sky-400">dispose</span>();</div>
<div class="pl-4">});</div>
<div>});</div>
</div>
<!-- HTML Usage Block -->
<div class="p-4 rounded-xl border border-border bg-card space-y-2">
<div class="text-xs font-semibold text-muted-foreground uppercase">HTML Usage in Your Templates:</div>
<pre class="bg-muted p-3 rounded-lg text-xs font-mono overflow-x-auto"><code><div hx-state='{ "elevation": 1.5 }'>
<canvas hx-three-mesh class="w-full h-64 rounded-xl border"></canvas>
<input type="range" min="-3" max="3" step="0.1" hx-model.number="elevation" class="w-full mt-2">
</div></code></pre>
</div>
</section>
<!-- Section 3: Interactive GIS Mapping Example -->
<section class="space-y-4">
<h3 class="text-lg font-bold tracking-tight">Example 2: Connecting an Interactive Map (Leaflet)</h3>
<p class="text-xs text-muted-foreground">Register an <code>hx-leaflet-map</code> directive that tracks coordinates and places pins:</p>
<div class="bg-[#1e293b] text-[#e2e8f0] rounded-xl p-5 font-mono text-xs overflow-x-auto space-y-2 border border-slate-700">
<div><span class="text-purple-400">HTMXUI</span>.<span class="text-sky-400">directive</span>(<span class="text-emerald-400">'hx-leaflet-map'</span>, (mapEl, _, { state, onCleanup }) => {</div>
<div class="pl-4"><span class="text-blue-400">const</span> map = L.<span class="text-sky-400">map</span>(mapEl).<span class="text-sky-400">setView</span>([state.lat || <span class="text-amber-400">51.505</span>, state.lng || -<span class="text-amber-400">0.09</span>], <span class="text-amber-400">13</span>);</div>
<div class="pl-4">L.<span class="text-sky-400">tileLayer</span>(<span class="text-emerald-400">'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'</span>).<span class="text-sky-400">addTo</span>(map);</div>
<div class="pl-4"><span class="text-blue-400">const</span> marker = L.<span class="text-sky-400">marker</span>([state.lat, state.lng]).<span class="text-sky-400">addTo</span>(map);</div>
<br>
<div class="pl-4"><span class="text-slate-400">// Listen to map clicks to mutate local Bolt state</span></div>
<div class="pl-4">map.<span class="text-sky-400">on</span>(<span class="text-emerald-400">'click'</span>, (e) => {</div>
<div class="pl-8">state.lat = e.latlng.lat;</div>
<div class="pl-8">state.lng = e.latlng.lng;</div>
<div class="pl-8">marker.<span class="text-sky-400">setLatLng</span>(e.latlng);</div>
<div class="pl-4">});</div>
<br>
<div class="pl-4"><span class="text-sky-400">onCleanup</span>(() => map.<span class="text-sky-400">remove</span>());</div>
<div>});</div>
</div>
</section>
</div>