diff --git a/web/src/components/Placeholder/pieces/DESIGN.md b/web/src/components/Placeholder/pieces/DESIGN.md
index 42b49f774..273c3cf58 100644
--- a/web/src/components/Placeholder/pieces/DESIGN.md
+++ b/web/src/components/Placeholder/pieces/DESIGN.md
@@ -46,3 +46,4 @@ Avoid padding an animation with duplicate frames just to hit a standard count. A
- `OwlBlink.svg`: five-frame blink/idle strip with breathing wings, blink, and ear-feather settle.
- `FalconIdle.svg`: four-frame idle strip with breathing, blink, alert head shift, and tail flick.
+- `WoodpeckerPeck.svg`: six-frame tree-trunk peck strip with red crest, chisel beak, barred wing, impact chips, recoil, and settle.
diff --git a/web/src/components/Placeholder/pieces/OwlBlink.svg b/web/src/components/Placeholder/pieces/OwlBlink.svg
index 9633f07ad..db2142846 100644
--- a/web/src/components/Placeholder/pieces/OwlBlink.svg
+++ b/web/src/components/Placeholder/pieces/OwlBlink.svg
@@ -3,9 +3,9 @@
A five-frame 32 by 32 pixel owl idle and blink animation strip.
@@ -32,17 +33,17 @@
-
-
+
+
-
+
-
+
@@ -68,8 +69,8 @@
-
-
+
+
diff --git a/web/src/components/Placeholder/pieces/WoodpeckerPeck.svg b/web/src/components/Placeholder/pieces/WoodpeckerPeck.svg
new file mode 100644
index 000000000..05e2a0ef5
--- /dev/null
+++ b/web/src/components/Placeholder/pieces/WoodpeckerPeck.svg
@@ -0,0 +1,162 @@
+
diff --git a/web/src/components/Placeholder/tileSprites.ts b/web/src/components/Placeholder/tileSprites.ts
index 8cce29fec..b7326b595 100644
--- a/web/src/components/Placeholder/tileSprites.ts
+++ b/web/src/components/Placeholder/tileSprites.ts
@@ -1,5 +1,6 @@
import FalconIdle from "./pieces/FalconIdle.svg?url";
import OwlBlink from "./pieces/OwlBlink.svg?url";
+import WoodpeckerPeck from "./pieces/WoodpeckerPeck.svg?url";
export interface TileSprite {
name: string;
@@ -27,6 +28,14 @@ export const TILE_SPRITES: TileSprite[] = [
frames: 4,
duration: 960,
},
+ {
+ name: "WoodpeckerPeck",
+ src: WoodpeckerPeck,
+ frameWidth: 32,
+ frameHeight: 32,
+ frames: 6,
+ duration: 1080,
+ },
];
export function pickTileSprite(): TileSprite {
diff --git a/web/tests/placeholder-pool.test.ts b/web/tests/placeholder-pool.test.ts
index 9944ce985..98503c65c 100644
--- a/web/tests/placeholder-pool.test.ts
+++ b/web/tests/placeholder-pool.test.ts
@@ -4,14 +4,15 @@ import { DEFAULT_MESSAGES, type PlaceholderVariant } from "@/components/Placehol
describe("TILE_SPRITES integrity", () => {
it("registers 32px by 32px sprite strips with animation-specific frame counts", () => {
- expect(TILE_SPRITES.map((sprite) => sprite.name)).toEqual(["OwlBlink", "FalconIdle"]);
+ expect(TILE_SPRITES.map((sprite) => sprite.name)).toEqual(["OwlBlink", "FalconIdle", "WoodpeckerPeck"]);
expect(TILE_SPRITES.map((sprite) => [sprite.name, sprite.frames])).toEqual([
["OwlBlink", 5],
["FalconIdle", 4],
+ ["WoodpeckerPeck", 6],
]);
for (const sprite of TILE_SPRITES) {
- expect(sprite.name).toMatch(/^[A-Z][A-Za-z]+(Idle|Hop|Blink|Drift|Flutter|Hover)$/);
+ expect(sprite.name).toMatch(/^[A-Z][A-Za-z]+(Idle|Hop|Blink|Drift|Flutter|Hover|Peck)$/);
expect(sprite.frameWidth).toBe(32);
expect(sprite.frameHeight).toBe(32);
expect(sprite.frames).toBeGreaterThanOrEqual(2);