Support configurable custom pet animation sequences and activity events
Summary
Please consider extending Codex custom pet support so pet.json can optionally describe animation behavior, not only the spritesheet asset.
The current custom pet feature is already useful, especially with the Hatch Pet skill, but custom pets are limited by hardcoded renderer behavior: frame counts, timing, sequence chaining, and event triggers are fixed by the app rather than by the pet manifest.
Proof Of Concept
I published a proof-of-concept mod here:
https://github.com/hlky/codex_app_pet_mod
Demo video:
https://github.com/user-attachments/assets/de321d1d-475e-4713-83f3-d1c082e1c6cd
Example custom pet:
https://github.com/hlky/codex_app_pet_mod/tree/master/assets/datachan-extended
The proof of concept patches a copied desktop app package to explore the behavior. I am not asking upstream to adopt the patching approach; the repo is meant to demonstrate the requested runtime behavior and a possible backwards-compatible pet.json shape.
Current Behavior
Custom pets can provide metadata and a spritesheet, but the app still owns the animation table and event mapping. That means a custom pet cannot reliably define:
- how many frames each row should play
- different timing per state
- longer idle or jumping sequences when the row has populated cells
- chained sequences like
running -> waving -> running-left - whether an active-state chain should loop or fall back to idle
- hover or drag-specific states
- richer activity states such as thinking, editing, edited, running a command, or command completed
This makes expressive custom pets difficult. The artwork can exist in the spritesheet, but the app may never play those cells or may return to the built-in idle behavior too quickly.
Proposed Manifest Shape
A backwards-compatible optional animation field could look like this:
{
"displayName": "Datachan Extended",
"description": "Custom pet with explicit animation behavior.",
"spritesheetPath": "spritesheet.webp",
"animation": {
"autoDetectFrames": true,
"idleSlowdown": 6,
"states": {
"idle": {
"row": 8,
"durationMs": 150,
"lastFrameDurationMs": 280
},
"running": {
"row": 7,
"durationMs": 120,
"lastFrameDurationMs": 220
},
"review": {
"row": 0,
"durationMs": 140,
"lastFrameDurationMs": 320
}
},
"chains": {
"idle": ["idle", "waving", "review"],
"running": {
"mode": "loop",
"sequence": ["waving", "idle", "running-left", "running-right", "running"]
}
},
"events": {
"hover": "jumping"
}
}
}
Requested Features
- Pass optional animation config through from custom pet manifests.
- Support per-state row/frame/timing config:
row/rowIndexframes/frameCountdurationMs/frameDurationMslastFrameDurationMsslowdown
- Use detected non-empty row cells when
framesis omitted, within the existing atlas geometry. - Support sequence chains per state.
- Support chain playback modes:
idleFallback: play the active chain once, then loop the configured idle chainloop: loop the active chain until the app state changesonce: play once and hold the final frame
- Support configurable event mappings, starting with hover and drag directions.
- Expose richer pet animation states for agent activity where possible:
thinkingeditingeditedrunning/ command runningran/ command completedreview
Activity State Note
The current app appears to collapse active local/cloud work into a single running mascot state. The UI already has richer activity labels for file edits, commands, searches, and tool calls. It would be useful to keep the existing internal task status model, but derive a separate pet animation state from the latest activity item. That avoids changing notification semantics while still allowing pets to react to editing, command execution, and thinking.
Compatibility
This can be additive:
- Existing pets without
animationkeep current behavior. - Existing built-in pets can keep the hardcoded defaults.
- Custom pets can opt into configuration only where needed.
- The existing 8-column by 9-row atlas can remain the first supported format.
Why This Matters
The Hatch Pet workflow can generate expressive custom spritesheets, but without manifest-controlled playback much of that work is lost. Allowing custom pets to describe their own animation behavior would make the feature more useful without requiring users to patch app bundles or ask upstream for every new pet-specific behavior.
7 Comments
First, thank you sincerely to the OpenAI Codex team for building one of the world's leading agentic coding tools. Codex has already brought a real leap in quality to everyday work and life for ordinary users like us. The effort behind it is very visible, and we are genuinely grateful.
I wanted to add a small real-world observation that matches this issue.
We recently created and installed a custom pet using the Hatch Pet workflow. The generated package appears to be correct: the spritesheet contains all expected atlas rows, including idle, running-left, running-right, waving, jumping, failed, waiting, running, and review. Validation also passed successfully with no errors or warnings.
However, during normal daily use, what we actually see most of the time is only:
Other states such as waving, jumping, failed, waiting, and review appear to exist in the asset, but they are rarely visible in ordinary interaction. From a user's perspective, this makes the pet feel much less alive than the generated spritesheet actually is.
One practical lesson for us was that the idle state carries most of the visible screen time. If the idle row has only subtle frame differences, the pet feels almost static, even when the spritesheet includes many expressive states elsewhere.
If the team has time, we would be grateful if you could consider:
This is only a humble suggestion from actual usage. Thank you again for the excellent work and for making Codex so useful in daily work.
This matches exactly what I ran into while experimenting with custom pets, and it is also what the proof-of-concept mod is trying to address.
The mod makes these behaviors configurable from
pet.json: longer per-row playback, idle personality chains, active-state chains, loop/fallback behavior, and event mappings. It would be great if some version of this could be adopted first-party so custom pet creators do not need to patch the app bundle.For example, the running state can now be configured as a looped chain:
Video of the configured running chain:
https://github.com/user-attachments/assets/ff5dfdf4-50e5-45c1-b677-6b4072578393
Thank you again for the quick reply and for sharing the proof-of-concept.
I should clarify that I am only speaking from an ordinary user's experience, not from deep knowledge of the implementation. Your POC and explanation are much more concrete than what I can provide.
From our side, the main value of my comment is simply as supporting evidence from real usage: a custom pet spritesheet can contain many expressive states, but in normal daily use an ordinary user may only see a small part of them, mostly idle and running.
Your configurable
pet.jsonapproach seems to address exactly that gap. I hope the Codex team can consider your work when they have time, so custom pet creators do not need to patch the app bundle.Thanks again for the work you put into this.
I’d like to add a detailed interaction-design proposal for how these richer pet activity states could work emotionally and visually:
Summary
I would love Codex pets to become expressive, stateful task companions rather than purely decorative mascots.
The same selected pet should visibly react to each stage of a task through full-body actions, facial expressions, and short comedic animations. This would make task status easier to understand at a glance while also creating emotional alignment between the user and the agent.
The central idea is:
Why this would be useful
This is not only about making Codex cuter.
A stateful pet could provide:
When users see the pet working hard, they may identify with it as another imperfect worker. Then, when it makes a mistake, the reaction becomes less like “this useless system failed again” and more like “it worked hard and still messed up—honestly, relatable.”
That small amount of emotional identification could genuinely reduce frustration and the urge to complain angrily about ChatGPT online.
Core animation principle
The normal running state must involve real work-like movement.
It should not be limited to a blinking eye, moving ear, wagging tail, or other decorative idle animation.
The pet should visibly perform labor:
This creates both:
The happy, energetic working state is also necessary to create contrast when something later goes wrong.
Proposed task states
1. Task received / preparing to work
For a large task, the pet opens a work order that unfolds into an extremely long scroll.
The scroll keeps rolling across the floor. The pet watches it unroll, freezes for a second, takes a breath, puts on its work gear, and starts.
This communicates that the instruction was received and that the task is genuinely large.
2. Running normally
The pet happily performs visible work:
It should look energetic, confident, and busy—not like an idle mascot.
3. Waiting for user input
The pet sits on the floor with its back turned to the user and draws circles on the ground.
Occasionally, it:
The feeling should be: “I am not pressuring you. I am just very quietly and dramatically waiting.”
4. Waiting for user review
This should be different from waiting for missing input.
After submitting the result, the pet stands beside it and nervously:
This should resemble an employee waiting for feedback after submitting work.
5. High-risk confirmation or permission required
The pet holds an enormous confirmation button with both hands.
The button is far too heavy. Its arms shake, its whole body trembles, and it looks at the user for help—but it cannot put the button down or press it itself.
This would clearly distinguish a high-risk approval request from ordinary missing input.
6. Waiting for an external tool or resource
The pet waits outside a closed door.
It occasionally lifts a small window or hatch in the door, peers inside, closes it, waits, and checks again.
This makes it visually clear that Codex is waiting on an external dependency, not on the user.
7. Missing file or required material
The pet searches boxes and pockets, turns a container upside down, and finds nothing.
It then holds up an incomplete checklist with a confused expression.
This should feel recoverable and puzzled rather than catastrophic.
8. Retry after failure
The pet should visibly carry the consequences of the previous attempt:
It steadies itself, adjusts its equipment, and tries again.
The retry animation should not look identical to the first attempt.
9. Repeating the same failed approach
When the agent becomes stuck in a loop, the pet runs directly into a wall.
It should:
If it repeats the same mistake, it should hesitate, stare at the wall, and somehow run into the same wall again anyway.
10. General task failure
The pet gets struck by lightning and becomes a small smoking charcoal version of itself.
Its facial expression is essential: it should look genuinely shocked and confused, as though thinking:
The emotional goal is shared disbelief. The interface should feel as surprised by the failure as the user is.
11. False completion / validation failure
The pet initially celebrates.
It raises a very long ribbon or banner, which wraps around its body several times until it is surrounded by celebration ribbons.
Then validation fails.
The ribbons suddenly tighten and pull backward, tying the pet up. It is dragged off balance and falls face-first onto the ground.
Afterward, it crawls back up, dusty and embarrassed, and flips a sign from:
“Complete”
to:
“Not yet”
This is especially appropriate when the agent announces completion before verifying its output.
12. Partial success
The pet drags the result into place but knows that something is incomplete.
After delivering it, the pet:
It should communicate: “Most of it is here, but I know this is not fully complete.”
13. User-cancelled task
The pet is working when it suddenly performs an emergency stop.
The cart, boxes, or files slide forward, and the pet catches them.
It then turns toward the user with a confused expression, as though asking:
Cancellation should not look like failure.
14. Rate limit or forced pause
The pet encounters a closed gate or temporarily sealed work area.
It realizes that work cannot continue and immediately takes advantage of the break rather than acting unhappy about being allowed to rest.
It could:
No real employee would resent being allowed to rest.
15. True completion
After the task is genuinely finished and validated, the pet:
This should feel like the conclusion of a long work shift, not just a generic celebration animation.
Design principles
Keep the same pet across all states
The emotional effect depends on users feeling that the same chosen companion is experiencing the task with them.
Changing to a different mascot for each state would weaken that attachment.
Use full-body action and expressive faces
The pet’s state should be understandable from its silhouette, movement, and expression, even without reading text.
Preserve strong contrast
The cheerful running state must feel energetic so that failures, retries, embarrassment, and exhaustion are funnier and more emotionally effective.
Do not hide technical information
The animation should supplement—not replace—clear status text, error messages, progress indicators, and actionable recovery instructions.
Make it optional and accessible
Users should be able to:
Closing thought
A good failure animation does not merely make an error “cute.”
It makes the interface visibly acknowledge:
That shared emotional reaction could make Codex feel more transparent, more companionable, and much less infuriating during long or difficult tasks.
On Codex Desktop 26.715.72359, build 5718, the active pet animation only plays about 1–3 cycles before falling back to idle even while the task is still running. Moving the pointer over the pet briefly retriggers the active animation, after which it stops again. Repeated hover produces play/stop/play/stop behavior. Expected: the active animation should loop continuously until the task state changes.
Reproduced on Codex Desktop for Windows, version
26.803.5235.0.Observed behavior
With a validated V2 custom pet spritesheet:
idle) uses the normal character form;running) uses a visually distinct active form.During one continuous task, the pet only switches to the
runninganimation briefly while assistant text is streaming. During reasoning/thinking and command execution, it falls back to theidleanimation even though the task is still active. This makes the pet appear idle for most of the actual task execution.Expected behavior
The pet should remain in the
runningmascot state for the entire active turn, including:It should return to
idleonly after the turn is complete.Additional verification
The custom atlas validates with zero errors and warnings, and row 7 is rendered correctly whenever the app actually selects
running. This indicates that the problem is not the custom spritesheet or pet ID.Inspection of the shipped renderer bundle confirms that the atlas mapping is correct (
idle= row 0,running= row 7). The visible behavior suggests that some reasoning/tool activity notifications are resolving to the informational/idle mascot state instead of preserving the active turn'srunningstate.This is still reproducible in
26.803.5235.0, so the active-state fallback reported above appears not to be fixed yet.I would like to add a concrete production case for the per-state frame-count part of this request, and one acceptance criterion that is not yet explicit in the issue: a custom state needs to be able to contain more than eight frames.
Environment
26.810.52044, build6662192 × 208cellsWhat we ran into
We are producing an illustrated full-body character rather than a simple pixel mascot. The character has long hair, a cape, a skirt, a tie, arms, and legs, all of which change silhouette and overlap during a run cycle.
The current
running-rightrow can contain only eight playable cells. In the observed runtime, those eight frames play as seven frames at120msplus a final frame at220ms, for a1060msloop. That is enough for a compact pixel gait, but it leaves very large pose-to-pose steps for a detailed illustrated character.This is not just a poorly constructed row. We rebuilt the gait from explicit contact/down/push/up phases and then repaired the worst transition:
-15.44px / +11.27pxto-6.88px / +2.71pxin alpha-centroid displacement;15.44pxto10.58px;192 × 208RGBA frame with transparent borders and no clipping;The result is visibly better, but it still reads as stepping because eight frames must cover the entire run cycle. Shortening the durations only makes the same spatial jumps happen faster. Distorting the key poses to reduce the jumps damages the gait and the character design.
Missing capability
The manifest proposal in this issue already includes
frameCountand timing fields, but the current atlas has eight columns. Please makeframeCountcapable of exceeding eight by also allowing flexible atlas geometry or per-state sprite strips.For our case, the useful target is 16 frames at roughly
60–65msper frame. This preserves an approximately one-second gait cycle while halving the pose interval. Sixteen frames are not a quality guarantee; they provide the temporal sampling budget needed for complex silhouettes.An illustrative shape could be:
The field names and storage format are only illustrative. Per-state strips would also solve the problem without widening every row. The important point is to decouple logical display size, physical atlas layout, and per-state frame count.
Suggested acceptance criteria
65msmeasures approximately1040msper loop and is not replaced by built-in timing.220ms.This would turn the existing
frameCountrequest into a real escape hatch from the fixed eight-frame ceiling, not only a way to select fewer populated cells inside the current grid.Motion comparison
Equal timing — 8 frames at 100ms each:
<img width="576" height="624" alt="Image" src="https://github.com/user-attachments/assets/38029f66-1970-41d3-9bbf-68e45ec31eb2" />
Observed Codex runtime timing — 7 frames at 120ms plus a 220ms final frame:
<img width="576" height="624" alt="Image" src="https://github.com/user-attachments/assets/65aacb81-ae06-41ab-8ec2-635522e0c8c9" />