feat(settings/options/2048): per-color scheme

This commit is contained in:
2026-02-24 12:36:38 +01:00
parent 7ac60d186f
commit f03ef33777

View File

@@ -42,28 +42,55 @@ const handleActivateA = () => {
}); });
}; };
// TODO: one color scheme per app color const app = useAppStore();
const TILE_COLORS: Record<number, { bg: string; fg: string }> = {
[0]: { bg: "#f7f7f7", fg: "#776e65" }, const TILE_VALUES = [0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096];
[2]: { bg: "#ebebf3", fg: "#292929" }, const APP_COLOR_INDEX = TILE_VALUES.indexOf(2048);
[4]: { bg: "#d3dbe3", fg: "#292929" },
[8]: { bg: "#bacbd3", fg: "#292929" }, const buildTileColors = (
[16]: { bg: "#a2bac3", fg: "#f9f6f2" }, base: string,
[32]: { bg: "#8aa2b2", fg: "#f9f6f2" }, ): Record<number, { bg: string; fg: string }> => {
[64]: { bg: "#7192a2", fg: "#f9f6f2" }, const result: Record<number, { bg: string; fg: string }> = {
[128]: { bg: "#698aa2", fg: "#f9f6f2" }, [0]: { bg: "#f7f7f7", fg: "#776e65" },
[256]: { bg: "#61829a", fg: "#f9f6f2" }, };
[512]: { bg: "#5c7b92", fg: "#f9f6f2" },
[1024]: { bg: "#57758a", fg: "#f9f6f2" }, // -2.5L, -0.8C for (let i = 1; i < TILE_VALUES.length; i += 1) {
[2048]: { bg: "#476277", fg: "#f9f6f2" }, const value = TILE_VALUES[i]!;
[4046]: { bg: "#173446", fg: "#f9f6f2" }, // 0 -> 1 = tile 2 -> 2048
const progress = (i - 1) / (APP_COLOR_INDEX - 1);
let lightnessBoost: number;
let chromaFactor: number;
if (i <= APP_COLOR_INDEX) {
lightnessBoost = (1 - progress) * 0.35;
chromaFactor = 0.05 + progress * 0.95;
} else {
const stepsAbove2048 = i - APP_COLOR_INDEX;
lightnessBoost = -stepsAbove2048 * 0.07;
chromaFactor = 1 + stepsAbove2048 * 0.15;
}
const bg = `oklch(from ${base} calc(l + ${lightnessBoost}) calc(c * ${chromaFactor}) h)`;
// change text color based on background lightness
const fg = `oklch(from ${bg} clamp(0, (0.6 - l) * 999, 1) 0 h)`;
result[value] = { bg, fg };
}
return result;
}; };
const LAST_TILE_COLOR =
Object.values(TILE_COLORS)[Object.values(TILE_COLORS).length - 1]!; const TILE_COLORS = computed(() => buildTileColors(app.color.hex));
const LAST_TILE_COLOR = computed(() => {
const values = Object.values(TILE_COLORS.value);
return values[values.length - 1]!;
});
const TILE_SIZE = 28; const TILE_SIZE = 28;
const ANIM_DURATION = 0.1; const ANIM_DURATION = 0.1;
const BORDER_COLOR = "#d7d7d7"; const BORDER_COLOR = computed(
() => `oklch(from ${app.color.hex} 0.88 0.015 h)`,
);
const BORDER_SIZE = 3; const BORDER_SIZE = 3;
const BOARD_X = 64; const BOARD_X = 64;
@@ -215,7 +242,7 @@ onRender((ctx) => {
assets.images.settings.bottomScreen.options._2048.frame.draw(ctx, -3, -3); assets.images.settings.bottomScreen.options._2048.frame.draw(ctx, -3, -3);
ctx.fillStyle = BORDER_COLOR; ctx.fillStyle = BORDER_COLOR.value;
ctx.fillRect( ctx.fillRect(
0, 0,
0, 0,
@@ -225,7 +252,7 @@ onRender((ctx) => {
for (let row = 0; row < BOARD_SIZE; row += 1) { for (let row = 0; row < BOARD_SIZE; row += 1) {
for (let col = 0; col < BOARD_SIZE; col += 1) { for (let col = 0; col < BOARD_SIZE; col += 1) {
ctx.fillStyle = TILE_COLORS[0]!.bg; ctx.fillStyle = TILE_COLORS.value[0]!.bg;
ctx.fillRect(cellX(col), cellY(row), TILE_SIZE, TILE_SIZE); ctx.fillRect(cellX(col), cellY(row), TILE_SIZE, TILE_SIZE);
} }
} }
@@ -236,7 +263,7 @@ onRender((ctx) => {
} }
for (const tile of tiles) { for (const tile of tiles) {
const color = TILE_COLORS[tile.value] ?? LAST_TILE_COLOR; const color = TILE_COLORS.value[tile.value] ?? LAST_TILE_COLOR.value;
ctx.save(); ctx.save();
const cx = tile.x + TILE_SIZE / 2; const cx = tile.x + TILE_SIZE / 2;
@@ -567,15 +594,6 @@ const slide = (rowDir: number, colDir: number) => {
useKeyDown(({ key }) => { useKeyDown(({ key }) => {
if (isAnimating.value) return; if (isAnimating.value) return;
switch (key) { switch (key) {
// TODO: remove this, testing only
case "n":
savedState.value.board = [
[0, 0, 2, 4],
[8, 16, 32, 64],
[128, 256, 512, 1024],
[2048, 4096, 8192, 16384],
];
break;
case "NDS_UP": case "NDS_UP":
case "NDS_SWIPE_UP": case "NDS_SWIPE_UP":
slide(-1, 0); slide(-1, 0);