all repos — emchess @ e3439f4fd1351a66738e364bb3c2a16038ca6e6a

feat: fix colors
Pablo Murad pblmrd@gmail.com
Thu, 30 Jul 2026 09:48:47 -0300
commit

e3439f4fd1351a66738e364bb3c2a16038ca6e6a

parent

582b0387fa0b9b6f7b51a8a13c4fee17764ffb39

4 files changed, 35 insertions(+), 33 deletions(-)

jump to
M src/game/engine.jssrc/game/engine.js

@@ -1,18 +1,10 @@

+// A real same-origin URL (not a blob), so Stockfish resolves its .wasm next to itself. +// The server must send the .wasm as application/wasm. const ENGINE_URL = new URL(`${import.meta.env.BASE_URL}stockfish/stockfish-18-lite-single.js`, location.href).href; -const WASM_URL = new URL(`${import.meta.env.BASE_URL}stockfish/stockfish-18-lite-single.wasm`, location.href).href; -// A tiny worker that fetches the wasm as a plain binary and hands it to Stockfish -// through Module.wasmBinary. That path ignores the response's MIME type, so a server -// that serves .wasm as text/plain (a very common misconfig) can't break the engine. -const BOOTSTRAP = `self.onmessage=function(e){var d=e.data||{};if(!d.__boot)return;` + - `fetch(d.wasmUrl).then(function(r){return r.arrayBuffer();}).then(function(buf){` + - `self.Module={wasmBinary:buf,locateFile:function(p){return p.slice(-5)==='.wasm'?d.wasmUrl:p;}};` + - `try{importScripts(d.jsUrl);postMessage('__ready');}catch(err){postMessage('__err '+err);}` + - `}).catch(function(err){postMessage('__err '+err);});};`; export class Engine { constructor() { this.listeners = []; - const bootUrl = URL.createObjectURL(new Blob([BOOTSTRAP], { type: "text/javascript" })); - this.worker = new Worker(bootUrl); + this.worker = new Worker(ENGINE_URL); this.worker.onmessage = (e) => { const line = typeof e.data === "string" ? e.data : String(e.data?.data ?? ""); for (const fn of this.listeners)

@@ -44,8 +36,6 @@ }

}); } async boot() { - this.worker.postMessage({ __boot: true, jsUrl: ENGINE_URL, wasmUrl: WASM_URL }); - await this.waitFor("__ready", 20000); this.send("uci"); await this.waitFor("uciok", 20000); this.send("isready");
M src/game/engine.tssrc/game/engine.ts

@@ -1,16 +1,8 @@

import type { Personality } from "./personalities"; +// A real same-origin URL (not a blob), so Stockfish resolves its .wasm next to itself. +// The server must send the .wasm as application/wasm. const ENGINE_URL = new URL(`${import.meta.env.BASE_URL}stockfish/stockfish-18-lite-single.js`, location.href).href; -const WASM_URL = new URL(`${import.meta.env.BASE_URL}stockfish/stockfish-18-lite-single.wasm`, location.href).href; - -// A tiny worker that fetches the wasm as a plain binary and hands it to Stockfish -// through Module.wasmBinary. That path ignores the response's MIME type, so a server -// that serves .wasm as text/plain (a very common misconfig) can't break the engine. -const BOOTSTRAP = `self.onmessage=function(e){var d=e.data||{};if(!d.__boot)return;` + - `fetch(d.wasmUrl).then(function(r){return r.arrayBuffer();}).then(function(buf){` + - `self.Module={wasmBinary:buf,locateFile:function(p){return p.slice(-5)==='.wasm'?d.wasmUrl:p;}};` + - `try{importScripts(d.jsUrl);postMessage('__ready');}catch(err){postMessage('__err '+err);}` + - `}).catch(function(err){postMessage('__err '+err);});};`; type Line = string;

@@ -20,8 +12,7 @@ private ready: Promise<void>;

private listeners: ((line: Line) => void)[] = []; constructor() { - const bootUrl = URL.createObjectURL(new Blob([BOOTSTRAP], { type: "text/javascript" })); - this.worker = new Worker(bootUrl); + this.worker = new Worker(ENGINE_URL); this.worker.onmessage = (e) => { const line = typeof e.data === "string" ? e.data : String(e.data?.data ?? ""); for (const fn of this.listeners) fn(line);

@@ -54,8 +45,6 @@ });

} private async boot() { - this.worker.postMessage({ __boot: true, jsUrl: ENGINE_URL, wasmUrl: WASM_URL }); - await this.waitFor("__ready", 20000); this.send("uci"); await this.waitFor("uciok", 20000); this.send("isready");
M src/style.csssrc/style.css

@@ -216,9 +216,28 @@ transition: transform .26s cubic-bezier(.2,.7,.25,1);

will-change: transform; } .piece .glyph { position: relative; z-index: 2; } -.piece::before { content: ""; position: absolute; bottom: 8%; width: 64%; height: 18%; border-radius: 50%; z-index: 1; } -.piece.w::before { background: rgba(252,249,240,.92); box-shadow: inset 0 0 0 1px rgba(0,0,0,.3); } -.piece.b::before { background: rgba(30,27,20,.85); box-shadow: inset 0 0 0 1px rgba(255,255,255,.28); } +/* Emoji share one glyph per type, so the light and dark armies are told apart by the + token each piece rides on, not by the emoji's own colors. */ +/* A grounding shadow plus a hairline light rim, so a mid-tone emoji (a grey wolf, say) + still reads on the dark army's token without being darkened into it. */ +.piece:not(.traditional) .glyph { + filter: drop-shadow(0 1px 1px rgba(0,0,0,.4)) drop-shadow(0 0 .5px rgba(255,255,255,.55)); +} +.piece::before { + content: ""; + position: absolute; + inset: 9%; + border-radius: 50%; + z-index: 1; +} +.piece.w::before { + background: radial-gradient(circle at 38% 32%, #fffdf6, #e7dcbe 78%); + box-shadow: 0 2px 4px rgba(0,0,0,.22), inset 0 0 0 2px rgba(90,70,28,.5); +} +.piece.b::before { + background: radial-gradient(circle at 38% 32%, #3b362a, #14110b 78%); + box-shadow: 0 2px 4px rgba(0,0,0,.38), inset 0 0 0 2px rgba(243,238,220,.5); +} .piece.traditional { font-family: var(--mono); font-size: calc(var(--sq) * .8); } .piece.traditional.w { color: #fbf7ec; text-shadow: 0 0 1px #000, 0 1px 1px rgba(0,0,0,.45); } .piece.traditional.b { color: #141109; }

@@ -230,11 +249,11 @@ @keyframes hop { 0% { transform: translateY(0); } 45% { transform: translateY(-24%); } 100% { transform: translateY(0); } }

.piece.threat::after { content: ""; position: absolute; - inset: 7%; + inset: 3%; border: 2px solid var(--check); border-radius: 50%; - opacity: .85; - z-index: 0; + opacity: .9; + z-index: 3; pointer-events: none; }
M vite.config.tsvite.config.ts

@@ -14,6 +14,10 @@ workbox: {

globPatterns: ["**/*.{js,css,html,wasm,woff,woff2,svg}"], // The Stockfish wasm is ~7MB, so raise the precache size limit. maximumFileSizeToCacheInBytes: 9 * 1024 * 1024, + // Take over at once and drop old caches, so a bad old cache can't linger. + skipWaiting: true, + clientsClaim: true, + cleanupOutdatedCaches: true, }, manifest: { name: "Emchess",