From 7c38bf9164a7ce96bb326fb507880dd7b32fd367 Mon Sep 17 00:00:00 2001 From: Idrees Hassan Date: Sun, 18 Jan 2026 19:14:18 -0500 Subject: [PATCH] Separate hat functions --- dist/extension.zip | Bin 150422 -> 150655 bytes dist/extension/birb.js | 183 ++++++++++++++++++++--------------- dist/obsidian/main.js | 183 ++++++++++++++++++++--------------- dist/userscript/birb.user.js | 183 ++++++++++++++++++++--------------- dist/web/birb.embed.js | 183 ++++++++++++++++++++--------------- dist/web/birb.js | 183 ++++++++++++++++++++--------------- src/birb.js | 87 ++--------------- src/hats.js | 100 +++++++++++++++++++ 8 files changed, 640 insertions(+), 462 deletions(-) create mode 100644 src/hats.js diff --git a/dist/extension.zip b/dist/extension.zip index 9a98b9237be991e35e13a1c1000ba846e8ccae1b..21abee3cfdc536478b5113038210e184d95fc077 100644 GIT binary patch delta 28084 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 delta 27797 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 diff --git a/dist/extension/birb.js b/dist/extension/birb.js index 423a1ee..ee81ae3 100644 --- a/dist/extension/birb.js +++ b/dist/extension/birb.js @@ -605,6 +605,103 @@ } } + const HAT = { + TOP_HAT: 'top-hat' + }; + + /** + * @param {string[][]} spriteSheet + * @returns {{ base: Layer[], down: Layer[] }} + */ + function createHatLayers(spriteSheet) { + const hatLayers = { + base: [], + down: [] + }; + for (const hatName in HAT) { + const hatKey = HAT[hatName]; + const hatLayer = buildHatLayer(spriteSheet, hatKey, false); + const downHatLayer = buildHatLayer(spriteSheet, hatKey, false, 1); + hatLayers.base.push(hatLayer); + hatLayers.down.push(downHatLayer); + } + return hatLayers; + } + + /** + * @param {string[][]} spriteSheet + * @param {string} hatName + * @param {boolean} [outlineBottom=false] + * @param {number} [yOffset=0] + * @returns {Layer} + */ + function buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { + const LEFT_PADDING = 6; + const RIGHT_PADDING = 14; + const TOP_PADDING = 4 + yOffset; + const BOTTOM_PADDING = Math.max(0, 16 - yOffset); + + const hatPixels = getLayerPixels(spriteSheet, 0, 12); + const paddedHatPixels = []; + + // Top padding + for (let y = 0; y < TOP_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + // Left and right padding + for (let y = 0; y < hatPixels.length; y++) { + const row = []; + for (let x = 0; x < LEFT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + for (let x = 0; x < hatPixels[y].length; x++) { + row.push(hatPixels[y][x]); + } + + for (let x = 0; x < RIGHT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + paddedHatPixels.push(row); + } + // Bottom padding + for (let y = 0; y < BOTTOM_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + + // Add outline + let neighborOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [-1, -1], + [1, -1], + ]; + if (outlineBottom) { + neighborOffsets.push([0, 1], [-1, 1], [1, 1]); + } + for (let y = 0; y < paddedHatPixels.length; y++) { + for (let x = 0; x < paddedHatPixels[y].length; x++) { + const pixel = paddedHatPixels[y][x]; + if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { + for (let [dx, dy] of neighborOffsets) { + const newX = x + dx; + const newY = y + dy; + if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { + paddedHatPixels[newY][newX] = PALETTE.BORDER; + } + } + } + } + } + return new Layer(paddedHatPixels); + } + /** * @typedef {keyof typeof Animations} AnimationType */ @@ -656,19 +753,18 @@ }; // Build hat layers - const hatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false); - const downHatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false, 1); + const hatLayers = createHatLayers(hatSpriteSheet); // Build frames from layers this.frames = { - base: new Frame([this.layers.base, this.layers.tuftBase, hatLayer]), - headDown: new Frame([this.layers.down, this.layers.tuftDown, downHatLayer]), - wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, hatLayer]), - wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, downHatLayer]), - heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartOne]), - heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), - heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartThree]), - heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), + base: new Frame([this.layers.base, this.layers.tuftBase, ...hatLayers.base]), + headDown: new Frame([this.layers.down, this.layers.tuftDown, ...hatLayers.down]), + wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, ...hatLayers.base]), + wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, ...hatLayers.down]), + heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartOne]), + heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base,this.layers.heartTwo]), + heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartThree]), + heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartTwo]), }; // Build animations from frames @@ -735,73 +831,6 @@ return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); } - buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { - const LEFT_PADDING = 6; - const RIGHT_PADDING = 14; - const TOP_PADDING = 4 + yOffset; - const BOTTOM_PADDING = Math.max(0, 16 - yOffset); - - const hatPixels = getLayerPixels(spriteSheet, 0, 12); - const paddedHatPixels = []; - - // Top padding - for (let y = 0; y < TOP_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - // Left and right padding - for (let y = 0; y < hatPixels.length; y++) { - const row = []; - for (let x = 0; x < LEFT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - for (let x = 0; x < hatPixels[y].length; x++) { - row.push(hatPixels[y][x]); - } - - for (let x = 0; x < RIGHT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - paddedHatPixels.push(row); - } - // Bottom padding - for (let y = 0; y < BOTTOM_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - - // Add outline - let neighborOffsets = [ - [-1, 0], - [1, 0], - [0, -1], - [-1, -1], - [1, -1], - ]; - if (outlineBottom) { - neighborOffsets.push([0, 1], [-1, 1], [1, 1]); - } - for (let y = 0; y < paddedHatPixels.length; y++) { - for (let x = 0; x < paddedHatPixels[y].length; x++) { - const pixel = paddedHatPixels[y][x]; - if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { - for (let [dx, dy] of neighborOffsets) { - const newX = x + dx; - const newY = y + dy; - if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { - paddedHatPixels[newY][newX] = PALETTE.BORDER; - } - } - } - } - } - return new Layer(paddedHatPixels); - } - /** * @returns {AnimationType} The current animation key diff --git a/dist/obsidian/main.js b/dist/obsidian/main.js index f02c753..ac84a97 100644 --- a/dist/obsidian/main.js +++ b/dist/obsidian/main.js @@ -610,6 +610,103 @@ module.exports = class PocketBird extends Plugin { } } + const HAT = { + TOP_HAT: 'top-hat' + }; + + /** + * @param {string[][]} spriteSheet + * @returns {{ base: Layer[], down: Layer[] }} + */ + function createHatLayers(spriteSheet) { + const hatLayers = { + base: [], + down: [] + }; + for (const hatName in HAT) { + const hatKey = HAT[hatName]; + const hatLayer = buildHatLayer(spriteSheet, hatKey, false); + const downHatLayer = buildHatLayer(spriteSheet, hatKey, false, 1); + hatLayers.base.push(hatLayer); + hatLayers.down.push(downHatLayer); + } + return hatLayers; + } + + /** + * @param {string[][]} spriteSheet + * @param {string} hatName + * @param {boolean} [outlineBottom=false] + * @param {number} [yOffset=0] + * @returns {Layer} + */ + function buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { + const LEFT_PADDING = 6; + const RIGHT_PADDING = 14; + const TOP_PADDING = 4 + yOffset; + const BOTTOM_PADDING = Math.max(0, 16 - yOffset); + + const hatPixels = getLayerPixels(spriteSheet, 0, 12); + const paddedHatPixels = []; + + // Top padding + for (let y = 0; y < TOP_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + // Left and right padding + for (let y = 0; y < hatPixels.length; y++) { + const row = []; + for (let x = 0; x < LEFT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + for (let x = 0; x < hatPixels[y].length; x++) { + row.push(hatPixels[y][x]); + } + + for (let x = 0; x < RIGHT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + paddedHatPixels.push(row); + } + // Bottom padding + for (let y = 0; y < BOTTOM_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + + // Add outline + let neighborOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [-1, -1], + [1, -1], + ]; + if (outlineBottom) { + neighborOffsets.push([0, 1], [-1, 1], [1, 1]); + } + for (let y = 0; y < paddedHatPixels.length; y++) { + for (let x = 0; x < paddedHatPixels[y].length; x++) { + const pixel = paddedHatPixels[y][x]; + if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { + for (let [dx, dy] of neighborOffsets) { + const newX = x + dx; + const newY = y + dy; + if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { + paddedHatPixels[newY][newX] = PALETTE.BORDER; + } + } + } + } + } + return new Layer(paddedHatPixels); + } + /** * @typedef {keyof typeof Animations} AnimationType */ @@ -661,19 +758,18 @@ module.exports = class PocketBird extends Plugin { }; // Build hat layers - const hatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false); - const downHatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false, 1); + const hatLayers = createHatLayers(hatSpriteSheet); // Build frames from layers this.frames = { - base: new Frame([this.layers.base, this.layers.tuftBase, hatLayer]), - headDown: new Frame([this.layers.down, this.layers.tuftDown, downHatLayer]), - wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, hatLayer]), - wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, downHatLayer]), - heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartOne]), - heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), - heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartThree]), - heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), + base: new Frame([this.layers.base, this.layers.tuftBase, ...hatLayers.base]), + headDown: new Frame([this.layers.down, this.layers.tuftDown, ...hatLayers.down]), + wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, ...hatLayers.base]), + wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, ...hatLayers.down]), + heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartOne]), + heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base,this.layers.heartTwo]), + heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartThree]), + heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartTwo]), }; // Build animations from frames @@ -740,73 +836,6 @@ module.exports = class PocketBird extends Plugin { return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); } - buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { - const LEFT_PADDING = 6; - const RIGHT_PADDING = 14; - const TOP_PADDING = 4 + yOffset; - const BOTTOM_PADDING = Math.max(0, 16 - yOffset); - - const hatPixels = getLayerPixels(spriteSheet, 0, 12); - const paddedHatPixels = []; - - // Top padding - for (let y = 0; y < TOP_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - // Left and right padding - for (let y = 0; y < hatPixels.length; y++) { - const row = []; - for (let x = 0; x < LEFT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - for (let x = 0; x < hatPixels[y].length; x++) { - row.push(hatPixels[y][x]); - } - - for (let x = 0; x < RIGHT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - paddedHatPixels.push(row); - } - // Bottom padding - for (let y = 0; y < BOTTOM_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - - // Add outline - let neighborOffsets = [ - [-1, 0], - [1, 0], - [0, -1], - [-1, -1], - [1, -1], - ]; - if (outlineBottom) { - neighborOffsets.push([0, 1], [-1, 1], [1, 1]); - } - for (let y = 0; y < paddedHatPixels.length; y++) { - for (let x = 0; x < paddedHatPixels[y].length; x++) { - const pixel = paddedHatPixels[y][x]; - if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { - for (let [dx, dy] of neighborOffsets) { - const newX = x + dx; - const newY = y + dy; - if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { - paddedHatPixels[newY][newX] = PALETTE.BORDER; - } - } - } - } - } - return new Layer(paddedHatPixels); - } - /** * @returns {AnimationType} The current animation key diff --git a/dist/userscript/birb.user.js b/dist/userscript/birb.user.js index f2c01f1..33cce0c 100644 --- a/dist/userscript/birb.user.js +++ b/dist/userscript/birb.user.js @@ -619,6 +619,103 @@ } } + const HAT = { + TOP_HAT: 'top-hat' + }; + + /** + * @param {string[][]} spriteSheet + * @returns {{ base: Layer[], down: Layer[] }} + */ + function createHatLayers(spriteSheet) { + const hatLayers = { + base: [], + down: [] + }; + for (const hatName in HAT) { + const hatKey = HAT[hatName]; + const hatLayer = buildHatLayer(spriteSheet, hatKey, false); + const downHatLayer = buildHatLayer(spriteSheet, hatKey, false, 1); + hatLayers.base.push(hatLayer); + hatLayers.down.push(downHatLayer); + } + return hatLayers; + } + + /** + * @param {string[][]} spriteSheet + * @param {string} hatName + * @param {boolean} [outlineBottom=false] + * @param {number} [yOffset=0] + * @returns {Layer} + */ + function buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { + const LEFT_PADDING = 6; + const RIGHT_PADDING = 14; + const TOP_PADDING = 4 + yOffset; + const BOTTOM_PADDING = Math.max(0, 16 - yOffset); + + const hatPixels = getLayerPixels(spriteSheet, 0, 12); + const paddedHatPixels = []; + + // Top padding + for (let y = 0; y < TOP_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + // Left and right padding + for (let y = 0; y < hatPixels.length; y++) { + const row = []; + for (let x = 0; x < LEFT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + for (let x = 0; x < hatPixels[y].length; x++) { + row.push(hatPixels[y][x]); + } + + for (let x = 0; x < RIGHT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + paddedHatPixels.push(row); + } + // Bottom padding + for (let y = 0; y < BOTTOM_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + + // Add outline + let neighborOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [-1, -1], + [1, -1], + ]; + if (outlineBottom) { + neighborOffsets.push([0, 1], [-1, 1], [1, 1]); + } + for (let y = 0; y < paddedHatPixels.length; y++) { + for (let x = 0; x < paddedHatPixels[y].length; x++) { + const pixel = paddedHatPixels[y][x]; + if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { + for (let [dx, dy] of neighborOffsets) { + const newX = x + dx; + const newY = y + dy; + if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { + paddedHatPixels[newY][newX] = PALETTE.BORDER; + } + } + } + } + } + return new Layer(paddedHatPixels); + } + /** * @typedef {keyof typeof Animations} AnimationType */ @@ -670,19 +767,18 @@ }; // Build hat layers - const hatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false); - const downHatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false, 1); + const hatLayers = createHatLayers(hatSpriteSheet); // Build frames from layers this.frames = { - base: new Frame([this.layers.base, this.layers.tuftBase, hatLayer]), - headDown: new Frame([this.layers.down, this.layers.tuftDown, downHatLayer]), - wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, hatLayer]), - wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, downHatLayer]), - heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartOne]), - heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), - heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartThree]), - heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), + base: new Frame([this.layers.base, this.layers.tuftBase, ...hatLayers.base]), + headDown: new Frame([this.layers.down, this.layers.tuftDown, ...hatLayers.down]), + wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, ...hatLayers.base]), + wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, ...hatLayers.down]), + heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartOne]), + heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base,this.layers.heartTwo]), + heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartThree]), + heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartTwo]), }; // Build animations from frames @@ -749,73 +845,6 @@ return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); } - buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { - const LEFT_PADDING = 6; - const RIGHT_PADDING = 14; - const TOP_PADDING = 4 + yOffset; - const BOTTOM_PADDING = Math.max(0, 16 - yOffset); - - const hatPixels = getLayerPixels(spriteSheet, 0, 12); - const paddedHatPixels = []; - - // Top padding - for (let y = 0; y < TOP_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - // Left and right padding - for (let y = 0; y < hatPixels.length; y++) { - const row = []; - for (let x = 0; x < LEFT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - for (let x = 0; x < hatPixels[y].length; x++) { - row.push(hatPixels[y][x]); - } - - for (let x = 0; x < RIGHT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - paddedHatPixels.push(row); - } - // Bottom padding - for (let y = 0; y < BOTTOM_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - - // Add outline - let neighborOffsets = [ - [-1, 0], - [1, 0], - [0, -1], - [-1, -1], - [1, -1], - ]; - if (outlineBottom) { - neighborOffsets.push([0, 1], [-1, 1], [1, 1]); - } - for (let y = 0; y < paddedHatPixels.length; y++) { - for (let x = 0; x < paddedHatPixels[y].length; x++) { - const pixel = paddedHatPixels[y][x]; - if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { - for (let [dx, dy] of neighborOffsets) { - const newX = x + dx; - const newY = y + dy; - if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { - paddedHatPixels[newY][newX] = PALETTE.BORDER; - } - } - } - } - } - return new Layer(paddedHatPixels); - } - /** * @returns {AnimationType} The current animation key diff --git a/dist/web/birb.embed.js b/dist/web/birb.embed.js index 2f4af0c..2f15ba2 100644 --- a/dist/web/birb.embed.js +++ b/dist/web/birb.embed.js @@ -605,6 +605,103 @@ } } + const HAT = { + TOP_HAT: 'top-hat' + }; + + /** + * @param {string[][]} spriteSheet + * @returns {{ base: Layer[], down: Layer[] }} + */ + function createHatLayers(spriteSheet) { + const hatLayers = { + base: [], + down: [] + }; + for (const hatName in HAT) { + const hatKey = HAT[hatName]; + const hatLayer = buildHatLayer(spriteSheet, hatKey, false); + const downHatLayer = buildHatLayer(spriteSheet, hatKey, false, 1); + hatLayers.base.push(hatLayer); + hatLayers.down.push(downHatLayer); + } + return hatLayers; + } + + /** + * @param {string[][]} spriteSheet + * @param {string} hatName + * @param {boolean} [outlineBottom=false] + * @param {number} [yOffset=0] + * @returns {Layer} + */ + function buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { + const LEFT_PADDING = 6; + const RIGHT_PADDING = 14; + const TOP_PADDING = 4 + yOffset; + const BOTTOM_PADDING = Math.max(0, 16 - yOffset); + + const hatPixels = getLayerPixels(spriteSheet, 0, 12); + const paddedHatPixels = []; + + // Top padding + for (let y = 0; y < TOP_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + // Left and right padding + for (let y = 0; y < hatPixels.length; y++) { + const row = []; + for (let x = 0; x < LEFT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + for (let x = 0; x < hatPixels[y].length; x++) { + row.push(hatPixels[y][x]); + } + + for (let x = 0; x < RIGHT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + paddedHatPixels.push(row); + } + // Bottom padding + for (let y = 0; y < BOTTOM_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + + // Add outline + let neighborOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [-1, -1], + [1, -1], + ]; + if (outlineBottom) { + neighborOffsets.push([0, 1], [-1, 1], [1, 1]); + } + for (let y = 0; y < paddedHatPixels.length; y++) { + for (let x = 0; x < paddedHatPixels[y].length; x++) { + const pixel = paddedHatPixels[y][x]; + if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { + for (let [dx, dy] of neighborOffsets) { + const newX = x + dx; + const newY = y + dy; + if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { + paddedHatPixels[newY][newX] = PALETTE.BORDER; + } + } + } + } + } + return new Layer(paddedHatPixels); + } + /** * @typedef {keyof typeof Animations} AnimationType */ @@ -656,19 +753,18 @@ }; // Build hat layers - const hatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false); - const downHatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false, 1); + const hatLayers = createHatLayers(hatSpriteSheet); // Build frames from layers this.frames = { - base: new Frame([this.layers.base, this.layers.tuftBase, hatLayer]), - headDown: new Frame([this.layers.down, this.layers.tuftDown, downHatLayer]), - wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, hatLayer]), - wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, downHatLayer]), - heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartOne]), - heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), - heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartThree]), - heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), + base: new Frame([this.layers.base, this.layers.tuftBase, ...hatLayers.base]), + headDown: new Frame([this.layers.down, this.layers.tuftDown, ...hatLayers.down]), + wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, ...hatLayers.base]), + wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, ...hatLayers.down]), + heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartOne]), + heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base,this.layers.heartTwo]), + heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartThree]), + heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartTwo]), }; // Build animations from frames @@ -735,73 +831,6 @@ return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); } - buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { - const LEFT_PADDING = 6; - const RIGHT_PADDING = 14; - const TOP_PADDING = 4 + yOffset; - const BOTTOM_PADDING = Math.max(0, 16 - yOffset); - - const hatPixels = getLayerPixels(spriteSheet, 0, 12); - const paddedHatPixels = []; - - // Top padding - for (let y = 0; y < TOP_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - // Left and right padding - for (let y = 0; y < hatPixels.length; y++) { - const row = []; - for (let x = 0; x < LEFT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - for (let x = 0; x < hatPixels[y].length; x++) { - row.push(hatPixels[y][x]); - } - - for (let x = 0; x < RIGHT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - paddedHatPixels.push(row); - } - // Bottom padding - for (let y = 0; y < BOTTOM_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - - // Add outline - let neighborOffsets = [ - [-1, 0], - [1, 0], - [0, -1], - [-1, -1], - [1, -1], - ]; - if (outlineBottom) { - neighborOffsets.push([0, 1], [-1, 1], [1, 1]); - } - for (let y = 0; y < paddedHatPixels.length; y++) { - for (let x = 0; x < paddedHatPixels[y].length; x++) { - const pixel = paddedHatPixels[y][x]; - if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { - for (let [dx, dy] of neighborOffsets) { - const newX = x + dx; - const newY = y + dy; - if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { - paddedHatPixels[newY][newX] = PALETTE.BORDER; - } - } - } - } - } - return new Layer(paddedHatPixels); - } - /** * @returns {AnimationType} The current animation key diff --git a/dist/web/birb.js b/dist/web/birb.js index 2f4af0c..2f15ba2 100644 --- a/dist/web/birb.js +++ b/dist/web/birb.js @@ -605,6 +605,103 @@ } } + const HAT = { + TOP_HAT: 'top-hat' + }; + + /** + * @param {string[][]} spriteSheet + * @returns {{ base: Layer[], down: Layer[] }} + */ + function createHatLayers(spriteSheet) { + const hatLayers = { + base: [], + down: [] + }; + for (const hatName in HAT) { + const hatKey = HAT[hatName]; + const hatLayer = buildHatLayer(spriteSheet, hatKey, false); + const downHatLayer = buildHatLayer(spriteSheet, hatKey, false, 1); + hatLayers.base.push(hatLayer); + hatLayers.down.push(downHatLayer); + } + return hatLayers; + } + + /** + * @param {string[][]} spriteSheet + * @param {string} hatName + * @param {boolean} [outlineBottom=false] + * @param {number} [yOffset=0] + * @returns {Layer} + */ + function buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { + const LEFT_PADDING = 6; + const RIGHT_PADDING = 14; + const TOP_PADDING = 4 + yOffset; + const BOTTOM_PADDING = Math.max(0, 16 - yOffset); + + const hatPixels = getLayerPixels(spriteSheet, 0, 12); + const paddedHatPixels = []; + + // Top padding + for (let y = 0; y < TOP_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + // Left and right padding + for (let y = 0; y < hatPixels.length; y++) { + const row = []; + for (let x = 0; x < LEFT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + for (let x = 0; x < hatPixels[y].length; x++) { + row.push(hatPixels[y][x]); + } + + for (let x = 0; x < RIGHT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + paddedHatPixels.push(row); + } + // Bottom padding + for (let y = 0; y < BOTTOM_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + + // Add outline + let neighborOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [-1, -1], + [1, -1], + ]; + if (outlineBottom) { + neighborOffsets.push([0, 1], [-1, 1], [1, 1]); + } + for (let y = 0; y < paddedHatPixels.length; y++) { + for (let x = 0; x < paddedHatPixels[y].length; x++) { + const pixel = paddedHatPixels[y][x]; + if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { + for (let [dx, dy] of neighborOffsets) { + const newX = x + dx; + const newY = y + dy; + if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { + paddedHatPixels[newY][newX] = PALETTE.BORDER; + } + } + } + } + } + return new Layer(paddedHatPixels); + } + /** * @typedef {keyof typeof Animations} AnimationType */ @@ -656,19 +753,18 @@ }; // Build hat layers - const hatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false); - const downHatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false, 1); + const hatLayers = createHatLayers(hatSpriteSheet); // Build frames from layers this.frames = { - base: new Frame([this.layers.base, this.layers.tuftBase, hatLayer]), - headDown: new Frame([this.layers.down, this.layers.tuftDown, downHatLayer]), - wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, hatLayer]), - wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, downHatLayer]), - heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartOne]), - heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), - heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartThree]), - heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), + base: new Frame([this.layers.base, this.layers.tuftBase, ...hatLayers.base]), + headDown: new Frame([this.layers.down, this.layers.tuftDown, ...hatLayers.down]), + wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, ...hatLayers.base]), + wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, ...hatLayers.down]), + heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartOne]), + heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base,this.layers.heartTwo]), + heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartThree]), + heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartTwo]), }; // Build animations from frames @@ -735,73 +831,6 @@ return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); } - buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { - const LEFT_PADDING = 6; - const RIGHT_PADDING = 14; - const TOP_PADDING = 4 + yOffset; - const BOTTOM_PADDING = Math.max(0, 16 - yOffset); - - const hatPixels = getLayerPixels(spriteSheet, 0, 12); - const paddedHatPixels = []; - - // Top padding - for (let y = 0; y < TOP_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - // Left and right padding - for (let y = 0; y < hatPixels.length; y++) { - const row = []; - for (let x = 0; x < LEFT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - for (let x = 0; x < hatPixels[y].length; x++) { - row.push(hatPixels[y][x]); - } - - for (let x = 0; x < RIGHT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - paddedHatPixels.push(row); - } - // Bottom padding - for (let y = 0; y < BOTTOM_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - - // Add outline - let neighborOffsets = [ - [-1, 0], - [1, 0], - [0, -1], - [-1, -1], - [1, -1], - ]; - if (outlineBottom) { - neighborOffsets.push([0, 1], [-1, 1], [1, 1]); - } - for (let y = 0; y < paddedHatPixels.length; y++) { - for (let x = 0; x < paddedHatPixels[y].length; x++) { - const pixel = paddedHatPixels[y][x]; - if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { - for (let [dx, dy] of neighborOffsets) { - const newX = x + dx; - const newY = y + dy; - if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { - paddedHatPixels[newY][newX] = PALETTE.BORDER; - } - } - } - } - } - return new Layer(paddedHatPixels); - } - /** * @returns {AnimationType} The current animation key diff --git a/src/birb.js b/src/birb.js index 55f56de..83f1490 100644 --- a/src/birb.js +++ b/src/birb.js @@ -3,6 +3,7 @@ import Layer from './animation/layer.js'; import Frame from './animation/frame.js'; import Anim from './animation/anim.js'; import { BirdType, PALETTE } from './animation/sprites.js'; +import { createHatLayers } from './hats.js'; /** * @typedef {keyof typeof Animations} AnimationType @@ -55,19 +56,18 @@ export class Birb { }; // Build hat layers - const hatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false); - const downHatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false, 1); + const hatLayers = createHatLayers(hatSpriteSheet); // Build frames from layers this.frames = { - base: new Frame([this.layers.base, this.layers.tuftBase, hatLayer]), - headDown: new Frame([this.layers.down, this.layers.tuftDown, downHatLayer]), - wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, hatLayer]), - wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, downHatLayer]), - heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartOne]), - heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), - heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartThree]), - heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]), + base: new Frame([this.layers.base, this.layers.tuftBase, ...hatLayers.base]), + headDown: new Frame([this.layers.down, this.layers.tuftDown, ...hatLayers.down]), + wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, ...hatLayers.base]), + wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, ...hatLayers.down]), + heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartOne]), + heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base,this.layers.heartTwo]), + heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartThree]), + heartFour: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, ...hatLayers.base, this.layers.heartTwo]), }; // Build animations from frames @@ -134,73 +134,6 @@ export class Birb { return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); } - buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { - const LEFT_PADDING = 6; - const RIGHT_PADDING = 14; - const TOP_PADDING = 4 + yOffset; - const BOTTOM_PADDING = Math.max(0, 16 - yOffset); - - const hatPixels = getLayerPixels(spriteSheet, 0, 12); - const paddedHatPixels = []; - - // Top padding - for (let y = 0; y < TOP_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - // Left and right padding - for (let y = 0; y < hatPixels.length; y++) { - const row = []; - for (let x = 0; x < LEFT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - for (let x = 0; x < hatPixels[y].length; x++) { - row.push(hatPixels[y][x]); - } - - for (let x = 0; x < RIGHT_PADDING; x++) { - row.push(PALETTE.TRANSPARENT); - } - - paddedHatPixels.push(row); - } - // Bottom padding - for (let y = 0; y < BOTTOM_PADDING; y++) { - paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) - .fill(PALETTE.TRANSPARENT) - ); - } - - // Add outline - let neighborOffsets = [ - [-1, 0], - [1, 0], - [0, -1], - [-1, -1], - [1, -1], - ]; - if (outlineBottom) { - neighborOffsets.push([0, 1], [-1, 1], [1, 1]); - } - for (let y = 0; y < paddedHatPixels.length; y++) { - for (let x = 0; x < paddedHatPixels[y].length; x++) { - const pixel = paddedHatPixels[y][x]; - if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { - for (let [dx, dy] of neighborOffsets) { - const newX = x + dx; - const newY = y + dy; - if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { - paddedHatPixels[newY][newX] = PALETTE.BORDER; - } - } - } - } - } - return new Layer(paddedHatPixels); - } - /** * @returns {AnimationType} The current animation key diff --git a/src/hats.js b/src/hats.js new file mode 100644 index 0000000..8d01392 --- /dev/null +++ b/src/hats.js @@ -0,0 +1,100 @@ +import Layer from "./animation/layer.js"; +import { PALETTE } from "./animation/sprites.js"; +import { getLayerPixels } from "./shared.js"; + +const HAT = { + TOP_HAT: 'top-hat' +}; + +/** + * @param {string[][]} spriteSheet + * @returns {{ base: Layer[], down: Layer[] }} + */ +export function createHatLayers(spriteSheet) { + const hatLayers = { + base: [], + down: [] + }; + for (const hatName in HAT) { + const hatKey = HAT[hatName]; + const hatLayer = buildHatLayer(spriteSheet, hatKey, false); + const downHatLayer = buildHatLayer(spriteSheet, hatKey, false, 1); + hatLayers.base.push(hatLayer); + hatLayers.down.push(downHatLayer); + } + return hatLayers; +} + +/** + * @param {string[][]} spriteSheet + * @param {string} hatName + * @param {boolean} [outlineBottom=false] + * @param {number} [yOffset=0] + * @returns {Layer} + */ +function buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) { + const LEFT_PADDING = 6; + const RIGHT_PADDING = 14; + const TOP_PADDING = 4 + yOffset; + const BOTTOM_PADDING = Math.max(0, 16 - yOffset); + + const hatPixels = getLayerPixels(spriteSheet, 0, 12); + const paddedHatPixels = []; + + // Top padding + for (let y = 0; y < TOP_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + // Left and right padding + for (let y = 0; y < hatPixels.length; y++) { + const row = []; + for (let x = 0; x < LEFT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + for (let x = 0; x < hatPixels[y].length; x++) { + row.push(hatPixels[y][x]); + } + + for (let x = 0; x < RIGHT_PADDING; x++) { + row.push(PALETTE.TRANSPARENT); + } + + paddedHatPixels.push(row); + } + // Bottom padding + for (let y = 0; y < BOTTOM_PADDING; y++) { + paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING) + .fill(PALETTE.TRANSPARENT) + ); + } + + // Add outline + let neighborOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [-1, -1], + [1, -1], + ]; + if (outlineBottom) { + neighborOffsets.push([0, 1], [-1, 1], [1, 1]); + } + for (let y = 0; y < paddedHatPixels.length; y++) { + for (let x = 0; x < paddedHatPixels[y].length; x++) { + const pixel = paddedHatPixels[y][x]; + if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) { + for (let [dx, dy] of neighborOffsets) { + const newX = x + dx; + const newY = y + dy; + if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) { + paddedHatPixels[newY][newX] = PALETTE.BORDER; + } + } + } + } + } + return new Layer(paddedHatPixels); +} \ No newline at end of file