diff --git a/src/web-ui/public/agent-companion-pets/bitblob/README.md b/src/web-ui/public/agent-companion-pets/bitblob/README.md index 5a770fd9a8..803d30586f 100644 --- a/src/web-ui/public/agent-companion-pets/bitblob/README.md +++ b/src/web-ui/public/agent-companion-pets/bitblob/README.md @@ -19,6 +19,22 @@ Each state was generated as its own grounded strip: quiet breathing/blinking; ri Deterministic extraction, registration, composition and edge cleanup use the skill's scripts. Jumping uses the supported shared-viewport extraction to preserve the generated vertical arc; other standard rows use connected-component extraction. +## Consistent state transitions + +The packaged atlas re-registers the existing artwork across all states, including +the neutral slot and look directions. Each cell is uniformly scaled against a +15,000-pixel alpha-weighted silhouette area, retaining 15% of its original +within-row area variation for breathing and squash. This avoids using the full +antenna height or a raised hand as a proxy for body size. The lower-body center +is aligned to x=95.5 and the baseline to y=194 in each 192×208 cell. Jump frames +use offsets of 0, 4, 16, 6, 0 pixels from that baseline. + +This corrects the former half-sized jump, oversized working/waiting frames and +per-frame size drift during review. The original poses, frame order, v2 layout +and transparency remain intact. BitBlob plays only the atlas animation in the +shared renderer; additional CSS breathing, hover squash and work/drag transforms +are disabled for this built-in pet so they do not compound its authored motion. + ## Verification Validation covers the v2 geometry, populated and unused cells, alpha/chroma cleanup, frame clipping and component extraction. Independent visual review covers all nine animations, every look direction and continuity around the row boundaries. Three isolated reviewers classify the randomized horizontal/vertical direction sheet; cardinal ambiguity blocks packaging. Runtime/transport integration checks belong to the companion feature tests rather than the image pipeline. diff --git a/src/web-ui/public/agent-companion-pets/bitblob/spritesheet.webp b/src/web-ui/public/agent-companion-pets/bitblob/spritesheet.webp index 26838c0660..4686e0c4ee 100644 Binary files a/src/web-ui/public/agent-companion-pets/bitblob/spritesheet.webp and b/src/web-ui/public/agent-companion-pets/bitblob/spritesheet.webp differ diff --git a/src/web-ui/src/flow_chat/components/AgentCompanionPet.test.tsx b/src/web-ui/src/flow_chat/components/AgentCompanionPet.test.tsx index 12813777aa..c549fb7144 100644 --- a/src/web-ui/src/flow_chat/components/AgentCompanionPet.test.tsx +++ b/src/web-ui/src/flow_chat/components/AgentCompanionPet.test.tsx @@ -51,6 +51,25 @@ function sprite() { } describe('pet sprite renderer', () => { + it('keeps built-in BitBlob motion in the atlas across session states', async () => { + const bitblob = { ...pet, id: 'bitblob' }; + for (const mood of ['rest', 'hover', 'working', 'waiting', 'analyzing', 'dragging'] as const) { + await act(async () => root.render()); + expect(sprite().style.animationName).toBe('openbitfun-petdex-walk'); + expect(sprite().style.imageRendering).toBe('auto'); + } + await act(async () => root.render()); + expect(sprite().dataset.petAction).toBe('jumping'); + expect(sprite().style.animationDuration).toBe('1.2s'); + await act(async () => root.render()); + expect(sprite().style.animation).toBe('none'); + // A user pet with the same id must retain its own/default presentation. + await act(async () => root.render()); + expect(sprite().style.animationName).toBe(''); + await act(async () => root.render()); + expect(sprite().style.animationName).toBe(''); + }); + it.each([1, 2])('plays all three standard actions with v%s frame geometry and keeps drag priority', async version => { vi.useFakeTimers(); vi.stubGlobal('Image', class { diff --git a/src/web-ui/src/flow_chat/components/AgentCompanionPet.tsx b/src/web-ui/src/flow_chat/components/AgentCompanionPet.tsx index 0ea7780c07..64099db191 100644 --- a/src/web-ui/src/flow_chat/components/AgentCompanionPet.tsx +++ b/src/web-ui/src/flow_chat/components/AgentCompanionPet.tsx @@ -483,6 +483,9 @@ export const AgentCompanionPet: React.FC = ({ className={`openbitfun-agent-companion-pet__petdex openbitfun-agent-companion-pet__petdex--${mood}`} style={{ imageRendering: pet.source === 'preset' && pet.id === 'bitblob' ? 'auto' : undefined, + // BitBlob's atlas already contains breathing, squash and movement. + // Extra mood transforms change its apparent size when a session changes state. + animationName: pet.source === 'preset' && pet.id === 'bitblob' ? 'openbitfun-petdex-walk' : undefined, '--openbitfun-petdex-src': `url("${petSrc}")`, '--openbitfun-petdex-row': row, '--openbitfun-petdex-frames': frames,