@hozo/canvas•HTML5 Canvas · React Native Skia

Declarative 2D Canvas & Data Visualization

Rendering massive datasets (thousands of points, heatmaps, or fluid charts) overwhelms DOM node trees. Hozo's 2D Canvas delivers a declarative JSX API that compiles to optimized batched Canvas operations on Web and native Skia draw calls on mobile.

Choosing Between SVG and Canvas

Hozo provides first-class support for both vector systems. Rather than forcing one paradigm across all use cases, library authors choose based on data density and interaction model:

Use SVG (@hozo/svg)
  • UI icons, vector logos, and design elements
  • Small to medium charts (< 500 data points)
  • When individual nodes need CSS hover transitions and DOM events
  • Zero runtime overhead on Web (emits native <svg>)
Use Canvas (@hozo/canvas)
  • High-frequency real-time time-series and candlestick charts
  • Large datasets (> 5,000 data points) and heatmaps
  • Custom particle animations, drawing pads, and filters
  • Single GPU surface with zero DOM node creation overhead

Solving the Platform Asymmetry

01

Imperative vs Declarative

Web Canvas is strictly imperative (ctx.fillRect), while React Native Skia is declarative. Hozo compiles declarative JSX into draw instructions, reconciling the asymmetry without runtime bloat.

02

Spatial Hit-Testing

Hozo deliberately does not create a fake DOM over Canvas. Hit-testing is implemented via spatial math, allowing precise gestures and tooltips on both mouse pointers and touch screens.

03

Accessible Sibling Tables

Canvas graphics are often invisible to screen readers. Hozo automatically pairs canvas visualizations with accessible semantic sibling tables so screen reader users can navigate the underlying data.

Declarative 2D Authoring

Write declarative components that compile to optimized draw loops on Web and Skia commands on Native.

import { Canvas, Rect, Path } from '@hozo/canvas'

export function DataBarChart({ points }) {
  return (
    <Canvas width={600} height={300} accessibilityLabel="Quarterly Revenue Trends">
      {points.map((p, i) => (
        <Rect
          key={i}
          x={i * 60 + 10}
          y={300 - p.value}
          width={40}
          height={p.value}
          fill="#c8a882"
        />
      ))}
    </Canvas>
  )
}