# Wallive Pet Package Reference

The authoring package is a macOS directory package with a `.pet` extension:

```text
Name.pet/
├── pet.json
└── states/
    ├── idle.webp
    ├── sleep.webp
    └── ...
```

Wallive Settings imports `Name.pet/` and copies its contents into the active runtime directory.

Every visible animation is authored as an in-place 30-frame horizontal strip. `fps` is playback speed, not the generated frame count. The pet's body anchor, baseline, and visual center stay fixed inside the cell; pose and expression may animate, but the whole pet must not walk, slide, drift, jump across the cell, or use camera movement. The final frame should connect cleanly back to frame 0.

Default manifest values:

```json
{
  "schemaVersion": 2,
  "id": "wallive-default-pet",
  "name": "Wallive Default Pet",
  "frame": {
    "width": 192,
    "height": 208
  },
  "animations": {
    "idle": { "image": "states/idle.webp", "frames": 30, "fps": 12, "loop": true },
    "sleep": { "image": "states/sleep.webp", "frames": 30, "fps": 8, "loop": true },
    "focus": { "image": "states/focus.webp", "frames": 30, "fps": 12, "loop": true },
    "cheer": { "image": "states/cheer.webp", "frames": 30, "fps": 14, "loop": true },
    "lowBattery": { "image": "states/lowBattery.webp", "frames": 30, "fps": 8, "loop": true },
    "hide": { "image": "states/hide.webp", "frames": 30, "fps": 1, "loop": true },
    "typing": { "image": "states/typing.webp", "frames": 30, "fps": 14, "loop": true },
    "waitingApproval": { "image": "states/waitingApproval.webp", "frames": 30, "fps": 12, "loop": true },
    "celebrate": { "image": "states/celebrate.webp", "frames": 30, "fps": 14, "loop": true },
    "confused": { "image": "states/confused.webp", "frames": 30, "fps": 12, "loop": true },
    "peekOut": { "image": "states/peekOut.webp", "frames": 30, "fps": 12, "loop": true }
  },
  "fallback": "idle"
}
```

Validation invariants:

- `schemaVersion` is `2`
- `id` and `name` are non-empty
- frame dimensions are positive
- every required Wallive state is present
- animation image is a relative path inside the package directory
- animation image file exists
- animation frames is exactly `30`
- animation fps is positive
- animation loop is `true`
- `fallback` names an existing animation
