GameTrophy
Methods
- .effectCallback({ scene })
- .unlock()
- .define(tag, registry)
- .subscribe(context, callback)
Custom States
| State | Description |
|---|---|
:state(unlocked) | The trophy has been unlocked |
Shadow DOM Parts
| Part | Description |
|---|---|
icon | The icon container |
name | The trophy name label |
tooltip | The description tooltip |
A declarative achievement tile. Place <game-trophy> elements anywhere in the game layout — typically grouped together on the result screen or in a persistent HUD area. Each trophy manages its own locked/unlocked visual state and integrates with the shell's trophy tracking.
Icons are rendered using <game-icon>, which reads the sprite sheet URL from the shell's spriteSheet signal (set via the sprite-sheet attribute).
Attributes
- id
-
string-- Unique trophy identifier. Used for persistence and for condition lookups viawhen-some-trophy="id". - name
-
string-- Display name shown below the icon. - icon
-
string-- Icon name. Renders a<game-icon name="...">element, which reads the sprite sheet URL fromshell.spriteSheet. - description
-
string-- Tooltip text shown when the trophy is tapped. - when-*
-
Any condition attribute for auto-unlock. The trophy is automatically unlocked when all conditions pass on entering the
resultstate.<game-trophy id="scorer" name="Scorer" icon="star" when-min-score="10" description="Score 10 or more" > </game-trophy> <game-trophy id="hat-trick" name="Hat Trick" icon="fire" when-min-streak="3" description="Get 3 correct in a row" > </game-trophy> <!-- Note: "streak" resolves via the stats map. It must be kept up to date via GameStatUpdateEvent("streak", n). <game-quiz> does this automatically. For custom games, dispatch the event yourself. --> <game-trophy id="collector" name="Collector" icon="chest" when-min-trophy-count="5" description="Unlock 5 other trophies" > </game-trophy>
Properties
- .unlocked
-
boolean--trueif the trophy has been unlocked. - .trophyId
-
string-- The element'sidattribute.
Methods
- .unlock()
-
Unlock this trophy. Idempotent — calling it on an already-unlocked trophy is a no-op. Registers the unlock with the shell (updating
shell.trophyCountandshell.isTrophyUnlocked()), persists to localStorage, and dispatches agame-trophy-unlockevent.
Events Dispatched
- game-trophy-unlock
-
Dispatched when the trophy is unlocked. Bubbles to the shell. Carries
.trophyIdand.trophyName.shell.addEventListener("game-trophy-unlock", (e) => { console.log(`Unlocked: ${e.trophyName} (${e.trophyId})`); });
Auto-Unlock
Trophies with condition attributes are checked automatically when the game enters the result state. Any trophy whose conditions all pass is unlocked via .unlock().
Tooltip
Clicking or tapping a trophy shows its description in a tooltip for 1.8 seconds.
Persistence
Unlocked trophy IDs are stored as a JSON array in localStorage under the key {storage-key}-trophies. On connect, if the shell has the trophy registered as already unlocked, the visual state is restored immediately.
Signal Access
| Signal | Usage |
|---|---|
shell.scene |
Watches for "result" to trigger auto-unlock checks |
shell.score, shell.round, shell.stats, shell.difficulty, etc. |
Read by matchesConditions() for when-* auto-unlock conditions |
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--game-trophy-color |
#fbbf24 |
Icon color for unlocked trophies |
Usage
<div when-some-scene="result" data-overlay>
<game-result-stat label="Score"></game-result-stat>
<div style="display: flex; gap: 8px; justify-content: center;">
<game-trophy
id="scorer"
name="Scorer"
icon="star"
when-min-score="10"
description="Score 10 or more"
>
</game-trophy>
<game-trophy
id="hat-trick"
name="Hat Trick"
icon="fire"
when-min-streak="3"
description="Get 3 correct in a row"
>
</game-trophy>
<game-trophy
id="speed-demon"
name="Speed Demon"
icon="bolt"
description="Complete the game in under 10 seconds"
>
</game-trophy>
</div>
<button commandfor="game" command="--restart">Play Again</button>
</div>
The speed-demon trophy has no auto-unlock condition, so it must be unlocked programmatically:
shell.addEventListener("game-lifecycle", (e) => {
if (e.action === "result") {
const totalTime = e.state.roundScores.reduce((a, b) => a + b, 0);
if (totalTime < 10000) {
document.querySelector("game-trophy#speed-demon").unlock();
}
}
});