diff --git a/packages/i18n/strings/en.json b/packages/i18n/strings/en.json
index 1158b0849..319f77ba7 100644
--- a/packages/i18n/strings/en.json
+++ b/packages/i18n/strings/en.json
@@ -1,4 +1,11 @@
{
+ "settings": {
+ "quality3": {
+ "low": "Low",
+ "medium": "Medium",
+ "high": "High"
+ }
+ },
"price": {
"free": "Free"
},
@@ -159,6 +166,11 @@
"name": "Changelogs",
"slogan": "BlitzKit patch notes",
"action": "Read up"
+ },
+ "settings": {
+ "name": "Settings",
+ "slogan": "",
+ "action": ""
}
},
diff --git a/packages/website-ue/public/media/tools/banners/settings.webp b/packages/website-ue/public/media/tools/banners/settings.webp
new file mode 100644
index 000000000..ff4f75757
Binary files /dev/null and b/packages/website-ue/public/media/tools/banners/settings.webp differ
diff --git a/packages/website-ue/src/components/Carousel.tsx b/packages/website-ue/src/components/Carousel.tsx
new file mode 100644
index 000000000..08271cb2e
--- /dev/null
+++ b/packages/website-ue/src/components/Carousel.tsx
@@ -0,0 +1,37 @@
+import { CaretLeftIcon, CaretRightIcon } from "@radix-ui/react-icons";
+import { type ReactNode } from "react";
+
+interface Props {
+ value: number;
+ onChange: (value: number) => void;
+ options: ReactNode[];
+}
+
+export function Carousel({ value, onChange, options }: Props) {
+ const isMin = value === 0;
+ const isMax = value === options.length - 1;
+
+ return (
+
+
{
+ if (!isMin) onChange(value - 1);
+ }}
+ >
+
+
+
+
{options[value]}
+
+
{
+ if (!isMax) onChange(value + 1);
+ }}
+ >
+
+
+
+ );
+}
diff --git a/packages/website-ue/src/components/Code/index.tsx b/packages/website-ue/src/components/Code/index.tsx
index 8811704e3..ef200ef39 100644
--- a/packages/website-ue/src/components/Code/index.tsx
+++ b/packages/website-ue/src/components/Code/index.tsx
@@ -1,14 +1,15 @@
-import type { ComponentProps } from "react";
import { classNames } from "../../ui/classNames";
+import { Text, type TextProps } from "../Text";
import styles from "./index.module.css";
-export interface CodeProps extends ComponentProps<"code"> {
+export interface CodeProps extends TextProps {
+ lowContrast?: boolean;
variant?: "ghost" | "solid";
}
export function Code({ className, variant = "ghost", ...props }: CodeProps) {
return (
- ;
+}
+
+function Inner() {
+ const parent = useRef(null!);
+ const settings = Settings.use();
+
+ return (
+
+
+ {stats.map((stat) => (
+
+ ))}
+
+
+
+ {settingsOrder[0].settings.map((setting) => (
+
+ {setting} = {settings[setting]}
+
+ ))}
+
+
+ );
+}
diff --git a/packages/website-ue/src/components/TankModelPart.tsx b/packages/website-ue/src/components/TankModelPart.tsx
index 8feff02bb..e8a3cee36 100644
--- a/packages/website-ue/src/components/TankModelPart.tsx
+++ b/packages/website-ue/src/components/TankModelPart.tsx
@@ -1,6 +1,8 @@
import { useGLTF } from "@react-three/drei";
import { useEffect } from "react";
import { Mesh, MeshStandardMaterial } from "three";
+import { SettingQuality3 } from "../config/settings";
+import { useSetting } from "../hooks/useSetting";
interface Props {
url: string;
@@ -8,6 +10,9 @@ interface Props {
}
export function TankModelPart({ url, map }: Props) {
+ const tankQuality = useSetting("tank_quality");
+ const lightingQuality = useSetting("lighting_quality");
+
const gltf = useGLTF(url);
const [root] = gltf.scene.children;
@@ -17,16 +22,32 @@ export function TankModelPart({ url, map }: Props) {
// TODO: remove this hack and fix the gltf
material.vertexColors = false;
material.needsUpdate = true;
+
+ if (tankQuality <= SettingQuality3.Medium) {
+ material.normalMap = null;
+ }
+
+ if (tankQuality <= SettingQuality3.Low) {
+ material.metalness = 0;
+ material.roughness = 1;
+
+ material.metalnessMap = null;
+ material.roughnessMap = null;
+ }
+
+ if (tankQuality <= SettingQuality3.Medium) {
+ material.aoMap = null;
+ }
}
}
for (const node of Object.values(gltf.nodes)) {
if (node instanceof Mesh) {
- node.castShadow = true;
- node.receiveShadow = true;
+ node.castShadow = lightingQuality >= SettingQuality3.Medium;
+ node.receiveShadow = lightingQuality >= SettingQuality3.High;
}
}
- }, [url]);
+ }, [url, tankQuality]);
useEffect(() => {
for (const child of root.children) {
diff --git a/packages/website-ue/src/components/TankopediaSandbox/index.module.css b/packages/website-ue/src/components/TankopediaSandbox/index.module.css
index b4372736a..e545b2a26 100644
--- a/packages/website-ue/src/components/TankopediaSandbox/index.module.css
+++ b/packages/website-ue/src/components/TankopediaSandbox/index.module.css
@@ -10,7 +10,7 @@
height: 100%;
.canvas {
- background-color: black;
+ background-color: black;
}
}
}
diff --git a/packages/website-ue/src/components/TankopediaSandbox/index.tsx b/packages/website-ue/src/components/TankopediaSandbox/index.tsx
index 695793afb..018cfe79f 100644
--- a/packages/website-ue/src/components/TankopediaSandbox/index.tsx
+++ b/packages/website-ue/src/components/TankopediaSandbox/index.tsx
@@ -1,6 +1,7 @@
import { type StageParameters } from "@protos/blitz_static_tank_upgrade_single_stage";
import { Canvas } from "@react-three/fiber";
import { fov } from "../../config/camera";
+import { RendererStats } from "../RendererStats";
import { TankModelChassis } from "../TankModelChassis";
import { TankModelGun } from "../TankModelGun";
import { TankModelHull } from "../TankModelHull";
@@ -17,7 +18,9 @@ interface TankopediaSandboxProps {
export function TankopediaSandbox({ parameters }: TankopediaSandboxProps) {
return (
-
+
+
+