Developers

The sandbox

Read this before you build. Every limit here is deliberate, and none of them are configurable.

No network. At all.

A Content Security Policy is injected before your code runs:

default-src 'self' 'unsafe-inline' data: blob:; connect-src 'none';
script-src 'self' 'unsafe-inline'

connect-src 'none' means no fetch, no XHR, no WebSocket, no beacon. No CDN scripts, no Google Fonts, no analytics, no error reporting, no API you own.

Everything ships in your folder. Inline your CSS, embed images as data URIs, bundle your own fonts.

This is the single most important thing to design around, and the most common reason a plugin that worked in a browser does nothing on the device. The simulator does not enforce it. Test on a device before you publish.

The only outside information available to you is data.weather().

You cannot leave your folder

File access is scoped to your own plugin directory. You cannot read another plugin's files, the app's files, or anything else on the device.

Navigation away from your own bundle is refused: links, redirects, window.location. Your plugin is one page, for its whole life.

localStorage does not persist, hairobo.storage does

The WebView's own storage is non-persistent: localStorage, cookies and caches are cleared between runs, and always will be. Anything you keep there is gone the moment your plugin closes.

Use hairobo.storage instead. It survives between runs, is scoped to your plugin id, needs no permission, and is deleted when the user uninstalls you. Full API in api.md. Its caps:

keys 200
key length 128 characters
one value 16 KB
whole store 256 KB

Values are strings, so JSON.stringify your own objects.

⚠️ Hitting a cap REJECTS the promise; it does not resolve false. That is the opposite of the rate limits below, and deliberately so: a rate limit clears on its own and retrying is correct, whereas a full store stays full until you remove something. Catch it.

It is not a database. If you need more than 256 KB, this is not the API for what you are building.

Rate limits

voice.speak one per 0.4s, 300 characters
motor.* one move per 0.35s
camera events about 6 per second, up to 8 faces

Exceeded calls resolve false and are dropped, not queued. A backlog of stale commands is worse than a missed one, especially for movement.

Ambient plugins yield

An ambient plugin gives up the screen the moment the robot leaves idle, and whenever the display deep-dims for battery. Do not depend on running continuously.

What you can rely on

Your page is a full modern WebView. Canvas, WebGL, CSS animation, Web Audio, touch: all of it works. The limits above are about the outside world, not about what you can build on screen.

The simulator fakes the camera

The simulator has no camera. It emits synthetic face events at the same 6 Hz the device uses, with however many people you set in the sidebar, spread across the frame and drifting. That is enough to exercise counting and layout, and nothing like a real room. Test multi-face on a device before you publish.

Storage in the simulator is backed by the browser's own localStorage with the same caps enforced, so you hit a cap there before a user hits it for you.

How the simulator runs your plugin

Drop your folder on it. It reads the files straight off your machine: nothing is uploaded, nothing is downloaded, and you do not need a server. This is the way to run your own plugin.

It provides the SDK, exactly as the app does. hairobo is defined before your first script runs, so your plugin needs no script tag for it. The same code runs here and on a robot, with nothing in it that exists only for the simulator.

A reference that is not in your folder is named in the log. A missing stylesheet used to show up as a page that simply looked wrong; now it says which file it wanted. The entry comes from your manifest's entry, so a plugin that does not use index.html still runs.

The path box is for the bundled examples, which sit next to the simulator on its own server. Your own plugin will not be there. Use the folder.

← Previous Permissions Next → Publishing
Preorder Deskmate dock

Reserve your dock.

Drop your details and we'll email you the moment it ships, with early-bird pricing.