コミットを比較

...

2 コミット

作成者 SHA1 メッセージ 日付
みてるぞ 0d7757b2df #370 2026-06-15 22:09:10 +09:00
みてるぞ ece95838f0 グカネータ公開 / 洗澡鹿のパス変更 (#361) (#369)
Reviewed-on: #369
Co-authored-by: miteruzo <miteruzo@naver.com>
Co-committed-by: miteruzo <miteruzo@naver.com>
2026-06-14 05:40:31 +09:00
9個のファイルの変更101行の追加281行の削除
バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 559 KiB

バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 146 KiB

バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 1.2 MiB

バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 188 KiB

バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 201 KiB

バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 196 KiB

バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 179 KiB

+1 -1
ファイルの表示
@@ -30,7 +30,7 @@ export type GekanatorQuestionSource =
| 'ai_generated' | 'ai_generated'
| 'admin_curated' | 'admin_curated'
export type GekanatorPerformanceMode = 'lite' | 'normal' export type GekanatorPerformanceMode = 'normal'
export type GekanatorQuestionCondition = export type GekanatorQuestionCondition =
| { type: 'tag'; key: string } | { type: 'tag'; key: string }
+34 -214
ファイルの表示
@@ -29,7 +29,6 @@ import type { FC } from 'react'
import type { GekanatorAnswerLog, import type { GekanatorAnswerLog,
GekanatorAnswerValue, GekanatorAnswerValue,
GekanatorExtraQuestion, GekanatorExtraQuestion,
GekanatorPerformanceMode,
GekanatorQuestionCondition, GekanatorQuestionCondition,
GekanatorQuestionKind, GekanatorQuestionKind,
GekanatorQuestion, GekanatorQuestion,
@@ -162,17 +161,16 @@ const confidenceTemperature = 6
const gameStorageKey = 'gekanator:game:v1' const gameStorageKey = 'gekanator:game:v1'
const recentGamesStorageKey = 'gekanator:recent-games:v1' const recentGamesStorageKey = 'gekanator:recent-games:v1'
const backgroundMotionStorageKey = 'gekanator:background-motion:v1' const backgroundMotionStorageKey = 'gekanator:background-motion:v1'
const performanceModeStorageKey = 'gekanator:performance-mode:v1'
const maxQuestionSuggestionsPerGame = 3 const maxQuestionSuggestionsPerGame = 3
const maxStoredRecentGames = 12 const maxStoredRecentGames = 12
const mascotAssetByState: Record<MascotState, string> = { const mascotAssetByState: Record<MascotState, string> = {
idle: '/gekanator/mascot-idle.png', idle: '/assets/gekanator/mascot-idle.png',
thinking_far: '/gekanator/mascot-thinking-far.png', thinking_far: '/assets/gekanator/mascot-thinking-far.png',
thinking_mid: '/gekanator/mascot-thinking-mid.png', thinking_mid: '/assets/gekanator/mascot-thinking-mid.png',
thinking_near: '/gekanator/mascot-thinking-near.png', thinking_near: '/assets/gekanator/mascot-thinking-near.png',
confident: '/gekanator/mascot-confident.png', confident: '/assets/gekanator/mascot-confident.png',
celebrate: '/gekanator/mascot-celebrate.png', celebrate: '/assets/gekanator/mascot-celebrate.png',
failed: '/gekanator/mascot-failed.png' } failed: '/assets/gekanator/mascot-failed.png' }
const mascotAltByState: Record<MascotState, string> = { const mascotAltByState: Record<MascotState, string> = {
idle: '待機する洗澡鹿', idle: '待機する洗澡鹿',
thinking_far: '遠くを見つめる洗澡鹿', thinking_far: '遠くを見つめる洗澡鹿',
@@ -391,14 +389,8 @@ const storeRecentGameSummary = (
} }
const loadBackgroundMotionMode = ( const loadBackgroundMotionMode = (): BackgroundMotionMode => {
performanceMode?: GekanatorPerformanceMode, const fallbackMode = 'on'
): BackgroundMotionMode => {
const fallbackMode =
performanceMode === 'lite' ? 'off'
: performanceMode === 'normal' ? 'on'
: detectDefaultPerformanceMode () === 'lite' ? 'off'
: 'on'
try try
{ {
const raw = localStorage.getItem (backgroundMotionStorageKey) const raw = localStorage.getItem (backgroundMotionStorageKey)
@@ -414,38 +406,6 @@ const loadBackgroundMotionMode = (
} }
const detectDefaultPerformanceMode = (): GekanatorPerformanceMode => {
if (typeof window === 'undefined')
return 'normal'
const isMobileWidth =
typeof window.matchMedia === 'function'
? window.matchMedia ('(max-width: 767px)').matches
: window.innerWidth <= 767
const memory = (navigator as Navigator & { deviceMemory?: number }).deviceMemory
if ((typeof memory === 'number' && memory <= 4) || isMobileWidth)
return 'lite'
return 'normal'
}
const loadPerformanceMode = (): GekanatorPerformanceMode => {
try
{
const raw = localStorage.getItem (performanceModeStorageKey)
if (raw === 'lite' || raw === 'normal')
return raw
}
catch
{
return detectDefaultPerformanceMode ()
}
return detectDefaultPerformanceMode ()
}
const resettableExtraQuestionState = (): { const resettableExtraQuestionState = (): {
extraQuestions: GekanatorExtraQuestion[] extraQuestions: GekanatorExtraQuestion[]
extraQuestionAnswers: Record<string, GekanatorAnswerValue> extraQuestionAnswers: Record<string, GekanatorAnswerValue>
@@ -1055,10 +1015,8 @@ const rankedEntriesForCounts = <T extends string | number> (
const buildQuestionsForCandidateIds = ( const buildQuestionsForCandidateIds = (
{ candidateIds, { candidateIds,
materialIndex, materialIndex,
performanceMode,
acceptedQuestions }: { candidateIds: number[] acceptedQuestions }: { candidateIds: number[]
materialIndex: GekanatorQuestionMaterialIndex materialIndex: GekanatorQuestionMaterialIndex
performanceMode: GekanatorPerformanceMode
acceptedQuestions: GekanatorQuestion[] }, acceptedQuestions: GekanatorQuestion[] },
): GekanatorQuestion[] => { ): GekanatorQuestion[] => {
const total = candidateIds.length const total = candidateIds.length
@@ -1089,7 +1047,6 @@ const buildQuestionsForCandidateIds = (
const monthDay = materialIndex.originalMonthDayByPostId.get (postId) const monthDay = materialIndex.originalMonthDayByPostId.get (postId)
if (monthDay) if (monthDay)
monthDayCounts.set (monthDay, (monthDayCounts.get (monthDay) ?? 0) + 1) monthDayCounts.set (monthDay, (monthDayCounts.get (monthDay) ?? 0) + 1)
if (performanceMode === 'normal')
materialIndex.titleTermsByPostId.get (postId)?.forEach (term => materialIndex.titleTermsByPostId.get (postId)?.forEach (term =>
titleTermCounts.set (term, (titleTermCounts.get (term) ?? 0) + 1)) titleTermCounts.set (term, (titleTermCounts.get (term) ?? 0) + 1))
const titleLength = materialIndex.titleLengthByPostId.get (postId) ?? 0 const titleLength = materialIndex.titleLengthByPostId.get (postId) ?? 0
@@ -1098,14 +1055,8 @@ const buildQuestionsForCandidateIds = (
++asciiCount ++asciiCount
}) })
const tagCap = const tagCap = total >= 120 ? 128 : 96
performanceMode === 'lite' const titleTermCap = total >= 80 ? 10 : total >= 24 ? 14 : 20
? total >= 80 ? 96 : 64
: total >= 120 ? 128 : 96
const titleTermCap =
performanceMode === 'lite'
? 0
: total >= 80 ? 10 : total >= 24 ? 14 : 20
const factCap = total >= 80 ? 8 : 12 const factCap = total >= 80 ? 8 : 12
const sortedLengths = [...titleLengths].sort ((a, b) => a - b) const sortedLengths = [...titleLengths].sort ((a, b) => a - b)
const titleLengthMedian = sortedLengths[Math.floor (sortedLengths.length / 2)] ?? 0 const titleLengthMedian = sortedLengths[Math.floor (sortedLengths.length / 2)] ?? 0
@@ -1181,7 +1132,6 @@ const buildQuestionsForCandidateIds = (
materialIndex })) materialIndex }))
}) })
if (performanceMode === 'normal')
rankedEntriesForCounts ({ counts: titleTermCounts, total, cap: titleTermCap }) rankedEntriesForCounts ({ counts: titleTermCounts, total, cap: titleTermCap })
.filter (([term]) => String (term).length <= 24) .filter (([term]) => String (term).length <= 24)
.forEach (([term]) => { .forEach (([term]) => {
@@ -1615,8 +1565,8 @@ const contradictionPenaltyFor = ({
} }
const chooseQuestion = ({ const chooseQuestion = (
posts, { posts,
questions, questions,
scores, scores,
answers, answers,
@@ -1624,11 +1574,8 @@ const chooseQuestion = ({
gameSeed, gameSeed,
recentFirstQuestionPenaltyById, recentFirstQuestionPenaltyById,
userPriorWeights, userPriorWeights,
performanceMode,
materialIndex, materialIndex,
matchIndex, matchIndex }: { posts: Post[]
}: {
posts: Post[]
questions: GekanatorQuestion[] questions: GekanatorQuestion[]
scores: Map<number, number> scores: Map<number, number>
answers: GekanatorAnswerLog[] answers: GekanatorAnswerLog[]
@@ -1636,20 +1583,15 @@ const chooseQuestion = ({
gameSeed: string gameSeed: string
recentFirstQuestionPenaltyById: Map<string, number> recentFirstQuestionPenaltyById: Map<string, number>
userPriorWeights: Map<number, number> userPriorWeights: Map<number, number>
performanceMode: GekanatorPerformanceMode
materialIndex: GekanatorQuestionMaterialIndex materialIndex: GekanatorQuestionMaterialIndex
matchIndex: GekanatorMatchIndex matchIndex: GekanatorMatchIndex },
}): GekanatorQuestion | null => { ): GekanatorQuestion | null => {
const candidateIds = posts.map (post => post.id)
const candidateIdSet = new Set (candidateIds)
const dynamicMatchIndex = new Map<string, Set<number>> () const dynamicMatchIndex = new Map<string, Set<number>> ()
const invertedSignature = (signature: string): string => const invertedSignature = (signature: string): string =>
signature.replace (/[01]/g, value => value === '1' ? '0' : '1') signature.replace (/[01]/g, value => value === '1' ? '0' : '1')
const redundantSignatures = ( const redundantSignatures = (candidates: Post[]): Set<string> => {
candidates: Post[],
): Set<string> => {
const signatures = new Set<string> () const signatures = new Set<string> ()
questions questions
.filter (question => askedIds.has (question.id)) .filter (question => askedIds.has (question.id))
@@ -1668,89 +1610,6 @@ const chooseQuestion = ({
return signatures return signatures
} }
if (performanceMode === 'lite')
{
const nonTagCount =
questions.filter (question => askedIds.has (question.id) && question.kind !== 'tag').length
const ranked = questions
.filter (question => !(askedIds.has (question.id)))
.map (question => {
if (isQuestionHardFilteredAfterAnswers (question, answers))
return null
const yes = matchingPostCountInIds ({
candidateIds,
candidateIdSet,
posts,
materialIndex,
matchIndex,
question,
dynamicMatchIndex })
const no = posts.length - yes
if (yes === 0 || no === 0)
return null
const splitScore = Math.abs (posts.length / 2 - yes) / posts.length
const minSide = posts.length < 10 ? 1 : Math.max (2, Math.floor (posts.length * .08))
const narrowPenalty = yes < minSide || no < minSide ? .18 : 0
const tagPenalty = question.kind === 'tag' && nonTagCount < 3 ? .1 : 0
const contradictionPenalty = contradictionPenaltyFor ({ question, answers })
const sourceBonus = sourcePriorityOffset (question)
const priorityBonus = priorityWeightOffset (question)
const categoryPenalty = questionCategoryPenalty (question, answers.length, 0)
return {
question,
score: splitScore * 100
+ narrowPenalty
+ tagPenalty
+ contradictionPenalty
+ sourceBonus
+ priorityBonus
+ categoryPenalty,
narrow: narrowPenalty > 0 }
})
.filter ((item): item is {
question: GekanatorQuestion
score: number
narrow: boolean } => item !== null && Number.isFinite (item.score))
.sort ((a, b) => {
if (a.score !== b.score)
return a.score - b.score
return a.question.id.localeCompare (b.question.id)
})
const pool = (
ranked.some (item => !(item.narrow))
? ranked.filter (item => !(item.narrow))
: ranked)
.slice (0, 8)
if (pool.length === 0)
return null
const bestScore = pool[0]?.score ?? 0
const weightedPool = pool.map (item => ({
...item,
weight: Math.exp ((bestScore - item.score) / 1.6) }))
const totalPoolWeight =
weightedPool.reduce ((sum, item) => sum + item.weight, 0) || 1
const seed = `${ gameSeed }:lite:${ [...askedIds].sort ().join ('|') }:${
weightedPool.map (item => `${ item.question.id }:${ item.score.toFixed (4) }`).join ('|')
}`
const target = deterministicUnitFloat (seed) * totalPoolWeight
let cumulative = 0
for (const item of weightedPool)
{
cumulative += item.weight
if (target <= cumulative)
return item.question
}
return weightedPool[weightedPool.length - 1]?.question ?? null
}
const scoredPosts = posts const scoredPosts = posts
.map (post => ({ post, score: scores.get (post.id) ?? 0 })) .map (post => ({ post, score: scores.get (post.id) ?? 0 }))
.sort ((a, b) => b.score - a.score) .sort ((a, b) => b.score - a.score)
@@ -2361,7 +2220,6 @@ const nextQuestionPlanFor = (
gameSeed, gameSeed,
recentFirstQuestionPenaltyById, recentFirstQuestionPenaltyById,
userPriorWeights, userPriorWeights,
performanceMode,
materialIndex, materialIndex,
matchIndex, matchIndex,
lastGuessQuestionCount, lastGuessQuestionCount,
@@ -2376,7 +2234,6 @@ const nextQuestionPlanFor = (
gameSeed: string gameSeed: string
recentFirstQuestionPenaltyById: Map<string, number> recentFirstQuestionPenaltyById: Map<string, number>
userPriorWeights: Map<number, number> userPriorWeights: Map<number, number>
performanceMode: GekanatorPerformanceMode
materialIndex: GekanatorQuestionMaterialIndex materialIndex: GekanatorQuestionMaterialIndex
matchIndex: GekanatorMatchIndex matchIndex: GekanatorMatchIndex
lastGuessQuestionCount: number lastGuessQuestionCount: number
@@ -2439,7 +2296,6 @@ const nextQuestionPlanFor = (
buildQuestionsForCandidateIds ({ buildQuestionsForCandidateIds ({
candidateIds: scopePosts.map (post => post.id), candidateIds: scopePosts.map (post => post.id),
materialIndex, materialIndex,
performanceMode,
acceptedQuestions }) acceptedQuestions })
if (eligiblePosts.length === 1) if (eligiblePosts.length === 1)
@@ -2505,7 +2361,6 @@ const nextQuestionPlanFor = (
gameSeed, gameSeed,
recentFirstQuestionPenaltyById, recentFirstQuestionPenaltyById,
userPriorWeights, userPriorWeights,
performanceMode,
materialIndex, materialIndex,
matchIndex }) matchIndex })
@@ -3108,10 +2963,8 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
const canPersistGame = user !== null const canPersistGame = user !== null
const [recentGames, setRecentGames] = useState<RecentGameSummary[]> ( const [recentGames, setRecentGames] = useState<RecentGameSummary[]> (
() => loadRecentGames ()) () => loadRecentGames ())
const [performanceMode] =
useState<GekanatorPerformanceMode> (() => loadPerformanceMode ())
const [backgroundMotionMode, setBackgroundMotionMode] = useState<BackgroundMotionMode> ( const [backgroundMotionMode, setBackgroundMotionMode] = useState<BackgroundMotionMode> (
() => loadBackgroundMotionMode (loadPerformanceMode ())) () => loadBackgroundMotionMode ())
const [prefersReducedMotion, setPrefersReducedMotion] = useState (false) const [prefersReducedMotion, setPrefersReducedMotion] = useState (false)
const [gameSeed, setGameSeed] = useState ( const [gameSeed, setGameSeed] = useState (
storedGame?.gameSeed ?? createGameSeed ()) storedGame?.gameSeed ?? createGameSeed ())
@@ -3328,17 +3181,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
} }
}, [backgroundMotionMode]) }, [backgroundMotionMode])
useEffect (() => {
try
{
localStorage.setItem (performanceModeStorageKey, performanceMode)
}
catch
{
return
}
}, [performanceMode])
const askedQuestionById = useMemo ( const askedQuestionById = useMemo (
() => new Map (askedQuestionBank.map (question => [question.id, question])), () => new Map (askedQuestionBank.map (question => [question.id, question])),
[askedQuestionBank]) [askedQuestionBank])
@@ -3361,9 +3203,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
() => new Map (scoringQuestions.map (question => [question.id, question])), () => new Map (scoringQuestions.map (question => [question.id, question])),
[scoringQuestions]) [scoringQuestions])
const recentFirstQuestionPenaltyById = useMemo (() => { const recentFirstQuestionPenaltyById = useMemo (() => {
if (performanceMode === 'lite')
return new Map<string, number> ()
const penalties = new Map<string, number> () const penalties = new Map<string, number> ()
recentGames.forEach ((game, index) => { recentGames.forEach ((game, index) => {
@@ -3376,12 +3215,10 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
}) })
return penalties return penalties
}, [performanceMode, recentGames]) }, [recentGames])
const userPriorWeights = useMemo ( const userPriorWeights = useMemo (
() => performanceMode === 'lite' () => userPriorWeightsFor (posts, recentGames),
? new Map<number, number> () [posts, recentGames])
: userPriorWeightsFor (posts, recentGames),
[performanceMode, posts, recentGames])
const availablePosts = useMemo ( const availablePosts = useMemo (
() => posts.filter (post => !(rejectedPostIds.has (post.id))), () => posts.filter (post => !(rejectedPostIds.has (post.id))),
[posts, rejectedPostIds]) [posts, rejectedPostIds])
@@ -3397,7 +3234,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
gameSeed, gameSeed,
recentFirstQuestionPenaltyById, recentFirstQuestionPenaltyById,
userPriorWeights, userPriorWeights,
performanceMode,
materialIndex, materialIndex,
matchIndex: acceptedQuestionMatchIndex, matchIndex: acceptedQuestionMatchIndex,
lastGuessQuestionCount, lastGuessQuestionCount,
@@ -3405,7 +3241,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
winningRunStartAnswerCount }), winningRunStartAnswerCount }),
[posts, eligiblePosts, availablePosts, acceptedQuestions, scores, [posts, eligiblePosts, availablePosts, acceptedQuestions, scores,
answers, askedIds, gameSeed, recentFirstQuestionPenaltyById, answers, askedIds, gameSeed, recentFirstQuestionPenaltyById,
userPriorWeights, performanceMode, materialIndex, acceptedQuestionMatchIndex, userPriorWeights, materialIndex, acceptedQuestionMatchIndex,
lastGuessQuestionCount, winningRunTargetId, winningRunStartAnswerCount]) lastGuessQuestionCount, winningRunTargetId, winningRunStartAnswerCount])
const winningRunTargetPost = useMemo ( const winningRunTargetPost = useMemo (
() => questionPlan.winningRunTargetId === null () => questionPlan.winningRunTargetId === null
@@ -3458,35 +3294,28 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
const reviewCorrectPost = const reviewCorrectPost =
posts.find (post => post.id === reviewCorrectPostId) ?? null posts.find (post => post.id === reviewCorrectPostId) ?? null
const effectiveResultWon = const effectiveResultWon =
resultWon ?? ( resultWon
reviewGuessedPostId !== null ?? ((reviewGuessedPostId !== null && reviewCorrectPostId !== null)
&& reviewCorrectPostId !== null
? reviewGuessedPostId === reviewCorrectPostId ? reviewGuessedPostId === reviewCorrectPostId
: null) : null)
const effectiveBackgroundMotionMode = const effectiveBackgroundMotionMode =
performanceMode === 'lite' backgroundMotionMode === 'off'
? 'off' ? 'off'
: backgroundMotionMode === 'off' : (prefersReducedMotion
? 'off'
: prefersReducedMotion
? 'calm' ? 'calm'
: backgroundMotionMode : backgroundMotionMode)
const backgroundPosts = useMemo ( const backgroundPosts = useMemo (
() => performanceMode === 'lite' () => backgroundPostsFor ({
? []
: backgroundPostsFor ({
phase, phase,
eligiblePosts, eligiblePosts,
availablePosts, availablePosts,
displayedGuess, displayedGuess,
reviewCorrectPost, reviewCorrectPost,
reviewGuessedPost }), reviewGuessedPost }),
[performanceMode, phase, eligiblePosts, availablePosts, displayedGuess, [phase, eligiblePosts, availablePosts, displayedGuess, reviewCorrectPost,
reviewCorrectPost, reviewGuessedPost]) reviewGuessedPost])
const backgroundVisualSeed = const backgroundVisualSeed =
performanceMode === 'lite' `${ gameSeed }:${ phase }:${ answers.length }:${ activeGuessId ?? '' }:${
? ''
: `${ gameSeed }:${ phase }:${ answers.length }:${ activeGuessId ?? '' }:${
questionPlan.question?.id ?? '' questionPlan.question?.id ?? ''
}:${ questionPlan.questionMode ?? '' }:${ winningRunQuestionsAsked }:${ }:${ questionPlan.questionMode ?? '' }:${ winningRunQuestionsAsked }:${
rejectedPostIds.size rejectedPostIds.size
@@ -3617,7 +3446,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
let recoveredQuestions = buildQuestionsForCandidateIds ({ let recoveredQuestions = buildQuestionsForCandidateIds ({
candidateIds: recoveredEligiblePosts.map (post => post.id), candidateIds: recoveredEligiblePosts.map (post => post.id),
materialIndex, materialIndex,
performanceMode,
acceptedQuestions }) acceptedQuestions })
let recoveredScoringQuestions = mergeQuestions ([ let recoveredScoringQuestions = mergeQuestions ([
...recoveredQuestions, ...recoveredQuestions,
@@ -3643,7 +3471,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
recoveredQuestions = buildQuestionsForCandidateIds ({ recoveredQuestions = buildQuestionsForCandidateIds ({
candidateIds: recoveredEligiblePosts.map (post => post.id), candidateIds: recoveredEligiblePosts.map (post => post.id),
materialIndex, materialIndex,
performanceMode,
acceptedQuestions }) acceptedQuestions })
recoveredScoringQuestions = mergeQuestions ([ recoveredScoringQuestions = mergeQuestions ([
...recoveredQuestions, ...recoveredQuestions,
@@ -3667,7 +3494,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
gameSeed, gameSeed,
recentFirstQuestionPenaltyById, recentFirstQuestionPenaltyById,
userPriorWeights, userPriorWeights,
performanceMode,
materialIndex, materialIndex,
matchIndex: acceptedQuestionMatchIndex }) matchIndex: acceptedQuestionMatchIndex })
const fallbackQuestion = nextQuestion ?? chooseFallbackQuestion ({ const fallbackQuestion = nextQuestion ?? chooseFallbackQuestion ({
@@ -3735,7 +3561,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
}, [ }, [
posts, posts,
gameSeed, gameSeed,
performanceMode,
materialIndex, materialIndex,
acceptedQuestions, acceptedQuestions,
acceptedQuestionMatchIndex, acceptedQuestionMatchIndex,
@@ -3806,7 +3631,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
gameSeed, gameSeed,
recentFirstQuestionPenaltyById, recentFirstQuestionPenaltyById,
userPriorWeights, userPriorWeights,
performanceMode,
materialIndex, materialIndex,
matchIndex: acceptedQuestionMatchIndex, matchIndex: acceptedQuestionMatchIndex,
lastGuessQuestionCount, lastGuessQuestionCount,
@@ -3840,7 +3664,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
gameSeed, gameSeed,
recentFirstQuestionPenaltyById, recentFirstQuestionPenaltyById,
userPriorWeights, userPriorWeights,
performanceMode,
materialIndex, materialIndex,
matchIndex: acceptedQuestionMatchIndex, matchIndex: acceptedQuestionMatchIndex,
lastGuessQuestionCount, lastGuessQuestionCount,
@@ -4071,7 +3894,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
gameSeed, gameSeed,
recentFirstQuestionPenaltyById, recentFirstQuestionPenaltyById,
userPriorWeights, userPriorWeights,
performanceMode,
materialIndex, materialIndex,
matchIndex: acceptedQuestionMatchIndex, matchIndex: acceptedQuestionMatchIndex,
lastGuessQuestionCount, lastGuessQuestionCount,
@@ -4286,7 +4108,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
<title>{`グカネータ | ${ SITE_TITLE }`}</title> <title>{`グカネータ | ${ SITE_TITLE }`}</title>
</Helmet> </Helmet>
{performanceMode !== 'lite' && (
<GekanatorBackdrop <GekanatorBackdrop
posts={backgroundPosts} posts={backgroundPosts}
mascotAsset={mascotAsset} mascotAsset={mascotAsset}
@@ -4295,7 +4116,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
visualSeed={backgroundVisualSeed} visualSeed={backgroundVisualSeed}
motionMode={effectiveBackgroundMotionMode} motionMode={effectiveBackgroundMotionMode}
winningRunTargetPost={winningRunActive ? winningRunTargetPost : null} winningRunTargetPost={winningRunActive ? winningRunTargetPost : null}
winningRunQuestionCount={winningRunQuestionsAsked}/>)} winningRunQuestionCount={winningRunQuestionsAsked}/>
<div className="relative z-10 mx-auto max-w-4xl space-y-6"> <div className="relative z-10 mx-auto max-w-4xl space-y-6">
<header className="flex flex-wrap items-end justify-between gap-3"> <header className="flex flex-wrap items-end justify-between gap-3">
@@ -4305,7 +4126,6 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
</h1> </h1>
</div> </div>
<div className="flex flex-wrap justify-end gap-2"> <div className="flex flex-wrap justify-end gap-2">
{performanceMode === 'normal' && (
<div className="rounded-full border border-yellow-300 bg-white/80 px-2 py-1 <div className="rounded-full border border-yellow-300 bg-white/80 px-2 py-1
text-xs shadow-sm backdrop-blur dark:border-red-800 text-xs shadow-sm backdrop-blur dark:border-red-800
dark:bg-red-950/75"> dark:bg-red-950/75">
@@ -4330,7 +4150,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
<span className="ml-2 text-[11px] text-neutral-500 dark:text-neutral-400"> <span className="ml-2 text-[11px] text-neutral-500 dark:text-neutral-400">
</span>)} </span>)}
</div>)} </div>
</div> </div>
</header> </header>
@@ -4608,7 +4428,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
{reviewGuessedPostId !== null && reviewCorrectPostId !== null && ( {reviewGuessedPostId !== null && reviewCorrectPostId !== null && (
<p className="text-sm text-neutral-600 dark:text-neutral-300"> <p className="text-sm text-neutral-600 dark:text-neutral-300">
: {reviewGuessedPostId === reviewCorrectPostId ? '当たり' : '違ひ'} : {reviewGuessedPostId === reviewCorrectPostId ? '当たり' : 'はずれ'}
</p>)} </p>)}
{saveMutation.isError && ( {saveMutation.isError && (