Skip to content

Application Development

Alex Tants edited this page Aug 2, 2026 · 1 revision

Application development

Directory structure

Applications are repository-level folders:

apps/
  my-app/
    main.canvas.js

The folder name is the stable app ID and must contain lowercase letters, digits, and hyphens. The source file carries metadata and display preferences in a TinyPanel JSDoc block; see Application JSDoc Configuration.

Minimal application

/**
 * @tinypanel
 * @name Hello Panel
 * @description Minimal TinyPanel application
 * @width 160
 * @height 128
 * @orientation landscape
 * @fps 1
 */

function render(ctx, state) {
  ctx.clear('#080b12');
  ctx.drawText('HELLO', 10, 10, { color: '#63e69a', scale: 2 });
}

The global render(ctx, state) function is required.

Frame state

state is immutable for a frame and exposes:

  • frame — successful render counter;
  • time — current timestamp in milliseconds;
  • width and height — renderer dimensions;
  • revision — active source revision;
  • data — optional server-provided cached data.

Application globals persist between frames until the source revision reloads. Use them for small cached values, request state, or animation state. Do not append unbounded data each frame.

Drawing APIs

Browser-style APIs include solid fills, paths, gradients, transforms, compositing, text, and images where supported by node-canvas.

TinyPanel helpers provide pixel-oriented primitives:

ctx.clear('#000000');
ctx.fillStyle = '#ff3399';
ctx.fillRect(10, 10, 30, 12);
ctx.fillCircle(80, 40, 16);
ctx.fillTriangle(20, 80, 40, 60, 60, 80);
ctx.strokeStyle = '#ffffff';
ctx.drawLine(0, 64, 159, 64);
ctx.drawText('READY', 4, 110, { color: '#63e69a', scale: 2 });

CSS hex colors are converted to RGB565. Final output is pixel-oriented and antialiasing is disabled where possible to keep small shapes sharp.

Gradients

const sky = ctx.createLinearGradient(0, 0, 0, 64);
sky.addColorStop(0, '#080018');
sky.addColorStop(1, '#d16500');

function render(ctx) {
  ctx.fillStyle = sky;
  ctx.fillRect(0, 0, 160, 64);
}

Cache static gradients and other reusable Canvas resources outside render() instead of recreating them on every frame.

Fetching data

fetch, URL, URLSearchParams, and AbortController are available. Start network requests in the background and render cached state; never await a request inside every frame.

Crypto Tracker demonstrates this model with the Binance Futures API. Its network refresh timing is independent from its app frame rate.

Editor workflow

  • Select an app or create one from App Library.
  • Choose autosave or manual Ctrl+S/Cmd+S mode in Editor settings.
  • Use fullscreen workspace when more code space is needed.
  • Runtime and validation errors appear in the Debug/Problems area.
  • console.log, console.warn, and console.error appear under App logs.

Invalid source is rejected before persistence. Runtime errors retain the last successful framebuffer.

Performance guidance

  • Select the lowest useful @fps.
  • Keep animation state bounded and use state.frame modulo a small period.
  • Cache gradients and reusable resources.
  • Avoid full-screen changes when a smaller dirty area produces the same result.
  • Watch Transport metrics and ACK latency; target FPS is an upper bound.