Skip to content
HusarpPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Lexling

Called WordGuess until 0.18.0 — see "The rename" below.

A "guess the secret word" game based on meaning, not letters. The engine picks a secret word (randomly, or a friend types one in for you). You type guesses; every guess gets a rank score telling you how close in meaning it is to the secret word — 1 means it's the closest word there is, 6547 means there are 6546 closer ones. Your top guesses are shown as boxes with color-fill progress bars (red = cold, green = hot), so you can steer toward the answer. Win by typing the exact word (any inflected form counts).

A second game, Letters, sits next to it in the same app: find a hidden word letter by letter, with green / yellow / grey feedback — like Wordle, but a new random word every game, as many games as you like, with the word length (3–13, or any), the number of tries (or unlimited), category, difficulty and Polish letters chosen by the player. Each game has its own card on the menu and its own list of games in progress. A third mode (a Scrabble-like game) is planned.

Playable in Polish and English (both the UI and the word libraries).

How it works (short version)

  • Word closeness is computed from word embeddings (precomputed word vectors, fastText), shipped with the game as a compact binary file — the game is fully offline.
  • The whole game is one HTML/JS web app (like Reckless Driving). On desktop it runs inside a native window via pywebview / WebView2; on Android the same app is packaged with Capacitor into an APK.
  • Windows gets the same Setup.exe install/update system as Lockdown and Reckless Driving: run the setup, it installs/updates in place, saves live outside the program folder and are never touched by an update. Update check asks GitHub for the latest release - on opening and on coming back to the app; a newer one shows at the bottom of the menu (since 0.56.0) - ✕ hides it until Lexling next starts. On Android Lexling downloads Lexling-X.Y.Z.apk itself and hands it to Android's installer (since 0.58.0): the first time, Android asks to let Lexling install apps; the file is removed once the new version runs. On Windows Lexling downloads LexlingSetup-X.Y.Z.exe itself, starts it and closes (since 0.58.0). A failed download: Try again, or GitHub. Settings → Updates: automatic checks on/off, Check now, GitHub, Get update. All as in ../APP-STANDARDS.md.

