Guess The Number
A number guessing game where players narrow down a target between 1 and 100 using a slider. Demonstrates reactive state with wcp-ui-state, derived values, and persistent storage for tracking a best score across sessions.
This example is a stress test. The binding expressions here are intentionally complex to push the limits of the expression parser — this is not representative of recommended usage. In practice, keep logic inside bind-event, bind-show, derive, and similar attributes simple. Move anything non-trivial (conditionals, multi-step mutations, derived calculations) into a <script> or a component method instead.
Guess My Number 1 to 100
Set the slider, then press Guess Higher — you guessed Lower — you guessed
tries
remaining
best
Code
The following example assumes that you have imported the component and set up the theme.
<div class="guess-number-game"> <wcp-ui-state id="guess-number-game-state"> <wcp-store type="number" name="$gameSeed" value="0"></wcp-store> <wcp-store type="number" name="$currentGuessInput" value="50"></wcp-store> <wcp-store type="number" name="$lastGuess" value="0"></wcp-store> <wcp-store type="number" name="$attemptCount" value="0"></wcp-store> <wcp-store type="number" name="$minimumPossibleValue" value="1"></wcp-store> <wcp-store type="number" name="$maximumPossibleValue" value="100"></wcp-store> <wcp-store type="number" name="$bestScore" persistent value="0"></wcp-store>
<wcp-store derive="(Date.now() % 100000 + $gameSeed * 37) % 100 + 1" name="$targetNumber"></wcp-store> <wcp-store derive="$lastGuess > 0 && $lastGuess === $targetNumber" name="$hasWon"></wcp-store>
<div class="guess-number-game-header"> <span class="guess-number-game-title">Guess My Number</span> <span class="guess-number-game-subtitle">1 to 100</span> </div>
<div class="guess-number-game-feedback" bind-class="'guess-number-game-feedback-' + ($attemptCount === 0 ? 'idle' : ($hasWon ? 'success' : ($lastGuess < $targetNumber ? 'higher' : 'lower')))" >13 collapsed lines
<span bind-show="$attemptCount === 0">Set the slider, then press Guess</span>
<span bind-show="$attemptCount > 0 && !$hasWon && $lastGuess < $targetNumber"> Higher — you guessed <b bind-text="$lastGuess"></b> </span>
<span bind-show="$attemptCount > 0 && !$hasWon && $lastGuess > $targetNumber"> Lower — you guessed <b bind-text="$lastGuess"></b> </span>
<span bind-show="$hasWon" bind-text="'Got it in ' + $attemptCount + ($attemptCount === 1 ? ' try' : ' tries') + '!'"></span> </div>
<div class="guess-number-game-picker">26 collapsed lines
<span class="guess-number-game-current-value" bind-text="$currentGuessInput"></span>
<input type="range" class="guess-number-game-slider" aria-label="Pick a number" bind-attr="min:$minimumPossibleValue; max:$maximumPossibleValue" bind-attr-toggle="disabled:$hasWon" bind-event="input:$currentGuessInput(Number(EVENT.target.value))" bind-prop="value:$currentGuessInput" />
<div class="guess-number-game-range-bar" bind-style=" --range-start:($minimumPossibleValue - 1) / 99 * 100; --range-end:($maximumPossibleValue - 1) / 99 * 100 " > <div class="guess-number-game-range-bar-fill"></div> </div>
<div class="guess-number-game-range-labels"> <span bind-text="$minimumPossibleValue"></span> <span bind-text="$maximumPossibleValue"></span> </div> </div>
<div class="guess-number-game-actions">36 collapsed lines
<button class="guess-number-game-guess-button" bind-attr-toggle="disabled:$hasWon" bind-event=" click: $lastGuess($currentGuessInput), $attemptCount($attemptCount + 1), $lastGuess < $targetNumber ? $minimumPossibleValue($lastGuess + 1) : ( $lastGuess > $targetNumber ? $maximumPossibleValue($lastGuess - 1) : $bestScore($bestScore === 0 || $attemptCount < $bestScore ? $attemptCount: $bestScore) ), $lastGuess < $targetNumber ? $currentGuessInput($lastGuess + 1) : ($lastGuess > $targetNumber ? $currentGuessInput($lastGuess - 1) : null) " > Guess </button>
<button class="guess-number-game-new-game-button" bind-event=" click: $gameSeed($gameSeed + 1), $lastGuess(0), $attemptCount(0), $minimumPossibleValue(1), $maximumPossibleValue(100), $currentGuessInput(50) " > New game </button> </div>
<div class="guess-number-game-statistics">14 collapsed lines
<div class="guess-number-game-statistic"> <span class="guess-number-game-statistic-label">tries</span> <span class="guess-number-game-statistic-value" bind-text="$attemptCount"></span> </div>
<div class="guess-number-game-statistic"> <span class="guess-number-game-statistic-label">remaining</span> <span class="guess-number-game-statistic-value" bind-text="$maximumPossibleValue - $minimumPossibleValue + 1"></span> </div>
<div class="guess-number-game-statistic"> <span class="guess-number-game-statistic-label">best</span> <span class="guess-number-game-statistic-value" bind-text="$bestScore > 0 ? $bestScore : '—'"></span> </div> </div> </wcp-ui-state></div>
<style>204 collapsed lines
.guess-number-game { max-inline-size: 400px; margin: 0 auto; font-family: var(--sb-md-font); color: var(--sb-color-text); }
.guess-number-game-header { display: flex; align-items: baseline; justify-content: space-between; padding-block-end: 1rem; margin-block-end: 0.75rem; border-block-end: 1px solid var(--sb-color-gray-6); }
.guess-number-game-title { font-size: var(--sb-text-xl); font-weight: 700; color: var(--sb-heading-color); }
.guess-number-game-subtitle { font-size: var(--sb-text-sm); color: var(--sb-color-gray-3); }
.guess-number-game-feedback { display: flex; align-items: center; min-block-size: 48px; padding: 0.5rem 1rem; margin-block-end: 0.75rem; font-size: var(--sb-text-sm); background: var(--sb-color-gray-7); border: 2px solid var(--sb-color-gray-5); border-radius: var(--wcp-bdr-rad-md); transition: background 0.15s, border-color 0.15s, color 0.15s;
b { font-weight: 700; font-variant-numeric: tabular-nums; } }
.guess-number-game-feedback-higher { color: var(--sb-note-text); background: var(--sb-note-background); border-color: var(--sb-note-border); }
.guess-number-game-feedback-lower { color: var(--sb-warning-text); background: var(--sb-warning-background); border-color: var(--sb-warning-border); }
.guess-number-game-feedback-success { font-weight: 600; color: var(--sb-tip-text); background: var(--sb-tip-background); border-color: var(--sb-tip-border); }
.guess-number-game-picker { padding: 1.25rem 1rem 0.75rem; margin-block-end: 0.75rem; text-align: center; background: var(--sb-color-gray-7); border: 1px solid var(--sb-color-gray-6); border-radius: var(--wcp-bdr-rad-md); }
.guess-number-game-current-value { display: block; margin-block-end: 1rem; font-size: var(--sb-text-5xl); font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1; color: var(--sb-color-accent-high); letter-spacing: -0.03em; }
.guess-number-game-slider { display: block; inline-size: 99%; accent-color: var(--sb-color-accent); cursor: pointer;
&:disabled { cursor: not-allowed; opacity: 0.35; } }
.guess-number-game-range-bar { position: relative; block-size: 6px; margin-block: 2em 0.4rem; margin-inline: 3px; overflow: hidden; background: var(--sb-color-gray-5); border-radius: 3px; }
.guess-number-game-range-bar-fill { position: absolute; inset: 0; inset-inline: calc(var(--range-start, 0) * 1%) calc((100 - var(--range-end, 100)) * 1%); background: var(--sb-color-accent); transition: left 0.15s ease, right 0.15s ease; }
.guess-number-game-range-labels { display: flex; justify-content: space-between; font-size: var(--sb-text-xs); font-variant-numeric: tabular-nums; color: var(--sb-color-gray-3); }
.guess-number-game-actions { display: grid; grid-template-columns: 1fr auto; gap: 0.5rem; margin-block-end: 0.75rem; }
.guess-number-game-guess-button, .guess-number-game-new-game-button { padding: 0.75rem 1.25rem; font-family: var(--sb-md-font); font-size: var(--sb-text-sm); font-weight: 600; letter-spacing: 0.03em; cursor: pointer; border: none; border-radius: var(--wcp-bdr-rad-md); transition: opacity 0.1s, background 0.1s; }
.guess-number-game-guess-button { color: var(--wcp-primary-content); background: var(--sb-color-accent);
&:disabled { cursor: default; opacity: 0.3; }
&:hover:not(:disabled) { opacity: 0.85; } }
.guess-number-game-new-game-button { color: var(--sb-color-gray-1); background: var(--sb-color-gray-6); border: 1px solid var(--sb-color-gray-5);
&:hover { background: var(--sb-color-gray-5); } }
.guess-number-game-statistics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; overflow: hidden; background: var(--sb-color-gray-5); border-radius: var(--wcp-bdr-rad-md); }
.guess-number-game-statistic { display: flex; flex-direction: column; gap: 0.1rem; align-items: center; padding: 0.625rem 0.5rem; background: var(--sb-color-gray-7); }
.guess-number-game-statistic-label { font-size: var(--sb-text-2xs); color: var(--sb-color-gray-3); text-transform: uppercase; letter-spacing: 0.1em; }
.guess-number-game-statistic-value { font-size: var(--sb-text-xl); font-weight: 700; font-variant-numeric: tabular-nums; color: var(--sb-color-gray-1); }</style>