Play it now: sudokui.app · free · open source · no ads · works offline
sudokUI (sudoku + UI) is a free, open-source sudoku studio for playing, practising and rating puzzles. It combines a first-class playing experience — in the spirit of SudokuPad — with the deepest verified solving-technique library available in a browser: 80 techniques catalogued, 77 implemented, from a beginner's first Naked Single to Exocets and Tridagons, each one explainable step by step.
It runs as an installable, offline-capable web app (PWA): Safari, Chrome, Edge and most Android browsers can add it to a home screen or desktop, and it plays offline once loaded. It is not in an app store yet; the steps for a Capacitor wrapper are under Mobile builds.
Play
- SVG board with given/entered digits, corner pencil marks (digit-bound 3×3 positions, Snyder-friendly), centre pencil marks, and multi-colour cell colouring
- Mouse, touch and full keyboard control; drag or modifier-click to multi-select, and on touch a Multi mode where taps add cells and a drag paints them in any direction; hold-modifier temporary input modes; undo/redo; timer & pause
- Auto-candidates with per-cell strike-through exclusions, one-click candidate fill, error check with restore-to-last-correct
- Set tracker (Settings, off by default): paint two groups of cells in two colours and a line under the board counts their cells and digits, says what each still needs, and proves whether they must hold the same digits by counting rows, columns and boxes, the way Phistomefel's ring is proved; a cell in both colours counts in neither and shows no colour
- Highlights that are not help: peers, matching digits, conflicts, and, a key press away when stuck, a ring around every cell left with exactly two candidates in the pair's two colours, so the same pair matches from across the board, where wings and chains begin
- Import/export puzzles as 81-character strings, as links from SudokuPad, f-puzzles, Sudoku Exchange and sudoku.coach (classic puzzles; a variant is refused by what it carries), or as the pencil-mark grid the forums paste (its candidates come along as centre marks, and Share copies the board back as one), copy any hint as a step line in Eureka or HoDoKu notation (see Text formats), or scan a photo of a printed puzzle (camera or file; turned, tilted or mirrored is fine) and check the result on the board before playing (see docs/scan.md) — every import is rated
- Shareable links:
sudokui.app/p/<81 chars>opens the exact puzzle, and pasted into a chat it previews with the band, the score and, if you choose, the techniques it needs; a win can be shared as a challenge with the time to beat
Learn
- Progressive hints: first the technique name, then the full explanation with the pattern drawn on the board, then one click to apply it. Every technique draws its logic: the houses it lives in as bands, chains as candidate-anchored arrows (solid for strong links, dashed for weak, HoDoKu-style), colouring as quiet ties with the witnesses as arrows, forcing chains as their line of forced singles. "Walk through it" reveals any drawing one idea at a time, ← and →, with a sentence for each (see docs/highlighting.md). A setting leaves the uniqueness family out of hints, Steps and Scan, for solvers who do not use it; the rating stays HoDoKu's
- Practice mode for 61 named techniques: pick one and get a generated puzzle that genuinely requires it — with nothing harder needed before it. The game fast-forwards through the routine steps so the chosen pattern is the very next move, the puzzle stays within one band of the technique, and the bar says found when your own move is the one it was prepared for. The rarest techniques come from puzzles found in advance by a multi-hour search, so they start instantly too
- Build a chain (⛓ in the Assist box): tap candidates one after another and the engine says what each link is (a bivalue cell, a conjugate pair, two candidates that see each other), draws the chain the way hints draw theirs, reads it back ("if the 4 in r1c1 is false, then the 5 in r1c1 is true, so...") and says what it proves; one click removes what your chain rules out (see docs/chain-trainer.md)
- Your record, on your device: every move you make is credited with the easiest technique that justifies it, a finished game is summed up ("45 moves of your own: 31 × Naked Single, 12 × Hidden Single, 1 × X-Wing. From hints: 1 × XY-Wing."), the guide shows what you have used unaided and sorts by learn next, the path (Learn → Your path) shows the techniques worth learning in the order puzzles need them with the next one a click from its practice, and the win dialog keeps your band records and the daily streak. The daily, with everyone's times: one published puzzle a day, the same for the whole world; finish it without help and, if you choose, send your time in to see how many solved it unassisted, the median, and the share you were faster than (no account, a random token per day). Why not?: when Check finds a wrong digit it says why, from a peer that already holds it to the forced singles that would break the board, and shows it (see docs/technique-stats.md)
- The guide (Learn → Theory, under the board): every one of the 80 techniques explained in three short parts (what the pattern is, why it works, how to spot it), most with a worked example drawn on a real board that you can open and play. A glossary defines the language of solving (strong link, conjugate pair, almost locked set…), and the terms inside every explanation link to it
- The same content is published as plain web pages: sudokui.app/learn has one page per technique, the glossary, and how the difficulty rating works with the full score table
- The complete technique catalogue is visible in-app with its ratings; unimplemented techniques are shown crossed out, so you always see the whole map of sudoku solving
Rate
- Every puzzle gets a difficulty score: the solver plays it with the easiest applicable technique at each step and sums per-technique scores (HoDoKu-compatible model)
- Eight bands: Beginner (≤400), Easy (≤800), Medium (≤1000), Tricky (≤1150), Hard (≤1600), Unfair (≤1800), Extreme (≤3000) and Nightmare above — the HoDoKu thresholds, with the extremes subdivided. One fish or wing makes a puzzle Tricky; several make it Hard
- Optional hidden-rating mode and "Surprise me"
Generate
- Unique-solution generator with rotational symmetry; every puzzle is minimal (no clue, or with symmetry no pair of clues, can be removed) and solvable by the technique catalogue
- Any difficulty band in well under a second: digging proves uniqueness with a propagating solver, and rating stops the moment a puzzle is past the band asked for. The hardest bands come from a shipped seed library, served through one of 10^12 isomorphisms each time so nothing repeats (see docs/generator.md)
- Background generation in a Web Worker — the UI never blocks
- Puzzles are pooled per difficulty and per technique, so new games and practice sessions usually start instantly
80 techniques catalogued, 77 implemented, 73 enabled in the default solve order. The ≈ entries are implemented and tested but disabled because they are provably redundant — anything they find, an enabled cheaper technique finds first.
| Family | Techniques |
|---|---|
| Singles | Full House · Naked Single · Hidden Single |
| Intersections | Locked Pair · Locked Triple · Pointing · Claiming |
| Subsets | Naked/Hidden Pair · Triple · Quadruple |
| Basic fish | X-Wing · Swordfish · Jellyfish · ≈ Squirmbag · ≈ Whale · ≈ Leviathan |
| Finned fish | Finned/Sashimi X-Wing · Swordfish · Jellyfish |
| Complex fish | Franken X-Wing · Franken Swordfish (set-cover fish theorem) |
| Single-digit patterns | Skyscraper · 2-String Kite · Turbot Fish · Empty Rectangle |
| Wings | XY-Wing · XYZ-Wing · W-Wing · WXYZ-Wing |
| Uniqueness | Unique Rectangle Types 1–6 · Hidden Rectangle · Avoidable Rectangles 1/2 · Extended Rectangles · BUG+1 |
| Colouring | Simple Colours · Multi Colours · 3D Medusa |
| Chains & loops | Remote Pairs · Chute Remote Pairs · X-Chain · X-Cycles · XY-Chain · AICs · Nice Loops — each with grouped and ALS-augmented variants |
| ALS | ALS-XZ · ALS-XY-Wing · ALS-XY-Chain · Sue de Coq · Death Blossom |
| Miscellaneous | Aligned Pair Exclusion · Fireworks · Tridagon (per-position impossibility proof) |
| Last resorts | Exocet (per-position template proof) · ≈ Double Exocet · Pattern Overlay · Nishio / Digit / Cell / Unit forcing · Forcing Net with intersections |
Not implemented, by editorial decision (still visible in-app, marked ✗): Twinned XY-Chains and SK Loops (historical patterns subsumed in practice by the AIC/ALS engines) and the generic linear Forcing Chain entry (AICs and Nice Loops are its linear forms; its net forms are implemented). These are documented decisions, not gaps — contributions welcome, see Adding a technique.
No technique ships unless it is fully understood and machine-verified.
- A soundness harness (tests/soundness.test.ts) solves batches of generated puzzles and probes every finder at every position: a step's placements must match the brute-force solution and its eliminations must never remove a solution digit. A finder that ever contradicts a solution fails the suite.
- Expensive finders get the same treatment on dedicated hunts (tests/hunt-heavy.test.ts).
- Rare patterns additionally get deterministic synthetic-position tests.
- The hardest patterns carry per-position proofs: every Exocet step re-proves its base/target relation by exhaustive digit-template enumeration, and every Tridagon step re-proves the local impossibility by exhaustively assigning the trio to the twelve pattern cells.
Requires Node 18+.
npm install
npm run dev # http://localhost:5173
npm test # engine, generator, practice and soundness tests
npm run build # production build + PWA service worker + static pagesnpm run build ends by generating the static pages (the technique guide,
glossary, rating explainer and landing pages) and sitemap.xml into dist/.
They are not served by npm run dev; to look at them, build and then run
npx wrangler dev. How they are made, and what to do after adding or
renaming a technique, is in docs/search.md.
Positions and steps travel between players as text, so sudokUI reads and
writes the formats the community, and HoDoKu, use
(src/content/textGrid.ts, src/content/eureka.ts,
src/content/importLinks.ts).
Import reads
- the 81-character puzzle string, dots or zeros for empty cells, with whatever frame is drawn around it;
- a link from SudokuPad (
sudokupad.app/scl…,/fpuzzles…or/scf…; a short id such assudokupad.app/6dP4FN27HBneeds SudokuPad's own lookup and is refused), f-puzzles (f-puzzles.com/?load=…), Sudoku Exchange (sudokuexchange.com/play/?s=…, long or shortened) or sudoku.coach (sudoku.coach/en/play/…), and the app's own/p/links, pasted on their own or inside a sentence; a variant puzzle (cages, thermometers, extra rules) is refused with what it carries; - the pencil-mark grid: nine rows of nine cells, a placed digit or the
cell's candidates in each, with or without box lines, drawn with
.,:,'and-(HoDoKu and most forum posts) or+and-(SudokuWiki); the candidates become centre marks under the exhaustive contract, so hints continue from them. A cell written as one digit is read as placed, as the forums read it; - HoDoKu's library string,
:0000:x:<81 cells>:<deleted candidates>:…, placed digits marked+and deleted candidates asdRCcodes (418= the 4 of r1c8); - the 81-character line followed by one candidate token per cell, or by
the
dRCcodes of the candidates removed.
Share → Position as text writes the pencil-mark grid as HoDoKu writes it, showing what the board shows (auto candidates, or your marks when they are your remaining candidates, else every candidate):
.-------------.-------------.-------------.
| 2 13 8 | 7 9 5 | 6 13 4 |
| 6 137 147 | 8 2 34 | 17 9 5 |
| 9 5 47 | 6 1 34 | 2 37 8 |
:-------------+-------------+-------------:
| 7 9 5 | 4 3 2 | 8 6 1 |
| 1 2 3 | 9 6 8 | 5 4 7 |
| 4 8 6 | 1 5 7 | 3 2 9 |
:-------------+-------------+-------------:
| 8 4 2 | 3 7 1 | 9 5 6 |
| 3 6 17 | 5 8 9 | 4 17 2 |
| 5 17 9 | 2 4 6 | 17 8 3 |
'-------------'-------------'-------------'
Hint → Copy step writes the technique's name and one line of notation.
A chain is Eureka notation: = a strong link, - a weak one, a group as
(2)r3c23, an ALS as (8=9){r78c8}, a continuous loop ending - loop:
XY-Chain: (4=3)r1c6 - (3=1)r5c6 - (1=6)r5c7 - (6=4)r2c7 => r1c9<>4
Every other technique is written the way HoDoKu writes it, the pattern
then => what it does, placements as r1c1=5 and removals as r1c1<>5:
X-Wing: 7 r38 c38 => r2c3<>7
Naked Pair: 2,5 in r9c27 => r9c6<>5
ALS-XZ: A=r8c2,r9c1 {159}, B=r7c8,r8c9 {159}, X=1, Z=5 => r7c1<>5
What the app is for, and the road ahead in order, is in docs/goals.md. A guided tour lives in docs/architecture.md; the production deployment runbook (Cloudflare Workers Builds) is docs/deployment.md.
src/
engine/ framework-free TypeScript solving engine
board.ts bitmask grid model, units/peers/candidates
bruteForce.ts backtracking solver + solution counter
ratings.ts technique catalogue: scores, difficulty bands, ordering
humanSolver.ts applies techniques in order, rates puzzles
generator.ts full-grid + hole-digging generator, targets, filters
transform.ts grid isomorphisms (how a seed is served, never twice)
worker.ts Web Worker for background generation & pooling
techniques/ one module per technique family, documented finders
content/ the written content: technique explanations, glossary,
rating explainer, worked examples, and the builder
that turns them into static pages; home.ts and share.ts
render the home pages and the share pages; dailies.ts
and dailies.json, the published daily puzzles
state/ zustand stores: game, settings, puzzle pools, the
daily's global times
ui/ React components: SVG board, controls, dialogs
worker/ the Cloudflare Worker: renders /p/<puzzle> and
/daily/<date> share pages, serves the daily's API over
D1 (daily.ts), hands everything else to the static files
migrations/ the D1 schema (applied by hand, docs/deployment.md)
scripts/ build-learn (static pages), hunt-examples (worked
examples), measure-frequency (how often each
technique is needed), build-seeds (the seed library),
bench-generator, og-card and og-share-cards (social
cards), promo screenshots
tests/ vitest suites incl. the soundness harness & hunts
The engine has no DOM or framework dependencies — it runs identically in the
browser, in a worker, and under Node in tests. Grids are flat typed arrays
(Uint8Array values, Uint16Array 9-bit candidate masks), so the whole
solver is allocation-light and rates most puzzles in a few milliseconds
(the monsters past 3000 take most of a second).
Bug reports, feature requests and technique contributions are all welcome — open an issue at github.com/AImenes/sudokUI/issues.
Every module starts with a documentation comment explaining the technique or
subsystem it implements, usually with a link to the reference definition
(sudokuwiki.org or HoDoKu). Reading src/engine/techniques/ top to bottom is
meant to double as a course in advanced sudoku solving.
- Write a finder in
src/engine/techniques/returning aStep(placements, eliminations, highlight data, human-readable description). - Register it in
humanSolver.tsand flipimplemented: trueinratings.ts. - Run
npm test— the soundness harness automatically validates the new finder wherever it fires. Add a synthetic-position test if the pattern is rare in random puzzles. - Explain it: add its entry to
src/content/techniqueDocs.ts(the type system insists on one per technique) and its address to the slug snapshot intests/content.test.ts. If it is another technique in disguise (a Hidden Single is a 1-fish), say so insrc/content/kin.ts. Runnpx vite-node scripts/hunt-examples.tsto find it a worked example.
Not done yet: the repository holds no native project. These are the steps for wrapping the web build with Capacitor when the time comes.
npm install @capacitor/core @capacitor/cli @capacitor/ios @capacitor/android
npx cap init sudokUI app.sudokui --web-dir dist
npm run build
npx cap add ios && npx cap open ios # Xcode
npx cap add android && npx cap open android # Android StudioToward the best open-source sudoku tool anywhere:
- Photo import — scan a puzzle from a newspaper or book with the camera (see docs/photo-import.md)
- Teacher / annotation mode — arrows, shapes and freehand drawing over the board for streams and classroom use
- Statistics & streaks — local solve history, per-technique mastery tracking; plays are counted without identifying anyone (two anonymous lines per game, an opt-in for offline ones, everything on sudokui.app/privacy); daily archive pages next (see docs/online-goals.md, phase 4); never accounts
- Curated library — classic named puzzles (Escargot, Golden Nugget…) and a daily puzzle per difficulty band, next to today's shared daily
- Custom solve-order editor — reorder/disable techniques and see how ratings change; export your own rating profile
- Accessibility & i18n — full screen-reader support, colour-blind-safe palettes, translated UI and hint text
- Native builds — ship the Capacitor iOS/Android wrappers to the stores
- Variants — Killer, X-Sudoku, Chaos/irregular boxes (engine units are already abstracted as cell lists)
The rating model (per-technique scores and difficulty bands) and much of the
technique semantics follow HoDoKu by Bernhard Hobiger; several newer
strategies follow the definitions documented at sudokuwiki.org. sudokUI
is an independent implementation, released under the GPL-3.0 license
(see LICENSE). The link import decodes f-puzzles and SudokuPad
payloads with a port of the base64 flavour of lz-string by pieroxy
(src/content/lzString.ts; MIT licence, copyright 2013 pieroxy).