Features

  • Random secret word, or "friend mode" (a friend secretly types the word).
  • 20 categories (animals, food, household, tools, nature, jobs, science, verbs, ...), a secret-length band (short / medium / long / any, shown against a histogram of the real word lengths) and a difficulty setting.
  • Autocomplete / suggestions while typing, restricted to words the game knows (with diacritic-insensitive matching for Polish — typing zolw finds żółw).
  • Multiple games at once: save, resume, give up (reveals the word); name a game on New game or rename it later - it shows as "Name (Game 12)". Settings can remember your New game choices for next time.
  • Statistics (no achievements, since 0.23.0): a General tab (every game, the time, games by mode) and one per game, each by language and by level. Since 0.60.0 every game keeps its own record from its first move - saved as it is played, so leaving, giving up or deleting a game keeps its numbers; a game with no move made does not count. Records and averages leave help out: Guess - hints (and a category, and a word a friend chose); Connect - words found with a hinted letter; Tiles - games with undo or best-move ratings on, and moves made with a hint. Where help is switched on, Lexling says so. (Numbers from before 0.60.0 cannot be split that way; they are kept, not shown.)
  • Polish + English, switchable.
  • Letters mode: one box per letter, its own on-screen keyboard (keys coloured by what the guesses showed; tap a tile to edit it; Space leaves a tile empty, ← → move along the row; the phone's keyboard as an option), no hints (since 0.34.0 - run out of tries and it is over), and its own statistics.
  • Time (since 0.62.0, Settings, both off by default): the current time under the Lexling name, and a reminder every so often (hours and minutes of your choice) of how long you have been playing - on-screen time only.
  • Collection (since 0.61.0, Menu): every word you typed in a game, per game and category, against the words each game can hide - found ones written out, the rest a dot each; "Only new words" on New game hides only words not collected yet.
  • Connect mode: drag across a circle of 4–10 letters to fill a small crossword; other real words are bonus words; free hints, a random letter at a time, until half of a word shows (rounded up); a hinted letter stays marked, in green, once its word is done. An option for one or two everyday two-letter words on the board (since 0.60.0). Its own statistics.
  • How to play on every New game screen: a short card, closed until you open it.
  • A gear in every game's top bar: the settings that matter while playing (Sound; in Tiles also its colours).
  • What a word means: words in the games open their meaning in the browser - sjp.pl for Polish, Wiktionary for English (no dictionary inside the app: it would be far too big).
  • No scores anywhere (since 0.29.0): the games are for fun; statistics show how you are doing, hints used included.
  • Tiles mode (since 0.35.0), the classic crossword-tile game for 2–5 players - people passing one device and/or the computer (six levels, Relaxed, Easy, Medium, Intermediate, Hard, Expert - Medium since 0.60.0; Settings → "Better bot reasoning" makes a level only how many words the computer knows, to compare), in the order you set, the first chosen or drawn. Four boards (Classic, Bonus, Diamond; Quick - 11 × 11 with about half the tiles), the full 100-tile sets, sjp.pl / ENABLE word lists. Play online (Android, since 0.53.0): 2–5 people, a phone each, over Nearby (since 0.63.0: Google's Nearby Connections - Bluetooth and Wi-Fi together, no pairing; needs Google Play services), Bluetooth or the local network (Wi-Fi) - or over the internet with a 6-character game code (since 0.59.0, once the Firebase project below is set up; Android and Windows) - one phone hosts the game (it alone keeps it; it lets each phone in), the others join, the host naming the players and choosing which one each phone takes over; while a phone is away the others play on and only its own turn waits - each phone shows whether the others are in the app or without a connection; a phone that drops out goes back to its own seat, and a saved game can be opened again later for any phones to take the seats. The host can skip the move of whoever is on turn, make a player give up (they stay to watch), or end the game for everyone. Everyone's statistics count the game. With more than two players, whoever gives up just drops out - their tiles go back to the bag - and the rest play on (since 0.54.0, every Tiles game). Place tiles by dragging, by tapping, or by typing on a PC; the board zooms in on a phone (and pinches). Hints in three levels (Small, Big, Master), exchange, pass, a letters-left list, check any word, each player's tiles in their colour and coloured bonus squares (both switchable, also mid-game), rule options (bonus squares every time, challenges, exchanges always, no seven-tile bonus, a clock per move or per game, hints off or limited per level, hints that cost points, undo against the computer, everyone's tiles shown between friends), moves played from a hint marked on the board, each score's "+points" of the last turn, move ratings (a game can be set to have none; after each of your moves - with the best move there was, or the rating alone - in History for every move with the best move under it, and for every player at the end: points against the best move there was), raised tiles, three looks for the bonus squares and five tile colours (the 🎨 button), and its own statistics by language and level. Points stay in this one - scoring is the game.

Run it (development)

Needs only Node.js. From the project folder:

node tools/serve.mjs

then open http://127.0.0.1:5173. (A server is required — ES modules and fetch() don't work from file://.)

Current state (v0.17.0): both games — Guess and Letters — fully playable in English and Polish on the real word data (60 000 Polish + 41 158 English words), with a Windows installer and an Android APK. What is still open is in PLAN.md.

The Letters, Connect and Tiles rules have tests against the real data: node tools/test-letters.mjs, node tools/test-connect.mjs and node tools/test-tiles.mjs; the online games' protocol node tools/test-session.mjs.

Size: Windows installer 52 MB, 65 MB installed; Android APK 34.5 MB (40 MB of it is the game, 39 MB word data).

The rename (0.18.0)

The app was called WordGuess until 0.18.0. On Windows, installing Lexling over WordGuess is an ordinary update: the setup recognises the old install, removes the old program and shortcuts, and moves the saves folder %LOCALAPPDATA%\WordGuess to %LOCALAPPDATA%\Lexling whole (the game does the same on its first start, whichever comes first). On Android the app ID changed to com.husarp.lexling, so Android sees a new app: it installs next to the old one, and games saved in the old app do not carry over. The GitHub repository moved to Husarp/lexling; GitHub forwards the old address, so older versions' update check still works.

Install on Windows / ship an update

& ".\scripts\build.ps1"

produces build\LexlingSetup.exe (~3 minutes). Run it: it installs for your account only (no admin prompt) into %LOCALAPPDATA%\Programs\Lexling, adds Start-menu and desktop shortcuts and an "Apps & features" entry. The same exe is the updater: run a newer one and it offers Update and replaces the program in place. Saved games and statistics live in %LOCALAPPDATA%\Lexling — outside the program folder — so updates never touch them; uninstalling keeps them unless you tick the box.

During every build the script starts the freshly built game hidden and refuses to package it unless it boots with the right version, its fonts work, saves are writable and both languages' word data loads. To bump the version, change it in app/js/version.js only.

The build needs Python with pywebview and pyinstaller: it uses .venv in this folder if there is one, otherwise the Car Crash project's.

Build the Android APK

& ".\scripts\build-android.ps1"             # build\Lexling-release.apk, signed with Lexling's key
& ".\scripts\build-android.ps1" -Install    # …and push it to a connected phone
& ".\scripts\build-android.ps1" -DebugBuild # build\Lexling-debug.apk, signed with the debug key

The release key. The APK is signed with Lexling's own key (since 0.22.5; releases carry it), which lives outside the repository; android/keystore.properties (git-ignored, never commit it) says where it is and holds its password. Back up both the key file and the password. Android installs an update only over an app signed with the same key: without them no update can ever be signed again, and every player would have to uninstall — losing their saves — to move to a newly signed Lexling. Without the file the script stops (an unsigned APK cannot be installed); -DebugBuild still works.

Needs the Android SDK (%LOCALAPPDATA%\Android\Sdk) and Android Studio's bundled JDK 21 — the script points at both, so neither has to be on PATH — plus npm install once for the Capacitor CLI. The APK wraps the very same app/ folder as the desktop build; cap sync copies it into android/.

Play online over the internet (Firebase)

Internet play goes through a free Firebase Realtime Database (Google; the free "Spark" plan has no end date and does not pause when unused). Lexling talks to it through its plain web interface - no library - and each player is signed in anonymously (no accounts). Until app/js/online-config.js holds the project's details, Internet is not offered.

Setting it up, once:

  1. console.firebase.google.com → Add project (e.g. lexling-online; the name ends up in the app's address for the database, which is public). Google Analytics is not needed.
  2. Build → Realtime Database → Create database, a location near the players, locked mode (never test mode: its rules switch everything off after 30 days).
  3. Realtime Database → Rules: replace everything with firebase/database.rules.json → Publish. (Each player writes only their own messages; only a room's host reads what is sent to it.)
  4. Build → Authentication → Get started → Sign-in method → Anonymous → Enable.
  5. Project settings → Your apps → Web (</>) → register → copy apiKey and databaseURL from the firebaseConfig it shows into app/js/online-config.js. (The apiKey only names the project; the rules protect the data.)

What it keeps: rooms/<code> while a game is hosted - the host's name and the messages not read yet (each side deletes what it has read); the host deletes the room when it stops. The free plan's limits (100 devices connected at once, 1 GB stored, 10 GB a month downloaded) are far above a word game's moves.

Rebuilding the word data

app/data/ is generated — never edit it by hand. It only needs rebuilding after changing something in tools/ (most likely the never-secret list or the category examples in tools/seeds.mjs):

node tools/build-data.mjs

Takes ~2 minutes and prints a report (category samples, weakest category members, most generic words, sanity checks such as pies (dog) → kot (cat) close, śruba (screw) far). It needs:

  • tools/raw/cc.pl.300.vec.gz and tools/raw/cc.en.300.vec.gz (2.6 GB, git-ignored) from https://dl.fbaipublicfiles.com/fasttext/vectors-crawl/ ;
  • LibreOffice installed with the Polish and English dictionaries (default location C:/Program Files/LibreOffice/share/extensions/, override with the WG_DICTS variable).

Tiles has word files of its own, app/data/<lang>/tiles.bin (a word graph, app/js/dawg.js), built from two word-game lists by node tools/build-tiles-words.mjs (~20 s). It needs, in tools/raw/tiles/ (git-ignored): slowa.txt from sjp.pl's "słownik do gier" (word-games dictionary; https://sjp.pl/sl/growy/ - unzip sjp-YYYYMMDD.zip) and enable1.txt (https://raw.githubusercontent.com/dolph/dictionary/master/enable1.txt), plus the LibreOffice dictionaries above (to leave out every form of a slur or vulgar word).

app/data/<lang>/pool.json - the words Letters, Connect and Guess never hide (not in the word-game list, plain English, abbreviations riding on a real word) and the words let back in (gra, muzyka) - is built by node tools/build-pool-fix.mjs from the same slowa.txt, sjp.pl's inflection list tools/raw/tiles/odm.txt (https://sjp.pl/sl/odmiany/ - unzip sjp-odm-YYYYMMDD.zip) and tools/raw/cc.pl.tokens.txt.

app/data/<lang>/spoken.txt - the Tiles words people really say, most said first, which the computer's levels below Hard keep to - is built by node tools/build-spoken.mjs (after the Tiles word files); it downloads FrequencyWords' subtitle lists into tools/raw/spoken/ itself.

Data sources & licences

The shipped word data is derived from these sources — keep this list in the game's credits when it is distributed (to-do in PLAN.md M5). Not legal advice; check the terms before selling.

Source Used for Licence
fastText cc.pl.300 / cc.en.300 (Facebook AI Research) word vectors CC BY-SA 3.0 — attribution + share-alike
sjp.pl Polish Hunspell dictionary (M. Futrega) Polish words + inflection GPL / LGPL / MPL / Apache 2.0 / CC SA (your choice)
SCOWL en_US Hunspell dictionary English words + inflection permissive (BSD-like), attribution
WordNet-based LibreOffice thesaurus English parts of speech WordNet licence (permissive, attribution)
SJP.PL "słownik do gier" (word-games dictionary, sjp.pl) Tiles: Polish words (app/data/pl/tiles.bin; changed: slurs and vulgar words left out) GPL 2 or CC BY 4.0 — we use CC BY 4.0: attribution
ENABLE word list Tiles: English words (app/data/en/tiles.bin) public domain
SJP.PL "odmiany" (sjp.pl inflection list) Letters / Connect: which words are base words (app/data/pl/pool.json) GPL 2, LGPL 2.1, Apache 2.0 or CC BY 4.0 — we use CC BY 4.0: attribution
FrequencyWords (Hermit Dave), from OpenSubtitles 2018 Tiles: the words people say, for the computer's levels (app/data/<lang>/spoken.txt) CC BY-SA 4.0 — attribution + share-alike
Barlow Condensed, Inter fonts SIL OFL (licence files in app/fonts/)

Licence

All rights reserved — © 2026 Husarp. The code is public to read, and the releases are free to download and play, but the game may not be copied, changed, shared, sold or built upon without written permission. The exceptions are the third-party parts above, which keep their own licences: the word data derived from fastText stays under CC BY-SA 3.0, the Polish Tiles word file derived from SJP.PL under CC BY 4.0, the spoken-word lists derived from FrequencyWords under CC BY-SA 4.0, and the fonts under the SIL OFL. Full terms in LICENSE.

Project layout

app/                the game itself — single-page app, no build step, no dependencies
  index.html        shell: no-flash boot (page colour + theme before first paint, fonts preloaded)
  css/app.css       design tokens + shared styles (verbatim from the design) + per-screen styles
  js/main.js        boot + hash router (#/games, #/game/<id> … so Back works on Android)
  js/screens.js     menu, game picker, new game (both modes), statistics, settings
  js/game.js        the Guess game screen (input, autocomplete, guess boxes, history, win / give-up)
  js/letters-game.js  the Letters game screen (letter boxes, hidden input, reveal, win / loss, copy result)
  js/letters.js     Letters rules: feedback, the keyboard, which words can be hidden and how hard
  js/tiles.js       Tiles rules: the boards, letter sets, bag and racks, checking and scoring a move, the end
  js/tiles-moves.js Tiles move finder (every legal move for a rack) and the computer player's levels
  js/tiles-game.js  the Tiles game screen: board, rack, zoom, placing, the computer's turns, the hand-over
                    between people, the history / letters-left / check panel, the end and the look-back
  js/session.js     Tiles online: what the host and the joining phones say (tests: tools/test-session.mjs)
  js/net.js         Tiles online: the connections - Nearby, Bluetooth or Wi-Fi (the Android plugins NearbyLinkPlugin,
                    BluetoothLinkPlugin, LanLinkPlugin and their shared Links), or the internet (net-web.js)
  js/net-web.js     Tiles online over the internet: Firebase's Realtime Database - rooms under a game code, anonymous
                    sign-in; its project in js/online-config.js, its access rules in firebase/database.rules.json
  js/dawg.js        the word graph Tiles looks words up in (build, save to bytes, load, walk)
  data/<lang>/tiles.bin  Tiles' word graphs (tools/build-tiles-words.mjs)
  js/engine.js      word data loading, rank scoring, form→lemma, autocomplete, secret picking
  js/store.js       settings, saved games, lifetime stats (localStorage)
  js/i18n.js        every UI string in EN + PL, plural rules, number/time formatting
  js/fit.js         text-fit guarantee (long labels shrink / wrap, never overflow)
  js/sound.js  js/ui.js  js/version.js
  fonts/            Barlow Condensed + Inter (bundled, OFL licences alongside)
  data/             generated word data (build output, not hand-edited)
design/v2/handoff/  the design agent's six screens — the visual source of truth (v1 kept in design/v1/)
design/letters/     the Letters mode handoff (six more screens, NOTES.md, strings.json). design/ is git-ignored
tools/              serve.mjs (dev server) and the word-data pipeline:
  build-data.mjs    the pipeline itself — every tuning number lives at its top
  lexicon.mjs       base words, parts of speech, inflected forms (Polish + English rules)
  hunspell.mjs      Hunspell .aff/.dic reader · fasttext.mjs  streaming .vec.gz reader + caches
  vecmath.mjs       normalise / centre · seeds.mjs  category examples + never-secret stoplist
  raw/              downloaded fastText vectors + caches (2.6 GB, git-ignored, build-time only)
desktop/main.py     the Windows app: WebView2 window + local server around app/ (saves, caching, self-test)
installer/          setup.py (LexlingSetup.exe: install / update / uninstall), lexling.spec (PyInstaller)
scripts/            build.ps1 (Windows installer) · build-android.ps1 (APK) — both output to build/
android/            Capacitor project: manifest, launcher icons; app/ is copied in by `cap sync`
assets/             lexling.ico / .png / -1024.png — the app icon, drawn by tools/make-icon.py
                    (concept 2b "Caret" black from "WordGuess Icon Ideas.dc.html")
PLAN.md             forward-looking backlog (what's next)
CHANGELOG.md        full history of every change
DESIGN.md           game & engine design — scoring, data format, OP-word handling, screens

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages