Scrabbdict is an iOS dictionary helper for word games. It can validate a word, find words that can be built from a set of tiles, and search dictionaries with a simple ? wildcard pattern.
The app is written in Swift and SwiftUI. State management uses The Composable Architecture, and analytics/crash reporting use Firebase.
© 2013-2026 Piotr Sochalewski
Scrabbdict is an independent, non-commercial hobby project. The developer does not derive profit from the application and has no affiliation, association, authorization, sponsorship, or endorsement from Hasbro, Mattel, NASPA Word List, Collins Coalition, Éditions Larousse, Polska Federacja Scrabble, Wydawnictwo Naukowe PWN or any other owner or publisher of the referenced word lists, trademarks, or related intellectual property.
All trademarks, service marks, trade names, word list names, and other protected designations referenced in or in connection with this application are the property of their respective owners. Their use is for identification and compatibility purposes only and does not imply any relationship with, or endorsement by, the respective owners.
The project source code is licensed under the Apache License, Version 2.0. See LICENSE.
The maintainer may continue to sign and publish the official App Store version independently. The app name, icon, App Store listing, bundle identifier, and backend configuration are not covered by the open source license.
This repository does not include full dictionaries because of licensing restrictions. It includes only small sample dictionaries: each sample contains approximately 0.0001 of the most popular words for the given language.
To build or test Scrabbdict with complete dictionary behavior, provide your own word lists and regenerate the DAWG files. You can also use the checked-in samples for development, but they are intentionally incomplete. Local tests are allowed to fail when run without full dictionaries.
Scrabbdict/- the iOS app target.Scrabbdict/Modules/- app modules with SwiftUI views, TCA reducers, and module-local subviews.Scrabbdict/Modules/App/- app entry point and application delegate.Scrabbdict/Modules/Scrabbdict/- main dictionary search module.Scrabbdict/Modules/Settings/- settings module.Scrabbdict/Services/- dictionary loading, validation, analytics, Crashlytics, and local storage clients.Scrabbdict/Models/- app domain models such asLanguage,Word, andSearchMode.Scrabbdict/Resources/- bundled app resources, including asset catalogs, localization, Settings metadata, and dictionaries.Scrabbdict/Resources/Dictionaries/- generated binary dictionary files used by the app, copied from.dictionaries/DAWGor.samples/DAWG.DAWGBuilder/- command-line generator that converts zipped.txtword lists into compact.dawgfiles.DAWGBuilder/RAW/- local ignored source word list archives copied from.dictionaries/RAWor.samples/RAW..samples/- checked-in sample.dawgand source.zipdictionary files used when the private dictionary submodule is unavailable.ScrabbdictTests/- unit, feature, and snapshot tests grouped by area.Marketing/AppStore/Scrabbdict.butterkit/- App Store screenshot project and exported PNG assets.Scripts/dawg- helper script that builds and runsDAWGBuilder.Scripts/swiftformat-lint.sh- Xcode build phase script that checks Swift formatting.Makefileand.mise.toml- local development tooling setup.
- macOS with Xcode installed.
- iOS 17.0 or newer deployment target.
- Swift Package Manager support through Xcode.
- A Firebase iOS app configuration file named
GoogleService-Info.plist. - Local development tools managed by mise: SwiftFormat and
git-format-staged.
Xcode resolves the Swift Package Manager dependencies from Scrabbdict.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved.
The Xcode project includes a SwiftFormat Lint build phase. Run the project setup once before building locally:
make initThat installs or verifies mise, installs the tools pinned in .mise.toml, and installs a pre-commit hook that formats staged Swift files.
Useful commands:
make format
make format-lintApp Store screenshots are maintained with ButterKit. The editable ButterKit project and exported PNG assets live under:
Marketing/AppStore/Scrabbdict.butterkit
The exported screenshots are part of the repository assets and should be regenerated from the ButterKit project when App Store presentation copy, device frames, or screenshot content changes.
The app imports Firebase Analytics and Crashlytics. To build your own copy, you must provide your own Firebase configuration:
-
Create or open a Firebase project.
-
Add an iOS app in Firebase using the bundle identifier you intend to build with. The checked-in project currently uses
pl.sochalewski.Scrabbdict. -
Download
GoogleService-Info.plist. -
Place it at:
Scrabbdict/GoogleService-Info.plist
For public forks, do not commit production Firebase credentials or service configuration unless you intentionally want that Firebase project to be used by other builds. A common approach is to keep a local GoogleService-Info.plist and commit a sanitized example file instead.
- Clone the repository.
- Run
make init. - Add your own
Scrabbdict/GoogleService-Info.plist. - Open
Scrabbdict.xcodeprojin Xcode. - Let Xcode resolve packages.
- Select the
Scrabbdictscheme. - Select an iOS simulator or a signing-capable device.
- Build and run from Xcode.
If you use a different Apple developer team or bundle identifier, update the target signing settings in Xcode before building for a device.
Open the project in Xcode, select the Scrabbdict scheme, and run the test action. The active test plan includes unit tests, feature reducer tests, and snapshot tests. Performance tests are kept in the plan but skipped by default.
The test plan is stored at:
ScrabbdictTests/Scrabbdict.xctestplan
Snapshot references are stored under:
ScrabbdictTests/Snapshots/__Snapshots__/
The repository samples are not full dictionaries. Tests that depend on complete word-list coverage may fail locally until you provide full dictionaries and regenerate the corresponding .dawg files.
Scrabbdict does not search raw text files at runtime. Instead, each word list is compiled into a DAWG: a Directed Acyclic Word Graph. A DAWG is similar to a trie, but equivalent suffix subgraphs are merged, so common endings are stored once instead of repeated for many words.
The generator in DAWGBuilder/ works broadly like this:
- Read a UTF-8
.txtword list from a.ziparchive, one word per line. - Sort the words.
- Insert each word into an incremental graph builder.
- Minimize completed branches by reusing previously seen equivalent nodes.
- Write a compact little-endian binary file with:
- a header containing magic/version/counts,
- a small alphabet table,
- a node table,
- an edge table.
The app loads generated .dawg files with memory-mapped Data when possible. Validation walks graph edges for an exact word. Tile search performs a depth-first traversal while consuming available letters. Pattern search treats ? as a single-character wildcard.
At a high level, the DAWG v3 binary layout is:
- header: magic, version, word count, node count, edge count, and alphabet count,
- alphabet table: the distinct
UInt16Unicode scalar values used by edge labels, - node table: each node stores
firstEdgeasUInt32and a packedUInt16edge count, with the high bit reserved as the word-terminating flag, - edge table: each edge stores a
UInt8alphabet index and a 24-bit little-endian target node index.
The binary format is defined in DAWGBuilder/DAWGBuilder.swift and read by Scrabbdict/Services/DAWG.swift.
Use the helper script from the repository root:
Scripts/dawgThat compiles DAWGBuilder with xcrun swiftc and writes generated dictionaries to:
Scrabbdict/Resources/Dictionaries/
Generate only selected languages:
Scripts/dawg pl_OSPS
Scripts/dawg en_US_nwl fr_ODSUse custom input or output directories:
Scripts/dawg --input-dir /path/to/word-lists --output-dir /tmp/dawgInput files are matched by language/file stem. By default, Scripts/dawg reads from DAWGBuilder/RAW. For example, pl_OSPS expects:
DAWGBuilder/RAW/pl_OSPS.zip
and produces:
Scrabbdict/Resources/Dictionaries/pl_OSPS.dawg
The app currently references these language identifiers:
en_GB_csw- English CSW-style (formerly SOWPODS) word list.en_US_nwl- English NASPA-style (formerly OTCWL) word list.fr_ODS- French ODS-style word list.pl_OSPS- Polish OSPS-style word list.
Names, descriptions, and language-specific behavior are defined in Scrabbdict/Models/Language.swift.
User-visible translations are maintained in:
Scrabbdict/Resources/Localizable.xcstrings
Keep locale-specific wording in the string catalog, but keep dictionary metadata that must stay identical across translations in code. In particular, dictionary word counts are defined as numeric values in Scrabbdict/Models/Language.swift and are injected into localized strings after locale-aware number formatting. Do not duplicate formatted word counts manually in each translation.
When updating dictionary names or descriptions, update all supported locales together (en, fr, and pl) and keep protected dictionary names, abbreviations, trademarks, and source names unchanged unless the underlying dictionary source changes. The string catalog comments mark terms that should not be translated.
User-visible third-party notices are maintained in:
Scrabbdict/Resources/Settings.bundle/Root.plist
When Swift Package Manager dependencies used by the app at runtime change, update that file to match Package.resolved. Test-only dependencies, such as snapshot testing tools, do not need to appear in the user-visible Settings bundle unless they become part of the shipped app.
- Keep generated
.dawgfiles in sync with their source.zipword list archives when changing dictionary data. - Keep legal notices and third-party notices current when changing dependencies, assets, or app branding.
- Prefix commit messages with
[AI]when the commit mainly contains AI-generated code, for example[AI] Optimize DAWG performance. - Do not commit personal signing credentials, provisioning profiles, private API keys, or production service configuration for forks.



