@pixoopal/clockface
v0.2.4
Published
Clockface SDK for PixooPal.
Readme
@pixoopal/clockface SDK
Small SDK for building PixooPal Clockfaces.
Examples of usage can be found at this repository.
Author note: Please note that this SDK, including this readme, was generated by AI. You are warned. It's fully usable though.
Main API
defineClockface(options)
Creates a Clockface instance from a friendly object API.
resolution: number or(context) => number.data: persistent string-backed fields created withdata.*.inputs: UI controls created withinput.*; nested arrays render as rows.interval: requested render interval in ms. You may want to use this to lower your FPS. This will not help you make clockface more speedier, as we're currently capped at [180ms for 64-64, 80ms for 32-32]. It's Pixoo's limitation. Maybe in the future some hero will write a custom firmware with optimized API, but I wouldn't count on that.getInterval(context): dynamic interval.frameQueueSize: queued frame count; This can help you to deal with CPU spikes in lower-spec machines.5-10recommended for predicable clockfaces, and0recommended for games like Snake.setup(context): runs before first render. Good place for initialization.render(context): draws the frame.start(context): runs when the Clockface starts.stop(context): runs when the Clockface stops.
Clockface Resolution
If you want a Community Clockface to follow PixooPal's RESOLUTION environment variable, you can do so like this:
export default defineClockface({
resolution: Number.parseInt(process.env.RESOLUTION) ?? 32,
render: (context) => {
}
});16*16 clockfaces will be correctly shown by 32/64 Pixoo.
Data Helpers
All data.* helpers return a typed default field; values are stored as strings in context.data.
data.string(defaultValue = '')data.number(defaultValue = 0)data.color(defaultValue = '#ffffff')data.select(defaultValue)
Input Helpers
All inputs take id, friendlyName, and optional settings. If id exists in data, non-button inputs update context.data[id] automatically before onSubmit.
input.text(id, friendlyName, options?)input.number(id, friendlyName, options?)input.color(id, friendlyName, options?)input.file(id, friendlyName, options?)input.select(id, friendlyName, options, inputOptions?)input.button(id, friendlyName, options?)
Common input options:
isSetting: whether the input is a setting. Settings are only shown inside WebUI (and not inside HA's Card) under gear icon.keyCodes: keyboard shortcuts usingKeyboardEvent.code, for example'ArrowUp'. Unlocks ext level gaming.
input.button('moveLeft', 'Left', {
keyCodes: ['ArrowLeft', 'KeyA'],
onSubmit: (_value, context) => {
context.persistence.set('direction', 'left');
}
});onSubmit(value, context): custom submit handler.min,max,step: number input bounds.accept: file input accept string.options: select options as{ value, label }.
Color Helpers
color.black:[0, 0, 0].color.white:[255, 255, 255].color.parse(value): parses'#rrggbb','#rgb', or RGB tuples.color.mix(start, end, amount): blends two colors, withamountclamped to0..1.
Clockface Context
Every lifecycle method receives context.
context.resolution: current size.context.data: string-backed persistent data.context.inputs: flat input list.context.buffer: mutable flat RGB buffer.context.canvas: drawing helpers.context.persistence: custom persisted state helpers.context.homeAssistant: Home Assistant bridge.context.lifecycle: timer and cleanup helpers.
Canvas Methods
context.canvas writes into context.buffer.
clear(fill?): fills the whole frame; default is black.getPixel(x, y): reads one RGB pixel.pixel(x, y, colorOrOptions): writes one pixel.blendPixel(x, y, color, opacity): alpha-blends one pixel.rect(x, y, width, height, options?): draws a rectangle withfill,stroke,opacity.circle(x, y, radius, options?): draws a circle withfill,stroke,opacity.text(text, x, y, options?): draws bitmap text; options includefill,fontName,opacity.media(asset, type, options?): draws image, gif, or video media; options includex,y,width,height.
Pixel buffer layout: ClockfacePixelBuffer is Uint8Array RGB. Pixel (x, y) starts at (x + y * size) * 3.
Persistence Methods
context.persistence stores extra state separately from context.data.
state: current raw persisted state object.get(key, fallback): reads one value.set(key, value): writes one value.update(values): merges several values.
Home Assistant Methods
context.homeAssistant is available when the host provides an integration.
connected: boolean connection state.renderJinja(template, variables?): renders a Jinja template.fetchBinary(url): fetches binary data and returns{ bytes, type }.callService(domain, service, data?, options?): calls a Home Assistant service;options.returnResponserequests a response.
Lifecycle Methods
Use context.lifecycle for work that must be cleaned up on stop.
cleanup(dispose): registers a cleanup callback.setInterval(handler, ms): creates an interval and auto-cleans it.setTimeout(handler, ms): creates a timeout and auto-cleans it.
Media API
Import from @pixoopal/clockface/media or @pixoopal/clockface/gif.
decodeMediaFile(file, options?): decodes GIF or video frames.decodeImageFile(file, options?): decodes and resizes an image to anImageFrame.decodeGifFile(file, options?): decodes GIF frames.decodeVideoFile(file, options?): decodes video frames throughffmpeg.createMediaAnimation(frames): creates an animation withreset,getFrame(index), andgetCurrentFrame(speed?).createGifAnimation(frames): alias ofcreateMediaAnimation.drawMediaFrame(context, frame): copies a full media frame into the buffer.drawGifFrame(context, frame): alias ofdrawMediaFrame.drawImageFrame(context, frame, options?): draws an image frame atx,y.drawImageFile(context, file, options?): decodes and draws an image file.drawMediaAnimationFrame(context, animation, speed?): draws the current animation frame.drawGifAnimationFrame(context, animation, speed?): alias ofdrawMediaAnimationFrame.normalizeGifPlaybackSpeed(value): clamps playback speed to the supported range.isGifFileInput(value): checks for file input shape.isMediaFileInput(value): alias-compatible media file check.isImageFileInput(value): checks for image-like file input.
Useful media options:
resolution,width,heightfit:'contain' | 'cover' | 'fill' | 'inside' | 'outside'background:{ r, g, b, alpha? }maxFramesvideoFrameRate
Image API
Import from @pixoopal/clockface/image for image-only helpers:
decodeImageFiledrawImageFiledrawImageFrameisImageFileInput
Bitmap Text API
Import from @pixoopal/clockface/bitmap-text.
configureBitmapTextAssets(assets): overrides bitmap font and emoji assets.getBitmapTextLineHeight(fontName?): returns font line height.getBitmapTextRenderHeight(text, fontName?): returns rendered text height.measureBitmapText(text, fontName?): returns text width in pixels.drawBitmapText(options): draws text into a raw buffer with{ buffer, size, text, x, y, fontName?, color?, clip? }.
Custom fonts and emoji packs in Community Clockfaces
Community Clockfaces can bundle their own bitmap fonts and emoji sheets. Put assets next to the Clockface source, import them, then call configureBitmapTextAssets before rendering text.
PixooPal loads .png, .jpg, .webp, .gif and .fnt files as text. Example of assets (could be found here)[https://github.com/Drun555/PixooPal-SDK/tree/master/src/assets]
import { defineClockface } from '@pixoopal/clockface';
import { configureBitmapTextAssets } from '@pixoopal/clockface/bitmap-text';
import fontDefinition from './assets/fonts/tiny.fnt';
import fontAtlas from './assets/fonts/tiny.png';
import emojiAtlas from './assets/emojis/tiny-emoji.png';
import emojiManifest from './assets/emojis/tiny-emoji.json' with { type: 'json' };
configureBitmapTextAssets({
fonts: {
veryCoolFont: { // your font name
definition: fontDefinition,
atlasPath: fontAtlas
}
},
emojiManifest,
emojiAtlasPath: emojiAtlas
});
export default defineClockface({
resolution: 64,
render: ({ canvas }) => {
canvas.clear();
canvas.text('Hi 🙂', 0, 0, { fontName: 'veryCoolFont', fill: '#ffffff' });
}
});