From 9d635eadb88349c751153966367a74e339f9abdc Mon Sep 17 00:00:00 2001 From: Juan Sebastian Montoya Date: Fri, 20 Sep 2024 00:46:42 -0500 Subject: [PATCH 1/7] feat(#15): add basic character and update camera to follow it --- index.html | 4 + index.js | 33 ++++++- modules/game-objects/camera.js | 51 ++++------- modules/game-objects/map-management.js | 2 +- modules/game-objects/player.js | 118 +++++++++++++++++++++++++ resources/character.png | Bin 0 -> 10952 bytes resources/overworld.json | 51 ++++++++--- 7 files changed, 214 insertions(+), 45 deletions(-) create mode 100644 modules/game-objects/player.js create mode 100644 resources/character.png diff --git a/index.html b/index.html index d8caa7e..01c925e 100644 --- a/index.html +++ b/index.html @@ -19,6 +19,10 @@ id="overworld" src="resources/overworld.png" /> +
diff --git a/index.js b/index.js index f392821..f84068e 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -import { GAME_HEIGHT, GAME_WIDTH } from "./modules/constants.js"; +import { GAME_HEIGHT, GAME_WIDTH, TILE_SIZE } from "./modules/constants.js"; import { Camera, CanvasResizer, @@ -6,6 +6,7 @@ import { GameObject, MapManagement, } from "./modules/game-objects/index.js"; +import { Player, SpriteSheet } from "./modules/game-objects/player.js"; const backgroundMaps = [ { @@ -29,6 +30,24 @@ const foregroundMaps = [ { name: "ocean", imageId: "overworld", elementId: "level2", layer: 2 }, ]; +const foregroundCollisionMaps = [ + { + name: "overworld", + imageId: "overworld", + elementId: "level1", + layer: 2, + selected: true, + collision: true, + }, + { + name: "ocean", + imageId: "overworld", + elementId: "level2", + layer: 2, + collision: true, + }, +]; + const clicableObjects = ["debug", "level1", "level2"]; class Game extends GameObject { @@ -41,11 +60,23 @@ class Game extends GameObject { height: GAME_HEIGHT, percentage: 0.9, }); + const player = new Player({ + speed: 1, + gameObjects: [new SpriteSheet({ imageId: "character", tileHeight: 32 })], + x: 6 * TILE_SIZE, + y: 4 * TILE_SIZE, + width: TILE_SIZE, + height: 2 * TILE_SIZE, + debug: true, + }); const camera = new Camera({ gameObjects: [ new MapManagement({ maps: backgroundMaps }), new MapManagement({ maps: foregroundMaps }), + player, + new MapManagement({ maps: foregroundCollisionMaps }), ], + target: player, }); const fpsCounter = new FpsCounter({ debug: false }); this.gameObjects = [canvasResizer, camera, fpsCounter]; diff --git a/modules/game-objects/camera.js b/modules/game-objects/camera.js index b2816c6..3aa8e2c 100644 --- a/modules/game-objects/camera.js +++ b/modules/game-objects/camera.js @@ -9,41 +9,23 @@ export class Camera extends GameObject { width = GAME_WIDTH, height = GAME_HEIGHT, speed = 1, + target = { x: 0, y: 0, width: 0, height: 0 }, // A camera that follows a target }) { super({ x, y, gameObjects, width, height }); this.speed = speed; - this.keys = [ - { key: "ArrowUp", pressed: false, value: [0, -1] }, - { key: "ArrowDown", pressed: false, value: [0, 1] }, - { key: "ArrowLeft", pressed: false, value: [-1, 0] }, - { key: "ArrowRight", pressed: false, value: [1, 0] }, - ]; - this.availableKeys = this.keys.reduce( - (acc, item) => ({ ...acc, [item.key]: item }), - {} - ); - this.eventEmitter.on("changeLevel", () => { + this.target = target; + this.eventEmitter.on("levelChanged", () => { this.x = x; this.y = y; }); + this.eventEmitter.on("targetChanged", (target) => { + this.target = target; + }); } update(delta) { - this.keys.forEach((item) => { - if (item.pressed) { - this.moveCamera(...item.value, delta); - } - }); - } - - onKeyPressed(key) { - if (!this.availableKeys[key]) return; - this.availableKeys[key].pressed = true; - } - - onKeyReleased(key) { - if (!this.availableKeys[key]) return; - this.availableKeys[key].pressed = false; + super.update(delta); + this.followTarget(); } render(ctx) { @@ -52,16 +34,19 @@ export class Camera extends GameObject { ); } - moveCamera(dx, dy, delta) { + followTarget() { + const { x, y, width: tWidth, height: tHeight } = this.target; + const centerX = x + tWidth / 2; + const centerY = y + tHeight / 2; const [item] = this.gameObjects; const { height, width } = item.selected ?? item; - this.x = Math.min( - Math.max(this.x + dx * Math.floor(delta * this.speed * 100), 0), - width * TILE_SIZE - this.width + this.x = Math.max( + 0, + Math.min(centerX - this.width / 2, width * TILE_SIZE - this.width) ); - this.y = Math.min( - Math.max(this.y + dy * Math.floor(delta * this.speed * 100), 0), - height * TILE_SIZE - this.height + this.y = Math.max( + 0, + Math.min(centerY - this.height / 2, height * TILE_SIZE - this.height) ); } } diff --git a/modules/game-objects/map-management.js b/modules/game-objects/map-management.js index a6dd3f7..88c174e 100644 --- a/modules/game-objects/map-management.js +++ b/modules/game-objects/map-management.js @@ -27,6 +27,6 @@ export class MapManagement extends GameObject { } const map = this.gameObjects.find((item) => item.elementId === elementId); this.selected = map.name; - this.eventEmitter.emit("changeLevel"); + this.eventEmitter.emit("levelChanged"); } } diff --git a/modules/game-objects/player.js b/modules/game-objects/player.js new file mode 100644 index 0000000..eb95597 --- /dev/null +++ b/modules/game-objects/player.js @@ -0,0 +1,118 @@ +import { GAME_HEIGHT, GAME_WIDTH, TILE_SIZE } from "../constants.js"; +import { GameObject } from "./game-object.js"; + +export class Sprite extends GameObject { + constructor({ image, x = 0, y = 0, width = 0, height = 0 }) { + super({ x, y, height, width }); + this.image = image; + this.imageWidth = this.image.width; + this.imageHeight = this.image.height; + } + + render(ctx, sourceX, sourceY) { + ctx.drawImage( + this.image, + this.x, + this.y, + this.width, + this.height, + sourceX, + sourceY, + this.width, + this.height + ); + } +} + +export class SpriteSheet extends GameObject { + constructor({ + imageId, + x = 0, + y = 0, + tileWidth = 16, + tileHeight = 16, + offsetX = 0, + offsetY = 0, + }) { + super({ x, y }); + this.image = document.getElementById(imageId); + this.imageWidth = this.image.width; + this.imageHeight = this.image.height; + this.tileWidth = tileWidth; + this.tileHeight = tileHeight; + this.offsetX = offsetX; + this.offsetY = offsetY; + this.sprites = this._getSprites(); + } + + _getSprites() { + const sprites = []; + for (let row = 0; row < this.imageHeight; row += this.tileHeight) { + for (let col = 0; col < this.imageWidth; col += this.tileHeight) { + sprites.push( + new Sprite({ + image: this.image, + x: col + this.offsetX, + y: row + this.offsetY, + width: this.tileWidth, + height: this.tileHeight, + }) + ); + } + } + return sprites; + } +} + +export class Player extends GameObject { + constructor({ gameObjects = [], x = 0, y = 0, speed = 1, ...args }) { + super({ x, y, gameObjects, ...args }); + this.speed = speed; + this.keys = [ + { key: "ArrowUp", pressed: false, value: [0, -1] }, + { key: "ArrowDown", pressed: false, value: [0, 1] }, + { key: "ArrowLeft", pressed: false, value: [-1, 0] }, + { key: "ArrowRight", pressed: false, value: [1, 0] }, + ]; + this.availableKeys = this.keys.reduce( + (acc, item) => ({ ...acc, [item.key]: item }), + {} + ); + this.eventEmitter.on("levelChanged", (...args) => { + this.x = x; + this.y = y; + }); + } + + update(delta) { + this.keys.forEach((item) => { + if (item.pressed) { + this.moveCharacter(...item.value, delta); + } + }); + } + + onKeyPressed(key) { + if (!this.availableKeys[key]) return; + this.availableKeys[key].pressed = true; + } + + onKeyReleased(key) { + if (!this.availableKeys[key]) return; + this.availableKeys[key].pressed = false; + } + + render(ctx, ...args) { + const [x, y] = args; + const [spriteSheet] = this.gameObjects; + const [item] = spriteSheet.sprites; + item.render(ctx, this.x - x, this.y - y); + } + + moveCharacter(dx, dy, delta) { + const speed = Math.floor(delta * this.speed * 100); + this.x = this.x + dx * speed; + this.y = this.y + dy * speed; + // TODO: Check for collisions and stop movement if needed + } +} diff --git a/resources/character.png b/resources/character.png new file mode 100644 index 0000000000000000000000000000000000000000..a50ceb040f5ad2821d1b4976c19ef2a849dd8fb3 GIT binary patch literal 10952 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 rwt*N%c~A(*HU9rpoH4&1lPRx!qQo<^V literal 0 HcmV?d00001 diff --git a/resources/overworld.json b/resources/overworld.json index 10984dd..a936f24 100644 --- a/resources/overworld.json +++ b/resources/overworld.json @@ -33,17 +33,48 @@ "x":0, "y":0 }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 605, 607, 606, 607, 606, 607, 606, 607, 606, 607, 606, 607, 606, 607, 606, 607, 607, 607, 607, 607, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 367, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 407, 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 9, 10, 11, 0, 0, 0, + 446, 446, 446, 446, 446, 446, 446, 446, 446, 447, 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 215, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":20, + "id":2, + "name":"Tile Layer 2", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":30, + "x":0, + "y":0 + }, { "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 485, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 525, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 565, 566, 566, 566, 566, 566, 566, 566, 566, 566, 566, 566, 566, 566, 566, 566, 566, 566, 449, 566, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 605, 607, 606, 607, 606, 607, 606, 607, 606, 607, 606, 607, 606, 607, 606, 607, 607, 607, 607, 607, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 367, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 522, 523, 523, 523, 523, 523, 523, 523, 523, 524, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 407, 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 562, 0, 12, 13, 9, 10, 11, 0, 0, 564, - 446, 446, 446, 446, 446, 446, 446, 446, 446, 447, 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 562, 0, 47, 53, 49, 50, 51, 0, 0, 564, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 487, 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 562, 0, 87, 88, 89, 90, 91, 214, 215, 564, - 526, 526, 526, 526, 526, 526, 526, 526, 526, 527, 568, 0, 450, 451, 0, 0, 0, 450, 451, 0, 562, 0, 127, 128, 129, 130, 131, 254, 255, 564, - 566, 566, 566, 566, 566, 566, 566, 566, 566, 567, 568, 0, 490, 491, 0, 0, 0, 490, 491, 0, 562, 0, 167, 168, 169, 170, 171, 294, 295, 564, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 522, 523, 523, 523, 523, 523, 523, 523, 523, 524, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 562, 0, 0, 0, 0, 0, 0, 0, 0, 564, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 562, 0, 47, 53, 49, 50, 51, 0, 0, 564, + 486, 486, 486, 486, 486, 486, 486, 486, 486, 487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 562, 0, 87, 88, 89, 90, 91, 0, 0, 564, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 527, 0, 0, 450, 451, 0, 0, 0, 450, 451, 0, 562, 0, 127, 128, 129, 130, 131, 254, 255, 564, + 566, 566, 566, 566, 566, 566, 566, 566, 566, 567, 0, 0, 490, 491, 0, 0, 0, 490, 491, 0, 562, 0, 167, 168, 169, 170, 171, 294, 295, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 562, 0, 0, 0, 0, 0, 0, 0, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 602, 603, 603, 642, 0, 641, 603, 603, 603, 604, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -55,8 +86,8 @@ 0, 0, 0, 0, 0, 0, 0, 0, 85, 86, 0, 0, 0, 0, 0, 85, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "height":20, - "id":2, - "name":"Tile Layer 2", + "id":6, + "name":"Tile Layer 3", "opacity":1, "type":"tilelayer", "visible":true, @@ -64,7 +95,7 @@ "x":0, "y":0 }], - "nextlayerid":3, + "nextlayerid":8, "nextobjectid":1, "orientation":"orthogonal", "renderorder":"right-down", From ad3226de525704361c666ab2a85bc42e3974cdd7 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Montoya Date: Fri, 20 Sep 2024 08:33:02 -0500 Subject: [PATCH 2/7] feat(#15): add new font --- index.css | 7 +++++++ index.html | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/index.css b/index.css index 3f1fcd8..04a6df7 100644 --- a/index.css +++ b/index.css @@ -19,3 +19,10 @@ body { #resources { display: none; } + +.pixelify-sans-regular { + font-family: "Pixelify Sans", sans-serif; + font-optical-sizing: auto; + font-weight: 600; + font-style: normal; +} \ No newline at end of file diff --git a/index.html b/index.html index 01c925e..8699c7d 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,19 @@ content="width=device-width, initial-scale=1.0" /> Game Engine + + + Date: Fri, 20 Sep 2024 08:34:45 -0500 Subject: [PATCH 3/7] feat(#15): use new font in fps counter --- modules/game-objects/fps-counter.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/game-objects/fps-counter.js b/modules/game-objects/fps-counter.js index 3d4b266..e56bdbb 100644 --- a/modules/game-objects/fps-counter.js +++ b/modules/game-objects/fps-counter.js @@ -1,8 +1,8 @@ import { GameObject } from "./game-object.js"; export class FpsCounter extends GameObject { - constructor({ debug = false }) { - super({ debug }); + constructor() { + super(); this.fps = 0; } @@ -15,7 +15,7 @@ export class FpsCounter extends GameObject { return; } ctx.fillStyle = "Red"; - ctx.font = "normal 12pt Arial"; + ctx.font = "normal 12pt Pixelify Sans"; ctx.fillText(this.fps + " fps", 5, 15); } } From 9403de104272a84f3de196aace30755f366b26b9 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Montoya Date: Fri, 20 Sep 2024 08:35:05 -0500 Subject: [PATCH 4/7] feat(#15): add basic animations implementation --- index.js | 19 +++++- modules/game-objects/player.js | 105 +++++++++++++++++++++++++++------ 2 files changed, 105 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index f84068e..61fed36 100644 --- a/index.js +++ b/index.js @@ -50,6 +50,21 @@ const foregroundCollisionMaps = [ const clicableObjects = ["debug", "level1", "level2"]; +const playerAnimations = { + idle: { + left: [51], + right: [17], + top: [34], + bottom: [0], + }, + walk: { + left: [51, 52, 53, 54], + right: [17, 18, 19, 20], + top: [34, 35, 36, 37], + bottom: [0, 1, 2, 3], + }, +}; + class Game extends GameObject { constructor({ canvas }) { super(); @@ -63,11 +78,11 @@ class Game extends GameObject { const player = new Player({ speed: 1, gameObjects: [new SpriteSheet({ imageId: "character", tileHeight: 32 })], + animations: playerAnimations, x: 6 * TILE_SIZE, y: 4 * TILE_SIZE, width: TILE_SIZE, height: 2 * TILE_SIZE, - debug: true, }); const camera = new Camera({ gameObjects: [ @@ -78,7 +93,7 @@ class Game extends GameObject { ], target: player, }); - const fpsCounter = new FpsCounter({ debug: false }); + const fpsCounter = new FpsCounter(); this.gameObjects = [canvasResizer, camera, fpsCounter]; this.canvas = canvas; diff --git a/modules/game-objects/player.js b/modules/game-objects/player.js index eb95597..31d9a21 100644 --- a/modules/game-objects/player.js +++ b/modules/game-objects/player.js @@ -1,26 +1,40 @@ -import { GAME_HEIGHT, GAME_WIDTH, TILE_SIZE } from "../constants.js"; +import { TILE_SIZE } from "../constants.js"; import { GameObject } from "./game-object.js"; +export class Animation extends GameObject { + constructor({ frames = [], name, x = 0, y = 0 }) { + super({ x, y }); + this.frames = frames; + this.name = name; + } +} + export class Sprite extends GameObject { - constructor({ image, x = 0, y = 0, width = 0, height = 0 }) { + constructor({ image, x = 0, y = 0, width = 0, height = 0, index = 0 }) { super({ x, y, height, width }); + this.index = index; this.image = image; this.imageWidth = this.image.width; this.imageHeight = this.image.height; } - render(ctx, sourceX, sourceY) { + render(ctx, destinationX, destinationY) { ctx.drawImage( this.image, this.x, this.y, this.width, this.height, - sourceX, - sourceY, + destinationX, + destinationY, this.width, this.height ); + if (this.debug) { + ctx.fillStyle = "Red"; + ctx.font = "normal 8pt Pixelify Sans"; + ctx.fillText(this.index, destinationX, destinationY + 8); + } } } @@ -29,8 +43,8 @@ export class SpriteSheet extends GameObject { imageId, x = 0, y = 0, - tileWidth = 16, - tileHeight = 16, + tileWidth = TILE_SIZE, + tileHeight = TILE_SIZE, offsetX = 0, offsetY = 0, }) { @@ -42,31 +56,44 @@ export class SpriteSheet extends GameObject { this.tileHeight = tileHeight; this.offsetX = offsetX; this.offsetY = offsetY; - this.sprites = this._getSprites(); } - _getSprites() { + get sprites() { + if (this.gameObjects?.length) { + return this.gameObjects; + } const sprites = []; + let index = 0; for (let row = 0; row < this.imageHeight; row += this.tileHeight) { - for (let col = 0; col < this.imageWidth; col += this.tileHeight) { + for (let col = 0; col < this.imageWidth; col += this.tileWidth) { sprites.push( new Sprite({ image: this.image, + index, x: col + this.offsetX, y: row + this.offsetY, width: this.tileWidth, height: this.tileHeight, }) ); + index++; } } - return sprites; + + return (this.gameObjects = sprites); } } export class Player extends GameObject { - constructor({ gameObjects = [], x = 0, y = 0, speed = 1, ...args }) { - super({ x, y, gameObjects, ...args }); + constructor({ + gameObjects = [], + animations = {}, + defaultAnimation = { idle: "bottom" }, + x = 0, + y = 0, + speed = 1, + }) { + super({ x, y, gameObjects }); this.speed = speed; this.keys = [ { key: "ArrowUp", pressed: false, value: [0, -1] }, @@ -82,14 +109,26 @@ export class Player extends GameObject { this.x = x; this.y = y; }); + + // TODO: Decouple animation into animation class + this.animations = animations; + this.defaultAnimation = defaultAnimation; + this.currentAnimation = defaultAnimation; + this.currentAnimationFrame = 0; } update(delta) { + let idle = true; this.keys.forEach((item) => { if (item.pressed) { - this.moveCharacter(...item.value, delta); + this.moveCharacter(delta, ...item.value); + this.updateAnimation(delta, "walk", ...item.value); + idle = false; } }); + if (idle) { + this.updateAnimation(delta, "idle"); + } } onKeyPressed(key) { @@ -103,16 +142,48 @@ export class Player extends GameObject { } render(ctx, ...args) { + // TODO: Decouple animation into animation class const [x, y] = args; const [spriteSheet] = this.gameObjects; - const [item] = spriteSheet.sprites; - item.render(ctx, this.x - x, this.y - y); + if (this.debug) { + spriteSheet.sprites.forEach((item, index) => { + item.render(ctx, this.x - x + index * TILE_SIZE, this.y - y); + }); + } else { + const [currentAnimationKey] = Object.keys(this.currentAnimation); + const currentAnimationDirection = + this.currentAnimation[currentAnimationKey]; + const frames = + this.animations[currentAnimationKey][currentAnimationDirection]; + if (!frames) { + throw Error("No animation defined for " + this.currentAnimation); + } + const item = frames.map((frame) => spriteSheet.sprites[frame])[ + Math.floor(this.currentAnimationFrame) % frames.length + ]; + item.render(ctx, this.x - x, this.y - y); + } } - moveCharacter(dx, dy, delta) { + moveCharacter(delta, dx, dy) { const speed = Math.floor(delta * this.speed * 100); this.x = this.x + dx * speed; this.y = this.y + dy * speed; // TODO: Check for collisions and stop movement if needed } + + // TODO: Decouple animation into animation class + updateAnimation(delta, animation, dx, dy) { + if (animation === "idle") { + const [value] = Object.values(this.currentAnimation); + this.currentAnimation = { [animation]: value }; + return; + } + if (dx !== 0) { + this.currentAnimation = { [animation]: dx > 0 ? "right" : "left" }; + } else if (dy !== 0) { + this.currentAnimation = { [animation]: dy > 0 ? "bottom" : "top" }; + } + this.currentAnimationFrame += 10 * delta; + } } From e2cd0ee490b662e331c22867cebc8f825d9a8534 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Montoya Date: Fri, 20 Sep 2024 11:40:18 -0500 Subject: [PATCH 5/7] feat(#15): fix centering player issue --- modules/game-objects/player.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/game-objects/player.js b/modules/game-objects/player.js index 31d9a21..1d2c2d4 100644 --- a/modules/game-objects/player.js +++ b/modules/game-objects/player.js @@ -92,8 +92,10 @@ export class Player extends GameObject { x = 0, y = 0, speed = 1, + width = TILE_SIZE, + height = TILE_SIZE, }) { - super({ x, y, gameObjects }); + super({ x, y, gameObjects, width, height }); this.speed = speed; this.keys = [ { key: "ArrowUp", pressed: false, value: [0, -1] }, From ea9d912e2f935a3fc302abcd9997c04a4096c2b4 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Montoya Date: Fri, 20 Sep 2024 15:55:32 -0500 Subject: [PATCH 6/7] feat(#15): separate sprite from player --- index.js | 3 +- modules/game-objects/animation.js | 7 +++ modules/game-objects/index.js | 3 + modules/game-objects/player.js | 83 ---------------------------- modules/game-objects/sprite-sheet.js | 49 ++++++++++++++++ modules/game-objects/sprite.js | 30 ++++++++++ 6 files changed, 91 insertions(+), 84 deletions(-) create mode 100644 modules/game-objects/animation.js create mode 100644 modules/game-objects/sprite-sheet.js create mode 100644 modules/game-objects/sprite.js diff --git a/index.js b/index.js index 61fed36..f3776e6 100644 --- a/index.js +++ b/index.js @@ -5,8 +5,9 @@ import { FpsCounter, GameObject, MapManagement, + Player, + SpriteSheet, } from "./modules/game-objects/index.js"; -import { Player, SpriteSheet } from "./modules/game-objects/player.js"; const backgroundMaps = [ { diff --git a/modules/game-objects/animation.js b/modules/game-objects/animation.js new file mode 100644 index 0000000..d9ac5f1 --- /dev/null +++ b/modules/game-objects/animation.js @@ -0,0 +1,7 @@ +export class Animation extends GameObject { + constructor({ frames = [], name, x = 0, y = 0 }) { + super({ x, y }); + this.frames = frames; + this.name = name; + } +} diff --git a/modules/game-objects/index.js b/modules/game-objects/index.js index fbeecb0..bae02d1 100644 --- a/modules/game-objects/index.js +++ b/modules/game-objects/index.js @@ -4,3 +4,6 @@ export { FpsCounter } from "./fps-counter.js"; export { GameObject } from "./game-object.js"; export { MapManagement } from "./map-management.js"; export { Map } from "./map.js"; +export { Player } from "./player.js"; +export { Sprite } from "./sprite.js"; +export { SpriteSheet } from "./sprite-sheet.js"; diff --git a/modules/game-objects/player.js b/modules/game-objects/player.js index 1d2c2d4..2af7011 100644 --- a/modules/game-objects/player.js +++ b/modules/game-objects/player.js @@ -1,89 +1,6 @@ import { TILE_SIZE } from "../constants.js"; import { GameObject } from "./game-object.js"; -export class Animation extends GameObject { - constructor({ frames = [], name, x = 0, y = 0 }) { - super({ x, y }); - this.frames = frames; - this.name = name; - } -} - -export class Sprite extends GameObject { - constructor({ image, x = 0, y = 0, width = 0, height = 0, index = 0 }) { - super({ x, y, height, width }); - this.index = index; - this.image = image; - this.imageWidth = this.image.width; - this.imageHeight = this.image.height; - } - - render(ctx, destinationX, destinationY) { - ctx.drawImage( - this.image, - this.x, - this.y, - this.width, - this.height, - destinationX, - destinationY, - this.width, - this.height - ); - if (this.debug) { - ctx.fillStyle = "Red"; - ctx.font = "normal 8pt Pixelify Sans"; - ctx.fillText(this.index, destinationX, destinationY + 8); - } - } -} - -export class SpriteSheet extends GameObject { - constructor({ - imageId, - x = 0, - y = 0, - tileWidth = TILE_SIZE, - tileHeight = TILE_SIZE, - offsetX = 0, - offsetY = 0, - }) { - super({ x, y }); - this.image = document.getElementById(imageId); - this.imageWidth = this.image.width; - this.imageHeight = this.image.height; - this.tileWidth = tileWidth; - this.tileHeight = tileHeight; - this.offsetX = offsetX; - this.offsetY = offsetY; - } - - get sprites() { - if (this.gameObjects?.length) { - return this.gameObjects; - } - const sprites = []; - let index = 0; - for (let row = 0; row < this.imageHeight; row += this.tileHeight) { - for (let col = 0; col < this.imageWidth; col += this.tileWidth) { - sprites.push( - new Sprite({ - image: this.image, - index, - x: col + this.offsetX, - y: row + this.offsetY, - width: this.tileWidth, - height: this.tileHeight, - }) - ); - index++; - } - } - - return (this.gameObjects = sprites); - } -} - export class Player extends GameObject { constructor({ gameObjects = [], diff --git a/modules/game-objects/sprite-sheet.js b/modules/game-objects/sprite-sheet.js new file mode 100644 index 0000000..747f847 --- /dev/null +++ b/modules/game-objects/sprite-sheet.js @@ -0,0 +1,49 @@ +import { TILE_SIZE } from "../constants.js"; +import { GameObject } from "./game-object.js"; +import { Sprite } from "./sprite.js"; + +export class SpriteSheet extends GameObject { + constructor({ + imageId, + x = 0, + y = 0, + tileWidth = TILE_SIZE, + tileHeight = TILE_SIZE, + offsetX = 0, + offsetY = 0, + }) { + super({ x, y }); + this.image = document.getElementById(imageId); + this.imageWidth = this.image.width; + this.imageHeight = this.image.height; + this.tileWidth = tileWidth; + this.tileHeight = tileHeight; + this.offsetX = offsetX; + this.offsetY = offsetY; + } + + get sprites() { + if (this.gameObjects?.length) { + return this.gameObjects; + } + const sprites = []; + let index = 0; + for (let row = 0; row < this.imageHeight; row += this.tileHeight) { + for (let col = 0; col < this.imageWidth; col += this.tileWidth) { + sprites.push( + new Sprite({ + image: this.image, + index, + x: col + this.offsetX, + y: row + this.offsetY, + width: this.tileWidth, + height: this.tileHeight, + }) + ); + index++; + } + } + + return (this.gameObjects = sprites); + } +} diff --git a/modules/game-objects/sprite.js b/modules/game-objects/sprite.js new file mode 100644 index 0000000..06cd55a --- /dev/null +++ b/modules/game-objects/sprite.js @@ -0,0 +1,30 @@ +import { GameObject } from "./game-object.js"; + +export class Sprite extends GameObject { + constructor({ image, x = 0, y = 0, width = 0, height = 0, index = 0 }) { + super({ x, y, height, width }); + this.index = index; + this.image = image; + this.imageWidth = this.image.width; + this.imageHeight = this.image.height; + } + + render(ctx, destinationX, destinationY) { + ctx.drawImage( + this.image, + this.x, + this.y, + this.width, + this.height, + destinationX, + destinationY, + this.width, + this.height + ); + if (this.debug) { + ctx.fillStyle = "Red"; + ctx.font = "normal 8pt Pixelify Sans"; + ctx.fillText(this.index, destinationX, destinationY + 8); + } + } +} From d0c859aab490569931509f646266c7bed2141777 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Montoya Date: Mon, 21 Jul 2025 16:46:43 -0500 Subject: [PATCH 7/7] refactor: streamline Game class initialization and update layer names in overworld.json --- index.js | 6 +- package.json | 10 +- resources/overworld.json | 4 +- yarn.lock | 594 --------------------------------------- 4 files changed, 7 insertions(+), 607 deletions(-) diff --git a/index.js b/index.js index f3776e6..af07a3e 100644 --- a/index.js +++ b/index.js @@ -69,7 +69,8 @@ const playerAnimations = { class Game extends GameObject { constructor({ canvas }) { super(); - + this.canvas = canvas; + this.ctx = this.canvas.getContext("2d"); const canvasResizer = new CanvasResizer({ canvas: canvas, width: GAME_WIDTH, @@ -96,9 +97,6 @@ class Game extends GameObject { }); const fpsCounter = new FpsCounter(); this.gameObjects = [canvasResizer, camera, fpsCounter]; - - this.canvas = canvas; - this.ctx = this.canvas.getContext("2d"); this.lastTime = 0; } diff --git a/package.json b/package.json index 3199538..8ffd819 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,9 @@ "version": "1.0.0", "main": "src/index.js", "scripts": { - "start": "serve . -n" + "start": "npx -y serve . -n" }, "repository": "git@git.jusemon.com:jusemon/evolver.git", "author": "Jusemon ", - "license": "MIT", - "dependencies": {}, - "devDependencies": { - "serve": "^14.2.3" - } -} \ No newline at end of file + "license": "MIT" +} diff --git a/resources/overworld.json b/resources/overworld.json index a936f24..b838bcf 100644 --- a/resources/overworld.json +++ b/resources/overworld.json @@ -25,7 +25,7 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 366, 366, 366, 366, 366, 366, 1, 1, 1, 323, 324, 324, 324, 324, 324, 324, 324, 324, 324, 325], "height":20, "id":1, - "name":"Tile Layer 1", + "name":"background", "opacity":1, "type":"tilelayer", "visible":true, @@ -56,7 +56,7 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "height":20, "id":2, - "name":"Tile Layer 2", + "name":"foreground", "opacity":1, "type":"tilelayer", "visible":true, diff --git a/yarn.lock b/yarn.lock index ffff1c7..3ff608a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,597 +2,3 @@ # yarn lockfile v1 -"@zeit/schemas@2.36.0": - version "2.36.0" - resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.36.0.tgz#7a1b53f4091e18d0b404873ea3e3c83589c765f2" - integrity sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg== - -accepts@~1.3.5: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -ajv@8.12.0: - version "8.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" - integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-align@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" - integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== - dependencies: - string-width "^4.1.0" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - -arch@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" - integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== - -arg@5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" - integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -boxen@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-7.0.0.tgz#9e5f8c26e716793fc96edcf7cf754cdf5e3fbf32" - integrity sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg== - dependencies: - ansi-align "^3.0.1" - camelcase "^7.0.0" - chalk "^5.0.1" - cli-boxes "^3.0.0" - string-width "^5.1.2" - type-fest "^2.13.0" - widest-line "^4.0.1" - wrap-ansi "^8.0.1" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== - -camelcase@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048" - integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== - -chalk-template@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-0.4.0.tgz#692c034d0ed62436b9062c1707fadcd0f753204b" - integrity sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg== - dependencies: - chalk "^4.1.2" - -chalk@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6" - integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w== - -chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^5.0.1: - version "5.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" - integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== - -cli-boxes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" - integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== - -clipboardy@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-3.0.0.tgz#f3876247404d334c9ed01b6f269c11d09a5e3092" - integrity sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg== - dependencies: - arch "^2.2.0" - execa "^5.1.1" - is-wsl "^2.2.0" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -compressible@~2.0.16: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - integrity sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA== - -cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -execa@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-url-parser@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" - integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ== - dependencies: - punycode "^1.3.2" - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -ini@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -is-docker@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-port-reachable@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-4.0.0.tgz#dac044091ef15319c8ab2f34604d8794181f8c2d" - integrity sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -"mime-db@>= 1.43.0 < 2": - version "1.53.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" - integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== - -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" - integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== - -mime-types@2.1.18: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" - integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== - dependencies: - mime-db "~1.33.0" - -mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimatch@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.0: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -path-is-inside@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-to-regexp@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" - integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== - -punycode@^1.3.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== - -punycode@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - -range-parser@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A== - -rc@^1.0.1, rc@^1.1.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -registry-auth-token@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" - integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ== - dependencies: - rc "^1.1.6" - safe-buffer "^5.0.1" - -registry-url@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" - integrity sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA== - dependencies: - rc "^1.0.1" - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -serve-handler@6.1.5: - version "6.1.5" - resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.5.tgz#a4a0964f5c55c7e37a02a633232b6f0d6f068375" - integrity sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg== - dependencies: - bytes "3.0.0" - content-disposition "0.5.2" - fast-url-parser "1.1.3" - mime-types "2.1.18" - minimatch "3.1.2" - path-is-inside "1.0.2" - path-to-regexp "2.2.1" - range-parser "1.2.0" - -serve@^14.2.3: - version "14.2.3" - resolved "https://registry.yarnpkg.com/serve/-/serve-14.2.3.tgz#047ba2b349354255bc09e0332cd41a92787836c9" - integrity sha512-VqUFMC7K3LDGeGnJM9h56D3XGKb6KGgOw0cVNtA26yYXHCcpxf3xwCTUaQoWlVS7i8Jdh3GjQkOB23qsXyjoyQ== - dependencies: - "@zeit/schemas" "2.36.0" - ajv "8.12.0" - arg "5.0.2" - boxen "7.0.0" - chalk "5.0.1" - chalk-template "0.4.0" - clipboardy "3.0.0" - compression "1.7.4" - is-port-reachable "4.0.0" - serve-handler "6.1.5" - update-check "1.5.4" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.3: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -string-width@^4.1.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^5.0.1, string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^7.0.1: - version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -type-fest@^2.13.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" - integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== - -update-check@1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.4.tgz#5b508e259558f1ad7dbc8b4b0457d4c9d28c8743" - integrity sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ== - dependencies: - registry-auth-token "3.3.2" - registry-url "3.1.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -widest-line@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-4.0.1.tgz#a0fc673aaba1ea6f0a0d35b3c2795c9a9cc2ebf2" - integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig== - dependencies: - string-width "^5.0.1" - -wrap-ansi@^8.0.1: - version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1"