From eda3f9fbc158589c0f05160a72fa7d67e68d24c0 Mon Sep 17 00:00:00 2001 From: Idrees Hassan Date: Sun, 26 Oct 2025 13:22:24 -0400 Subject: [PATCH] Change files to use a consistent case --- src/Frame.js | 2 +- src/birb.js | 4 +-- src/frame.js | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/layer.js | 14 ++++++++++ 4 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 src/frame.js create mode 100644 src/layer.js diff --git a/src/Frame.js b/src/Frame.js index 1310561..14ecb33 100644 --- a/src/Frame.js +++ b/src/Frame.js @@ -1,6 +1,6 @@ // @ts-check import { TRANSPARENT, Directions } from './constants.js'; -import Layer from './Layer.js'; +import Layer from './layer.js'; import BirdType from './birdType.js'; class Frame { diff --git a/src/birb.js b/src/birb.js index bef0e6c..0b9d39d 100644 --- a/src/birb.js +++ b/src/birb.js @@ -23,8 +23,8 @@ import { Directions } from './constants.js'; -import Frame from './Frame.js'; -import Layer from './Layer.js'; +import Frame from './frame.js'; +import Layer from './layer.js'; import BirdType from './birdType.js'; // @ts-ignore diff --git a/src/frame.js b/src/frame.js new file mode 100644 index 0000000..14ecb33 --- /dev/null +++ b/src/frame.js @@ -0,0 +1,74 @@ +// @ts-check +import { TRANSPARENT, Directions } from './constants.js'; +import Layer from './layer.js'; +import BirdType from './birdType.js'; + +class Frame { + + /** @type {{ [tag: string]: string[][] }} */ + #pixelsByTag = {}; + + /** + * @param {Layer[]} layers + */ + constructor(layers) { + /** @type {Set} */ + let tags = new Set(); + for (let layer of layers) { + tags.add(layer.tag); + } + tags.add("default"); + for (let tag of tags) { + let maxHeight = layers.reduce((max, layer) => Math.max(max, layer.pixels.length), 0); + if (layers[0].tag !== "default") { + throw new Error("First layer must have the 'default' tag"); + } + 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(TRANSPARENT)); + } + // Combine layers + for (let i = 1; i < layers.length; i++) { + if (layers[i].tag === "default" || layers[i].tag === tag) { + let layerPixels = layers[i].pixels; + 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] !== TRANSPARENT ? layerPixels[y][x] : this.pixels[y + topMargin][x]; + } + } + } + } + this.#pixelsByTag[tag] = this.pixels.map(row => row.slice()); + } + } + + /** + * @param {string} [tag] + * @returns {string[][]} + */ + getPixels(tag = "default") { + return this.#pixelsByTag[tag] ?? this.#pixelsByTag["default"]; + } + + /** + * @param {CanvasRenderingContext2D} ctx + * @param {BirdType} [species] + * @param {number} direction + * @param {number} canvasPixelSize + */ + draw(ctx, direction, canvasPixelSize, species) { + const pixels = this.getPixels(species?.tags[0]); + for (let y = 0; y < pixels.length; y++) { + const row = pixels[y]; + for (let x = 0; x < pixels[y].length; x++) { + const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1]; + ctx.fillStyle = species?.colors[cell] ?? cell; + ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize); + }; + }; + } +} + +export default Frame; \ No newline at end of file diff --git a/src/layer.js b/src/layer.js new file mode 100644 index 0000000..84c6661 --- /dev/null +++ b/src/layer.js @@ -0,0 +1,14 @@ +// @ts-check + +class Layer { + /** + * @param {string[][]} pixels + * @param {string} [tag] + */ + constructor(pixels, tag = "default") { + this.pixels = pixels; + this.tag = tag; + } +} + +export default Layer; \ No newline at end of file