Viewport

A panning/zooming wrapper that keeps child content in world space while the camera moves.

Zoom or pan here

Usage

<script lang="ts">
	import { Viewport } from '@obelus/trioxide';
	let viewport = $state({ x: 0, y: 0, zoom: 1 });
</script>

<Viewport
	bind:viewport
	min-zoom={0.25}
	max-zoom={20}
	pattern="grid"
	pattern-color="var(--trioxide_neutral-8)"
>
	<div class="h-32 w-32 rounded-md bg-(--trioxide_highlight-4)"></div>
</Viewport>
  • Bind viewport to react to panning/zooming or to programmatically set the camera.
  • Scroll/trackpad pans by default; hold Ctrl/Cmd while scrolling to zoom at the cursor position.
  • Left mouse drag also pans the canvas; set pan-with-mouse={false} if your content already uses dragging.
  • Touch: pinch to zoom, single-finger drag to pan.
  • Place any elements inside; they are translated and scaled together.

Props

  • bind:viewport: { x: number; y: number; zoom: number } — camera state in pixels and scale.
  • min-zoom / max-zoom: zoom clamp (default 0.2 / 20).
  • pan-with-mouse: allow left-click drag panning (default true); scroll and touch gestures still work when disabled.
  • pattern: 'none' | 'dots' | 'grid' | 'cross' — canvas pattern behind your content (default 'none').
  • pattern-color: CSS color or CSS variable for the pattern (default #fff).
  • min-cell-size: smallest pattern spacing in px; Viewport crossfades between larger spacings as you zoom (default 3).
  • grid-size: multiplier between pattern spacings (default 5); higher values make the pattern stay sparse at low zoom.
  • Rest props are forwarded to the outer <div> so you can add classes, inline styles, or aria attributes.