• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
alexwein

alexwein

thinkalittlelonger

a little game where you think of big words
Public
Like
thinkalittlelonger
Home
Code
5
frontend
6
scripts
2
towniePrompts
3
README.md
H
index.ts
Branches
1
Pull requests
Remixes
History
Environment variables
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
towniePrompts
/
done-01.md
Code
/
towniePrompts
/
done-01.md
Search
…
Viewing readonly version of main branch: v217
View latest version
done-01.md

I have forked the Val Town React Hono Starter, but made no other changes to the code outside of this todo.md file. help me create make this word game. Let's focus on building out the front-end for now.

  • Title: What's the Biggest Word You Can Think of?

The player is prompted with some constraints and must think of the biggest word they can that fulfills the constraints.

examples:

  • What's the biggest word you can think of that starts with P and ends with P?
  • What's the biggest word you can think of that contains the letters EVE in order (without anything in between)?

Frontend React Components:

  • Header
  • Prompt
    • title
    • constraint
    • examples
  • CurrentGuess
    • Cursor
    • lengthCounter
  • SubmitButton
  • trash button
  • keyboard
    • key

gameState: [preGame, inGame, postGame]

inGame: currentRound currentGuess cursorPosition

Prompt Component

  • the title always starts with "What's the biggest word you can think of"
  • the constraint

