08 — Canvas
flexium-canvas lets you declare canvas drawings as JSX — primitives like <DrawRect>, <DrawCircle>, <DrawText> map directly to canvas paint calls. Signal updates re-paint only the affected region.
tsx
import { Canvas, DrawRect, DrawCircle, DrawText } from 'flexium-canvas/dom'
import { useMouse, useLoop } from 'flexium-canvas/interactive'
import { use } from 'flexium/core'
export function BouncingBall() {
const [x, setX] = use(100)
const [y, setY] = use(100)
const [vx, setVx] = use(2)
const [vy, setVy] = use(3)
useLoop(() => {
setX(prev => {
const next = prev + vx
if (next < 0 || next > 400) setVx(v => -v)
return next
})
setY(prev => {
const next = prev + vy
if (next < 0 || next > 300) setVy(v => -v)
return next
})
})
return (
<Canvas width={400} height={300} background="#0d1117">
<DrawCircle cx={x} cy={y} r={20} fill="#3b82f6" />
<DrawText x={10} y={20} text={`(${x.toFixed(0)}, ${y.toFixed(0)})`} fill="white" />
</Canvas>
)
}Available primitives
<DrawRect x y width height fill stroke /><DrawCircle cx cy r fill stroke /><DrawArc cx cy r start end fill stroke /><DrawLine x1 y1 x2 y2 stroke strokeWidth /><DrawPath d fill stroke />— SVG-style path data<DrawText x y text font fill stroke />
All accept signal values — change a signal and the primitive re-paints.
Interactive hooks
useMouse()—{ x, y, down }for the canvasuseKeyboard()—{ key, down }mapuseLoop(fn)— callsfnon every animation frame, capped to monitor refresh rate
tsx
function DrawingApp() {
const { x, y, down } = useMouse()
const [points, setPoints] = use<{x:number,y:number}[]>([])
// Add a point when mouse pressed
if (down && points[points.length - 1]?.x !== x) {
setPoints(p => [...p, { x, y }])
}
return (
<Canvas width={500} height={500}>
{points.map(p => <DrawCircle cx={p.x} cy={p.y} r={2} fill="white" />)}
</Canvas>
)
}Re-paint granularity
Canvas itself doesn't support partial repaint, but flexium-canvas tracks which primitives reference which signals and only re-orders the affected ones in the paint command list. For a 10,000-particle simulation with 100 moving, only 100 commands re-evaluate per frame.
API surface used
<Canvas width height background />— paint surface<DrawRect>/<DrawCircle>/<DrawArc>/<DrawLine>/<DrawPath>/<DrawText>— primitivesuseMouse()/useKeyboard()/useLoop()— interactive hooks
Next
→ Production deploy — vite-plugin-flexium optimize: 'auto'.