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

FieldWhat it is
namethe pet's name, e.g. "Goose"
themewhere it lives and what it is, in a sentence
personalitywhat it is like
stylehow it is drawn
aboutanything else worth knowing
colorits own colour, "#rrggbb": agents may use it for their lines
credit, licensewho made the art, and how it may be used
privateoptional, 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, tallpixels from a frame's centre down to the feet, and Idle's visible height
scaleoptional, 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}
sceneoptional: the pet's own scene (below)
animsthe 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:

FieldWhat it is
w, hthe pictures' size, in their own pixels (e.g. 140×120)
scaleoptional, 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
picturesoffsets: 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
keepoptional [x0, y0, x1, y1]: the part to keep in view on a smaller screen
workspotoptional {w, h, x, y, pictures: {on, off, night}}: its desk, always in the scene
targetoptional [x, y]: something the pet can aim at, such as a hoop's rim (see the hoop shot below)
swishoptional {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:

FieldWhat it is
namee.g. "Idle", "Walk", "Party"
w, hframe size in pixels
rows1 (it faces you) or 8 (directions: down, down-right, right, up-right, up, up-left, left, down-left)
frameshow many frames
durationseach frame's time in 1/60 s
rush, hit, returnoptional frame markers for strikes: lunge, impact, back
dashoptional, 1: during a strike (rush to return) the device also slides the pet forward a little
atoffset 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 -->

StateKindDevice addsPlays the first one the pet has
wandermoodWalk → Idle
idlemoodIdle
workingmoodWork (facing its screen, at the desk) → Idle (facing its screen, at the desk)
typing_fastmoodWorkFast (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)
donereactionheartPose (×0.8) → Hop (×0.8)
needs_youmood!Alert → Hop
errorreactionxCringe → Hurt (device shakes it)
dizzyreactionRotate
waking_upreactionDeepBreath → Wake → Hop
asleepmoodzzzSleep
watchingmood...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)
busymood...Busy → Charge (×0.5, at the desk)
partymoodParty → Dance (×0.7) → Twirl (×0.6) → Hop (×0.8)
dancingmoodnoteDancing → Dance (×0.6) → Twirl (×0.45) → Nod (×0.6) → Hop (×0.5)
fightingmoodFighting → 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)
eatingmoodEating → Eat (×0.6) → Charge (×0.35)
quietmoodQuiet → Sit (×0.5) → Laying (×0.5) → Idle (×0.4)
downmoodDown → Pain (×0.5) → Hurt (×0.35)
celebratereactionheartCelebrate → Dance (×0.75) → Twirl (×0.6) → Pose (×0.7) → Hop (×0.9)
notedreactionNoted → Nod (×0.6) → Idle
surprisedreactionshockSurprised → LostBalance (×0.8) → Hop (×0.8)
pettedreactionheartPetted → Appeal (×0.6) → TailWhip (×0.6) → Nod (×0.6) → Hop (×0.6)
grumpyreactionangryGrumpy → RearUp (×0.7) → Charge (×0.5)
confusedreaction?Confused → Idle
yawnreactionYawn → DeepBreath (×0.7) → Idle (×0.5)
oopsreactionOops → 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.