diff --git a/README.md b/README.md index 7773cf36cbbe9448145fafb2714336178d444c39..5e68628ba767b031e640d3daedb329379a286772 100644 --- a/README.md +++ b/README.md @@ -2,5 +2,7 @@ ## External code -This entry uses [player-small.js](https://sb.bitsnbites.eu/player-small.js) from SoundBox. `player-small.js` is licensed +- [player-small.js](https://sb.bitsnbites.eu/player-small.js) from SoundBox. `player-small.js` is licensed under [the zlib/libpng License](https://opensource.org/license/Zlib). + +- diff --git a/assets/font.aseprite b/assets/font.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..cd7b4971ae6bd3bb043bb04813d1e54bf6af7dca Binary files /dev/null and b/assets/font.aseprite differ diff --git a/assets/fontSheet.aseprite b/assets/fontSheet.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..cf6fbfad09826c5ed718aa5abfbd7341bea72d62 Binary files /dev/null and b/assets/fontSheet.aseprite differ diff --git a/hampsterengine b/hampsterengine index fbfeacd075bf597acf3de2b5f803cd46ca6583df..87eea2e2f818e955307768a179031c2111e43061 160000 --- a/hampsterengine +++ b/hampsterengine @@ -1 +1 @@ -Subproject commit fbfeacd075bf597acf3de2b5f803cd46ca6583df +Subproject commit 87eea2e2f818e955307768a179031c2111e43061 diff --git a/package.json b/package.json index e1117a399e14de065e451936cadcfe38d7d5ecba..6b56efc43917e106d54e603ba48b04279a27f898 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,10 @@ "dev:js": "esbuild src/js/main.js --bundle --watch --sourcemap --format=iife --loader:.webp=dataurl --outfile=build/main.js", "dev:html": "browser-sync build src --watch --https", "build": "run-s clear build:*", - "build:js": "esbuild src/js/main.js --bundle --minify --format=iife --loader:.webp=dataurl --outfile=build/main.js", + "build:js": "esbuild src/js/main.js --bundle --format=iife --loader:.webp=dataurl | terser -c -m --mangle-props keep_quoted -o build/main.js", "build:html": "html-inline src/index.html -b build | html-minifier -c configs/html-minifier.json -o build/index.html", "build:zip": "zip -FS -qjX9 build/game.zip build/index.html && advzip -z -4 build/game.zip", - "build:zipSize": "node configs/size.js" + "build:zipSize": "node utils/size.js" }, "devDependencies": { "advzip-bin": "^2.0.0", diff --git a/src/img/font.json b/src/img/font.json new file mode 100644 index 0000000000000000000000000000000000000000..063b441944839a6a5190ed7e9b3d5bbc096aa96e --- /dev/null +++ b/src/img/font.json @@ -0,0 +1,346 @@ +{ "frames": [ + { + "filename": "0", + "frame": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "1", + "frame": { "x": 6, "y": 0, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "2", + "frame": { "x": 12, "y": 0, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "3", + "frame": { "x": 18, "y": 0, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "4", + "frame": { "x": 24, "y": 0, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "5", + "frame": { "x": 30, "y": 0, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "6", + "frame": { "x": 36, "y": 0, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "7", + "frame": { "x": 0, "y": 8, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "8", + "frame": { "x": 6, "y": 8, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "9", + "frame": { "x": 12, "y": 8, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "10", + "frame": { "x": 18, "y": 8, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "11", + "frame": { "x": 24, "y": 8, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "12", + "frame": { "x": 30, "y": 8, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "13", + "frame": { "x": 36, "y": 8, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "14", + "frame": { "x": 0, "y": 16, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "15", + "frame": { "x": 6, "y": 16, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "16", + "frame": { "x": 12, "y": 16, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "17", + "frame": { "x": 18, "y": 16, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "18", + "frame": { "x": 24, "y": 16, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "19", + "frame": { "x": 30, "y": 16, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "20", + "frame": { "x": 36, "y": 16, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "21", + "frame": { "x": 0, "y": 24, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "22", + "frame": { "x": 6, "y": 24, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "23", + "frame": { "x": 12, "y": 24, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "24", + "frame": { "x": 18, "y": 24, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "25", + "frame": { "x": 24, "y": 24, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "26", + "frame": { "x": 30, "y": 24, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "27", + "frame": { "x": 36, "y": 24, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "28", + "frame": { "x": 0, "y": 32, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "29", + "frame": { "x": 6, "y": 32, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "30", + "frame": { "x": 12, "y": 32, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "31", + "frame": { "x": 18, "y": 32, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "32", + "frame": { "x": 24, "y": 32, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "33", + "frame": { "x": 30, "y": 32, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "34", + "frame": { "x": 36, "y": 32, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "35", + "frame": { "x": 0, "y": 40, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + }, + { + "filename": "36", + "frame": { "x": 6, "y": 40, "w": 6, "h": 8 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 6, "h": 8 }, + "sourceSize": { "w": 6, "h": 8 }, + "duration": 100 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.7-arm64", + "image": "font.webp", + "format": "I8", + "size": { "w": 42, "h": 48 }, + "scale": "1", + "slices": [ + ] + } +} diff --git a/src/img/font.webp b/src/img/font.webp new file mode 100644 index 0000000000000000000000000000000000000000..fad7b19026b5af571b749beb30d8c48767a8c388 Binary files /dev/null and b/src/img/font.webp differ diff --git a/src/js/main.js b/src/js/main.js index 585c46e95f5ad73731a0916b24b92590ee2d142a..c97615ee7fab4b2fcfb133da5f2f1092a0c6226d 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -6,7 +6,10 @@ import SoundBox from "./sb-player-small"; // import {mus_DEMOSONG} from "./songs/DEMOSONGDONOTCOMMIT"; // dependencies used for debugging. comment out code that uses this and they won't be included -import Stats from "stats.js"; +// import Stats from "stats.js"; + +// Images +import font from "../img/font.webp"; // Rooms import {rm_mainMenu} from "./rooms/mainMenu"; @@ -15,6 +18,9 @@ import {rm_DEBUG_button} from "./rooms/debug_button"; import {rm_DEBUG_mouse} from "./rooms/debug_mouse"; import {rm_DEBUG_music} from "./rooms/debug_music"; import {rm_DEBUG_INCURSION} from "./rooms/debug_incursion"; +import {rm_DEBUG_text} from "./rooms/debug_text"; +import Mouse from "../../hampsterengine/src/mouse"; +import {FontRenderer} from "./objects"; // Music // There is none @@ -23,34 +29,41 @@ import {rm_DEBUG_INCURSION} from "./rooms/debug_incursion"; const canvas = new Canvas('canvas'); const engine = new Engine(canvas); const assets = engine.assetStore; +assets.addImage('font', font); + +const fontRenderer = new FontRenderer(assets.get('font')); +window.fR = fontRenderer +// const mouse = new Mouse(engine); +// window.mouse = mouse; -canvas.width = 640; -canvas.height = 480; -canvas.pixelRatio = 2; +canvas.width = 256*4; +canvas.height = 240*4; +canvas.pixelRatio = 4; canvas.ctx.setTransform(canvas.pixelRatio, 0, 0, canvas.pixelRatio, 0, 0); canvas.ctx.imageSmoothingEnabled = false; engine.running = false; // Game uses this as a pause state actually // Parse query parameters -const query = new URLSearchParams(window.location.search) +const query = new URLSearchParams(window.location.search); engine.registerRoom(rm_mainMenu, 'mainMenu'); engine.registerRoom(rm_game, 'game'); -engine.registerRoom(rm_DEBUG_button, 'debug_button'); -engine.registerRoom(rm_DEBUG_mouse, 'debug_mouse'); +// engine.registerRoom(rm_DEBUG_button, 'debug_button'); +// engine.registerRoom(rm_DEBUG_mouse, 'debug_mouse'); // engine.registerRoom(rm_DEBUG_music, 'debug_music'); engine.registerRoom(rm_DEBUG_INCURSION, 'debug_incursion'); +engine.registerRoom(rm_DEBUG_text, 'debug_text'); // Init stats.js -const stats = new Stats(); -stats.showPanel(0); -document.body.appendChild( stats.dom ); +// const stats = new Stats(); +// stats.showPanel(0); +// document.body.appendChild( stats.dom ); function main() { try { - stats.begin(); + // stats.begin(); engine.frames++; canvas.fill(engine.room.bgColor ?? 'black'); @@ -60,7 +73,7 @@ function main() { // engine.drawCursor(); - stats.end(); + // stats.end(); // Ask to run at the next frame requestAnimationFrame(main); @@ -75,10 +88,12 @@ function main() { canvas.drawImage(logo, 10, 10, logo.width, logo.height) canvas.setFillColor('black'); - canvas.drawText(e, 10, canvas.height-10, { - maxWidth: canvas.width-20, + canvas.drawText(e, 5, canvas.height-5, { + maxWidth: canvas.width-10, textBaseline: 'bottom' }); + + throw e; } } @@ -102,7 +117,6 @@ if (query.get('room')) { // Ensure assets are loaded. function load() { - stats.begin(); if (engine.loading) { engine.loadLoop(); setTimeout(load, 1000/60); @@ -110,7 +124,6 @@ function load() { main(); setInterval(physicsTick, 1000/60); // Update physics 60 times a second } - stats.end(); } load(); diff --git a/src/js/objects.js b/src/js/objects.js index f9dbd59ed57dfc4e0b2f4eae304f3f20e17b7cac..ddaa16d7488b0a02b0c8732d8dba9fd2ea6536b4 100644 --- a/src/js/objects.js +++ b/src/js/objects.js @@ -126,6 +126,53 @@ export class Logo extends Entity { } +export class FontRenderer { + constructor(font) { + this.font = font; + this.h = 8; + this.w = 6; + } + + draw(text, x, y) { + text = text.toUpperCase(); + let split + try{ + split = text.split(""); + } catch (TypeError) { + return; + } + for (let i = 0; i < split.length; i++) { + const char = split[i]; + const code = char.charCodeAt(); + let slice; + if (code < 90 && code > 64) slice = code - 65; // Starts at 0 (LETTER) + else if (code < 58 && code > 48) slice = 25 + (code - 59) // Starts at 25 + else if (code === 91) slice = 35; + else if (code === 93) slice = 36; + else slice = 37; + + if (slice < 0) { + canvas.setFillColor('red'); + // debugger + } + else canvas.setFillColor('black'); + // canvas.drawText(`${Math.round(slice)}`, x+(i*(this.w+1)), y, {}) + canvas.sliceImage( + this.font, + x+(i*(this.w+1)), y, + this.w, this.h, + this.w * (slice % 7), this.h * Math.round(slice / 7), this.w, this.h); + } + } + + drawLines(text, x, y) { + const lines = text.split(/\n/); + for (let i = 0; i < lines.length; i++) { + this.draw(lines[i], x, y+(i*(this.h+1))); + } + } +} + // ENTITIES export class Player extends Entity { diff --git a/src/js/rooms/debug_mouse.js b/src/js/rooms/debug_mouse.js index 22389fc4f52023d7dd2385bf9593ae5f6566f258..866410c006f588f02434f84573303950f1b1dcc8 100644 --- a/src/js/rooms/debug_mouse.js +++ b/src/js/rooms/debug_mouse.js @@ -6,18 +6,18 @@ export const rm_DEBUG_mouse = new Room(); rm_DEBUG_mouse.drawGui = _=> { // Draw the last click - const lastClick = engine.lastClickPos; + const lastClick = mouse.lastClickPos; canvas.setFillColor('red'); canvas.setStrokeColor('red'); canvas.drawLine(lastClick.x, 0, lastClick.x, canvas.height); canvas.drawLine(0, lastClick.y, canvas.width, lastClick.y); canvas.drawText(`LAST(${Math.round(lastClick.x)},${Math.round(lastClick.y)})`, lastClick.x+2, lastClick.y-2, {}) - const cur = engine.mouse; + const cur = mouse.mouse; - if (engine.mouseDown) { + if (mouse.mouseDown) { // Draw the mousedown position - const moused = engine.mouseDownPos; + const moused = mouse.mouseDownPos; canvas.setFillColor('green'); canvas.setStrokeColor('green'); canvas.drawLine(moused.x, 0, moused.x, canvas.height); diff --git a/src/js/rooms/debug_text.js b/src/js/rooms/debug_text.js new file mode 100644 index 0000000000000000000000000000000000000000..2f0e3f6725b490266e847fdca9a6e9542f639ac8 --- /dev/null +++ b/src/js/rooms/debug_text.js @@ -0,0 +1,21 @@ + +import {Room} from "../../../hampsterengine/src/things"; + +export const rm_DEBUG_text = new Room(); + +const sample_text = `haiiiiiii this is the text test room +if you're here, welcome! +why are you looking at the debug rooms??? they're boring!! +im not hiding any cut content here. i dont have time for that + +here is the same message with a pixel art font:` + +rm_DEBUG_text.drawGui = _=>{ + canvas.setFillColor('black'); + + canvas.drawText(sample_text, canvas.center.x, 10, { + textBaseline: 'top', textAlign: 'center', maxWidth: canvas.width-20, size: 16 + }) + + fR.drawLines(sample_text, 10, canvas.center.y); +} diff --git a/src/js/rooms/mainMenu.js b/src/js/rooms/mainMenu.js index 3b4782bb515ff26e957e8502cd9a4d128125bfa1..1d551880873d450eddd9a0e191f829a83b98e1bd 100644 --- a/src/js/rooms/mainMenu.js +++ b/src/js/rooms/mainMenu.js @@ -10,16 +10,10 @@ logo.y = 45; logo.align = 2 rm_mainMenu.entities.push(logo); -const newGameButton = new MainMenuButton('New Game', _=>{ - engine.room = engine.getRoomIndex('game'); -}); -newGameButton.x = 30; -newGameButton.y = 70; -rm_mainMenu.entities.push(newGameButton); - rm_mainMenu.drawGui = _ => { canvas.setFillColor('#0f0f0f'); - canvas.drawText("(c) bye 2024", 30, canvas.height-25,{ - font: '8px serif' - }); + + canvas.drawText("Press [ENTER] to start.", 30, canvas.height-55, {}); + canvas.drawText("(c) bye 2024", 30, canvas.height-35, {}); + canvas.drawText("Uses 3rd-party licenses. Press [L] to read.", 30, canvas.height-25, {}); } \ No newline at end of file diff --git a/configs/size.js b/utils/size.js similarity index 100% rename from configs/size.js rename to utils/size.js diff --git a/utils/sprite_editor/index.html b/utils/sprite_editor/index.html new file mode 100644 index 0000000000000000000000000000000000000000..613f1826f45a1fa7a0e143bedaa315799be6f54b --- /dev/null +++ b/utils/sprite_editor/index.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Sprite editor</title> +</head> +<body> + <canvas id=a> + <script> + ctx=a.getContext`2d` // ctx + pallette="000f000f000fff00fff0f" // color palette (you can remove the colors you didn't use to save bytes) + pixels=[]; + "@@@@HHA@@A@@HIIAACCHQCSHARBHHIIA".replace(/./g, + character=>{ + characterCode=character.charCodeAt(), + pixels.push(characterCode&7), // Gets the last three bits + pixels.push((characterCode>>3)&7) // Gets the first three bits + }) // pixel decoding + size=8; + for (let y = 0; y < size; y++) { + for (let x = 0; x < size; x++) { + if (pixels[y * size + x]) { + ctx.fillStyle = "#" + pallette.substr(3 * (pixels[y * size + x] - 1), 3), + ctx.fillRect(x, y, 1, 1) + } + } + } // drawing + </script> +</body> +</html> \ No newline at end of file