-
+
+
-
-
-
-
+
+
-
-
+
+
+
+
+
@@ -65,10 +172,6 @@
-
-
diff --git a/package.json b/package.json
index fa983b7..70890e1 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,7 @@
"fireworks-js": "^2.10.8"
},
"lint-staged": {
- "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": [
+ "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc,css}": [
"biome check --write --no-errors-on-unmatched"
]
}
diff --git a/public/assets/object-svgs/bomb.svg b/public/assets/object-svgs/bomb.svg
index 6d59085..4dfb5ea 100644
--- a/public/assets/object-svgs/bomb.svg
+++ b/public/assets/object-svgs/bomb.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/cores/1.svg b/public/assets/object-svgs/cores/1.svg
index 19dd949..7262d2e 100644
--- a/public/assets/object-svgs/cores/1.svg
+++ b/public/assets/object-svgs/cores/1.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/cores/2.svg b/public/assets/object-svgs/cores/2.svg
index 43750f3..d82c064 100644
--- a/public/assets/object-svgs/cores/2.svg
+++ b/public/assets/object-svgs/cores/2.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/resource.svg b/public/assets/object-svgs/resource.svg
index 15d212a..60e3b0a 100644
--- a/public/assets/object-svgs/resource.svg
+++ b/public/assets/object-svgs/resource.svg
@@ -14,9 +14,6 @@
id="defs2" />
diff --git a/public/assets/object-svgs/units/builder/1.svg b/public/assets/object-svgs/units/builder/1.svg
index 910d4c4..9c4824a 100644
--- a/public/assets/object-svgs/units/builder/1.svg
+++ b/public/assets/object-svgs/units/builder/1.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/units/builder/2.svg b/public/assets/object-svgs/units/builder/2.svg
index 5a35057..6152bf5 100644
--- a/public/assets/object-svgs/units/builder/2.svg
+++ b/public/assets/object-svgs/units/builder/2.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/units/carrier/1.svg b/public/assets/object-svgs/units/carrier/1.svg
index 5fccfb3..cee179d 100644
--- a/public/assets/object-svgs/units/carrier/1.svg
+++ b/public/assets/object-svgs/units/carrier/1.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/units/carrier/2.svg b/public/assets/object-svgs/units/carrier/2.svg
index ff87f4b..a953ee5 100644
--- a/public/assets/object-svgs/units/carrier/2.svg
+++ b/public/assets/object-svgs/units/carrier/2.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/units/miner/1.svg b/public/assets/object-svgs/units/miner/1.svg
index f2ad10c..19c0edb 100644
--- a/public/assets/object-svgs/units/miner/1.svg
+++ b/public/assets/object-svgs/units/miner/1.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/units/miner/2.svg b/public/assets/object-svgs/units/miner/2.svg
index ac26189..74af943 100644
--- a/public/assets/object-svgs/units/miner/2.svg
+++ b/public/assets/object-svgs/units/miner/2.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/units/tank/1.svg b/public/assets/object-svgs/units/tank/1.svg
index 871a0c5..f9a33a1 100644
--- a/public/assets/object-svgs/units/tank/1.svg
+++ b/public/assets/object-svgs/units/tank/1.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/units/tank/2.svg b/public/assets/object-svgs/units/tank/2.svg
index fffaab5..e55c37a 100644
--- a/public/assets/object-svgs/units/tank/2.svg
+++ b/public/assets/object-svgs/units/tank/2.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/units/warrior/1.svg b/public/assets/object-svgs/units/warrior/1.svg
index 45ad532..5dee38d 100644
--- a/public/assets/object-svgs/units/warrior/1.svg
+++ b/public/assets/object-svgs/units/warrior/1.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/units/warrior/2.svg b/public/assets/object-svgs/units/warrior/2.svg
index 52cd1cc..aacbd38 100644
--- a/public/assets/object-svgs/units/warrior/2.svg
+++ b/public/assets/object-svgs/units/warrior/2.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/object-svgs/wall.svg b/public/assets/object-svgs/wall.svg
index ec1f5ac..3796566 100644
--- a/public/assets/object-svgs/wall.svg
+++ b/public/assets/object-svgs/wall.svg
@@ -15,9 +15,6 @@
id="defs1" />
diff --git a/public/assets/ui-svgs/core-logo.svg b/public/assets/ui-svgs/core-logo.svg
index ab8d69a..d4333e0 100644
--- a/public/assets/ui-svgs/core-logo.svg
+++ b/public/assets/ui-svgs/core-logo.svg
@@ -1,6 +1,5 @@
diff --git a/public/assets/ui-svgs/dark-mode-moon.svg b/public/assets/ui-svgs/dark-mode-moon.svg
new file mode 100644
index 0000000..0fadbe0
--- /dev/null
+++ b/public/assets/ui-svgs/dark-mode-moon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/assets/ui-svgs/dark-mode-sun.svg b/public/assets/ui-svgs/dark-mode-sun.svg
new file mode 100644
index 0000000..e5b25b6
--- /dev/null
+++ b/public/assets/ui-svgs/dark-mode-sun.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/assets/ui-svgs/github-logo.svg b/public/assets/ui-svgs/github-logo.svg
index d5e6491..99c1a1b 100644
--- a/public/assets/ui-svgs/github-logo.svg
+++ b/public/assets/ui-svgs/github-logo.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/ui-svgs/pause.svg b/public/assets/ui-svgs/pause.svg
index f78e5c1..bafcfde 100644
--- a/public/assets/ui-svgs/pause.svg
+++ b/public/assets/ui-svgs/pause.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/ui-svgs/play.svg b/public/assets/ui-svgs/play.svg
index 566dacb..915c223 100644
--- a/public/assets/ui-svgs/play.svg
+++ b/public/assets/ui-svgs/play.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/ui-svgs/skip_end.svg b/public/assets/ui-svgs/skip_end.svg
index ea4913f..33a23a8 100644
--- a/public/assets/ui-svgs/skip_end.svg
+++ b/public/assets/ui-svgs/skip_end.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/ui-svgs/skip_start.svg b/public/assets/ui-svgs/skip_start.svg
index 0b1c2a6..a7ac94e 100644
--- a/public/assets/ui-svgs/skip_start.svg
+++ b/public/assets/ui-svgs/skip_start.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/ui-svgs/speed_down.svg b/public/assets/ui-svgs/speed_down.svg
index 0dcd517..201518e 100644
--- a/public/assets/ui-svgs/speed_down.svg
+++ b/public/assets/ui-svgs/speed_down.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/ui-svgs/speed_up.svg b/public/assets/ui-svgs/speed_up.svg
index 3f6d0ff..8993c19 100644
--- a/public/assets/ui-svgs/speed_up.svg
+++ b/public/assets/ui-svgs/speed_up.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/ui-svgs/tick_next.svg b/public/assets/ui-svgs/tick_next.svg
index 3b486d0..cc2ab6d 100644
--- a/public/assets/ui-svgs/tick_next.svg
+++ b/public/assets/ui-svgs/tick_next.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/public/assets/ui-svgs/tick_previous.svg b/public/assets/ui-svgs/tick_previous.svg
index bb25fb1..6240e7b 100644
--- a/public/assets/ui-svgs/tick_previous.svg
+++ b/public/assets/ui-svgs/tick_previous.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/src/css/styles.css b/src/css/styles.css
index e612cfc..0a79a48 100644
--- a/src/css/styles.css
+++ b/src/css/styles.css
@@ -5,11 +5,64 @@
}
:root {
+ --svg-canvas-scale: 100%;
+
+ --core-purple: #6a0dad;
+}
+:root[data-theme="light"] {
--hp-color: #c70202ff;
--balance-color: #008600ff;
--cooldown-color: #0066ffff;
- --svg-canvas-scale: 100%;
- --core-purple: #6a0dad;
+
+ --panel-bg: color-mix(in srgb, var(--core-purple) 7%, white);
+ --panel-outline: color-mix(in srgb, var(--core-purple) 50%, white);
+ --panel-track: #a4a4a4;
+ --panel-thumb: var(--core-purple);
+
+ --text: #333333;
+ --tooltip-shadow-contrast: #ffffff;
+
+ --app-bg: color-mix(in srgb, var(--core-purple) 25%, white);
+ --grid-bg: var(--panel-bg);
+
+ --corner-buttons-color: var(--core-purple);
+
+ --svg-icon-fill: #000000;
+
+ --fireworks-darkening-layer: rgba(0, 0, 0, 0.75);
+}
+:root[data-theme="dark"] {
+ --hp-color: rgb(242, 12, 12);
+ --balance-color: rgb(0, 215, 0);
+ --cooldown-color: #0066ffff;
+
+ --panel-bg: #4d4d73;
+ --panel-outline: #9f9fe3;
+ --panel-track: #6f6fd6;
+ --panel-thumb: color-mix(in srgb, var(--core-purple) 30%, white);
+
+ --text: #e8e8ea;
+ --tooltip-shadow-contrast: #000000;
+
+ --app-bg: color-mix(in srgb, var(--core-purple) 40%, black);
+ --grid-bg: color-mix(in srgb, var(--panel-bg) 50%, black);
+
+ --corner-buttons-color: color-mix(in srgb, var(--core-purple) 35%, white);
+
+ --svg-icon-fill: #ffffff;
+
+ --fireworks-darkening-layer: rgba(0, 0, 0, 0.5);
+}
+
+:root[data-theme="dark"] .game-object {
+ filter: invert(100%) sepia(96%) saturate(17%) hue-rotate(214deg)
+ brightness(104%) contrast(100);
+}
+:root[data-theme="light"] .game-object.team-1 {
+ opacity: 0.5;
+}
+:root[data-theme="dark"] .game-object.team-1 {
+ opacity: 0.7;
}
html,
@@ -20,20 +73,49 @@ body {
overflow: hidden;
overscroll-behavior: none;
font-family: "JetBrains Mono", monospace;
- background-color: color-mix(in srgb, var(--core-purple) 20%, white);
+ color: var(--text);
+ background-color: var(--app-bg);
}
/* SVG Output Canvas */
+#svg-canvas {
+ width: var(--svg-canvas-scale);
+ height: var(--svg-canvas-scale);
+ aspect-ratio: 1 / 1;
+ outline: 2px solid var(--panel-outline);
+ background-color: var(--grid-bg);
+ border-radius: 10px;
+ margin: 10px 0 10px 0;
+ color: var(--svg-icon-fill);
+}
+
+.grid-cell {
+ fill: var(--grid-bg);
+ pointer-events: none;
+}
+
#tooltip {
position: fixed;
display: none;
padding: 10px;
- background: white;
- border: 1px solid #333;
+ background: var(--panel-bg);
+ border: 1px solid var(--panel-outline);
border-radius: 0 10px 10px 10px;
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.3);
+ color: var(--text);
pointer-events: none;
}
+#tooltip span[style*="var(--hp-color)"],
+#tooltip span[style*="var(--balance-color)"],
+#tooltip span[style*="var(--cooldown-color)"] {
+ text-shadow:
+ 0 0 2px var(--tooltip-shadow-contrast),
+ 0 0 4px var(--tooltip-shadow-contrast);
+}
+
+svg path {
+ fill: var(--svg-icon-fill);
+}
/* Structure */
.container {
@@ -58,53 +140,73 @@ body {
.teamName {
font-size: 1.5rem;
font-weight: bold;
- color: #333;
+ color: var(--text);
text-align: center;
- background-color: #f0f0f0;
+ background-color: var(--panel-bg);
+ outline: 2px solid var(--panel-outline);
padding: 0.5rem 1rem;
margin: 10px;
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- outline: 2px solid #ccc;
-}
-
-#svg-canvas {
- width: var(--svg-canvas-scale);
- height: var(--svg-canvas-scale);
- aspect-ratio: 1 / 1;
- outline: 2px solid #ccc;
- background-color: #f9f9f9;
- border-radius: 10px;
- margin: 10px 0 10px 0;
}
/* Time Controls */
-#time-controls {
+.control-panel {
display: flex;
align-items: center;
- justify-content: space-between;
- gap: 1rem;
+ justify-content: center;
+ gap: 3.5rem;
padding: 0.5rem 1rem;
- background-color: #f0f0f0;
+ background-color: var(--panel-bg);
border-radius: 0 0 20px 20px;
- z-index: 5000;
+ outline: 2px solid var(--panel-outline);
width: max-content;
margin: 0 auto;
- position: relative;
- outline: #ccc solid 2px;
+ z-index: 5000;
}
-.controls-bar,
-.main-buttons {
+.control-row {
display: flex;
align-items: center;
gap: 0.5rem;
- margin: 0 20px 0 20px;
+ margin: 0;
+ flex-wrap: nowrap;
}
-.main-buttons button {
- padding: 0.75rem;
- background-color: #555;
+.control-panel button {
+ background: none;
+ border: none;
+ cursor: pointer;
+ padding: 0.5rem;
+ border-radius: 4px;
+}
+
+.icon-button img {
+ width: 1.5rem;
+ height: 1.5rem;
+ display: block;
+}
+
+.control-panel button img {
+ width: 1.5rem;
+ height: auto;
+}
+
+:root[data-theme="light"] .control-panel button.active,
+:root[data-theme="light"] .control-panel button:active {
+ background-color: color-mix(in srgb, var(--core-purple) 30%, white);
+}
+:root[data-theme="dark"] .control-panel button.active,
+:root[data-theme="dark"] .control-panel button:active {
+ background-color: color-mix(in srgb, var(--core-purple) 80%, black);
+}
+:root[data-theme="light"] .icon-button.active,
+:root[data-theme="light"] .icon-button:active {
+ background-color: color-mix(in srgb, var(--core-purple) 30%, white);
+}
+:root[data-theme="dark"] .icon-button.active,
+:root[data-theme="dark"] .icon-button:active {
+ background-color: color-mix(in srgb, var(--core-purple) 80%, black);
}
.slider-group {
@@ -112,9 +214,10 @@ body {
flex-direction: column;
align-items: center;
gap: 2px;
- width: 6rem;
+ width: 7rem;
box-sizing: border-box;
}
+
.slider-group label {
width: 100%;
font-size: 0.9rem;
@@ -127,76 +230,83 @@ body {
text-overflow: ellipsis;
}
-#time-controls button {
- background: none;
- border: none;
- cursor: pointer;
- padding: 0.5rem;
+.control-panel input[type="number"] {
+ width: 3.25rem;
+ color: var(--text);
+ background: var(--panel-bg);
+ border: 1px solid var(--panel-outline);
border-radius: 4px;
-}
-#time-controls button:active,
-#time-controls button.active {
- background-color: color-mix(in srgb, var(--core-purple) 40%, white);
-}
-
-#time-controls button img {
- width: 1.5rem;
- height: auto;
+ padding: 0.25rem 0.35rem;
}
-#time-controls input[type="range"] {
+.control-panel input[type="range"] {
-webkit-appearance: none;
appearance: none;
- width: 6rem;
+ width: 7rem;
height: 0.5rem;
- background: #a4a4a4;
+ background: var(--panel-track);
border-radius: 0.25rem;
}
-#time-controls input[type="range"]::-webkit-slider-runnable-track {
+.control-panel input[type="range"]::-webkit-slider-runnable-track {
height: 100%;
- background: #a4a4a4;
+ background: var(--panel-track);
border-radius: 0.25rem;
}
-#time-controls input[type="range"]::-webkit-slider-thumb {
+.control-panel input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 1rem;
height: 1rem;
margin-top: -0.25rem;
- background: var(--core-purple);
+ background: var(--panel-thumb);
border-radius: 50%;
cursor: pointer;
}
-#time-controls input[type="range"] {
- -moz-appearance: none;
- appearance: none;
-}
-
-#time-controls input[type="range"]::-moz-range-track {
+.control-panel input[type="range"]::-moz-range-track {
height: 0.5rem;
- background: #ddd;
+ background: var(--panel-track);
border-radius: 0.25rem;
}
-#time-controls input[type="range"]::-moz-range-progress {
- background: var(--core-purple);
+.control-panel input[type="range"]::-moz-range-progress {
+ background: var(--panel-thumb);
height: 0.5rem;
border-radius: 0.25rem;
}
-#time-controls input[type="range"]::-moz-range-thumb {
+.control-panel input[type="range"]::-moz-range-thumb {
width: 1rem;
height: 1rem;
- background: var(--core-purple);
+ background: var(--panel-thumb);
border: none;
border-radius: 50%;
cursor: pointer;
}
-#time-controls input[type="number"] {
- width: 3rem;
+.top-bar {
+ display: grid;
+ grid-template-columns: auto max-content auto;
+ align-items: start;
+ justify-content: center;
+ gap: 0.5rem;
+ padding: 0;
+ z-index: 5000;
+}
+
+.icon-button {
+ padding: 0.5rem 0.6rem;
+ background-color: var(--panel-bg);
+ outline: 2px solid var(--panel-outline);
+ border: none;
+ border-radius: 0 0 12px 12px;
+ cursor: pointer;
+}
+
+:root[data-theme="dark"] .icon-button img,
+:root[data-theme="dark"] .control-panel button img {
+ filter: invert(1);
}
/* corner buttons */
@@ -205,7 +315,7 @@ body {
position: absolute;
width: 7rem;
height: 7rem;
- background-color: var(--core-purple);
+ background-color: var(--corner-buttons-color);
background-size: 40%;
background-repeat: no-repeat;
transition: transform 0.1s ease-in-out;
@@ -218,20 +328,42 @@ body {
#corner-bottom-left {
bottom: 0;
left: 0;
- background-image: url("/assets/ui-svgs/github-logo.svg");
clip-path: polygon(0 100%, 0 0, 100% 100%);
- background-position: 17% 83%;
transform-origin: bottom left;
}
+#corner-bottom-left::after {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background-image: url("/assets/ui-svgs/github-logo.svg");
+ background-size: 40%;
+ background-repeat: no-repeat;
+ background-position: 17% 83%;
+ pointer-events: none;
+}
+:root[data-theme="light"] #corner-bottom-left::after {
+ filter: invert(1);
+}
#corner-top-right {
top: 0;
right: 0;
- background-image: url("/assets/ui-svgs/core-logo.svg");
clip-path: polygon(0 0, 100% 0, 100% 100%);
- background-position: 83% 17%;
transform-origin: top right;
}
+#corner-top-right::after {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background-image: url("/assets/ui-svgs/core-logo.svg");
+ background-size: 40%;
+ background-repeat: no-repeat;
+ background-position: 83% 17%;
+ pointer-events: none;
+}
+:root[data-theme="light"] #corner-top-right::after {
+ filter: invert(1);
+}
/* Winner Display */
@@ -259,7 +391,7 @@ body {
left: 0;
width: 100vw;
height: 100vh;
- background-color: rgba(0, 0, 0, 0.75);
+ background-color: var(--fireworks-darkening-layer);
z-index: 500;
pointer-events: none;
}
diff --git a/src/ts/input_manager/themeManager.ts b/src/ts/input_manager/themeManager.ts
new file mode 100644
index 0000000..ed7cc0e
--- /dev/null
+++ b/src/ts/input_manager/themeManager.ts
@@ -0,0 +1,70 @@
+type ThemeMode = "light" | "dark";
+
+const themeToggleButton = document.getElementById(
+ "theme-toggle-button",
+) as HTMLButtonElement | null;
+const themeIcon = document.getElementById(
+ "theme-icon",
+) as HTMLImageElement | null;
+
+const STORAGE_KEY = "ui.theme";
+const mql = window.matchMedia
+ ? window.matchMedia("(prefers-color-scheme: dark)")
+ : null;
+
+function resolveTheme(): ThemeMode {
+ const v = localStorage.getItem(STORAGE_KEY);
+ if (v === "light" || v === "dark") return v as ThemeMode;
+ return mql?.matches ? "dark" : "light";
+}
+
+function applyToDOM(mode: ThemeMode): void {
+ document.documentElement.setAttribute("data-theme", mode);
+ if (themeToggleButton)
+ themeToggleButton.setAttribute(
+ "aria-pressed",
+ mode === "dark" ? "true" : "false",
+ );
+ if (themeIcon) {
+ themeIcon.src =
+ mode === "dark"
+ ? "/assets/ui-svgs/dark-mode-sun.svg"
+ : "/assets/ui-svgs/dark-mode-moon.svg";
+ themeIcon.alt =
+ mode === "dark" ? "Switch to Light Mode" : "Switch to Dark Mode";
+ }
+}
+
+export function applyTheme(mode: ThemeMode): void {
+ localStorage.setItem(STORAGE_KEY, mode);
+ applyToDOM(mode);
+}
+
+export function loadSavedTheme(): void {
+ applyToDOM(resolveTheme());
+
+ if (mql) {
+ const onSystemChange = (e: MediaQueryListEvent) => {
+ const hasOverride =
+ localStorage.getItem(STORAGE_KEY) === "light" ||
+ localStorage.getItem(STORAGE_KEY) === "dark";
+ if (!hasOverride) applyToDOM(e.matches ? "dark" : "light");
+ };
+ if ("addEventListener" in mql) {
+ mql.addEventListener("change", onSystemChange);
+ } else if (typeof (mql as any).addListener === "function") {
+ (mql as any).addListener(onSystemChange);
+ }
+ }
+
+ window.addEventListener("storage", (e) => {
+ if (e.key === STORAGE_KEY) applyToDOM(resolveTheme());
+ });
+}
+
+export function toggleTheme(): void {
+ const next = resolveTheme() === "dark" ? "light" : "dark";
+ localStorage.setItem(STORAGE_KEY, next);
+ applyToDOM(next);
+}
+themeToggleButton?.addEventListener("click", toggleTheme);
diff --git a/src/ts/time_manager/timeManager.ts b/src/ts/input_manager/timeManager.ts
similarity index 98%
rename from src/ts/time_manager/timeManager.ts
rename to src/ts/input_manager/timeManager.ts
index 57fe026..5aa1d49 100644
--- a/src/ts/time_manager/timeManager.ts
+++ b/src/ts/input_manager/timeManager.ts
@@ -1,5 +1,6 @@
import { setRenderFireworks } from "../renderer/fireworksRenderer";
import { getTotalReplayTicks } from "../replay_loader/replayLoader";
+import { applyTheme } from "./themeManager";
const playButton = document.getElementById(
"play-pause-button",
@@ -291,6 +292,8 @@ export async function setupTimeManager() {
button: speedDownButton,
},
f: { action: () => toggleFullscreen(), button: fullscreenToggleButton },
+ d: { action: () => applyTheme("dark") },
+ l: { action: () => applyTheme("light") },
};
window.addEventListener("keydown", (event) => {
diff --git a/src/ts/main.ts b/src/ts/main.ts
index 2350e55..14267a7 100644
--- a/src/ts/main.ts
+++ b/src/ts/main.ts
@@ -1,3 +1,5 @@
+import { loadSavedTheme } from "./input_manager/themeManager.js";
+
const svgCanvas = document.getElementById("svg-canvas") as HTMLElement;
window.addEventListener("DOMContentLoaded", async () => {
@@ -25,7 +27,7 @@ window.addEventListener("DOMContentLoaded", async () => {
const { setupReplayLoader } = await import("./replay_loader/replayLoader.js");
const { setupTimeManager, startPlayback, isAtEnd } = await import(
- "./time_manager/timeManager.js"
+ "./input_manager/timeManager.js"
);
const { setupRenderer } = await import("./renderer/renderer.js");
@@ -73,4 +75,7 @@ window.addEventListener("DOMContentLoaded", async () => {
window.addEventListener("resize", updateSvgSize);
window.addEventListener("load", updateSvgSize);
updateSvgSize();
+
+ // theme
+ loadSavedTheme();
});
diff --git a/src/ts/renderer/objectRenderer.ts b/src/ts/renderer/objectRenderer.ts
index 4dbf276..e0dadea 100644
--- a/src/ts/renderer/objectRenderer.ts
+++ b/src/ts/renderer/objectRenderer.ts
@@ -1,10 +1,10 @@
+import type { tickData } from "../input_manager/timeManager";
import { getBarMetrics, type TickObject } from "../replay_loader/object";
import {
getActionsByExecutor,
getNameOfUnitType,
getStateAt,
} from "../replay_loader/replayLoader";
-import type { tickData } from "../time_manager/timeManager";
import {
EaseInOutTimingCurve,
MidTickIncreaseTimingCurve,
@@ -202,7 +202,7 @@ function drawObject(
img = document.createElementNS(svgNS, "image");
img.setAttribute("data-obj-id", obj.id.toString());
}
-
+ img.classList.add("game-object");
img.classList.remove("not-touched");
img.classList.remove("team-0", "team-1");
if (obj.type === 0 || obj.type === 1) {
diff --git a/src/ts/renderer/renderer.ts b/src/ts/renderer/renderer.ts
index 1a3ad00..63dbc29 100644
--- a/src/ts/renderer/renderer.ts
+++ b/src/ts/renderer/renderer.ts
@@ -1,3 +1,4 @@
+import { getCurrentTickData, isDirty } from "../input_manager/timeManager";
import type { GameConfig } from "../replay_loader/config";
import { formatObjectData, type TickObject } from "../replay_loader/object";
import {
@@ -5,7 +6,6 @@ import {
getGameMisc,
getStateAt,
} from "../replay_loader/replayLoader";
-import { getCurrentTickData, isDirty } from "../time_manager/timeManager";
import { calcAndDrawObject, initializeTeamMapping } from "./objectRenderer";
const svgNS = "http://www.w3.org/2000/svg";
@@ -104,7 +104,7 @@ function refreshTooltipFromSVGPoint(
if (obj) {
tooltipElement.innerHTML = formatObjectData(obj);
} else {
- tooltipElement.innerHTML = `📍 Position: [${tx}, ${ty}]`;
+ tooltipElement.innerHTML = `📍 Position: [x: ${tx}, y: ${ty}]`;
}
}
export async function setupRenderer(): Promise {
@@ -151,14 +151,11 @@ export async function setupRenderer(): Promise {
for (let y = 0; y < gridSize; y++) {
for (let x = 0; x < gridSize; x++) {
const rect = document.createElementNS(svgNS, "rect");
- rect.setAttribute("class", "persistent");
+ rect.setAttribute("class", "grid-cell persistent");
rect.setAttribute("x", x.toString());
rect.setAttribute("y", y.toString());
rect.setAttribute("width", "1");
rect.setAttribute("height", "1");
- rect.setAttribute("fill", "#f7f7f7");
- rect.setAttribute("stroke", "black");
- rect.setAttribute("stroke-width", "0.01");
svgCanvas.appendChild(rect);
}
}
diff --git a/src/ts/replay_loader/object.ts b/src/ts/replay_loader/object.ts
index 1897f9d..a612266 100644
--- a/src/ts/replay_loader/object.ts
+++ b/src/ts/replay_loader/object.ts
@@ -63,13 +63,13 @@ export function formatObjectData(obj: TickObject): string {
lines.push({
line: `❓ Object Type: ${objectTypeNames[obj.type] || "Unknown"}`,
priority: 4,
- color: "black",
+ color: "var(--text)",
});
- lines.push({ line: `#️⃣ ID: ${obj.id}`, priority: 5, color: "black" });
+ lines.push({ line: `#️⃣ ID: ${obj.id}`, priority: 5, color: "var(--text)" });
lines.push({
- line: `📍 Position: [${obj.x}, ${obj.y}]`,
+ line: `📍 Position: [x: ${obj.x}, y: ${obj.y}]`,
priority: 6,
- color: "black",
+ color: "var(--text)",
});
switch (obj.type) {
@@ -77,7 +77,7 @@ export function formatObjectData(obj: TickObject): string {
lines.push({
line: `🏁 Team ID: ${obj.teamId}`,
priority: 5,
- color: "black",
+ color: "var(--text)",
});
lines.push({
line: `💰 Balance: ${obj.balance}`,
@@ -89,7 +89,7 @@ export function formatObjectData(obj: TickObject): string {
lines.push({
line: `🏁 Team ID: ${obj.teamId}`,
priority: 5,
- color: "black",
+ color: "var(--text)",
});
lines.push({
line: `💰 Balance: ${obj.balance}`,
@@ -114,7 +114,7 @@ export function formatObjectData(obj: TickObject): string {
lines.push({
line: `💣 Explosion Countdown: ${obj.countdown}`,
priority: -1,
- color: "black",
+ color: "var(--text)",
});
break;
}
diff --git a/src/ts/replay_loader/replayLoader.ts b/src/ts/replay_loader/replayLoader.ts
index 31a08da..15b34b6 100644
--- a/src/ts/replay_loader/replayLoader.ts
+++ b/src/ts/replay_loader/replayLoader.ts
@@ -1,5 +1,5 @@
+import { resetTimeManager } from "../input_manager/timeManager";
import { setupRenderer } from "../renderer/renderer";
-import { resetTimeManager } from "../time_manager/timeManager";
import type { TickAction } from "./action";
import type { GameConfig } from "./config";
import type { TickObject } from "./object";