From 579967a302b8d185d62e2a787671c4497acffdd6 Mon Sep 17 00:00:00 2001 From: Idrees Hassan Date: Sun, 18 Jan 2026 18:10:43 -0500 Subject: [PATCH] Rename color constants enum --- dist/extension.zip | Bin 149589 -> 149636 bytes dist/extension/birb.js | 256 ++++++++++++++++++----------------- dist/obsidian/main.js | 256 ++++++++++++++++++----------------- dist/userscript/birb.user.js | 256 ++++++++++++++++++----------------- dist/web/birb.embed.js | 256 ++++++++++++++++++----------------- dist/web/birb.js | 256 ++++++++++++++++++----------------- src/animation/frame.js | 6 +- src/animation/sprites.js | 246 +++++++++++++++++---------------- src/application.js | 8 +- 9 files changed, 788 insertions(+), 752 deletions(-) diff --git a/dist/extension.zip b/dist/extension.zip index 8e973139c8a4fe11e0df27c9787c7b69d7b4bb25..36f701089e223e20f93c729659742d13a184c5a5 100644 GIT binary patch delta 26148 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 diff --git a/dist/extension/birb.js b/dist/extension/birb.js index bf95dbd..d1df198 100644 --- a/dist/extension/birb.js +++ b/dist/extension/birb.js @@ -226,8 +226,11 @@ return document.documentElement.clientHeight; } - /** Indicators for parts of the base bird sprite sheet */ - const Sprite = { + /** + * Palette color names + * @type {Record} + */ + const PALETTE = { THEME_HIGHLIGHT: "theme-highlight", TRANSPARENT: "transparent", OUTLINE: "outline", @@ -248,25 +251,28 @@ FEATHER_SPINE: "feather-spine", }; - /** @type {Record} */ + /** + * Mapping of sprite sheet colors to palette colors + * @type {Record} + */ const SPRITE_SHEET_COLOR_MAP = { - "transparent": Sprite.TRANSPARENT, - "#ffffff": Sprite.BORDER, - "#000000": Sprite.OUTLINE, - "#010a19": Sprite.BEAK, - "#190301": Sprite.EYE, - "#af8e75": Sprite.FOOT, - "#639bff": Sprite.FACE, - "#99e550": Sprite.HOOD, - "#d95763": Sprite.NOSE, - "#f8b143": Sprite.BELLY, - "#ec8637": Sprite.UNDERBELLY, - "#578ae6": Sprite.WING, - "#326ed9": Sprite.WING_EDGE, - "#c82e2e": Sprite.HEART, - "#501a1a": Sprite.HEART_BORDER, - "#ff6b6b": Sprite.HEART_SHINE, - "#373737": Sprite.FEATHER_SPINE, + "transparent": PALETTE.TRANSPARENT, + "#ffffff": PALETTE.BORDER, + "#000000": PALETTE.OUTLINE, + "#010a19": PALETTE.BEAK, + "#190301": PALETTE.EYE, + "#af8e75": PALETTE.FOOT, + "#639bff": PALETTE.FACE, + "#99e550": PALETTE.HOOD, + "#d95763": PALETTE.NOSE, + "#f8b143": PALETTE.BELLY, + "#ec8637": PALETTE.UNDERBELLY, + "#578ae6": PALETTE.WING, + "#326ed9": PALETTE.WING_EDGE, + "#c82e2e": PALETTE.HEART, + "#501a1a": PALETTE.HEART_BORDER, + "#ff6b6b": PALETTE.HEART_SHINE, + "#373737": PALETTE.FEATHER_SPINE, }; class BirdType { @@ -280,20 +286,20 @@ this.name = name; this.description = description; const defaultColors = { - [Sprite.TRANSPARENT]: "transparent", - [Sprite.OUTLINE]: "#000000", - [Sprite.BORDER]: "#ffffff", - [Sprite.BEAK]: "#000000", - [Sprite.EYE]: "#000000", - [Sprite.HEART]: "#c82e2e", - [Sprite.HEART_BORDER]: "#501a1a", - [Sprite.HEART_SHINE]: "#ff6b6b", - [Sprite.FEATHER_SPINE]: "#373737", - [Sprite.HOOD]: colors.face, - [Sprite.NOSE]: colors.face, + [PALETTE.TRANSPARENT]: "transparent", + [PALETTE.OUTLINE]: "#000000", + [PALETTE.BORDER]: "#ffffff", + [PALETTE.BEAK]: "#000000", + [PALETTE.EYE]: "#000000", + [PALETTE.HEART]: "#c82e2e", + [PALETTE.HEART_BORDER]: "#501a1a", + [PALETTE.HEART_SHINE]: "#ff6b6b", + [PALETTE.FEATHER_SPINE]: "#373737", + [PALETTE.HOOD]: colors.face, + [PALETTE.NOSE]: colors.face, }; /** @type {Record} */ - this.colors = { ...defaultColors, ...colors, [Sprite.THEME_HIGHLIGHT]: colors[Sprite.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; + this.colors = { ...defaultColors, ...colors, [PALETTE.THEME_HIGHLIGHT]: colors[PALETTE.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; this.tags = tags; } } @@ -302,127 +308,127 @@ const SPECIES = { bluebird: new BirdType("Eastern Bluebird", "Native to North American and very social, though can be timid around people.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#639bff", - [Sprite.BELLY]: "#f8b143", - [Sprite.UNDERBELLY]: "#ec8637", - [Sprite.WING]: "#578ae6", - [Sprite.WING_EDGE]: "#326ed9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#639bff", + [PALETTE.BELLY]: "#f8b143", + [PALETTE.UNDERBELLY]: "#ec8637", + [PALETTE.WING]: "#578ae6", + [PALETTE.WING_EDGE]: "#326ed9", }), shimaEnaga: new BirdType("Shima Enaga", "Small, fluffy birds found in the snowy regions of Japan, these birds are highly sought after by ornithologists and nature photographers.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffffff", - [Sprite.BELLY]: "#ebe9e8", - [Sprite.UNDERBELLY]: "#ebd9d0", - [Sprite.WING]: "#f3d3c1", - [Sprite.WING_EDGE]: "#2d2d2d", - [Sprite.THEME_HIGHLIGHT]: "#d7ac93", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffffff", + [PALETTE.BELLY]: "#ebe9e8", + [PALETTE.UNDERBELLY]: "#ebd9d0", + [PALETTE.WING]: "#f3d3c1", + [PALETTE.WING_EDGE]: "#2d2d2d", + [PALETTE.THEME_HIGHLIGHT]: "#d7ac93", }), tuftedTitmouse: new BirdType("Tufted Titmouse", "Native to the eastern United States, full of personality, and notably my wife's favorite bird.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#c7cad7", - [Sprite.BELLY]: "#e4e5eb", - [Sprite.UNDERBELLY]: "#d7cfcb", - [Sprite.WING]: "#b1b5c5", - [Sprite.WING_EDGE]: "#9d9fa9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#c7cad7", + [PALETTE.BELLY]: "#e4e5eb", + [PALETTE.UNDERBELLY]: "#d7cfcb", + [PALETTE.WING]: "#b1b5c5", + [PALETTE.WING_EDGE]: "#9d9fa9", }, ["tuft"]), europeanRobin: new BirdType("European Robin", "Native to western Europe, this is the quintessential robin. Quite friendly, you'll often find them searching for worms.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffaf34", - [Sprite.HOOD]: "#aaa094", - [Sprite.BELLY]: "#ffaf34", - [Sprite.UNDERBELLY]: "#babec2", - [Sprite.WING]: "#aaa094", - [Sprite.WING_EDGE]: "#888580", - [Sprite.THEME_HIGHLIGHT]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffaf34", + [PALETTE.HOOD]: "#aaa094", + [PALETTE.BELLY]: "#ffaf34", + [PALETTE.UNDERBELLY]: "#babec2", + [PALETTE.WING]: "#aaa094", + [PALETTE.WING_EDGE]: "#888580", + [PALETTE.THEME_HIGHLIGHT]: "#ffaf34", }), redCardinal: new BirdType("Red Cardinal", "Native to the eastern United States, this strikingly red bird is hard to miss.", { - [Sprite.BEAK]: "#d93619", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#31353d", - [Sprite.HOOD]: "#e83a1b", - [Sprite.BELLY]: "#e83a1b", - [Sprite.UNDERBELLY]: "#dc3719", - [Sprite.WING]: "#d23215", - [Sprite.WING_EDGE]: "#b1321c", + [PALETTE.BEAK]: "#d93619", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#31353d", + [PALETTE.HOOD]: "#e83a1b", + [PALETTE.BELLY]: "#e83a1b", + [PALETTE.UNDERBELLY]: "#dc3719", + [PALETTE.WING]: "#d23215", + [PALETTE.WING_EDGE]: "#b1321c", }, ["tuft"]), americanGoldfinch: new BirdType("American Goldfinch", "Coloured a brilliant yellow, this bird feeds almost entirely on the seeds of plants such as thistle, sunflowers, and coneflowers.", { - [Sprite.BEAK]: "#ffaf34", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#fff255", - [Sprite.NOSE]: "#383838", - [Sprite.HOOD]: "#383838", - [Sprite.BELLY]: "#fff255", - [Sprite.UNDERBELLY]: "#f5ea63", - [Sprite.WING]: "#e8e079", - [Sprite.WING_EDGE]: "#191919", - [Sprite.THEME_HIGHLIGHT]: "#ffcc00" + [PALETTE.BEAK]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#fff255", + [PALETTE.NOSE]: "#383838", + [PALETTE.HOOD]: "#383838", + [PALETTE.BELLY]: "#fff255", + [PALETTE.UNDERBELLY]: "#f5ea63", + [PALETTE.WING]: "#e8e079", + [PALETTE.WING_EDGE]: "#191919", + [PALETTE.THEME_HIGHLIGHT]: "#ffcc00" }), barnSwallow: new BirdType("Barn Swallow", "Agile birds that often roost in man-made structures, these birds are known to build nests near Ospreys for protection.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#db7c4d", - [Sprite.BELLY]: "#f7e1c9", - [Sprite.UNDERBELLY]: "#ebc9a3", - [Sprite.WING]: "#2252a9", - [Sprite.WING_EDGE]: "#1c448b", - [Sprite.HOOD]: "#2252a9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#db7c4d", + [PALETTE.BELLY]: "#f7e1c9", + [PALETTE.UNDERBELLY]: "#ebc9a3", + [PALETTE.WING]: "#2252a9", + [PALETTE.WING_EDGE]: "#1c448b", + [PALETTE.HOOD]: "#2252a9", }), mistletoebird: new BirdType("Mistletoebird", "Native to Australia, these birds eat mainly mistletoe and in turn spread the seeds far and wide.", { - [Sprite.FOOT]: "#6c6a7c", - [Sprite.FACE]: "#352e6d", - [Sprite.BELLY]: "#fd6833", - [Sprite.UNDERBELLY]: "#e6e1d8", - [Sprite.WING]: "#342b7c", - [Sprite.WING_EDGE]: "#282065", + [PALETTE.FOOT]: "#6c6a7c", + [PALETTE.FACE]: "#352e6d", + [PALETTE.BELLY]: "#fd6833", + [PALETTE.UNDERBELLY]: "#e6e1d8", + [PALETTE.WING]: "#342b7c", + [PALETTE.WING_EDGE]: "#282065", }), redAvadavat: new BirdType("Red Avadavat", "Native to India and southeast Asia, these birds are also known as Strawberry Finches due to their speckled plumage.", { - [Sprite.BEAK]: "#f71919", - [Sprite.FOOT]: "#af7575", - [Sprite.FACE]: "#cb092b", - [Sprite.BELLY]: "#ae1724", - [Sprite.UNDERBELLY]: "#831b24", - [Sprite.WING]: "#7e3030", - [Sprite.WING_EDGE]: "#490f0f", + [PALETTE.BEAK]: "#f71919", + [PALETTE.FOOT]: "#af7575", + [PALETTE.FACE]: "#cb092b", + [PALETTE.BELLY]: "#ae1724", + [PALETTE.UNDERBELLY]: "#831b24", + [PALETTE.WING]: "#7e3030", + [PALETTE.WING_EDGE]: "#490f0f", }), scarletRobin: new BirdType("Scarlet Robin", "Native to Australia, this striking robin can be found in Eucalyptus forests.", { - [Sprite.FOOT]: "#494949", - [Sprite.FACE]: "#3d3d3d", - [Sprite.BELLY]: "#fc5633", - [Sprite.UNDERBELLY]: "#dcdcdc", - [Sprite.WING]: "#2b2b2b", - [Sprite.WING_EDGE]: "#ebebeb", - [Sprite.THEME_HIGHLIGHT]: "#fc5633", + [PALETTE.FOOT]: "#494949", + [PALETTE.FACE]: "#3d3d3d", + [PALETTE.BELLY]: "#fc5633", + [PALETTE.UNDERBELLY]: "#dcdcdc", + [PALETTE.WING]: "#2b2b2b", + [PALETTE.WING_EDGE]: "#ebebeb", + [PALETTE.THEME_HIGHLIGHT]: "#fc5633", }), americanRobin: new BirdType("American Robin", "While not a true robin, this social North American bird is so named due to its orange coloring. It seems unbothered by nearby humans.", { - [Sprite.BEAK]: "#e89f30", - [Sprite.FOOT]: "#9f8075", - [Sprite.FACE]: "#2d2d2d", - [Sprite.BELLY]: "#eb7a3a", - [Sprite.UNDERBELLY]: "#eb7a3a", - [Sprite.WING]: "#444444", - [Sprite.WING_EDGE]: "#232323", - [Sprite.THEME_HIGHLIGHT]: "#eb7a3a", + [PALETTE.BEAK]: "#e89f30", + [PALETTE.FOOT]: "#9f8075", + [PALETTE.FACE]: "#2d2d2d", + [PALETTE.BELLY]: "#eb7a3a", + [PALETTE.UNDERBELLY]: "#eb7a3a", + [PALETTE.WING]: "#444444", + [PALETTE.WING_EDGE]: "#232323", + [PALETTE.THEME_HIGHLIGHT]: "#eb7a3a", }), carolinaWren: new BirdType("Carolina Wren", "Native to the eastern United States, these little birds are known for their curious and energetic nature.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#edc7a9", - [Sprite.NOSE]: "#f7eee5", - [Sprite.HOOD]: "#c58a5b", - [Sprite.BELLY]: "#e1b796", - [Sprite.UNDERBELLY]: "#c79e7c", - [Sprite.WING]: "#c58a5b", - [Sprite.WING_EDGE]: "#866348", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#edc7a9", + [PALETTE.NOSE]: "#f7eee5", + [PALETTE.HOOD]: "#c58a5b", + [PALETTE.BELLY]: "#e1b796", + [PALETTE.UNDERBELLY]: "#c79e7c", + [PALETTE.WING]: "#c58a5b", + [PALETTE.WING_EDGE]: "#866348", }), }; @@ -460,7 +466,7 @@ this.pixels = layers[0].pixels.map(row => row.slice()); // Pad from top with transparent pixels while (this.pixels.length < maxHeight) { - this.pixels.unshift(new Array(this.pixels[0].length).fill(Sprite.TRANSPARENT)); + this.pixels.unshift(new Array(this.pixels[0].length).fill(PALETTE.TRANSPARENT)); } // Combine layers for (let i = 1; i < layers.length; i++) { @@ -469,7 +475,7 @@ let topMargin = maxHeight - layerPixels.length; for (let y = 0; y < layerPixels.length; y++) { for (let x = 0; x < layerPixels[y].length; x++) { - this.pixels[y + topMargin][x] = layerPixels[y][x] !== Sprite.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; + this.pixels[y + topMargin][x] = layerPixels[y][x] !== PALETTE.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; } } } @@ -2400,7 +2406,7 @@ function switchSpecies(type) { currentSpecies = type; // Update CSS variable --birb-highlight to be wing color - document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[Sprite.THEME_HIGHLIGHT]); + document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[PALETTE.THEME_HIGHLIGHT]); save(); } @@ -2668,7 +2674,7 @@ const b = pixels[index + 2]; const a = pixels[index + 3]; if (a === 0) { - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); continue; } const hex = `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; @@ -2678,7 +2684,7 @@ } if (SPRITE_SHEET_COLOR_MAP[hex] === undefined) { error(`Unknown color: ${hex}`); - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); } row.push(SPRITE_SHEET_COLOR_MAP[hex]); } diff --git a/dist/obsidian/main.js b/dist/obsidian/main.js index e3154b5..255ba72 100644 --- a/dist/obsidian/main.js +++ b/dist/obsidian/main.js @@ -231,8 +231,11 @@ module.exports = class PocketBird extends Plugin { return document.documentElement.clientHeight; } - /** Indicators for parts of the base bird sprite sheet */ - const Sprite = { + /** + * Palette color names + * @type {Record} + */ + const PALETTE = { THEME_HIGHLIGHT: "theme-highlight", TRANSPARENT: "transparent", OUTLINE: "outline", @@ -253,25 +256,28 @@ module.exports = class PocketBird extends Plugin { FEATHER_SPINE: "feather-spine", }; - /** @type {Record} */ + /** + * Mapping of sprite sheet colors to palette colors + * @type {Record} + */ const SPRITE_SHEET_COLOR_MAP = { - "transparent": Sprite.TRANSPARENT, - "#ffffff": Sprite.BORDER, - "#000000": Sprite.OUTLINE, - "#010a19": Sprite.BEAK, - "#190301": Sprite.EYE, - "#af8e75": Sprite.FOOT, - "#639bff": Sprite.FACE, - "#99e550": Sprite.HOOD, - "#d95763": Sprite.NOSE, - "#f8b143": Sprite.BELLY, - "#ec8637": Sprite.UNDERBELLY, - "#578ae6": Sprite.WING, - "#326ed9": Sprite.WING_EDGE, - "#c82e2e": Sprite.HEART, - "#501a1a": Sprite.HEART_BORDER, - "#ff6b6b": Sprite.HEART_SHINE, - "#373737": Sprite.FEATHER_SPINE, + "transparent": PALETTE.TRANSPARENT, + "#ffffff": PALETTE.BORDER, + "#000000": PALETTE.OUTLINE, + "#010a19": PALETTE.BEAK, + "#190301": PALETTE.EYE, + "#af8e75": PALETTE.FOOT, + "#639bff": PALETTE.FACE, + "#99e550": PALETTE.HOOD, + "#d95763": PALETTE.NOSE, + "#f8b143": PALETTE.BELLY, + "#ec8637": PALETTE.UNDERBELLY, + "#578ae6": PALETTE.WING, + "#326ed9": PALETTE.WING_EDGE, + "#c82e2e": PALETTE.HEART, + "#501a1a": PALETTE.HEART_BORDER, + "#ff6b6b": PALETTE.HEART_SHINE, + "#373737": PALETTE.FEATHER_SPINE, }; class BirdType { @@ -285,20 +291,20 @@ module.exports = class PocketBird extends Plugin { this.name = name; this.description = description; const defaultColors = { - [Sprite.TRANSPARENT]: "transparent", - [Sprite.OUTLINE]: "#000000", - [Sprite.BORDER]: "#ffffff", - [Sprite.BEAK]: "#000000", - [Sprite.EYE]: "#000000", - [Sprite.HEART]: "#c82e2e", - [Sprite.HEART_BORDER]: "#501a1a", - [Sprite.HEART_SHINE]: "#ff6b6b", - [Sprite.FEATHER_SPINE]: "#373737", - [Sprite.HOOD]: colors.face, - [Sprite.NOSE]: colors.face, + [PALETTE.TRANSPARENT]: "transparent", + [PALETTE.OUTLINE]: "#000000", + [PALETTE.BORDER]: "#ffffff", + [PALETTE.BEAK]: "#000000", + [PALETTE.EYE]: "#000000", + [PALETTE.HEART]: "#c82e2e", + [PALETTE.HEART_BORDER]: "#501a1a", + [PALETTE.HEART_SHINE]: "#ff6b6b", + [PALETTE.FEATHER_SPINE]: "#373737", + [PALETTE.HOOD]: colors.face, + [PALETTE.NOSE]: colors.face, }; /** @type {Record} */ - this.colors = { ...defaultColors, ...colors, [Sprite.THEME_HIGHLIGHT]: colors[Sprite.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; + this.colors = { ...defaultColors, ...colors, [PALETTE.THEME_HIGHLIGHT]: colors[PALETTE.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; this.tags = tags; } } @@ -307,127 +313,127 @@ module.exports = class PocketBird extends Plugin { const SPECIES = { bluebird: new BirdType("Eastern Bluebird", "Native to North American and very social, though can be timid around people.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#639bff", - [Sprite.BELLY]: "#f8b143", - [Sprite.UNDERBELLY]: "#ec8637", - [Sprite.WING]: "#578ae6", - [Sprite.WING_EDGE]: "#326ed9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#639bff", + [PALETTE.BELLY]: "#f8b143", + [PALETTE.UNDERBELLY]: "#ec8637", + [PALETTE.WING]: "#578ae6", + [PALETTE.WING_EDGE]: "#326ed9", }), shimaEnaga: new BirdType("Shima Enaga", "Small, fluffy birds found in the snowy regions of Japan, these birds are highly sought after by ornithologists and nature photographers.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffffff", - [Sprite.BELLY]: "#ebe9e8", - [Sprite.UNDERBELLY]: "#ebd9d0", - [Sprite.WING]: "#f3d3c1", - [Sprite.WING_EDGE]: "#2d2d2d", - [Sprite.THEME_HIGHLIGHT]: "#d7ac93", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffffff", + [PALETTE.BELLY]: "#ebe9e8", + [PALETTE.UNDERBELLY]: "#ebd9d0", + [PALETTE.WING]: "#f3d3c1", + [PALETTE.WING_EDGE]: "#2d2d2d", + [PALETTE.THEME_HIGHLIGHT]: "#d7ac93", }), tuftedTitmouse: new BirdType("Tufted Titmouse", "Native to the eastern United States, full of personality, and notably my wife's favorite bird.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#c7cad7", - [Sprite.BELLY]: "#e4e5eb", - [Sprite.UNDERBELLY]: "#d7cfcb", - [Sprite.WING]: "#b1b5c5", - [Sprite.WING_EDGE]: "#9d9fa9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#c7cad7", + [PALETTE.BELLY]: "#e4e5eb", + [PALETTE.UNDERBELLY]: "#d7cfcb", + [PALETTE.WING]: "#b1b5c5", + [PALETTE.WING_EDGE]: "#9d9fa9", }, ["tuft"]), europeanRobin: new BirdType("European Robin", "Native to western Europe, this is the quintessential robin. Quite friendly, you'll often find them searching for worms.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffaf34", - [Sprite.HOOD]: "#aaa094", - [Sprite.BELLY]: "#ffaf34", - [Sprite.UNDERBELLY]: "#babec2", - [Sprite.WING]: "#aaa094", - [Sprite.WING_EDGE]: "#888580", - [Sprite.THEME_HIGHLIGHT]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffaf34", + [PALETTE.HOOD]: "#aaa094", + [PALETTE.BELLY]: "#ffaf34", + [PALETTE.UNDERBELLY]: "#babec2", + [PALETTE.WING]: "#aaa094", + [PALETTE.WING_EDGE]: "#888580", + [PALETTE.THEME_HIGHLIGHT]: "#ffaf34", }), redCardinal: new BirdType("Red Cardinal", "Native to the eastern United States, this strikingly red bird is hard to miss.", { - [Sprite.BEAK]: "#d93619", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#31353d", - [Sprite.HOOD]: "#e83a1b", - [Sprite.BELLY]: "#e83a1b", - [Sprite.UNDERBELLY]: "#dc3719", - [Sprite.WING]: "#d23215", - [Sprite.WING_EDGE]: "#b1321c", + [PALETTE.BEAK]: "#d93619", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#31353d", + [PALETTE.HOOD]: "#e83a1b", + [PALETTE.BELLY]: "#e83a1b", + [PALETTE.UNDERBELLY]: "#dc3719", + [PALETTE.WING]: "#d23215", + [PALETTE.WING_EDGE]: "#b1321c", }, ["tuft"]), americanGoldfinch: new BirdType("American Goldfinch", "Coloured a brilliant yellow, this bird feeds almost entirely on the seeds of plants such as thistle, sunflowers, and coneflowers.", { - [Sprite.BEAK]: "#ffaf34", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#fff255", - [Sprite.NOSE]: "#383838", - [Sprite.HOOD]: "#383838", - [Sprite.BELLY]: "#fff255", - [Sprite.UNDERBELLY]: "#f5ea63", - [Sprite.WING]: "#e8e079", - [Sprite.WING_EDGE]: "#191919", - [Sprite.THEME_HIGHLIGHT]: "#ffcc00" + [PALETTE.BEAK]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#fff255", + [PALETTE.NOSE]: "#383838", + [PALETTE.HOOD]: "#383838", + [PALETTE.BELLY]: "#fff255", + [PALETTE.UNDERBELLY]: "#f5ea63", + [PALETTE.WING]: "#e8e079", + [PALETTE.WING_EDGE]: "#191919", + [PALETTE.THEME_HIGHLIGHT]: "#ffcc00" }), barnSwallow: new BirdType("Barn Swallow", "Agile birds that often roost in man-made structures, these birds are known to build nests near Ospreys for protection.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#db7c4d", - [Sprite.BELLY]: "#f7e1c9", - [Sprite.UNDERBELLY]: "#ebc9a3", - [Sprite.WING]: "#2252a9", - [Sprite.WING_EDGE]: "#1c448b", - [Sprite.HOOD]: "#2252a9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#db7c4d", + [PALETTE.BELLY]: "#f7e1c9", + [PALETTE.UNDERBELLY]: "#ebc9a3", + [PALETTE.WING]: "#2252a9", + [PALETTE.WING_EDGE]: "#1c448b", + [PALETTE.HOOD]: "#2252a9", }), mistletoebird: new BirdType("Mistletoebird", "Native to Australia, these birds eat mainly mistletoe and in turn spread the seeds far and wide.", { - [Sprite.FOOT]: "#6c6a7c", - [Sprite.FACE]: "#352e6d", - [Sprite.BELLY]: "#fd6833", - [Sprite.UNDERBELLY]: "#e6e1d8", - [Sprite.WING]: "#342b7c", - [Sprite.WING_EDGE]: "#282065", + [PALETTE.FOOT]: "#6c6a7c", + [PALETTE.FACE]: "#352e6d", + [PALETTE.BELLY]: "#fd6833", + [PALETTE.UNDERBELLY]: "#e6e1d8", + [PALETTE.WING]: "#342b7c", + [PALETTE.WING_EDGE]: "#282065", }), redAvadavat: new BirdType("Red Avadavat", "Native to India and southeast Asia, these birds are also known as Strawberry Finches due to their speckled plumage.", { - [Sprite.BEAK]: "#f71919", - [Sprite.FOOT]: "#af7575", - [Sprite.FACE]: "#cb092b", - [Sprite.BELLY]: "#ae1724", - [Sprite.UNDERBELLY]: "#831b24", - [Sprite.WING]: "#7e3030", - [Sprite.WING_EDGE]: "#490f0f", + [PALETTE.BEAK]: "#f71919", + [PALETTE.FOOT]: "#af7575", + [PALETTE.FACE]: "#cb092b", + [PALETTE.BELLY]: "#ae1724", + [PALETTE.UNDERBELLY]: "#831b24", + [PALETTE.WING]: "#7e3030", + [PALETTE.WING_EDGE]: "#490f0f", }), scarletRobin: new BirdType("Scarlet Robin", "Native to Australia, this striking robin can be found in Eucalyptus forests.", { - [Sprite.FOOT]: "#494949", - [Sprite.FACE]: "#3d3d3d", - [Sprite.BELLY]: "#fc5633", - [Sprite.UNDERBELLY]: "#dcdcdc", - [Sprite.WING]: "#2b2b2b", - [Sprite.WING_EDGE]: "#ebebeb", - [Sprite.THEME_HIGHLIGHT]: "#fc5633", + [PALETTE.FOOT]: "#494949", + [PALETTE.FACE]: "#3d3d3d", + [PALETTE.BELLY]: "#fc5633", + [PALETTE.UNDERBELLY]: "#dcdcdc", + [PALETTE.WING]: "#2b2b2b", + [PALETTE.WING_EDGE]: "#ebebeb", + [PALETTE.THEME_HIGHLIGHT]: "#fc5633", }), americanRobin: new BirdType("American Robin", "While not a true robin, this social North American bird is so named due to its orange coloring. It seems unbothered by nearby humans.", { - [Sprite.BEAK]: "#e89f30", - [Sprite.FOOT]: "#9f8075", - [Sprite.FACE]: "#2d2d2d", - [Sprite.BELLY]: "#eb7a3a", - [Sprite.UNDERBELLY]: "#eb7a3a", - [Sprite.WING]: "#444444", - [Sprite.WING_EDGE]: "#232323", - [Sprite.THEME_HIGHLIGHT]: "#eb7a3a", + [PALETTE.BEAK]: "#e89f30", + [PALETTE.FOOT]: "#9f8075", + [PALETTE.FACE]: "#2d2d2d", + [PALETTE.BELLY]: "#eb7a3a", + [PALETTE.UNDERBELLY]: "#eb7a3a", + [PALETTE.WING]: "#444444", + [PALETTE.WING_EDGE]: "#232323", + [PALETTE.THEME_HIGHLIGHT]: "#eb7a3a", }), carolinaWren: new BirdType("Carolina Wren", "Native to the eastern United States, these little birds are known for their curious and energetic nature.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#edc7a9", - [Sprite.NOSE]: "#f7eee5", - [Sprite.HOOD]: "#c58a5b", - [Sprite.BELLY]: "#e1b796", - [Sprite.UNDERBELLY]: "#c79e7c", - [Sprite.WING]: "#c58a5b", - [Sprite.WING_EDGE]: "#866348", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#edc7a9", + [PALETTE.NOSE]: "#f7eee5", + [PALETTE.HOOD]: "#c58a5b", + [PALETTE.BELLY]: "#e1b796", + [PALETTE.UNDERBELLY]: "#c79e7c", + [PALETTE.WING]: "#c58a5b", + [PALETTE.WING_EDGE]: "#866348", }), }; @@ -465,7 +471,7 @@ module.exports = class PocketBird extends Plugin { this.pixels = layers[0].pixels.map(row => row.slice()); // Pad from top with transparent pixels while (this.pixels.length < maxHeight) { - this.pixels.unshift(new Array(this.pixels[0].length).fill(Sprite.TRANSPARENT)); + this.pixels.unshift(new Array(this.pixels[0].length).fill(PALETTE.TRANSPARENT)); } // Combine layers for (let i = 1; i < layers.length; i++) { @@ -474,7 +480,7 @@ module.exports = class PocketBird extends Plugin { let topMargin = maxHeight - layerPixels.length; for (let y = 0; y < layerPixels.length; y++) { for (let x = 0; x < layerPixels[y].length; x++) { - this.pixels[y + topMargin][x] = layerPixels[y][x] !== Sprite.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; + this.pixels[y + topMargin][x] = layerPixels[y][x] !== PALETTE.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; } } } @@ -2443,7 +2449,7 @@ module.exports = class PocketBird extends Plugin { function switchSpecies(type) { currentSpecies = type; // Update CSS variable --birb-highlight to be wing color - document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[Sprite.THEME_HIGHLIGHT]); + document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[PALETTE.THEME_HIGHLIGHT]); save(); } @@ -2711,7 +2717,7 @@ module.exports = class PocketBird extends Plugin { const b = pixels[index + 2]; const a = pixels[index + 3]; if (a === 0) { - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); continue; } const hex = `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; @@ -2721,7 +2727,7 @@ module.exports = class PocketBird extends Plugin { } if (SPRITE_SHEET_COLOR_MAP[hex] === undefined) { error(`Unknown color: ${hex}`); - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); } row.push(SPRITE_SHEET_COLOR_MAP[hex]); } diff --git a/dist/userscript/birb.user.js b/dist/userscript/birb.user.js index df89919..01018f5 100644 --- a/dist/userscript/birb.user.js +++ b/dist/userscript/birb.user.js @@ -240,8 +240,11 @@ return document.documentElement.clientHeight; } - /** Indicators for parts of the base bird sprite sheet */ - const Sprite = { + /** + * Palette color names + * @type {Record} + */ + const PALETTE = { THEME_HIGHLIGHT: "theme-highlight", TRANSPARENT: "transparent", OUTLINE: "outline", @@ -262,25 +265,28 @@ FEATHER_SPINE: "feather-spine", }; - /** @type {Record} */ + /** + * Mapping of sprite sheet colors to palette colors + * @type {Record} + */ const SPRITE_SHEET_COLOR_MAP = { - "transparent": Sprite.TRANSPARENT, - "#ffffff": Sprite.BORDER, - "#000000": Sprite.OUTLINE, - "#010a19": Sprite.BEAK, - "#190301": Sprite.EYE, - "#af8e75": Sprite.FOOT, - "#639bff": Sprite.FACE, - "#99e550": Sprite.HOOD, - "#d95763": Sprite.NOSE, - "#f8b143": Sprite.BELLY, - "#ec8637": Sprite.UNDERBELLY, - "#578ae6": Sprite.WING, - "#326ed9": Sprite.WING_EDGE, - "#c82e2e": Sprite.HEART, - "#501a1a": Sprite.HEART_BORDER, - "#ff6b6b": Sprite.HEART_SHINE, - "#373737": Sprite.FEATHER_SPINE, + "transparent": PALETTE.TRANSPARENT, + "#ffffff": PALETTE.BORDER, + "#000000": PALETTE.OUTLINE, + "#010a19": PALETTE.BEAK, + "#190301": PALETTE.EYE, + "#af8e75": PALETTE.FOOT, + "#639bff": PALETTE.FACE, + "#99e550": PALETTE.HOOD, + "#d95763": PALETTE.NOSE, + "#f8b143": PALETTE.BELLY, + "#ec8637": PALETTE.UNDERBELLY, + "#578ae6": PALETTE.WING, + "#326ed9": PALETTE.WING_EDGE, + "#c82e2e": PALETTE.HEART, + "#501a1a": PALETTE.HEART_BORDER, + "#ff6b6b": PALETTE.HEART_SHINE, + "#373737": PALETTE.FEATHER_SPINE, }; class BirdType { @@ -294,20 +300,20 @@ this.name = name; this.description = description; const defaultColors = { - [Sprite.TRANSPARENT]: "transparent", - [Sprite.OUTLINE]: "#000000", - [Sprite.BORDER]: "#ffffff", - [Sprite.BEAK]: "#000000", - [Sprite.EYE]: "#000000", - [Sprite.HEART]: "#c82e2e", - [Sprite.HEART_BORDER]: "#501a1a", - [Sprite.HEART_SHINE]: "#ff6b6b", - [Sprite.FEATHER_SPINE]: "#373737", - [Sprite.HOOD]: colors.face, - [Sprite.NOSE]: colors.face, + [PALETTE.TRANSPARENT]: "transparent", + [PALETTE.OUTLINE]: "#000000", + [PALETTE.BORDER]: "#ffffff", + [PALETTE.BEAK]: "#000000", + [PALETTE.EYE]: "#000000", + [PALETTE.HEART]: "#c82e2e", + [PALETTE.HEART_BORDER]: "#501a1a", + [PALETTE.HEART_SHINE]: "#ff6b6b", + [PALETTE.FEATHER_SPINE]: "#373737", + [PALETTE.HOOD]: colors.face, + [PALETTE.NOSE]: colors.face, }; /** @type {Record} */ - this.colors = { ...defaultColors, ...colors, [Sprite.THEME_HIGHLIGHT]: colors[Sprite.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; + this.colors = { ...defaultColors, ...colors, [PALETTE.THEME_HIGHLIGHT]: colors[PALETTE.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; this.tags = tags; } } @@ -316,127 +322,127 @@ const SPECIES = { bluebird: new BirdType("Eastern Bluebird", "Native to North American and very social, though can be timid around people.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#639bff", - [Sprite.BELLY]: "#f8b143", - [Sprite.UNDERBELLY]: "#ec8637", - [Sprite.WING]: "#578ae6", - [Sprite.WING_EDGE]: "#326ed9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#639bff", + [PALETTE.BELLY]: "#f8b143", + [PALETTE.UNDERBELLY]: "#ec8637", + [PALETTE.WING]: "#578ae6", + [PALETTE.WING_EDGE]: "#326ed9", }), shimaEnaga: new BirdType("Shima Enaga", "Small, fluffy birds found in the snowy regions of Japan, these birds are highly sought after by ornithologists and nature photographers.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffffff", - [Sprite.BELLY]: "#ebe9e8", - [Sprite.UNDERBELLY]: "#ebd9d0", - [Sprite.WING]: "#f3d3c1", - [Sprite.WING_EDGE]: "#2d2d2d", - [Sprite.THEME_HIGHLIGHT]: "#d7ac93", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffffff", + [PALETTE.BELLY]: "#ebe9e8", + [PALETTE.UNDERBELLY]: "#ebd9d0", + [PALETTE.WING]: "#f3d3c1", + [PALETTE.WING_EDGE]: "#2d2d2d", + [PALETTE.THEME_HIGHLIGHT]: "#d7ac93", }), tuftedTitmouse: new BirdType("Tufted Titmouse", "Native to the eastern United States, full of personality, and notably my wife's favorite bird.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#c7cad7", - [Sprite.BELLY]: "#e4e5eb", - [Sprite.UNDERBELLY]: "#d7cfcb", - [Sprite.WING]: "#b1b5c5", - [Sprite.WING_EDGE]: "#9d9fa9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#c7cad7", + [PALETTE.BELLY]: "#e4e5eb", + [PALETTE.UNDERBELLY]: "#d7cfcb", + [PALETTE.WING]: "#b1b5c5", + [PALETTE.WING_EDGE]: "#9d9fa9", }, ["tuft"]), europeanRobin: new BirdType("European Robin", "Native to western Europe, this is the quintessential robin. Quite friendly, you'll often find them searching for worms.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffaf34", - [Sprite.HOOD]: "#aaa094", - [Sprite.BELLY]: "#ffaf34", - [Sprite.UNDERBELLY]: "#babec2", - [Sprite.WING]: "#aaa094", - [Sprite.WING_EDGE]: "#888580", - [Sprite.THEME_HIGHLIGHT]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffaf34", + [PALETTE.HOOD]: "#aaa094", + [PALETTE.BELLY]: "#ffaf34", + [PALETTE.UNDERBELLY]: "#babec2", + [PALETTE.WING]: "#aaa094", + [PALETTE.WING_EDGE]: "#888580", + [PALETTE.THEME_HIGHLIGHT]: "#ffaf34", }), redCardinal: new BirdType("Red Cardinal", "Native to the eastern United States, this strikingly red bird is hard to miss.", { - [Sprite.BEAK]: "#d93619", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#31353d", - [Sprite.HOOD]: "#e83a1b", - [Sprite.BELLY]: "#e83a1b", - [Sprite.UNDERBELLY]: "#dc3719", - [Sprite.WING]: "#d23215", - [Sprite.WING_EDGE]: "#b1321c", + [PALETTE.BEAK]: "#d93619", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#31353d", + [PALETTE.HOOD]: "#e83a1b", + [PALETTE.BELLY]: "#e83a1b", + [PALETTE.UNDERBELLY]: "#dc3719", + [PALETTE.WING]: "#d23215", + [PALETTE.WING_EDGE]: "#b1321c", }, ["tuft"]), americanGoldfinch: new BirdType("American Goldfinch", "Coloured a brilliant yellow, this bird feeds almost entirely on the seeds of plants such as thistle, sunflowers, and coneflowers.", { - [Sprite.BEAK]: "#ffaf34", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#fff255", - [Sprite.NOSE]: "#383838", - [Sprite.HOOD]: "#383838", - [Sprite.BELLY]: "#fff255", - [Sprite.UNDERBELLY]: "#f5ea63", - [Sprite.WING]: "#e8e079", - [Sprite.WING_EDGE]: "#191919", - [Sprite.THEME_HIGHLIGHT]: "#ffcc00" + [PALETTE.BEAK]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#fff255", + [PALETTE.NOSE]: "#383838", + [PALETTE.HOOD]: "#383838", + [PALETTE.BELLY]: "#fff255", + [PALETTE.UNDERBELLY]: "#f5ea63", + [PALETTE.WING]: "#e8e079", + [PALETTE.WING_EDGE]: "#191919", + [PALETTE.THEME_HIGHLIGHT]: "#ffcc00" }), barnSwallow: new BirdType("Barn Swallow", "Agile birds that often roost in man-made structures, these birds are known to build nests near Ospreys for protection.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#db7c4d", - [Sprite.BELLY]: "#f7e1c9", - [Sprite.UNDERBELLY]: "#ebc9a3", - [Sprite.WING]: "#2252a9", - [Sprite.WING_EDGE]: "#1c448b", - [Sprite.HOOD]: "#2252a9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#db7c4d", + [PALETTE.BELLY]: "#f7e1c9", + [PALETTE.UNDERBELLY]: "#ebc9a3", + [PALETTE.WING]: "#2252a9", + [PALETTE.WING_EDGE]: "#1c448b", + [PALETTE.HOOD]: "#2252a9", }), mistletoebird: new BirdType("Mistletoebird", "Native to Australia, these birds eat mainly mistletoe and in turn spread the seeds far and wide.", { - [Sprite.FOOT]: "#6c6a7c", - [Sprite.FACE]: "#352e6d", - [Sprite.BELLY]: "#fd6833", - [Sprite.UNDERBELLY]: "#e6e1d8", - [Sprite.WING]: "#342b7c", - [Sprite.WING_EDGE]: "#282065", + [PALETTE.FOOT]: "#6c6a7c", + [PALETTE.FACE]: "#352e6d", + [PALETTE.BELLY]: "#fd6833", + [PALETTE.UNDERBELLY]: "#e6e1d8", + [PALETTE.WING]: "#342b7c", + [PALETTE.WING_EDGE]: "#282065", }), redAvadavat: new BirdType("Red Avadavat", "Native to India and southeast Asia, these birds are also known as Strawberry Finches due to their speckled plumage.", { - [Sprite.BEAK]: "#f71919", - [Sprite.FOOT]: "#af7575", - [Sprite.FACE]: "#cb092b", - [Sprite.BELLY]: "#ae1724", - [Sprite.UNDERBELLY]: "#831b24", - [Sprite.WING]: "#7e3030", - [Sprite.WING_EDGE]: "#490f0f", + [PALETTE.BEAK]: "#f71919", + [PALETTE.FOOT]: "#af7575", + [PALETTE.FACE]: "#cb092b", + [PALETTE.BELLY]: "#ae1724", + [PALETTE.UNDERBELLY]: "#831b24", + [PALETTE.WING]: "#7e3030", + [PALETTE.WING_EDGE]: "#490f0f", }), scarletRobin: new BirdType("Scarlet Robin", "Native to Australia, this striking robin can be found in Eucalyptus forests.", { - [Sprite.FOOT]: "#494949", - [Sprite.FACE]: "#3d3d3d", - [Sprite.BELLY]: "#fc5633", - [Sprite.UNDERBELLY]: "#dcdcdc", - [Sprite.WING]: "#2b2b2b", - [Sprite.WING_EDGE]: "#ebebeb", - [Sprite.THEME_HIGHLIGHT]: "#fc5633", + [PALETTE.FOOT]: "#494949", + [PALETTE.FACE]: "#3d3d3d", + [PALETTE.BELLY]: "#fc5633", + [PALETTE.UNDERBELLY]: "#dcdcdc", + [PALETTE.WING]: "#2b2b2b", + [PALETTE.WING_EDGE]: "#ebebeb", + [PALETTE.THEME_HIGHLIGHT]: "#fc5633", }), americanRobin: new BirdType("American Robin", "While not a true robin, this social North American bird is so named due to its orange coloring. It seems unbothered by nearby humans.", { - [Sprite.BEAK]: "#e89f30", - [Sprite.FOOT]: "#9f8075", - [Sprite.FACE]: "#2d2d2d", - [Sprite.BELLY]: "#eb7a3a", - [Sprite.UNDERBELLY]: "#eb7a3a", - [Sprite.WING]: "#444444", - [Sprite.WING_EDGE]: "#232323", - [Sprite.THEME_HIGHLIGHT]: "#eb7a3a", + [PALETTE.BEAK]: "#e89f30", + [PALETTE.FOOT]: "#9f8075", + [PALETTE.FACE]: "#2d2d2d", + [PALETTE.BELLY]: "#eb7a3a", + [PALETTE.UNDERBELLY]: "#eb7a3a", + [PALETTE.WING]: "#444444", + [PALETTE.WING_EDGE]: "#232323", + [PALETTE.THEME_HIGHLIGHT]: "#eb7a3a", }), carolinaWren: new BirdType("Carolina Wren", "Native to the eastern United States, these little birds are known for their curious and energetic nature.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#edc7a9", - [Sprite.NOSE]: "#f7eee5", - [Sprite.HOOD]: "#c58a5b", - [Sprite.BELLY]: "#e1b796", - [Sprite.UNDERBELLY]: "#c79e7c", - [Sprite.WING]: "#c58a5b", - [Sprite.WING_EDGE]: "#866348", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#edc7a9", + [PALETTE.NOSE]: "#f7eee5", + [PALETTE.HOOD]: "#c58a5b", + [PALETTE.BELLY]: "#e1b796", + [PALETTE.UNDERBELLY]: "#c79e7c", + [PALETTE.WING]: "#c58a5b", + [PALETTE.WING_EDGE]: "#866348", }), }; @@ -474,7 +480,7 @@ this.pixels = layers[0].pixels.map(row => row.slice()); // Pad from top with transparent pixels while (this.pixels.length < maxHeight) { - this.pixels.unshift(new Array(this.pixels[0].length).fill(Sprite.TRANSPARENT)); + this.pixels.unshift(new Array(this.pixels[0].length).fill(PALETTE.TRANSPARENT)); } // Combine layers for (let i = 1; i < layers.length; i++) { @@ -483,7 +489,7 @@ let topMargin = maxHeight - layerPixels.length; for (let y = 0; y < layerPixels.length; y++) { for (let x = 0; x < layerPixels[y].length; x++) { - this.pixels[y + topMargin][x] = layerPixels[y][x] !== Sprite.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; + this.pixels[y + topMargin][x] = layerPixels[y][x] !== PALETTE.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; } } } @@ -2405,7 +2411,7 @@ function switchSpecies(type) { currentSpecies = type; // Update CSS variable --birb-highlight to be wing color - document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[Sprite.THEME_HIGHLIGHT]); + document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[PALETTE.THEME_HIGHLIGHT]); save(); } @@ -2673,7 +2679,7 @@ const b = pixels[index + 2]; const a = pixels[index + 3]; if (a === 0) { - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); continue; } const hex = `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; @@ -2683,7 +2689,7 @@ } if (SPRITE_SHEET_COLOR_MAP[hex] === undefined) { error(`Unknown color: ${hex}`); - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); } row.push(SPRITE_SHEET_COLOR_MAP[hex]); } diff --git a/dist/web/birb.embed.js b/dist/web/birb.embed.js index 077d90d..722645a 100644 --- a/dist/web/birb.embed.js +++ b/dist/web/birb.embed.js @@ -226,8 +226,11 @@ return document.documentElement.clientHeight; } - /** Indicators for parts of the base bird sprite sheet */ - const Sprite = { + /** + * Palette color names + * @type {Record} + */ + const PALETTE = { THEME_HIGHLIGHT: "theme-highlight", TRANSPARENT: "transparent", OUTLINE: "outline", @@ -248,25 +251,28 @@ FEATHER_SPINE: "feather-spine", }; - /** @type {Record} */ + /** + * Mapping of sprite sheet colors to palette colors + * @type {Record} + */ const SPRITE_SHEET_COLOR_MAP = { - "transparent": Sprite.TRANSPARENT, - "#ffffff": Sprite.BORDER, - "#000000": Sprite.OUTLINE, - "#010a19": Sprite.BEAK, - "#190301": Sprite.EYE, - "#af8e75": Sprite.FOOT, - "#639bff": Sprite.FACE, - "#99e550": Sprite.HOOD, - "#d95763": Sprite.NOSE, - "#f8b143": Sprite.BELLY, - "#ec8637": Sprite.UNDERBELLY, - "#578ae6": Sprite.WING, - "#326ed9": Sprite.WING_EDGE, - "#c82e2e": Sprite.HEART, - "#501a1a": Sprite.HEART_BORDER, - "#ff6b6b": Sprite.HEART_SHINE, - "#373737": Sprite.FEATHER_SPINE, + "transparent": PALETTE.TRANSPARENT, + "#ffffff": PALETTE.BORDER, + "#000000": PALETTE.OUTLINE, + "#010a19": PALETTE.BEAK, + "#190301": PALETTE.EYE, + "#af8e75": PALETTE.FOOT, + "#639bff": PALETTE.FACE, + "#99e550": PALETTE.HOOD, + "#d95763": PALETTE.NOSE, + "#f8b143": PALETTE.BELLY, + "#ec8637": PALETTE.UNDERBELLY, + "#578ae6": PALETTE.WING, + "#326ed9": PALETTE.WING_EDGE, + "#c82e2e": PALETTE.HEART, + "#501a1a": PALETTE.HEART_BORDER, + "#ff6b6b": PALETTE.HEART_SHINE, + "#373737": PALETTE.FEATHER_SPINE, }; class BirdType { @@ -280,20 +286,20 @@ this.name = name; this.description = description; const defaultColors = { - [Sprite.TRANSPARENT]: "transparent", - [Sprite.OUTLINE]: "#000000", - [Sprite.BORDER]: "#ffffff", - [Sprite.BEAK]: "#000000", - [Sprite.EYE]: "#000000", - [Sprite.HEART]: "#c82e2e", - [Sprite.HEART_BORDER]: "#501a1a", - [Sprite.HEART_SHINE]: "#ff6b6b", - [Sprite.FEATHER_SPINE]: "#373737", - [Sprite.HOOD]: colors.face, - [Sprite.NOSE]: colors.face, + [PALETTE.TRANSPARENT]: "transparent", + [PALETTE.OUTLINE]: "#000000", + [PALETTE.BORDER]: "#ffffff", + [PALETTE.BEAK]: "#000000", + [PALETTE.EYE]: "#000000", + [PALETTE.HEART]: "#c82e2e", + [PALETTE.HEART_BORDER]: "#501a1a", + [PALETTE.HEART_SHINE]: "#ff6b6b", + [PALETTE.FEATHER_SPINE]: "#373737", + [PALETTE.HOOD]: colors.face, + [PALETTE.NOSE]: colors.face, }; /** @type {Record} */ - this.colors = { ...defaultColors, ...colors, [Sprite.THEME_HIGHLIGHT]: colors[Sprite.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; + this.colors = { ...defaultColors, ...colors, [PALETTE.THEME_HIGHLIGHT]: colors[PALETTE.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; this.tags = tags; } } @@ -302,127 +308,127 @@ const SPECIES = { bluebird: new BirdType("Eastern Bluebird", "Native to North American and very social, though can be timid around people.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#639bff", - [Sprite.BELLY]: "#f8b143", - [Sprite.UNDERBELLY]: "#ec8637", - [Sprite.WING]: "#578ae6", - [Sprite.WING_EDGE]: "#326ed9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#639bff", + [PALETTE.BELLY]: "#f8b143", + [PALETTE.UNDERBELLY]: "#ec8637", + [PALETTE.WING]: "#578ae6", + [PALETTE.WING_EDGE]: "#326ed9", }), shimaEnaga: new BirdType("Shima Enaga", "Small, fluffy birds found in the snowy regions of Japan, these birds are highly sought after by ornithologists and nature photographers.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffffff", - [Sprite.BELLY]: "#ebe9e8", - [Sprite.UNDERBELLY]: "#ebd9d0", - [Sprite.WING]: "#f3d3c1", - [Sprite.WING_EDGE]: "#2d2d2d", - [Sprite.THEME_HIGHLIGHT]: "#d7ac93", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffffff", + [PALETTE.BELLY]: "#ebe9e8", + [PALETTE.UNDERBELLY]: "#ebd9d0", + [PALETTE.WING]: "#f3d3c1", + [PALETTE.WING_EDGE]: "#2d2d2d", + [PALETTE.THEME_HIGHLIGHT]: "#d7ac93", }), tuftedTitmouse: new BirdType("Tufted Titmouse", "Native to the eastern United States, full of personality, and notably my wife's favorite bird.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#c7cad7", - [Sprite.BELLY]: "#e4e5eb", - [Sprite.UNDERBELLY]: "#d7cfcb", - [Sprite.WING]: "#b1b5c5", - [Sprite.WING_EDGE]: "#9d9fa9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#c7cad7", + [PALETTE.BELLY]: "#e4e5eb", + [PALETTE.UNDERBELLY]: "#d7cfcb", + [PALETTE.WING]: "#b1b5c5", + [PALETTE.WING_EDGE]: "#9d9fa9", }, ["tuft"]), europeanRobin: new BirdType("European Robin", "Native to western Europe, this is the quintessential robin. Quite friendly, you'll often find them searching for worms.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffaf34", - [Sprite.HOOD]: "#aaa094", - [Sprite.BELLY]: "#ffaf34", - [Sprite.UNDERBELLY]: "#babec2", - [Sprite.WING]: "#aaa094", - [Sprite.WING_EDGE]: "#888580", - [Sprite.THEME_HIGHLIGHT]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffaf34", + [PALETTE.HOOD]: "#aaa094", + [PALETTE.BELLY]: "#ffaf34", + [PALETTE.UNDERBELLY]: "#babec2", + [PALETTE.WING]: "#aaa094", + [PALETTE.WING_EDGE]: "#888580", + [PALETTE.THEME_HIGHLIGHT]: "#ffaf34", }), redCardinal: new BirdType("Red Cardinal", "Native to the eastern United States, this strikingly red bird is hard to miss.", { - [Sprite.BEAK]: "#d93619", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#31353d", - [Sprite.HOOD]: "#e83a1b", - [Sprite.BELLY]: "#e83a1b", - [Sprite.UNDERBELLY]: "#dc3719", - [Sprite.WING]: "#d23215", - [Sprite.WING_EDGE]: "#b1321c", + [PALETTE.BEAK]: "#d93619", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#31353d", + [PALETTE.HOOD]: "#e83a1b", + [PALETTE.BELLY]: "#e83a1b", + [PALETTE.UNDERBELLY]: "#dc3719", + [PALETTE.WING]: "#d23215", + [PALETTE.WING_EDGE]: "#b1321c", }, ["tuft"]), americanGoldfinch: new BirdType("American Goldfinch", "Coloured a brilliant yellow, this bird feeds almost entirely on the seeds of plants such as thistle, sunflowers, and coneflowers.", { - [Sprite.BEAK]: "#ffaf34", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#fff255", - [Sprite.NOSE]: "#383838", - [Sprite.HOOD]: "#383838", - [Sprite.BELLY]: "#fff255", - [Sprite.UNDERBELLY]: "#f5ea63", - [Sprite.WING]: "#e8e079", - [Sprite.WING_EDGE]: "#191919", - [Sprite.THEME_HIGHLIGHT]: "#ffcc00" + [PALETTE.BEAK]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#fff255", + [PALETTE.NOSE]: "#383838", + [PALETTE.HOOD]: "#383838", + [PALETTE.BELLY]: "#fff255", + [PALETTE.UNDERBELLY]: "#f5ea63", + [PALETTE.WING]: "#e8e079", + [PALETTE.WING_EDGE]: "#191919", + [PALETTE.THEME_HIGHLIGHT]: "#ffcc00" }), barnSwallow: new BirdType("Barn Swallow", "Agile birds that often roost in man-made structures, these birds are known to build nests near Ospreys for protection.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#db7c4d", - [Sprite.BELLY]: "#f7e1c9", - [Sprite.UNDERBELLY]: "#ebc9a3", - [Sprite.WING]: "#2252a9", - [Sprite.WING_EDGE]: "#1c448b", - [Sprite.HOOD]: "#2252a9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#db7c4d", + [PALETTE.BELLY]: "#f7e1c9", + [PALETTE.UNDERBELLY]: "#ebc9a3", + [PALETTE.WING]: "#2252a9", + [PALETTE.WING_EDGE]: "#1c448b", + [PALETTE.HOOD]: "#2252a9", }), mistletoebird: new BirdType("Mistletoebird", "Native to Australia, these birds eat mainly mistletoe and in turn spread the seeds far and wide.", { - [Sprite.FOOT]: "#6c6a7c", - [Sprite.FACE]: "#352e6d", - [Sprite.BELLY]: "#fd6833", - [Sprite.UNDERBELLY]: "#e6e1d8", - [Sprite.WING]: "#342b7c", - [Sprite.WING_EDGE]: "#282065", + [PALETTE.FOOT]: "#6c6a7c", + [PALETTE.FACE]: "#352e6d", + [PALETTE.BELLY]: "#fd6833", + [PALETTE.UNDERBELLY]: "#e6e1d8", + [PALETTE.WING]: "#342b7c", + [PALETTE.WING_EDGE]: "#282065", }), redAvadavat: new BirdType("Red Avadavat", "Native to India and southeast Asia, these birds are also known as Strawberry Finches due to their speckled plumage.", { - [Sprite.BEAK]: "#f71919", - [Sprite.FOOT]: "#af7575", - [Sprite.FACE]: "#cb092b", - [Sprite.BELLY]: "#ae1724", - [Sprite.UNDERBELLY]: "#831b24", - [Sprite.WING]: "#7e3030", - [Sprite.WING_EDGE]: "#490f0f", + [PALETTE.BEAK]: "#f71919", + [PALETTE.FOOT]: "#af7575", + [PALETTE.FACE]: "#cb092b", + [PALETTE.BELLY]: "#ae1724", + [PALETTE.UNDERBELLY]: "#831b24", + [PALETTE.WING]: "#7e3030", + [PALETTE.WING_EDGE]: "#490f0f", }), scarletRobin: new BirdType("Scarlet Robin", "Native to Australia, this striking robin can be found in Eucalyptus forests.", { - [Sprite.FOOT]: "#494949", - [Sprite.FACE]: "#3d3d3d", - [Sprite.BELLY]: "#fc5633", - [Sprite.UNDERBELLY]: "#dcdcdc", - [Sprite.WING]: "#2b2b2b", - [Sprite.WING_EDGE]: "#ebebeb", - [Sprite.THEME_HIGHLIGHT]: "#fc5633", + [PALETTE.FOOT]: "#494949", + [PALETTE.FACE]: "#3d3d3d", + [PALETTE.BELLY]: "#fc5633", + [PALETTE.UNDERBELLY]: "#dcdcdc", + [PALETTE.WING]: "#2b2b2b", + [PALETTE.WING_EDGE]: "#ebebeb", + [PALETTE.THEME_HIGHLIGHT]: "#fc5633", }), americanRobin: new BirdType("American Robin", "While not a true robin, this social North American bird is so named due to its orange coloring. It seems unbothered by nearby humans.", { - [Sprite.BEAK]: "#e89f30", - [Sprite.FOOT]: "#9f8075", - [Sprite.FACE]: "#2d2d2d", - [Sprite.BELLY]: "#eb7a3a", - [Sprite.UNDERBELLY]: "#eb7a3a", - [Sprite.WING]: "#444444", - [Sprite.WING_EDGE]: "#232323", - [Sprite.THEME_HIGHLIGHT]: "#eb7a3a", + [PALETTE.BEAK]: "#e89f30", + [PALETTE.FOOT]: "#9f8075", + [PALETTE.FACE]: "#2d2d2d", + [PALETTE.BELLY]: "#eb7a3a", + [PALETTE.UNDERBELLY]: "#eb7a3a", + [PALETTE.WING]: "#444444", + [PALETTE.WING_EDGE]: "#232323", + [PALETTE.THEME_HIGHLIGHT]: "#eb7a3a", }), carolinaWren: new BirdType("Carolina Wren", "Native to the eastern United States, these little birds are known for their curious and energetic nature.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#edc7a9", - [Sprite.NOSE]: "#f7eee5", - [Sprite.HOOD]: "#c58a5b", - [Sprite.BELLY]: "#e1b796", - [Sprite.UNDERBELLY]: "#c79e7c", - [Sprite.WING]: "#c58a5b", - [Sprite.WING_EDGE]: "#866348", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#edc7a9", + [PALETTE.NOSE]: "#f7eee5", + [PALETTE.HOOD]: "#c58a5b", + [PALETTE.BELLY]: "#e1b796", + [PALETTE.UNDERBELLY]: "#c79e7c", + [PALETTE.WING]: "#c58a5b", + [PALETTE.WING_EDGE]: "#866348", }), }; @@ -460,7 +466,7 @@ this.pixels = layers[0].pixels.map(row => row.slice()); // Pad from top with transparent pixels while (this.pixels.length < maxHeight) { - this.pixels.unshift(new Array(this.pixels[0].length).fill(Sprite.TRANSPARENT)); + this.pixels.unshift(new Array(this.pixels[0].length).fill(PALETTE.TRANSPARENT)); } // Combine layers for (let i = 1; i < layers.length; i++) { @@ -469,7 +475,7 @@ let topMargin = maxHeight - layerPixels.length; for (let y = 0; y < layerPixels.length; y++) { for (let x = 0; x < layerPixels[y].length; x++) { - this.pixels[y + topMargin][x] = layerPixels[y][x] !== Sprite.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; + this.pixels[y + topMargin][x] = layerPixels[y][x] !== PALETTE.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; } } } @@ -2385,7 +2391,7 @@ function switchSpecies(type) { currentSpecies = type; // Update CSS variable --birb-highlight to be wing color - document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[Sprite.THEME_HIGHLIGHT]); + document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[PALETTE.THEME_HIGHLIGHT]); save(); } @@ -2653,7 +2659,7 @@ const b = pixels[index + 2]; const a = pixels[index + 3]; if (a === 0) { - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); continue; } const hex = `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; @@ -2663,7 +2669,7 @@ } if (SPRITE_SHEET_COLOR_MAP[hex] === undefined) { error(`Unknown color: ${hex}`); - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); } row.push(SPRITE_SHEET_COLOR_MAP[hex]); } diff --git a/dist/web/birb.js b/dist/web/birb.js index 077d90d..722645a 100644 --- a/dist/web/birb.js +++ b/dist/web/birb.js @@ -226,8 +226,11 @@ return document.documentElement.clientHeight; } - /** Indicators for parts of the base bird sprite sheet */ - const Sprite = { + /** + * Palette color names + * @type {Record} + */ + const PALETTE = { THEME_HIGHLIGHT: "theme-highlight", TRANSPARENT: "transparent", OUTLINE: "outline", @@ -248,25 +251,28 @@ FEATHER_SPINE: "feather-spine", }; - /** @type {Record} */ + /** + * Mapping of sprite sheet colors to palette colors + * @type {Record} + */ const SPRITE_SHEET_COLOR_MAP = { - "transparent": Sprite.TRANSPARENT, - "#ffffff": Sprite.BORDER, - "#000000": Sprite.OUTLINE, - "#010a19": Sprite.BEAK, - "#190301": Sprite.EYE, - "#af8e75": Sprite.FOOT, - "#639bff": Sprite.FACE, - "#99e550": Sprite.HOOD, - "#d95763": Sprite.NOSE, - "#f8b143": Sprite.BELLY, - "#ec8637": Sprite.UNDERBELLY, - "#578ae6": Sprite.WING, - "#326ed9": Sprite.WING_EDGE, - "#c82e2e": Sprite.HEART, - "#501a1a": Sprite.HEART_BORDER, - "#ff6b6b": Sprite.HEART_SHINE, - "#373737": Sprite.FEATHER_SPINE, + "transparent": PALETTE.TRANSPARENT, + "#ffffff": PALETTE.BORDER, + "#000000": PALETTE.OUTLINE, + "#010a19": PALETTE.BEAK, + "#190301": PALETTE.EYE, + "#af8e75": PALETTE.FOOT, + "#639bff": PALETTE.FACE, + "#99e550": PALETTE.HOOD, + "#d95763": PALETTE.NOSE, + "#f8b143": PALETTE.BELLY, + "#ec8637": PALETTE.UNDERBELLY, + "#578ae6": PALETTE.WING, + "#326ed9": PALETTE.WING_EDGE, + "#c82e2e": PALETTE.HEART, + "#501a1a": PALETTE.HEART_BORDER, + "#ff6b6b": PALETTE.HEART_SHINE, + "#373737": PALETTE.FEATHER_SPINE, }; class BirdType { @@ -280,20 +286,20 @@ this.name = name; this.description = description; const defaultColors = { - [Sprite.TRANSPARENT]: "transparent", - [Sprite.OUTLINE]: "#000000", - [Sprite.BORDER]: "#ffffff", - [Sprite.BEAK]: "#000000", - [Sprite.EYE]: "#000000", - [Sprite.HEART]: "#c82e2e", - [Sprite.HEART_BORDER]: "#501a1a", - [Sprite.HEART_SHINE]: "#ff6b6b", - [Sprite.FEATHER_SPINE]: "#373737", - [Sprite.HOOD]: colors.face, - [Sprite.NOSE]: colors.face, + [PALETTE.TRANSPARENT]: "transparent", + [PALETTE.OUTLINE]: "#000000", + [PALETTE.BORDER]: "#ffffff", + [PALETTE.BEAK]: "#000000", + [PALETTE.EYE]: "#000000", + [PALETTE.HEART]: "#c82e2e", + [PALETTE.HEART_BORDER]: "#501a1a", + [PALETTE.HEART_SHINE]: "#ff6b6b", + [PALETTE.FEATHER_SPINE]: "#373737", + [PALETTE.HOOD]: colors.face, + [PALETTE.NOSE]: colors.face, }; /** @type {Record} */ - this.colors = { ...defaultColors, ...colors, [Sprite.THEME_HIGHLIGHT]: colors[Sprite.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; + this.colors = { ...defaultColors, ...colors, [PALETTE.THEME_HIGHLIGHT]: colors[PALETTE.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; this.tags = tags; } } @@ -302,127 +308,127 @@ const SPECIES = { bluebird: new BirdType("Eastern Bluebird", "Native to North American and very social, though can be timid around people.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#639bff", - [Sprite.BELLY]: "#f8b143", - [Sprite.UNDERBELLY]: "#ec8637", - [Sprite.WING]: "#578ae6", - [Sprite.WING_EDGE]: "#326ed9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#639bff", + [PALETTE.BELLY]: "#f8b143", + [PALETTE.UNDERBELLY]: "#ec8637", + [PALETTE.WING]: "#578ae6", + [PALETTE.WING_EDGE]: "#326ed9", }), shimaEnaga: new BirdType("Shima Enaga", "Small, fluffy birds found in the snowy regions of Japan, these birds are highly sought after by ornithologists and nature photographers.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffffff", - [Sprite.BELLY]: "#ebe9e8", - [Sprite.UNDERBELLY]: "#ebd9d0", - [Sprite.WING]: "#f3d3c1", - [Sprite.WING_EDGE]: "#2d2d2d", - [Sprite.THEME_HIGHLIGHT]: "#d7ac93", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffffff", + [PALETTE.BELLY]: "#ebe9e8", + [PALETTE.UNDERBELLY]: "#ebd9d0", + [PALETTE.WING]: "#f3d3c1", + [PALETTE.WING_EDGE]: "#2d2d2d", + [PALETTE.THEME_HIGHLIGHT]: "#d7ac93", }), tuftedTitmouse: new BirdType("Tufted Titmouse", "Native to the eastern United States, full of personality, and notably my wife's favorite bird.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#c7cad7", - [Sprite.BELLY]: "#e4e5eb", - [Sprite.UNDERBELLY]: "#d7cfcb", - [Sprite.WING]: "#b1b5c5", - [Sprite.WING_EDGE]: "#9d9fa9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#c7cad7", + [PALETTE.BELLY]: "#e4e5eb", + [PALETTE.UNDERBELLY]: "#d7cfcb", + [PALETTE.WING]: "#b1b5c5", + [PALETTE.WING_EDGE]: "#9d9fa9", }, ["tuft"]), europeanRobin: new BirdType("European Robin", "Native to western Europe, this is the quintessential robin. Quite friendly, you'll often find them searching for worms.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffaf34", - [Sprite.HOOD]: "#aaa094", - [Sprite.BELLY]: "#ffaf34", - [Sprite.UNDERBELLY]: "#babec2", - [Sprite.WING]: "#aaa094", - [Sprite.WING_EDGE]: "#888580", - [Sprite.THEME_HIGHLIGHT]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffaf34", + [PALETTE.HOOD]: "#aaa094", + [PALETTE.BELLY]: "#ffaf34", + [PALETTE.UNDERBELLY]: "#babec2", + [PALETTE.WING]: "#aaa094", + [PALETTE.WING_EDGE]: "#888580", + [PALETTE.THEME_HIGHLIGHT]: "#ffaf34", }), redCardinal: new BirdType("Red Cardinal", "Native to the eastern United States, this strikingly red bird is hard to miss.", { - [Sprite.BEAK]: "#d93619", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#31353d", - [Sprite.HOOD]: "#e83a1b", - [Sprite.BELLY]: "#e83a1b", - [Sprite.UNDERBELLY]: "#dc3719", - [Sprite.WING]: "#d23215", - [Sprite.WING_EDGE]: "#b1321c", + [PALETTE.BEAK]: "#d93619", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#31353d", + [PALETTE.HOOD]: "#e83a1b", + [PALETTE.BELLY]: "#e83a1b", + [PALETTE.UNDERBELLY]: "#dc3719", + [PALETTE.WING]: "#d23215", + [PALETTE.WING_EDGE]: "#b1321c", }, ["tuft"]), americanGoldfinch: new BirdType("American Goldfinch", "Coloured a brilliant yellow, this bird feeds almost entirely on the seeds of plants such as thistle, sunflowers, and coneflowers.", { - [Sprite.BEAK]: "#ffaf34", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#fff255", - [Sprite.NOSE]: "#383838", - [Sprite.HOOD]: "#383838", - [Sprite.BELLY]: "#fff255", - [Sprite.UNDERBELLY]: "#f5ea63", - [Sprite.WING]: "#e8e079", - [Sprite.WING_EDGE]: "#191919", - [Sprite.THEME_HIGHLIGHT]: "#ffcc00" + [PALETTE.BEAK]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#fff255", + [PALETTE.NOSE]: "#383838", + [PALETTE.HOOD]: "#383838", + [PALETTE.BELLY]: "#fff255", + [PALETTE.UNDERBELLY]: "#f5ea63", + [PALETTE.WING]: "#e8e079", + [PALETTE.WING_EDGE]: "#191919", + [PALETTE.THEME_HIGHLIGHT]: "#ffcc00" }), barnSwallow: new BirdType("Barn Swallow", "Agile birds that often roost in man-made structures, these birds are known to build nests near Ospreys for protection.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#db7c4d", - [Sprite.BELLY]: "#f7e1c9", - [Sprite.UNDERBELLY]: "#ebc9a3", - [Sprite.WING]: "#2252a9", - [Sprite.WING_EDGE]: "#1c448b", - [Sprite.HOOD]: "#2252a9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#db7c4d", + [PALETTE.BELLY]: "#f7e1c9", + [PALETTE.UNDERBELLY]: "#ebc9a3", + [PALETTE.WING]: "#2252a9", + [PALETTE.WING_EDGE]: "#1c448b", + [PALETTE.HOOD]: "#2252a9", }), mistletoebird: new BirdType("Mistletoebird", "Native to Australia, these birds eat mainly mistletoe and in turn spread the seeds far and wide.", { - [Sprite.FOOT]: "#6c6a7c", - [Sprite.FACE]: "#352e6d", - [Sprite.BELLY]: "#fd6833", - [Sprite.UNDERBELLY]: "#e6e1d8", - [Sprite.WING]: "#342b7c", - [Sprite.WING_EDGE]: "#282065", + [PALETTE.FOOT]: "#6c6a7c", + [PALETTE.FACE]: "#352e6d", + [PALETTE.BELLY]: "#fd6833", + [PALETTE.UNDERBELLY]: "#e6e1d8", + [PALETTE.WING]: "#342b7c", + [PALETTE.WING_EDGE]: "#282065", }), redAvadavat: new BirdType("Red Avadavat", "Native to India and southeast Asia, these birds are also known as Strawberry Finches due to their speckled plumage.", { - [Sprite.BEAK]: "#f71919", - [Sprite.FOOT]: "#af7575", - [Sprite.FACE]: "#cb092b", - [Sprite.BELLY]: "#ae1724", - [Sprite.UNDERBELLY]: "#831b24", - [Sprite.WING]: "#7e3030", - [Sprite.WING_EDGE]: "#490f0f", + [PALETTE.BEAK]: "#f71919", + [PALETTE.FOOT]: "#af7575", + [PALETTE.FACE]: "#cb092b", + [PALETTE.BELLY]: "#ae1724", + [PALETTE.UNDERBELLY]: "#831b24", + [PALETTE.WING]: "#7e3030", + [PALETTE.WING_EDGE]: "#490f0f", }), scarletRobin: new BirdType("Scarlet Robin", "Native to Australia, this striking robin can be found in Eucalyptus forests.", { - [Sprite.FOOT]: "#494949", - [Sprite.FACE]: "#3d3d3d", - [Sprite.BELLY]: "#fc5633", - [Sprite.UNDERBELLY]: "#dcdcdc", - [Sprite.WING]: "#2b2b2b", - [Sprite.WING_EDGE]: "#ebebeb", - [Sprite.THEME_HIGHLIGHT]: "#fc5633", + [PALETTE.FOOT]: "#494949", + [PALETTE.FACE]: "#3d3d3d", + [PALETTE.BELLY]: "#fc5633", + [PALETTE.UNDERBELLY]: "#dcdcdc", + [PALETTE.WING]: "#2b2b2b", + [PALETTE.WING_EDGE]: "#ebebeb", + [PALETTE.THEME_HIGHLIGHT]: "#fc5633", }), americanRobin: new BirdType("American Robin", "While not a true robin, this social North American bird is so named due to its orange coloring. It seems unbothered by nearby humans.", { - [Sprite.BEAK]: "#e89f30", - [Sprite.FOOT]: "#9f8075", - [Sprite.FACE]: "#2d2d2d", - [Sprite.BELLY]: "#eb7a3a", - [Sprite.UNDERBELLY]: "#eb7a3a", - [Sprite.WING]: "#444444", - [Sprite.WING_EDGE]: "#232323", - [Sprite.THEME_HIGHLIGHT]: "#eb7a3a", + [PALETTE.BEAK]: "#e89f30", + [PALETTE.FOOT]: "#9f8075", + [PALETTE.FACE]: "#2d2d2d", + [PALETTE.BELLY]: "#eb7a3a", + [PALETTE.UNDERBELLY]: "#eb7a3a", + [PALETTE.WING]: "#444444", + [PALETTE.WING_EDGE]: "#232323", + [PALETTE.THEME_HIGHLIGHT]: "#eb7a3a", }), carolinaWren: new BirdType("Carolina Wren", "Native to the eastern United States, these little birds are known for their curious and energetic nature.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#edc7a9", - [Sprite.NOSE]: "#f7eee5", - [Sprite.HOOD]: "#c58a5b", - [Sprite.BELLY]: "#e1b796", - [Sprite.UNDERBELLY]: "#c79e7c", - [Sprite.WING]: "#c58a5b", - [Sprite.WING_EDGE]: "#866348", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#edc7a9", + [PALETTE.NOSE]: "#f7eee5", + [PALETTE.HOOD]: "#c58a5b", + [PALETTE.BELLY]: "#e1b796", + [PALETTE.UNDERBELLY]: "#c79e7c", + [PALETTE.WING]: "#c58a5b", + [PALETTE.WING_EDGE]: "#866348", }), }; @@ -460,7 +466,7 @@ this.pixels = layers[0].pixels.map(row => row.slice()); // Pad from top with transparent pixels while (this.pixels.length < maxHeight) { - this.pixels.unshift(new Array(this.pixels[0].length).fill(Sprite.TRANSPARENT)); + this.pixels.unshift(new Array(this.pixels[0].length).fill(PALETTE.TRANSPARENT)); } // Combine layers for (let i = 1; i < layers.length; i++) { @@ -469,7 +475,7 @@ let topMargin = maxHeight - layerPixels.length; for (let y = 0; y < layerPixels.length; y++) { for (let x = 0; x < layerPixels[y].length; x++) { - this.pixels[y + topMargin][x] = layerPixels[y][x] !== Sprite.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; + this.pixels[y + topMargin][x] = layerPixels[y][x] !== PALETTE.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; } } } @@ -2385,7 +2391,7 @@ function switchSpecies(type) { currentSpecies = type; // Update CSS variable --birb-highlight to be wing color - document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[Sprite.THEME_HIGHLIGHT]); + document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[PALETTE.THEME_HIGHLIGHT]); save(); } @@ -2653,7 +2659,7 @@ const b = pixels[index + 2]; const a = pixels[index + 3]; if (a === 0) { - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); continue; } const hex = `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; @@ -2663,7 +2669,7 @@ } if (SPRITE_SHEET_COLOR_MAP[hex] === undefined) { error(`Unknown color: ${hex}`); - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); } row.push(SPRITE_SHEET_COLOR_MAP[hex]); } diff --git a/src/animation/frame.js b/src/animation/frame.js index 757619b..d51515d 100644 --- a/src/animation/frame.js +++ b/src/animation/frame.js @@ -1,5 +1,5 @@ import { Directions } from '../shared.js'; -import { Sprite, BirdType } from './sprites.js'; +import { PALETTE, BirdType } from './sprites.js'; import Layer from './layer.js'; class Frame { @@ -25,7 +25,7 @@ class Frame { this.pixels = layers[0].pixels.map(row => row.slice()); // Pad from top with transparent pixels while (this.pixels.length < maxHeight) { - this.pixels.unshift(new Array(this.pixels[0].length).fill(Sprite.TRANSPARENT)); + this.pixels.unshift(new Array(this.pixels[0].length).fill(PALETTE.TRANSPARENT)); } // Combine layers for (let i = 1; i < layers.length; i++) { @@ -34,7 +34,7 @@ class Frame { let topMargin = maxHeight - layerPixels.length; for (let y = 0; y < layerPixels.length; y++) { for (let x = 0; x < layerPixels[y].length; x++) { - this.pixels[y + topMargin][x] = layerPixels[y][x] !== Sprite.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; + this.pixels[y + topMargin][x] = layerPixels[y][x] !== PALETTE.TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; } } } diff --git a/src/animation/sprites.js b/src/animation/sprites.js index ff9b372..9ff5e80 100644 --- a/src/animation/sprites.js +++ b/src/animation/sprites.js @@ -1,5 +1,8 @@ -/** Indicators for parts of the base bird sprite sheet */ -export const Sprite = { +/** + * Palette color names + * @type {Record} + */ +export const PALETTE = { THEME_HIGHLIGHT: "theme-highlight", TRANSPARENT: "transparent", OUTLINE: "outline", @@ -20,25 +23,28 @@ export const Sprite = { FEATHER_SPINE: "feather-spine", }; -/** @type {Record} */ +/** + * Mapping of sprite sheet colors to palette colors + * @type {Record} + */ export const SPRITE_SHEET_COLOR_MAP = { - "transparent": Sprite.TRANSPARENT, - "#ffffff": Sprite.BORDER, - "#000000": Sprite.OUTLINE, - "#010a19": Sprite.BEAK, - "#190301": Sprite.EYE, - "#af8e75": Sprite.FOOT, - "#639bff": Sprite.FACE, - "#99e550": Sprite.HOOD, - "#d95763": Sprite.NOSE, - "#f8b143": Sprite.BELLY, - "#ec8637": Sprite.UNDERBELLY, - "#578ae6": Sprite.WING, - "#326ed9": Sprite.WING_EDGE, - "#c82e2e": Sprite.HEART, - "#501a1a": Sprite.HEART_BORDER, - "#ff6b6b": Sprite.HEART_SHINE, - "#373737": Sprite.FEATHER_SPINE, + "transparent": PALETTE.TRANSPARENT, + "#ffffff": PALETTE.BORDER, + "#000000": PALETTE.OUTLINE, + "#010a19": PALETTE.BEAK, + "#190301": PALETTE.EYE, + "#af8e75": PALETTE.FOOT, + "#639bff": PALETTE.FACE, + "#99e550": PALETTE.HOOD, + "#d95763": PALETTE.NOSE, + "#f8b143": PALETTE.BELLY, + "#ec8637": PALETTE.UNDERBELLY, + "#578ae6": PALETTE.WING, + "#326ed9": PALETTE.WING_EDGE, + "#c82e2e": PALETTE.HEART, + "#501a1a": PALETTE.HEART_BORDER, + "#ff6b6b": PALETTE.HEART_SHINE, + "#373737": PALETTE.FEATHER_SPINE, }; export class BirdType { @@ -52,20 +58,20 @@ export class BirdType { this.name = name; this.description = description; const defaultColors = { - [Sprite.TRANSPARENT]: "transparent", - [Sprite.OUTLINE]: "#000000", - [Sprite.BORDER]: "#ffffff", - [Sprite.BEAK]: "#000000", - [Sprite.EYE]: "#000000", - [Sprite.HEART]: "#c82e2e", - [Sprite.HEART_BORDER]: "#501a1a", - [Sprite.HEART_SHINE]: "#ff6b6b", - [Sprite.FEATHER_SPINE]: "#373737", - [Sprite.HOOD]: colors.face, - [Sprite.NOSE]: colors.face, + [PALETTE.TRANSPARENT]: "transparent", + [PALETTE.OUTLINE]: "#000000", + [PALETTE.BORDER]: "#ffffff", + [PALETTE.BEAK]: "#000000", + [PALETTE.EYE]: "#000000", + [PALETTE.HEART]: "#c82e2e", + [PALETTE.HEART_BORDER]: "#501a1a", + [PALETTE.HEART_SHINE]: "#ff6b6b", + [PALETTE.FEATHER_SPINE]: "#373737", + [PALETTE.HOOD]: colors.face, + [PALETTE.NOSE]: colors.face, }; /** @type {Record} */ - this.colors = { ...defaultColors, ...colors, [Sprite.THEME_HIGHLIGHT]: colors[Sprite.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; + this.colors = { ...defaultColors, ...colors, [PALETTE.THEME_HIGHLIGHT]: colors[PALETTE.THEME_HIGHLIGHT] ?? colors.hood ?? colors.face }; this.tags = tags; } } @@ -74,126 +80,126 @@ export class BirdType { export const SPECIES = { bluebird: new BirdType("Eastern Bluebird", "Native to North American and very social, though can be timid around people.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#639bff", - [Sprite.BELLY]: "#f8b143", - [Sprite.UNDERBELLY]: "#ec8637", - [Sprite.WING]: "#578ae6", - [Sprite.WING_EDGE]: "#326ed9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#639bff", + [PALETTE.BELLY]: "#f8b143", + [PALETTE.UNDERBELLY]: "#ec8637", + [PALETTE.WING]: "#578ae6", + [PALETTE.WING_EDGE]: "#326ed9", }), shimaEnaga: new BirdType("Shima Enaga", "Small, fluffy birds found in the snowy regions of Japan, these birds are highly sought after by ornithologists and nature photographers.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffffff", - [Sprite.BELLY]: "#ebe9e8", - [Sprite.UNDERBELLY]: "#ebd9d0", - [Sprite.WING]: "#f3d3c1", - [Sprite.WING_EDGE]: "#2d2d2d", - [Sprite.THEME_HIGHLIGHT]: "#d7ac93", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffffff", + [PALETTE.BELLY]: "#ebe9e8", + [PALETTE.UNDERBELLY]: "#ebd9d0", + [PALETTE.WING]: "#f3d3c1", + [PALETTE.WING_EDGE]: "#2d2d2d", + [PALETTE.THEME_HIGHLIGHT]: "#d7ac93", }), tuftedTitmouse: new BirdType("Tufted Titmouse", "Native to the eastern United States, full of personality, and notably my wife's favorite bird.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#c7cad7", - [Sprite.BELLY]: "#e4e5eb", - [Sprite.UNDERBELLY]: "#d7cfcb", - [Sprite.WING]: "#b1b5c5", - [Sprite.WING_EDGE]: "#9d9fa9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#c7cad7", + [PALETTE.BELLY]: "#e4e5eb", + [PALETTE.UNDERBELLY]: "#d7cfcb", + [PALETTE.WING]: "#b1b5c5", + [PALETTE.WING_EDGE]: "#9d9fa9", }, ["tuft"]), europeanRobin: new BirdType("European Robin", "Native to western Europe, this is the quintessential robin. Quite friendly, you'll often find them searching for worms.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#ffaf34", - [Sprite.HOOD]: "#aaa094", - [Sprite.BELLY]: "#ffaf34", - [Sprite.UNDERBELLY]: "#babec2", - [Sprite.WING]: "#aaa094", - [Sprite.WING_EDGE]: "#888580", - [Sprite.THEME_HIGHLIGHT]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#ffaf34", + [PALETTE.HOOD]: "#aaa094", + [PALETTE.BELLY]: "#ffaf34", + [PALETTE.UNDERBELLY]: "#babec2", + [PALETTE.WING]: "#aaa094", + [PALETTE.WING_EDGE]: "#888580", + [PALETTE.THEME_HIGHLIGHT]: "#ffaf34", }), redCardinal: new BirdType("Red Cardinal", "Native to the eastern United States, this strikingly red bird is hard to miss.", { - [Sprite.BEAK]: "#d93619", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#31353d", - [Sprite.HOOD]: "#e83a1b", - [Sprite.BELLY]: "#e83a1b", - [Sprite.UNDERBELLY]: "#dc3719", - [Sprite.WING]: "#d23215", - [Sprite.WING_EDGE]: "#b1321c", + [PALETTE.BEAK]: "#d93619", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#31353d", + [PALETTE.HOOD]: "#e83a1b", + [PALETTE.BELLY]: "#e83a1b", + [PALETTE.UNDERBELLY]: "#dc3719", + [PALETTE.WING]: "#d23215", + [PALETTE.WING_EDGE]: "#b1321c", }, ["tuft"]), americanGoldfinch: new BirdType("American Goldfinch", "Coloured a brilliant yellow, this bird feeds almost entirely on the seeds of plants such as thistle, sunflowers, and coneflowers.", { - [Sprite.BEAK]: "#ffaf34", - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#fff255", - [Sprite.NOSE]: "#383838", - [Sprite.HOOD]: "#383838", - [Sprite.BELLY]: "#fff255", - [Sprite.UNDERBELLY]: "#f5ea63", - [Sprite.WING]: "#e8e079", - [Sprite.WING_EDGE]: "#191919", - [Sprite.THEME_HIGHLIGHT]: "#ffcc00" + [PALETTE.BEAK]: "#ffaf34", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#fff255", + [PALETTE.NOSE]: "#383838", + [PALETTE.HOOD]: "#383838", + [PALETTE.BELLY]: "#fff255", + [PALETTE.UNDERBELLY]: "#f5ea63", + [PALETTE.WING]: "#e8e079", + [PALETTE.WING_EDGE]: "#191919", + [PALETTE.THEME_HIGHLIGHT]: "#ffcc00" }), barnSwallow: new BirdType("Barn Swallow", "Agile birds that often roost in man-made structures, these birds are known to build nests near Ospreys for protection.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#db7c4d", - [Sprite.BELLY]: "#f7e1c9", - [Sprite.UNDERBELLY]: "#ebc9a3", - [Sprite.WING]: "#2252a9", - [Sprite.WING_EDGE]: "#1c448b", - [Sprite.HOOD]: "#2252a9", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#db7c4d", + [PALETTE.BELLY]: "#f7e1c9", + [PALETTE.UNDERBELLY]: "#ebc9a3", + [PALETTE.WING]: "#2252a9", + [PALETTE.WING_EDGE]: "#1c448b", + [PALETTE.HOOD]: "#2252a9", }), mistletoebird: new BirdType("Mistletoebird", "Native to Australia, these birds eat mainly mistletoe and in turn spread the seeds far and wide.", { - [Sprite.FOOT]: "#6c6a7c", - [Sprite.FACE]: "#352e6d", - [Sprite.BELLY]: "#fd6833", - [Sprite.UNDERBELLY]: "#e6e1d8", - [Sprite.WING]: "#342b7c", - [Sprite.WING_EDGE]: "#282065", + [PALETTE.FOOT]: "#6c6a7c", + [PALETTE.FACE]: "#352e6d", + [PALETTE.BELLY]: "#fd6833", + [PALETTE.UNDERBELLY]: "#e6e1d8", + [PALETTE.WING]: "#342b7c", + [PALETTE.WING_EDGE]: "#282065", }), redAvadavat: new BirdType("Red Avadavat", "Native to India and southeast Asia, these birds are also known as Strawberry Finches due to their speckled plumage.", { - [Sprite.BEAK]: "#f71919", - [Sprite.FOOT]: "#af7575", - [Sprite.FACE]: "#cb092b", - [Sprite.BELLY]: "#ae1724", - [Sprite.UNDERBELLY]: "#831b24", - [Sprite.WING]: "#7e3030", - [Sprite.WING_EDGE]: "#490f0f", + [PALETTE.BEAK]: "#f71919", + [PALETTE.FOOT]: "#af7575", + [PALETTE.FACE]: "#cb092b", + [PALETTE.BELLY]: "#ae1724", + [PALETTE.UNDERBELLY]: "#831b24", + [PALETTE.WING]: "#7e3030", + [PALETTE.WING_EDGE]: "#490f0f", }), scarletRobin: new BirdType("Scarlet Robin", "Native to Australia, this striking robin can be found in Eucalyptus forests.", { - [Sprite.FOOT]: "#494949", - [Sprite.FACE]: "#3d3d3d", - [Sprite.BELLY]: "#fc5633", - [Sprite.UNDERBELLY]: "#dcdcdc", - [Sprite.WING]: "#2b2b2b", - [Sprite.WING_EDGE]: "#ebebeb", - [Sprite.THEME_HIGHLIGHT]: "#fc5633", + [PALETTE.FOOT]: "#494949", + [PALETTE.FACE]: "#3d3d3d", + [PALETTE.BELLY]: "#fc5633", + [PALETTE.UNDERBELLY]: "#dcdcdc", + [PALETTE.WING]: "#2b2b2b", + [PALETTE.WING_EDGE]: "#ebebeb", + [PALETTE.THEME_HIGHLIGHT]: "#fc5633", }), americanRobin: new BirdType("American Robin", "While not a true robin, this social North American bird is so named due to its orange coloring. It seems unbothered by nearby humans.", { - [Sprite.BEAK]: "#e89f30", - [Sprite.FOOT]: "#9f8075", - [Sprite.FACE]: "#2d2d2d", - [Sprite.BELLY]: "#eb7a3a", - [Sprite.UNDERBELLY]: "#eb7a3a", - [Sprite.WING]: "#444444", - [Sprite.WING_EDGE]: "#232323", - [Sprite.THEME_HIGHLIGHT]: "#eb7a3a", + [PALETTE.BEAK]: "#e89f30", + [PALETTE.FOOT]: "#9f8075", + [PALETTE.FACE]: "#2d2d2d", + [PALETTE.BELLY]: "#eb7a3a", + [PALETTE.UNDERBELLY]: "#eb7a3a", + [PALETTE.WING]: "#444444", + [PALETTE.WING_EDGE]: "#232323", + [PALETTE.THEME_HIGHLIGHT]: "#eb7a3a", }), carolinaWren: new BirdType("Carolina Wren", "Native to the eastern United States, these little birds are known for their curious and energetic nature.", { - [Sprite.FOOT]: "#af8e75", - [Sprite.FACE]: "#edc7a9", - [Sprite.NOSE]: "#f7eee5", - [Sprite.HOOD]: "#c58a5b", - [Sprite.BELLY]: "#e1b796", - [Sprite.UNDERBELLY]: "#c79e7c", - [Sprite.WING]: "#c58a5b", - [Sprite.WING_EDGE]: "#866348", + [PALETTE.FOOT]: "#af8e75", + [PALETTE.FACE]: "#edc7a9", + [PALETTE.NOSE]: "#f7eee5", + [PALETTE.HOOD]: "#c58a5b", + [PALETTE.BELLY]: "#e1b796", + [PALETTE.UNDERBELLY]: "#c79e7c", + [PALETTE.WING]: "#c58a5b", + [PALETTE.WING_EDGE]: "#866348", }), }; \ No newline at end of file diff --git a/src/application.js b/src/application.js index da7dfe6..42806a0 100644 --- a/src/application.js +++ b/src/application.js @@ -23,7 +23,7 @@ import { getWindowHeight } from './shared.js'; import { - Sprite, + PALETTE, SPRITE_SHEET_COLOR_MAP, SPECIES } from './animation/sprites.js'; @@ -730,7 +730,7 @@ function startApplication(birbPixels, featherPixels) { function switchSpecies(type) { currentSpecies = type; // Update CSS variable --birb-highlight to be wing color - document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[Sprite.THEME_HIGHLIGHT]); + document.documentElement.style.setProperty("--birb-highlight", SPECIES[type].colors[PALETTE.THEME_HIGHLIGHT]); save(); } @@ -1012,7 +1012,7 @@ function loadSpriteSheetPixels(dataUri, templateColors = true) { const b = pixels[index + 2]; const a = pixels[index + 3]; if (a === 0) { - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); continue; } const hex = `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; @@ -1022,7 +1022,7 @@ function loadSpriteSheetPixels(dataUri, templateColors = true) { } if (SPRITE_SHEET_COLOR_MAP[hex] === undefined) { error(`Unknown color: ${hex}`); - row.push(Sprite.TRANSPARENT); + row.push(PALETTE.TRANSPARENT); } row.push(SPRITE_SHEET_COLOR_MAP[hex]); }