wordtym
Android & iOS
WordTym

An Endless
Puzzle Book

A themed word search app for tablets, native on both Android and iOS. It generates puzzles on demand from a curated 11,281-word corpus across 42 themes, keeps one puzzle in progress across sessions, and never runs out of material. The grid is a centered square sized to the window, so it plays at any width — including split-screen, resized mid-puzzle. Word to your mother.

Coming soonGoogle PlayComing soonApp Store

No accounts, no network, no trackers. Everything stays on the device.

2

Platforms

42

Themes

11,281

Unique Words

226

Levels

41

Trophies

788

Tests

0

Ads

0

Trackers

Two Native Builds, One Puzzle

Not a cross-platform framework and not a shared runtime — Kotlin with Jetpack Compose on Android, Swift with SwiftUI on iOS, each written against its own platform. What keeps them honest is a parity suite rather than shared code.

Android

Kotlin · Jetpack Compose · Room

Modules
:app, :core-data, :core-puzzle
Storage
Room + KSP, DataStore for settings
Floor
minSdk 31, target and compile 36
Tests
468, all on the JVM under Robolectric

iOS

Swift 5.9 · SwiftUI · GRDB

Targets
WordtymApp, WordtymData, WordtymPuzzle
Storage
GRDB over SQLite, UserDefaults for settings
Floor
iOS 17, iPad first with iPhone supported
Tests
320 across the three targets, parity included

What makes it the same game

A seed produces the same grid on both platforms.

Generation is deterministic, so this is testable rather than aspirational. The parity suite asserts it in four layers, in order — because a mismatch in the first would otherwise surface as an unexplainable difference in the fourth.

01

The generator

PCG-XSH-RR, hand-implemented on both, checked value for value

02

The word bag

The same draws in the same order from the same deck

03

Generation

Full puzzles across all 43 themes at all three sizes

04

Progression

Scoring, streaks, milestones and records

Reference vectors are generated from the Android build and regenerated whenever generation changes, so Android is the definition and iOS is checked against it. The backup format and the settings keys match too — a backup written on one platform restores on the other.

Never the Same Puzzle Twice

Freshness is a draw-policy problem, not a content-volume problem. Combinatorially nobody repeats a puzzle set — what players actually notice is repeated words. So three things work together.

A bag draw, without replacement

Each category keeps a shuffled deck per length band, consumed without replacement. That turns roughly one repeat per puzzle forever into a guarantee of zero repeats for ⌊N/k⌋ consecutive puzzles.

A 200-word global recency window

Rolling, and shared across every category. It kills the GOAT-in-Farm-then-GOAT-in-Animals effect that a per-category deck alone cannot see.

Filler drawn from the theme's own letters

Filler letters are sampled from the category's letter frequencies, never uniform random. Uniform filler is the classic tell that makes theme words pop out of the noise.

The corpus has depth to spare. 42 authored categories hold 14,592 category memberships, but a word that belongs to three themes is still one word — 2,502 words appear in more than one category, so the collection counts 11,281 unique words. That unique count is computed from the corpus at import rather than hardcoded, and it is the denominator the player sees.

What It Does

Single-player, offline, and built to be lived in.

Endless Generation

Puzzles are generated on demand from a 42-theme corpus and stored as ~50-byte seeds rather than grids. Even a 60-word category yields on the order of 10¹² distinct 12-word puzzles — nobody repeats a set, ever.

Three Difficulties

11×11, 13×13 and 15×15 grids with 8, 12 and 16 words. Difficulty comes from the grid — size, word count, allowed directions — never from vocabulary rarity. Every word stays reachable at every level.

No Fail State

No countdown, no penalty for a wrong drag, no way to lose a puzzle in progress. Challenge you choose is fun; difficulty imposed mid-puzzle is not. Every progression mechanic lives between puzzles.

The Word Collection

The spine of progression: a lifetime count of unique words discovered out of 11,281, with per-theme rings. Intrinsic to the content rather than a generic XP grind, and it pairs exactly with the no-repeat bag draw.

Streaks & Trophies

Four streaks, per-theme mastery, personal bests, and 41 trophies across seven families. Every one is forgiving by construction — streaks get a grace day and a broken one never erases its longest-ever record.

Offline, Always

No accounts, no cloud sync, no leaderboards and no analytics. Android declares exactly one permission — VIBRATE — and it is there because the target tablet ignores the platform haptic constants entirely. Everything lives in one database on the device.

The App

Landscape on a tablet, edge to edge, with the progression layer living in the top bar rather than interrupting anything.

First run

First run

The corpus imports from the bundled asset into Room, and re-imports only when the asset's version stamp changes.

Home

Home

Level and collection ring in the top bar, streak beside it, and puzzles solved and time played as the two counters worth keeping.

The governing principle

Nothing is ever gated.

No level, rank, milestone, streak, or record unlocks, restricts, or changes anything. Every theme and every difficulty is available from first launch, forever. Progression is decoration — trophies, animations, a ring filling in.

The only thing ever dimmed is a difficulty whose grid does not physically fit the window.

The Design System

The palette is sampled from the app's own art — k-means over the icon, wordmark and mascot — rather than invented. The art is navy-native, so the interface is too.

Palette

Page and panel are held to genuinely different values, so cards and progress tracks read as distinct surfaces rather than smudges.

RoleLightDark
Page ground#F2F6FD#05103A
Panel#FFFFFF#0A1B4F
Letters / body#0B1A3F#F7F9FD
Hairline, panel edge#D7E3F5#1B2E63
Primary accent#0E5FB8#5FC8F0
Muted text#5A6B8C#8AA0C8
Reward (tertiary)#8A5A00#FCBE44

Found-word bands

Six colours cycling, separated in lightness as well as hue so they stay distinguishable under all common colour vision deficiencies.

1violet#A78BFA
2amber#FCBE44
3rose#FF7E9D
4lime#BFE355
5cyan#2ABCF6
6mint#3FD4A8

Drawn near-opaque at 0.92. A band is the found word's surface: the letters over it flip to ink and gain weight, so a solved word scans as solved from across the board, and the later band simply wins a crossing cell — which is how two highlighter passes actually look. The cycling order interleaves light and dark on purpose, because words take their band from their index in the bank and neighbouring indices are the pair most likely to appear together.

Inter, and only Inter

A variable font (wght 100–900, opsz 14–32), so every weight is requested through FontVariation settings and optical sizing is pinned per role. Grid letters are SemiBold at ~0.54 × cell size with +3% tracking — legibility in isolation is the only criterion, and letterforms must not confuse I/l/1 or O/0. Display type is Black, tracked tight, so titles rhyme with the wordmark rather than arguing with it.

An open letter field, not tiles

The beveled tile is the brand's identity mark — icon, trophies, category cards — and it is deliberately not the reading surface. A tile is opaque, so a selection stroke has nowhere to go but on top of it, and a diagonal word becomes a staircase rather than a clean band.

Material You is declined on purpose

minSdk 31 makes dynamic colour available, but it derives the palette from the device wallpaper and would override the designed colours — including the six band colours chosen to stay distinguishable under colour vision deficiency.