# PLAYFORM offline vocabulary

`manifest.json` schema 1 / datasets 1.0.0 describes nine languages. The five new datasets live in `datasets/<language>/words.json`; the existing four are references to unchanged word-engine dictionaries. Full pinned originals and upstream notices are in `sources/`. These are separately licensed data files, not game rules.

Run `python3 factory/dictionaries/tools/build.py` to regenerate offline. Run `python3 factory/dictionaries/tools/test_integrity.py` for integrity and reproducibility checks. Sources must be explicitly updated and reviewed; building never downloads. Manifests include source versions, revisions, original/filtered/rejected counts, reasons, SHA-256 hashes, locale policy, licensing and age metadata. Portuguese uses VERO Brazilian Portuguese (`pt-BR`) only.

Python consumers import `vocabulary.py`, call `load('pt', minimum=3, maximum=8)`, and use `normalize`/`valid`. `load` checks hashes. Godot consumers copy `runtime/` to `addons/playform_dictionaries/` and run `python3 factory/dictionaries/tools/package_godot.py pt /tmp/vocabulary` to produce a game-independent per-length pack, copy it into their project, and configure `language.root` to its packaged vocabulary root. `dictionary.gd` performs character validation and membership; no neighbor graph, transformations, hints, Solve or puzzle rules are imported. The word-engine retains compatible wrapper scripts and OneLetter-specific age pools, graphs and starts.

Normalization uses NFC and uppercase without accent stripping. Python handles complete Unicode NFC; Godot handles canonical base-plus-mark composition for the supported Latin alphabets. Unsupported combining sequences fail validation. Length counts Unicode scalars after normalization, not bytes; all accepted letters are one scalar. ß stays ẞ. Swedish Å/Ä/Ö are distinct. Dutch IJ remains two letters, not a ligature. Uppercase proper names are filtered in new headword lists, and Hunspell affix-only/forbidden flags are respected. No affix forms are invented.

There is no reliable educational age data. New OneLetter minor pools use existing length caps, ASCII-only headwords and explicit taboo exclusions. This is a mechanical conservative filter, not a claim of age suitability; a native-speaker content review is still required before release. Adults retain all supported accents. Sparse combinations are unavailable rather than fabricated.

Connect the Words should consume `load` or the standalone Godot dictionary loader, then implement its own relationships and generation. It must not import OneLetter neighbor/chain/Hint/Solve rules. Shared words can be filtered by length and custom reviewed allowlists; age metadata is null when unsupported.

Redistribution: preserve upstream license and attribution notices, complete corresponding originals, generated datasets and modification scripts. Italian GPL-3.0; Portuguese MPL-2.0; Dutch BSD-3-Clause; Indonesian LGPL-3.0-only; Swedish LGPL-3.0. Licenses apply to separately distributed data; retain modifiable data files. OneLetter packages notices as exported text resources, and complete corresponding source in the release companion directory. Release builds also retain a `dictionary-sources` companion directory. Review distribution/store conditions before first publication.

Startup reuse: `factory/scripts/generate-startup-branding.py LOGO ICON OUTPUT` proportionally resizes existing artwork; generates a native iOS aspect-fit launch image, Godot boot logo and Android system-splash safe image. Android square artwork occupies 45% of the canvas, fitting inside the 2/3-diameter mask-safe circle. It does not change launcher assets. Factory release configuration opts in with `startup_branding.logo`.