CurrentGuess Component

  • Displays the currentGuess state, which is updated through the keyboard component.
  • tapping/clicking on a letter in the current guess adjusts the cursor position
  • the cursor should be a thin vertical line that strobes at a standard speed for a text editor.
  • use a monospaced font
  • Left justify the currentGuess
  • Use a font size so that 15 letters fits within the width. when the currentGuess gets larger, dynamically resize the font so that the full word fits. Don't allow input after 30 letters (should be handled in keyboard keys below)
  • the lengthCounter component should display the number of letters in the CurrentGuess. It should float above the top right corner of the currentGuess, similar to a notification count on an app icon (but don't use red)

Submit Button

  • A button that submits the current guess
  • has an selectable property
    • if the currentWord is blank,
    • certain constraints (like "ends with" or "uses every letter in a set") will make the currentGuess unselectable if the constraint is not met
    • when the current guess is submitted, the currentRound is incremented and the next round's constraint is presented. the current guess is reset to blank.
    • If it is the final round, submitting changes gameState to postGame

Trash button

The trash button resets the currentGuess to blank without submitting. It should be a trash icon.

Submit and Trash buttons should appear on the same line, with trash being to the left of submit, and submit taking up 4x the width of the trash button.

keyboard component

  • should always be up when gameState=inGame
  • It should fill the bottom third of the screen on mobile
  • Follow QWERTY layout, but only have keys for
    • the 26 Letters in the alphabet
    • to the left of Z, there should be a key with a backspace icon. The back button removes the letter at the cursor.
    • to the right of M, there should be left and right arrow keys.
  • Keys should have an selectable property, unselectable keys should be indicated visually in css, but by default all keys are selectable.
  • pressing a key adds the letter to the currentGuess at the cursor position.

edits 1: mobile/desktop experience

  • Mobile experience should be prioritized.
  • Make the desktop version look a little more like the mobile version: rather than being full screen, it should be portrait-mode and centered in the screen.
  • On desktop (and on mobile with attached keyboard), keyboard input should still word.

edits 2:

make the following tweaks:

  1. Add a header at the top: "a word game by Alex Wein"
  2. there should be less white space. Increase the size of the other elements slightly so that there's not as much blank space.
  3. and distribute the blank space more evenly
  4. On mobile, when I have 14 letters in the currentGuess, the cursor moves to a new line. ensure currentGuess is always a single line and doesn't change height.

make the letterCount bigger, keep it's position visually anchored to the top right of the currentGuess (not the container)

undo the last update and try again: I liked how the currentGuess looked (the size of the box should never change), I just want to move the counter down so it's not floating on its own. The counter should display 0 when the current guess is blank

The changes to the make the length counter bigger were successful and you should repeat them. Made the length counter bigger:

Increased font size from 0.9rem to 1rem Increased padding from 3px 9px to 4px 10px Increased min-width from 28px to 32px Increased border-radius to 16px for a larger, rounder look

that's better but not quite there yet. I want the letterCount to partially overlap with the white div with currentGuess at the top right corner.


messyQueries.ts

This is an export from an Observable notebook. I want you to read it, and return a fully formed duckDB query against the wordnik table the query should be a union all of the results of the separate sql queries in the file try to preserve the sql coding style in the query (from-first, lowercase, etc.)

fields in result:

  • id: int where the first query is 1, the next is 2, etc.
  • rule: string: use text in the comment of each query above the where clause
  • word: string: word from wordnik
  • n_letters: int: length(word)

update todo.md with the correct query but make no other changes to todo.md:

from ( -- 1: ends with p from wordnik select 1 as id, 'ends with p' as rule, word, length(word) as n_letters where word like '%p' union all -- 2: starts and ends with p from wordnik select 2 as id, 'starts and ends with p' as rule, word, length(word) as n_letters where word like 'p%p' union all -- 3: has the letters dog in sequence from wordnik select 3 as id, 'has the letters dog in sequence' as rule, word, length(word) as n_letters where word like '%d%o%g%' union all -- 4: starts with the letters OVER from wordnik select 4 as id, 'starts with the letters OVER' as rule, word, length(word) as n_letters where word like 'over%' union all -- 5: ends with the letters OVER from wordnik select 5 as id, 'ends with the letters OVER' as rule, word, length(word) as n_letters where word like '%over' union all -- 6: all vowels are As from wordnik select 6 as id, 'all vowels are As' as rule, word, length(word) as n_letters where word similar to '[^eiouy]+' union all -- 7: only uses QWERTY from wordnik select 7 as id, 'only uses QWERTY' as rule, word, length(word) as n_letters where word similar to '[qwerty]+' union all -- 8: can be typed only using your left hand from wordnik select 8 as id, 'can be typed only using your left hand' as rule, word, length(word) as n_letters where word similar to '[qwertasdfgzxcvb]+' union all -- 9: has exactly two Cs from wordnik select 9 as id, 'has exactly two Cs' as rule, word, length(word) as n_letters where length(word) - length(replace(word, 'c', '')) = 2 union all -- 10: has the letters ABC in any order from wordnik select 10 as id, 'has the letters ABC in any order' as rule, word, length(word) as n_letters where word like '%a%' and word like '%b%' and word like '%c%' union all -- 11: no s no t no e no a from wordnik select 11 as id, 'no s no t no e no a' as rule, word, length(word) as n_letters where word similar to '[^stea]+' ) select * order by id, n_letters desc

edit frontend/rounds.ts:

  • apply the structure of the first element to the others: highlight takes an array of letters, validation is an unquoted function, examples is a list of words. { round: 1, title: "starts with HI", highlight: ["H", "I"], validation: str => /^hi.*/.test(str.toLowerCase()), unselectable_keys: [], examples: ["hit", "hint", "hill",] },
  • make this array exportable.
  • import the rounds array in the App component to use for the rounds of the game.
  • leverage the other features of the rounds data:
    • the examples should be between the prompt and the currentGuess
    • in the currentGuess, on the keyboard, and in the displayex examples, the letters in round.highlight should be visually distinct from the the other letters.
    • the submit button should only be clickable if validation returns true.
    • make the unselectable keys unselectable. With keyboard input, typing an unselectable letter doesn't do anything

game Over

Help me begin to build out the postGame view:

  • during the game, record the list of words the player submitted.
  • upon submitting the final guess, send that data to the backend.
    • we will validate that submissions are actual words on the backend. Skip the actual validation for now. instead use a stub that says every submission has a 75% change of being valid. Do this on the backend.
    • the postGame state should present a table of the results, that lists each word.
      • if it the word is valid, list the number of letters in it.
      • visually indicate valid and invalid words using versions of red and green that are discernible for standard colorblindness.
      • the last line of the table should a "total" that sums up the letters in all valid words.

validation strategy

help me devise a good strategy for validation. Currently, I have a list of valid words in a table format.

  • create a database initialization script that loads the csv into sql.

  • update the project readme with instructions to run the this initialization (so the project is easy to remix)

  • update the validation logic build earlier in the conversation.

  • below the first few lines of the csv.

  • A version currently lives at https://gist.githubusercontent.com/a-lexwein/e3e6a0817c71d57c063c238f519f8b45/raw/9a06a1e2f5e4c479bb653ff39dbb65f77cd60cff/thinkOfWords.csv

id,rule,word,n_letters
1,starts with HI,histocompatibilities,20
1,starts with HI,histopathologically,19
1,starts with HI,historiographically,19
1,starts with HI,histocompatibility,18

don't suggest code changes yet, instead, build out a strategy in markdown that I can freshly prompt townie with.

Put that prompt immediately below here in this file todo.md:


Townie Prompt: Implement Word Validation with SQLite

Context

This is a word game where players must think of the biggest word that fits a given constraint (e.g., "starts with HI"). We need to validate that submitted words are real English words AND that they satisfy the round's constraint.

A CSV file containing valid words for each round is available at: https://gist.githubusercontent.com/a-lexwein/e3e6a0817c71d57c063c238f519f8b45/raw/9a06a1e2f5e4c479bb653ff39dbb65f77cd60cff/thinkOfWords.csv

The CSV format is:

id,rule,word,n_letters
1,starts with HI,histocompatibilities,20
1,starts with HI,histopathologically,19
...

Where id corresponds to the round number and rule describes the constraint.

Tasks

1. Create Database Initialization Script

Create a new file scripts/initDb.ts that:

  • Fetches the CSV from the gist URL above
  • Parses the CSV data
  • Creates a SQLite table called valid_words with columns:
    • id (INTEGER) - the round number
    • rule (TEXT) - the constraint description
    • word (TEXT) - the valid word (lowercase)
    • n_letters (INTEGER) - word length
  • Creates an index on (id, word) for fast lookups
  • Inserts all rows from the CSV
  • This script should be idempotent (safe to run multiple times - drop and recreate table)

Use Val Town's SQLite: import { sqlite } from "https://esm.town/v/std/sqlite";

2. Update README.md

Add a "Setup" or "Database Initialization" section that explains:

  • The game requires a word database to validate submissions
  • How to run the initialization script (visit the script's endpoint or run it manually)
  • Note that this only needs to be done once, or when the word list is updated

3. Update Backend Validation Logic

Modify the /api/validate endpoint in index.ts to:

  • Accept submissions in format { submissions: [{ round: number, word: string }] }
  • For each submission, query the valid_words table to check if the word exists for that round
  • Query: SELECT 1 FROM valid_words WHERE id = ? AND word = ? (lowercase the word before querying)
  • Return { results: [{ round, word, isValid: boolean }] }

4. File Structure After Changes

index.ts              # Main HTTP handler with /api/validate endpoint
scripts/
  initDb.ts           # Database initialization script (HTTP type so it can be triggered)
README.md             # Updated with setup instructions
frontend/             # (no changes needed)

Important Notes

  • The valid_words table pre-validates words against round constraints, so we only need to check if the (round, word) pair exists
  • Words should be compared case-insensitively (store and query in lowercase)
  • The init script should be an HTTP val so it can be easily triggered via browser or curl
  • Keep the init script simple - just fetch, parse, and insert

  • for the inGame view, add a component that indicates how many rounds there are and what the current round is.
  • it should take up a single like and say "Round 1/5"
  • After the text, use an minimal svg chart that resembles a subway map. each round is a circle, and as the game progresses, the current round is visually indicated (through color and an additional outline)

styling cleanup

  • pick a complete coherent color pallet: use a dark background and light text. maintain color-blind friendly coloring for valid and invalid words, but you can pick new colors.

  • the size of the text in the prompt-title should be smaller than the prompt-constraint.

  • ensure that the height of the in-game element never changes and fully fills the screen on mobile.

    • the longest prompt size in the current dataset is under 60 characters. Ensure that 75 characters fits cleanly.
    • include logic to responsively size the text when greater than 70 characters.
  • use the same header component across all states. start with this, but make it its own component so we can tweak later

Think A Little Longer. a word game by Alex Wein
  • refactor if needed and add comments and documentation so that is is easy to adjust the color palette

  • change it back to something with dark text on a light background

  • on postGame view, the results table would be the full width of the screen/gameContainer.

  • the gameContainer shouldn't grow in width, once the text gets too long, resize the text


FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2026 Val Town, Inc.