A 2D canvas rendering library for Deno that brings the HTML5 Canvas API to native applications. Powered by NanoVG for vector graphics, SDL3 for window management, and OpenGL for rendering.
- Familiar API - HTML5 Canvas
- Multi-threaded architecture with command batching
- FFI bindings to native C++ library
- Type-safe API with full TypeScript support
Supported platforms: macOS (arm64), Linux (x64, arm64), Windows (x64, arm64).
Deno — no install step; the examples below work as-is.
Bun — Bun doesn't resolve jsr: specifiers natively, so install from JSR's npm proxy first:
bunx jsr add @diyorbek/canvas-nativeThen drop the jsr: prefix from imports throughout the examples below — e.g. 'jsr:@diyorbek/canvas-native' becomes '@diyorbek/canvas-native'.
Everything lives in one script — the library handles the window, event loop, and worker setup internally.
// demo.ts
import {
createCanvas,
requestAnimationFrame,
} from 'jsr:@diyorbek/canvas-native';
const { ctx, width, height } = await createCanvas(400, 300, 'Hello');
function draw(t: number) {
ctx.clearRect(0, 0, width, height);
const r = 50 + Math.sin(t / 300) * 30;
ctx.beginPath();
ctx.arc(width / 2, height / 2, r, 0, Math.PI * 2);
ctx.fillStyle = 'tomato';
ctx.fill();
ctx.fillStyle = 'black';
ctx.font = '16px sans-serif';
ctx.fillText('Hello, Canvas Native', 20, 30);
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);# Bun
bun demo.ts
# Deno
deno --allow-ffi --allow-env --allow-read demo.ts
⚠️ Heads-up: your script runs twice.Internally,
createCanvas()re-launches your script as a Web Worker — the main thread runs the native window loop, and the worker runs your drawing code. That means any code at the top level of your file executes on both threads, once on each.// ✅ Safe — only imports and createCanvas() before the await import { createCanvas, requestAnimationFrame, } from 'jsr:@diyorbek/canvas-native'; const { ctx, width, height } = await createCanvas(800, 500, 'Demo'); // All your setup and drawing code goes here. // It only runs in the worker.// ⚠️ Runs twice — avoid import { createCanvas } from 'jsr:@diyorbek/canvas-native'; console.log('starting up'); // prints twice await fetch('https://example.com'); // hits the network twice const { ctx } = await createCanvas(800, 500, 'Demo');If you need full control and want to guarantee single-execution of setup code, use the two-file API below.
Use this when you need finer control over the main/worker split, or want to guarantee that setup code only runs once.
app.ts — main thread (creates the window):
import { createWindow } from 'jsr:@diyorbek/canvas-native/app';
const { mainLoop } = await createWindow(800, 500, 'My App', './worker.ts');
mainLoop();worker.ts — drawing thread:
import {
initCanvas,
requestAnimationFrame,
} from 'jsr:@diyorbek/canvas-native/worker';
const ctx = await initCanvas();
const W = 800;
const H = 500;
function draw(t: number) {
ctx.clearRect(0, 0, W, H);
ctx.fillStyle = '#f00';
ctx.fillRect(100, 100, 200, 150);
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);# Bun
bun app.ts
# Deno
deno --allow-ffi --allow-env --allow-read app.tsPrerequisites: Deno, CMake 3.24+, a C++23 compiler.
git clone https://github.com/diyorbek/canvas-native
cd canvas-native
cmake -B build && cmake --build build --target canvasnativeThe build output at ./build/libcanvasnative.* is picked up automatically.
canvas-native looks for the native library in this order:
CANVAS_NATIVE_LIBenv var (absolute path to your own build)./build/libcanvasnative.{dylib,so,dll}in the current working directory (local dev builds)- Cache directory
~/Library/Caches/canvas-native/v<version>/on macOS$XDG_CACHE_HOME/canvas-native/v<version>/on Linux%LOCALAPPDATA%\canvas-native\v<version>\on Windows
- Downloaded from GitHub Releases (with SHA-256 checksum verification) and cached
- Currently implements a subset of the Canvas 2D API
- Some advanced features are not supported by NanoVG and need custom implementation
- Platform-specific quirks may exist (primarily tested on macOS)
Contributions are welcome! Areas for enhancement:
- Additional Canvas 2D methods
- Performance optimizations
- Platform support improvements
- Documentation and examples
- Bug fixes and error handling
- Complete Canvas 2D API coverage
- Improve color string parsing
- Input handling (keyboard, mouse events)
- Animation frame scheduling (
requestAnimationFrame) - Cross-platform testing and optimization
