From 344e7caa81962694e8fa1b08beec77301d0b3558 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Thu, 27 Nov 2025 13:05:08 -0600
Subject: [PATCH] feat: overhead lighting
---
.../HeroSection/components/Options/index.tsx | 16 +++++
.../TankSandbox/components/Lighting.tsx | 71 ++++++++++---------
.../src/stores/tankopediaPersistent/index.ts | 2 +
3 files changed, 55 insertions(+), 34 deletions(-)
diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx
index 59fdca5a6..a9659776d 100644
--- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx
+++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx
@@ -12,6 +12,7 @@ import {
EyeOpenIcon,
ShadowInnerIcon,
ShadowNoneIcon,
+ SunIcon,
} from "@radix-ui/react-icons";
import {
Button,
@@ -73,6 +74,7 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
const { strings, unwrap } = useLocale();
const revealed = Tankopedia.use((state) => state.revealed);
const disturbed = Tankopedia.use((state) => state.disturbed);
+ const highGraphics = TankopediaPersistent.use((state) => state.highGraphics);
return (
<>
@@ -349,6 +351,20 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
+ {
+ TankopediaPersistent.mutate((draft) => {
+ draft.highGraphics = !draft.highGraphics;
+ });
+ }}
+ color={highGraphics ? undefined : "gray"}
+ variant={highGraphics ? "solid" : "surface"}
+ >
+
+
+
(null!);
const t0 = useRef(0);
@@ -17,6 +26,7 @@ export function Lighting() {
const display = Tankopedia.use((state) => state.display);
const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay);
const animationTime = useRef(REVEAL_ANIMATION_TIME);
+ const highGraphics = TankopediaPersistent.use((state) => state.highGraphics);
useEffect(() => {
Tankopedia.mutate((draft) => {
@@ -35,9 +45,7 @@ export function Lighting() {
const t = 0.5 * Math.sin(Math.PI * (x + 0.5)) + 0.5;
for (const child of wrapper.current.children) {
- if (child instanceof HemisphereLight) {
- child.intensity = HEMISPHERE_INTENSITY * t;
- } else if (child instanceof SpotLight) {
+ if (child instanceof SpotLight) {
child.angle = ANGLE * t;
}
}
@@ -60,34 +68,29 @@ export function Lighting() {
return (
-
+ {times(LIGHTS_COUNT, (index) => {
+ const x = index / (LIGHTS_COUNT - 1);
+ const theta = 2 * Math.PI * (index / LIGHTS_COUNT) + THETA_OFFSET;
+ const position = [
+ LIGHT_DISTANCE * Math.sin(theta),
+ lerp(LIGHT_HEIGHT_0, LIGHT_HEIGHT_1, x),
+ LIGHT_DISTANCE * Math.cos(theta),
+ ] as const;
+ const intensity = lerp(INTENSITY_0, INTENSITY_1, x);
-
-
-
+ return (
+
+ );
+ })}
);
}
diff --git a/packages/website/src/stores/tankopediaPersistent/index.ts b/packages/website/src/stores/tankopediaPersistent/index.ts
index 1b1cc2839..ced9cf380 100644
--- a/packages/website/src/stores/tankopediaPersistent/index.ts
+++ b/packages/website/src/stores/tankopediaPersistent/index.ts
@@ -15,6 +15,7 @@ export interface TankopediaPersistent {
showPrimaryArmor: boolean;
recentlyViewed: number[];
hideTankModelUnderArmor: boolean;
+ highGraphics: boolean;
sort: {
by: TankopediaSortBy;
@@ -33,6 +34,7 @@ export const TankopediaPersistent = new Varuna(
showExternalModules: true,
showPrimaryArmor: true,
recentlyViewed: [],
+ highGraphics: true,
sort: {
by: "meta.none",
direction: "ascending",