Eggs
An egg (.egg) is one pet in one file: its animations, palette, scene, and a short description. The device and the simulator read eggs as they are and never decode images. The base pets come ready in pets/. This page is the contract between the engine (engine/egg/egg.cpp) and whatever makes eggs.
The file
"NEGG" 4 bytes
description length 4 bytes, little-endian
description JSON, UTF-8 (below)
blocks palette, pictures and frames, where the description says
Every block is found by its offset from the start of the file ("at"). Pictures and frames are one byte per pixel: an index into the palette, row by row; index 0 is transparent in frames. The palette is RGB565, two bytes per colour, little-endian; colour 0 is unused. A reader ignores fields it doesn't know.
The description
| Field | What it is |
|---|---|
name | the pet's name, e.g. "Goose" |
theme | where it lives and what it is, in a sentence |
personality | what it is like |
style | how it is drawn |
about | anything else worth knowing |
color | its own colour, "#rrggbb": agents may use it for their lines |
credit, license | who made the art, and how it may be used |
private | optional, true: the art may not be shared; firmware builds leave the egg out unless asked to include it |
notes | {animation or state name: what it looks like}, shown to agents in GET /agents |
feet, tall | pixels from a frame's centre down to the feet, and Idle's visible height |
scale | optional, 1 to 4: screen pixels per pixel of the pet's frames (0 or missing: the screen's own, 2 on the LCD) |
palette | {"count": n, "at": offset} |
scene | optional: the pet's own scene (below) |
anims | the animations (below) |
The words (theme to notes) are what the pet's guide for agents and GET /v1/pets show, for every pet on the device.
The scene
Without a scene the pet lives in a plain room with a desk and laptop. With one:
| Field | What it is |
|---|---|
w, h | the pictures' size, in their own pixels (e.g. 140×120) |
scale | optional, 1 to 4 (default 1): screen pixels per picture pixel, so 140×120 at 2 fills a 280×240 screen. Every position below is in picture pixels |
pictures | offsets: day (required), and optional morning, afternoon, evening, night |
floor | [[x, y], ...]: the polygon the pet may walk on |
home | [x, y]: where it stands to work and sleep |
keep | optional [x0, y0, x1, y1]: the part to keep in view on a smaller screen |
workspot | optional {w, h, x, y, pictures: {on, off, night}}: its desk, always in the scene |
target | optional [x, y]: something the pet can aim at, such as a hoop's rim (see the hoop shot below) |
swish | optional {w, h, x, y, pictures: {day, night}}: drawn over the scene while the ball drops through the target; index 0 is transparent, and without night the day picture is dimmed |
Times of day. The pet shows the picture for the time of day by its clock (morning from 6:00, afternoon from 12:00, evening from 18:00, night from 20:30), fading between them. A missing picture falls back: morning and afternoon to day; evening to night; night to day dimmed.
Other screens. On a screen smaller than the pictures, the scene is cropped around keep (or home); on a larger one it is centred and its edges carried on. The floor, home and work spot move with it. On a round screen the pet only goes where it is fully in view.
Animations
Each entry of anims:
| Field | What it is |
|---|---|
name | e.g. "Idle", "Walk", "Party" |
w, h | frame size in pixels |
rows | 1 (it faces you) or 8 (directions: down, down-right, right, up-right, up, up-left, left, down-left) |
frames | how many frames |
durations | each frame's time in 1/60 s |
rush, hit, return | optional frame markers for strikes: lunge, impact, back |
dash | optional, 1: during a strike (rush to return) the device also slides the pet forward a little |
at | offset of the frames (below) |
Frames. Each frame is stored cropped to its visible pixels. The block starts with one box per frame, row by row, 8 bytes each: x, y, w, h as little-endian u16, the box's place inside the w × h frame. Then each frame's w × h pixels of its box follow, in the same order. Everything outside a box is transparent. An empty frame has w = h = 0.
What a pet must have: Idle and Walk, with all 8 rows (the pet walks in every direction on its floor). Everything else is optional. Each state walks down a list of animation names and plays the first one the pet has; a pet can always bring its own animation for a state under the state's own name, e.g. Party for party, and that comes first.
The states
Moods last until something changes them; reactions play once and return. The device adds the bubbles (♥, !, Zzz, …, ♪, ?, the angry mark, the shock mark) itself, for every pet. Anything on the network can ask for a state ({"state": "party", "for": 600}) or send an everyday event that leads to one; GET / on the pet explains the API. This table is generated from the engine by tools/specdoc.py.
<!-- STATES -->
| State | Kind | Device adds | Plays the first one the pet has |
|---|---|---|---|
wander | mood | Walk → Idle | |
idle | mood | Idle | |
working | mood | Work (facing its screen, at the desk) → Idle (facing its screen, at the desk) | |
typing_fast | mood | WorkFast (at the desk) → Shock (strike frames, looped, at the desk) → Emit (strike frames, looped, at the desk) → SpAttack (strike frames, looped, at the desk) → MultiStrike (strike frames, looped, at the desk) → MultiScratch (strike frames, looped, at the desk) → QuickStrike (strike frames, looped, at the desk) → Strike (strike frames, looped, at the desk) → Attack (strike frames, looped, at the desk) | |
done | reaction | heart | Pose (×0.8) → Hop (×0.8) |
needs_you | mood | ! | Alert → Hop |
error | reaction | x | Cringe → Hurt (device shakes it) |
dizzy | reaction | Rotate | |
waking_up | reaction | DeepBreath → Wake → Hop | |
asleep | mood | zzz | Sleep |
watching | mood | ... | Watch → Sit (facing its screen, ×0.2, at the desk) → LookUp (facing its screen, ×0.12, at the desk) → Idle (facing its screen, at the desk) |
busy | mood | ... | Busy → Charge (×0.5, at the desk) |
party | mood | Party → Dance (×0.7) → Twirl (×0.6) → Hop (×0.8) | |
dancing | mood | note | Dancing → Dance (×0.6) → Twirl (×0.45) → Nod (×0.6) → Hop (×0.5) |
fighting | mood | Fighting → MultiStrike (facing right, strike frames, looped) → QuickStrike (facing right, strike frames, looped) → Kick (facing right, strike frames, looped) → Strike (facing right, strike frames, looped) → Attack (facing right, strike frames, looped) | |
eating | mood | Eating → Eat (×0.6) → Charge (×0.35) | |
quiet | mood | Quiet → Sit (×0.5) → Laying (×0.5) → Idle (×0.4) | |
down | mood | Down → Pain (×0.5) → Hurt (×0.35) | |
celebrate | reaction | heart | Celebrate → Dance (×0.75) → Twirl (×0.6) → Pose (×0.7) → Hop (×0.9) |
noted | reaction | Noted → Nod (×0.6) → Idle | |
surprised | reaction | shock | Surprised → LostBalance (×0.8) → Hop (×0.8) |
petted | reaction | heart | Petted → Appeal (×0.6) → TailWhip (×0.6) → Nod (×0.6) → Hop (×0.6) |
grumpy | reaction | angry | Grumpy → RearUp (×0.7) → Charge (×0.5) |
confused | reaction | ? | Confused → Idle |
yawn | reaction | Yawn → DeepBreath (×0.7) → Idle (×0.5) | |
oops | reaction | Oops → Trip (×0.75) → Cringe (×0.7) → Hurt (×0.6) |
<!-- /STATES -->
The hoop shot (optional)
The goose doesn't have one; pet-folder.md lists what a folder needs for it. A pet with a Shoot animation (8 rows, its release marked as the hit frame), a Ball animation (1 row, a small ball drawn centred on its point) and optionally Catch (1 row), in a scene with a target, plays a hoop shot while the user types fast instead of its WorkFast: it turns to the target, plays Shoot, and from the frame after hit the device flies the ball: an arc from the top of the pet to the target (40 ticks), down through it (10), two bounces back to the pet (16 + 10), then Catch. Shoot's frames after hit must not show the ball, and Catch starts without it and ends holding it, so the ball is never drawn twice.