Support configurable custom pet animation sequences and activity events

Open 💬 7 comments Opened May 3, 2026 by hlky

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

  1. Pass optional animation config through from custom pet manifests.
  2. Support per-state row/frame/timing config:
  • row / rowIndex
  • frames / frameCount
  • durationMs / frameDurationMs
  • lastFrameDurationMs
  • slowdown
  1. Use detected non-empty row cells when frames is omitted, within the existing atlas geometry.
  2. Support sequence chains per state.
  3. Support chain playback modes:
  • idleFallback: play the active chain once, then loop the configured idle chain
  • loop: loop the active chain until the app state changes
  • once: play once and hold the final frame
  1. Support configurable event mappings, starting with hover and drag directions.
  2. Expose richer pet animation states for agent activity where possible:
  • thinking
  • editing
  • edited
  • running / command running
  • ran / command completed
  • review

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 animation keep 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.

View original on GitHub ↗

7 Comments

Lee-take · 3 months ago

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:

  1. the idle pose, and
  2. the running pose, mainly while the pet moves.

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:

  • a simple way to preview or manually trigger each pet state;
  • documentation for when each animation row is used;
  • a lightweight debug/test mode for custom pet creators;
  • optional personality idle behavior, so a custom pet can occasionally cycle through safe actions such as waving, annoyed, phone-checking, or review poses while idle.

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.

hlky · 3 months ago

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:

"chains": {
  "idle": [
    "review"
  ],
  "running": {
    "mode": "loop",
    "sequence": [
      "waving",
      "idle",
      "idle",
      "running-left",
      "running-right",
      "idle",
      "idle",
      "jumping",
      "idle",
      "failed",
      "idle",
      "review",
      "review"
    ]
  }
}

Video of the configured running chain:

https://github.com/user-attachments/assets/ff5dfdf4-50e5-45c1-b677-6b4072578393

Lee-take · 3 months ago

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.json approach 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.

fefaith7 · 1 month ago

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:

The pet should feel like a tiny overworked coworker whose body language turns task states into emotional, comedic micro-stories.

Why this would be useful

This is not only about making Codex cuter.

A stateful pet could provide:

  • A peripheral task-status indicator
  • A clearer distinction between working, waiting, blocked, retrying, partially completed, and truly completed
  • A stronger sense that the agent is genuinely doing work for the user
  • Emotional relief when the agent fails
  • A sense of companionship during long-running tasks

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:

  • Carrying boxes
  • Pushing a file cart
  • Hauling documents
  • Dragging packages
  • Running back and forth with data
  • Sweating, pausing briefly, and returning to work

This creates both:

  1. Agency: “Something is actively working for me.”
  2. Identification: “This tiny overworked creature looks a little like me.”

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:

  • Carrying boxes
  • Pushing carts
  • Moving files
  • Sorting documents
  • Running between workstations

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:

  1. Turns its head to peek at the user
  2. Quickly raises a small “Your turn” or “Need input” sign
  3. Immediately turns back around
  4. Continues drawing circles

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:

  • Peeks around the left and right sides
  • Watches the user’s reaction
  • Twists its hands or feet
  • Fidgets in place
  • Keeps an eraser or correction tool ready

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:

  • Bandages
  • Scratches
  • Dirt marks
  • A swollen bump on its head
  • A bent or crooked helmet

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:

  1. Accelerate confidently
  2. Hit the wall
  3. Flatten completely against it like a pancake
  4. Remain stuck for a moment
  5. Slowly slide down the wall
  6. Collapse into a crumpled shape on the floor

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:

“Wait—what? How did this happen?”

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:

  • Looks guilty
  • Avoids eye contact
  • Touches its fingertips together nervously
  • Glances at the damaged or incomplete part
  • Presents a small warning sign

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:

“Oh—are we stopping now?”

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:

  • Sit down
  • Open a lunchbox
  • Stretch out comfortably
  • Nap beside its tools
  • Look completely satisfied with the unexpected break

No real employee would resent being allowed to rest.

15. True completion

After the task is genuinely finished and validated, the pet:

  1. Delivers the completed result
  2. Stamps it with a clear PASS mark
  3. Looks proud for one second
  4. Falls straight backward
  5. Lies with all four limbs spread out
  6. Exposes its round belly
  7. Falls asleep immediately
  8. Snores with a nose bubble

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:

  • Turn pets off
  • Reduce motion
  • Disable sound effects
  • Choose subtle or highly expressive animation modes

Closing thought

A good failure animation does not merely make an error “cute.”

It makes the interface visibly acknowledge:

“Yes, this went wrong. Yes, it is ridiculous. I am experiencing the disaster with you.”

That shared emotional reaction could make Codex feel more transparent, more companionable, and much less infuriating during long or difficult tasks.

tn9design · 1 month ago

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.

turboinfo-1 · 21 days ago

Reproduced on Codex Desktop for Windows, version 26.803.5235.0.

Observed behavior

With a validated V2 custom pet spritesheet:

  • row 0 (idle) uses the normal character form;
  • row 7 (running) uses a visually distinct active form.

During one continuous task, the pet only switches to the running animation briefly while assistant text is streaming. During reasoning/thinking and command execution, it falls back to the idle animation 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 running mascot state for the entire active turn, including:

  • reasoning/thinking;
  • command execution and tool calls;
  • assistant text streaming.

It should return to idle only 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's running state.

This is still reproducible in 26.803.5235.0, so the active-state fallback reported above appears not to be fixed yet.

wuyak · 8 days ago

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

  • Codex Desktop for macOS on Apple Silicon
  • Version 26.810.52044, build 6662
  • Custom v2 illustrated pet using 192 × 208 cells

What 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-right row can contain only eight playable cells. In the observed runtime, those eight frames play as seven frames at 120ms plus a final frame at 220ms, for a 1060ms loop. 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:

  • the two transitions around the repaired frame improved from -15.44px / +11.27px to -6.88px / +2.71px in alpha-centroid displacement;
  • the maximum adjacent displacement over the full loop dropped from 15.44px to 10.58px;
  • every source frame is an independent 192 × 208 RGBA frame with transparent borders and no clipping;
  • slicing the assembled row reproduces the source frames pixel-for-pixel.

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 frameCount and timing fields, but the current atlas has eight columns. Please make frameCount capable 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–65ms per 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:

{
  "spritesheetPath": "spritesheet.webp",
  "atlas": {
    "columns": 16,
    "rows": 11,
    "cellWidth": 192,
    "cellHeight": 208
  },
  "animation": {
    "states": {
      "running-right": {
        "row": 1,
        "frameCount": 16,
        "frameDurationMs": 65,
        "loop": true
      },
      "running-left": {
        "row": 2,
        "frameCount": 16,
        "frameDurationMs": 65,
        "loop": true
      }
    }
  }
}

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

  1. Existing v1/v2 pets without animation metadata remain unchanged.
  2. A custom state can declare and visibly play all 16 frames; frames 9–16 are not ignored.
  3. Different states can use different frame counts, such as idle 6, waving 4, and running-right 16.
  4. A 16-frame state configured at 65ms measures approximately 1040ms per loop and is not replaced by built-in timing.
  5. Optional per-frame or final-frame timing is honored; the last frame is not forced to 220ms.
  6. Package validation, creator preview, and actual desktop playback interpret the same manifest consistently.
  7. Reduce Motion continues to work.
  8. No app-bundle patching or re-signing is required.

This would turn the existing frameCount request 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" />