feat: upgrade Guess

This commit is contained in:
TrèsAbhi committed 2025-09-01 19:22:38 -05:00
1 parent 7d164e415a
commit f56c31fb48
5 files changed
+80 -82

No files matched your search

@@ -1,13 +1,13 @@
import { Box } from '@radix-ui/themes';
import { useEffect } from 'react';
import { awaitableModelDefinitions } from '../../core/awaitables/modelDefinitions';
import { awaitableProvisionDefinitions } from '../../core/awaitables/provisionDefinitions';
import { tankToDuelMember } from '../../core/blitzkit/tankToDuelMember';
import { Var } from '../../core/radix/var';
import { Duel } from '../../stores/duel';
import { GuessEphemeral } from '../../stores/guessEphemeral';
import { TankopediaEphemeral } from '../../stores/tankopediaEphemeral';
import './index.css';
import { Box } from "@radix-ui/themes";
import { useEffect } from "react";
import { awaitableModelDefinitions } from "../../core/awaitables/modelDefinitions";
import { awaitableProvisionDefinitions } from "../../core/awaitables/provisionDefinitions";
import { tankToDuelMember } from "../../core/blitzkit/tankToDuelMember";
import { Var } from "../../core/radix/var";
import { Duel } from "../../stores/duel";
import { Guess } from "../../stores/guessEphemeral";
import { TankopediaEphemeral } from "../../stores/tankopediaEphemeral";
import "./index.css";
const [modelDefinitions, provisionDefinitions] = await Promise.all([
awaitableModelDefinitions,
@@ -15,8 +15,8 @@ const [modelDefinitions, provisionDefinitions] = await Promise.all([
]);
export function GuessBackground() {
const guessState = GuessEphemeral.use((state) => state.guessState);
const tank = GuessEphemeral.use((state) => state.tank);
const guessState = Guess.use((state) => state.guessState);
const tank = Guess.use((state) => state.tank);
const mutateDuel = Duel.useMutation();
useEffect(() => {
@@ -37,13 +37,13 @@ export function GuessBackground() {
top="0"
left="0"
style={{
transitionDuration: '2s',
transitionDuration: "2s",
backgroundColor: Var(
guessState === null
? 'accent-2'
? "accent-2"
: guessState
? 'jade-3'
: 'tomato-3',
? "jade-3"
: "tomato-3"
),
}}
>
@@ -51,7 +51,7 @@ export function GuessBackground() {
width="100%"
height="100%"
style={{
background: `radial-gradient(circle, ${Var('color-panel-translucent')}, ${Var('color-panel-solid')})`,
background: `radial-gradient(circle, ${Var("color-panel-translucent")}, ${Var("color-panel-solid")})`,
}}
/>
</Box>
@@ -65,13 +65,13 @@ export function GuessBackground() {
left="0"
style={{
backgroundImage: `
radial-gradient(circle, ${Var('white-a1')} 20%, transparent 20%),
radial-gradient(circle at 0 0, ${Var('white-a1')} 10%, transparent 10%),
radial-gradient(circle at 100% 0, ${Var('white-a1')} 10%, transparent 10%),
radial-gradient(circle at 0 100%, ${Var('white-a1')} 10%, transparent 10%),
radial-gradient(circle at 100% 100%, ${Var('white-a1')} 10%, transparent 10%)
radial-gradient(circle, ${Var("white-a1")} 20%, transparent 20%),
radial-gradient(circle at 0 0, ${Var("white-a1")} 10%, transparent 10%),
radial-gradient(circle at 100% 0, ${Var("white-a1")} 10%, transparent 10%),
radial-gradient(circle at 0 100%, ${Var("white-a1")} 10%, transparent 10%),
radial-gradient(circle at 100% 100%, ${Var("white-a1")} 10%, transparent 10%)
`,
backgroundSize: '4rem 4rem',
backgroundSize: "4rem 4rem",
}}
/>
</>
@@ -1,22 +1,22 @@
import { GuessEphemeral } from '../stores/guessEphemeral';
import { SmartCanvas } from './SmartCanvas';
import { Controls } from './Tankopedia/HeroSection/components/TankSandbox/components/Control';
import { Lighting } from './Tankopedia/HeroSection/components/TankSandbox/components/Lighting';
import { TankModel } from './Tankopedia/HeroSection/components/TankSandbox/components/TankModel';
import { Guess } from "../stores/guessEphemeral";
import { SmartCanvas } from "./SmartCanvas";
import { Controls } from "./Tankopedia/HeroSection/components/TankSandbox/components/Control";
import { Lighting } from "./Tankopedia/HeroSection/components/TankSandbox/components/Lighting";
import { TankModel } from "./Tankopedia/HeroSection/components/TankSandbox/components/TankModel";
const BRIGHTNESS = 2 ** -5.5;
const CONTRAST = 2 ** 2;
export function GuessRenderer() {
const guessState = GuessEphemeral.use((state) => state.guessState);
const guessState = Guess.use((state) => state.guessState);
const isRevealed = guessState !== null;
return (
<SmartCanvas
style={{
filter: `grayscale(${isRevealed ? 0 : 1}) contrast(${isRevealed ? 1 : CONTRAST}) brightness(${isRevealed ? 1 : BRIGHTNESS})`,
transitionDuration: isRevealed ? '2s' : undefined,
transitionProperty: 'filter',
transitionDuration: isRevealed ? "2s" : undefined,
transitionProperty: "filter",
}}
camera={{ position: [-5, 5, -5] }}
>
+26 -27
View File
@@ -2,13 +2,13 @@ import {
SEARCH_KEYS,
TankDefinition,
TIER_ROMAN_NUMERALS,
} from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
} from "@blitzkit/core";
import { literals } from "@blitzkit/i18n";
import {
ArrowRightIcon,
MagnifyingGlassIcon,
PaperPlaneIcon,
} from '@radix-ui/react-icons';
} from "@radix-ui/react-icons";
import {
Box,
Button,
@@ -17,16 +17,16 @@ import {
Spinner,
Text,
TextField,
} from '@radix-ui/themes';
import fuzzysort from 'fuzzysort';
import { debounce } from 'lodash-es';
import { useCallback, useEffect, useRef, useState } from 'react';
import { awaitableTankDefinitions } from '../core/awaitables/tankDefinitions';
import { awaitableTankNames } from '../core/awaitables/tankNames';
import { useLocale } from '../hooks/useLocale';
import { GuessEphemeral } from '../stores/guessEphemeral';
import { classIcons } from './ClassIcon';
import { SearchResults } from './SearchResults';
} from "@radix-ui/themes";
import fuzzysort from "fuzzysort";
import { debounce } from "lodash-es";
import { useCallback, useEffect, useRef, useState } from "react";
import { awaitableTankDefinitions } from "../core/awaitables/tankDefinitions";
import { awaitableTankNames } from "../core/awaitables/tankNames";
import { useLocale } from "../hooks/useLocale";
import { Guess } from "../stores/guessEphemeral";
import { classIcons } from "./ClassIcon";
import { SearchResults } from "./SearchResults";
const { go } = fuzzysort;
@@ -38,16 +38,15 @@ const [tankNames, tankDefinitions] = await Promise.all([
const ids = Object.keys(tankDefinitions.tanks);
export function Guesser() {
const tank = GuessEphemeral.use((state) => state.tank);
const guessState = GuessEphemeral.use((state) => state.guessState);
const correctGuesses = GuessEphemeral.use((state) => state.correctGuesses);
const totalGuesses = GuessEphemeral.use((state) => state.totalGuesses);
const tank = Guess.use((state) => state.tank);
const guessState = Guess.use((state) => state.guessState);
const correctGuesses = Guess.use((state) => state.correctGuesses);
const totalGuesses = Guess.use((state) => state.totalGuesses);
const { strings, unwrap } = useLocale();
const input = useRef<HTMLInputElement>(null);
const [searching, setSearching] = useState(false);
const [results, setResults] = useState<TankDefinition[] | null>(null);
const [selected, setSelected] = useState<TankDefinition | null>(null);
const mutateGuessEphemeral = GuessEphemeral.useMutation();
const requestSearch = useCallback(() => {
setSelected(null);
@@ -72,10 +71,10 @@ export function Guesser() {
});
setResults(
searchResults.map((result) => tankDefinitions.tanks[result.obj.id]),
searchResults.map((result) => tankDefinitions.tanks[result.obj.id])
);
}, 500),
[],
[]
);
useEffect(() => {
@@ -88,7 +87,7 @@ export function Guesser() {
position="absolute"
bottom="0"
left="50%"
style={{ transform: 'translateX(-50%)' }}
style={{ transform: "translateX(-50%)" }}
width="100%"
p="4"
maxWidth="25rem"
@@ -138,7 +137,7 @@ export function Guesser() {
</Card>
)}
<Flex justify="center" style={{ userSelect: 'none' }}>
<Flex justify="center" style={{ userSelect: "none" }}>
<Text>
{literals(strings.website.tools.guess.stats, [
`${correctGuesses}`,
@@ -164,12 +163,12 @@ export function Guesser() {
<Button
size="3"
color={guessState === null && selected === null ? 'red' : undefined}
color={guessState === null && selected === null ? "red" : undefined}
onClick={() => {
if (guessState === null) {
const correct = selected !== null && selected.id === tank.id;
mutateGuessEphemeral((draft) => {
Guess.mutate((draft) => {
draft.guessState = correct;
draft.totalGuesses++;
draft.correctGuesses += correct ? 1 : 0;
@@ -178,12 +177,12 @@ export function Guesser() {
const id = Number(ids[Math.floor(Math.random() * ids.length)]);
const tank = tankDefinitions.tanks[id];
mutateGuessEphemeral((draft) => {
Guess.mutate((draft) => {
if (!input.current) return;
draft.tank = tank;
draft.guessState = null;
input.current.value = '';
input.current.value = "";
});
}
}}
@@ -192,7 +191,7 @@ export function Guesser() {
<>
{
strings.website.tools.guess.search[
selected === null ? 'skip' : 'guess'
selected === null ? "skip" : "guess"
]
}
{selected === null ? <ArrowRightIcon /> : <PaperPlaneIcon />}
@@ -13,7 +13,7 @@ import {
useLocale,
} from "../../../hooks/useLocale";
import { Duel } from "../../../stores/duel";
import { GuessEphemeral } from "../../../stores/guessEphemeral";
import { Guess } from "../../../stores/guessEphemeral";
import { TankopediaEphemeral } from "../../../stores/tankopediaEphemeral";
const [tankDefinitions, modelDefinitions, provisionDefinitions] =
@@ -26,20 +26,20 @@ const [tankDefinitions, modelDefinitions, provisionDefinitions] =
const ids = Object.keys(tankDefinitions.tanks);
export function Page({ locale }: LocaleAcceptorProps) {
const initialId = Number(ids[Math.floor(Math.random() * ids.length)]);
const initialTank = tankDefinitions.tanks[initialId];
const id = Number(ids[Math.floor(Math.random() * ids.length)]);
const tank = tankDefinitions.tanks[id];
Guess.useInitialization(tank);
return (
<GuessEphemeral.Provider data={initialTank}>
<LocaleProvider locale={locale}>
<Container />
</LocaleProvider>
</GuessEphemeral.Provider>
<LocaleProvider locale={locale}>
<Container />
</LocaleProvider>
);
}
function Container() {
const tank = GuessEphemeral.use((state) => state.tank);
const tank = Guess.use((state) => state.tank);
const model = modelDefinitions.models[tank.id];
TankopediaEphemeral.useInitialization(model);
@@ -53,8 +53,8 @@ function Container() {
function Content() {
const { unwrap } = useLocale();
const tank = GuessEphemeral.use((state) => state.tank);
const guessState = GuessEphemeral.use((state) => state.guessState);
const tank = Guess.use((state) => state.tank);
const guessState = Guess.use((state) => state.guessState);
const isRevealed = guessState !== null;
const name = unwrap(tank.name);
const fontSize = `min(48vh, ${55 / name.length}vw)`;
+12 -13
View File
@@ -1,20 +1,19 @@
import type { TankDefinition } from '@blitzkit/core';
import { create } from 'zustand';
import { createContextualStore } from '../core/zustand/createContextualStore';
import type { TankDefinition } from "@blitzkit/core";
import { Varuna } from "varuna";
export interface GuessEphemeral {
export interface Guess {
tank: TankDefinition;
// true = correct, false = incorrect, null = not guessed
/**
* true = correct, false = incorrect, null = not guessed
*/
guessState: boolean | null;
totalGuesses: number;
correctGuesses: number;
}
export const GuessEphemeral = createContextualStore((tank: TankDefinition) =>
create<GuessEphemeral>()(() => ({
tank,
guessState: null,
totalGuesses: 0,
correctGuesses: 0,
})),
);
export const Guess = new Varuna<Guess, TankDefinition>((tank) => ({
tank,
guessState: null,
totalGuesses: 0,
correctGuesses: 0,
}));