open-standards/aac/aac-rs/tools/pagesets/DESIGN-core.md
2026-10-15 13:15:15 -04:00

42 KiB
Raw Permalink Blame History

Growing Core — design

A core vocabulary that grows from one button to eighty without any word leaving the place it lives. It is our own: its words come from open research lists and spoken frequency, its layout from a stated rule and a solver, and no word, position, wording or name comes from Core First, Crescendo, Super Core, WordPower, Gateway, Essence or any other vendor set.

  • Source: data/growing-core.yaml (what is in the set and when it appears), data/growing-core.layout.yaml (where everything sits, solved once and reviewed), data/lexicon.en.yaml (every word's class and sense).
  • Output: one .obz package per size (growing-core-<size>.obz), plus two hide-and-reveal examples. Packages are not committed: catalog.py builds them wherever they are served (the site's build, into /app/models/pagesets/, each named by its content), and aac-core's tests build them for themselves. What is committed is the catalogue, aac-rs/data/pagesets/index.json, which names each package with its size and SHA-256 and is compiled into the app.
  • Check: python3 tools/pagesets/build.py --check (the tables below), python3 tools/pagesets/catalog.py --check (the packages the sources build are the ones the catalogue names; the site's build runs it and fails otherwise), and cargo test -p aac-core --test pagesets.
  • Rebuild: python3 tools/pagesets/build.py (the tables), catalog.py --write (the catalogue), build.py --out DIR (the packages, for a look); Python 3.11+ and PyYAML, no network. Re-solve the layout: python3 tools/pagesets/solve.py core, which reproduces the committed one byte for byte; any change to the design means re-solving, reviewing the grids, and committing the layout and the catalogue with it.

Tables between <!-- table:… --> markers are written by build.py from the packages the sources build; do not edit them by hand.

1. How it grows

One point per word

Every item on the core lives at one point (v, u) of the screen, v down and u across, each from 0 to 1. On any grid R × C it is drawn in the cell that contains its point: row ⌊v·R⌋, column ⌊u·C⌋. So:

  • A word's place at every size is a function of its point alone. Nothing about growing to a bigger grid can move it anywhere else.
  • Every button a word has, at every size, contains the same point. A word learned at 3×3 in the top right is in the top right at 8×10, and the motor plan of reaching for it carries over.
  • On any grid a word is at most half a cell (of that grid) from its point, so between two sizes its button moves less than one cell of the smaller grid.

The ladder is 1×1, 1×2, 2×2, 2×3, 3×3, 3×4, 4×5, 5×6, 6×8, 7×9, 8×10 (eleven sizes; 1×1 and 1×2 are both there, for a first switch-like button and a first choice).

Stages, and a board that is full at every size

Each item has a stage, the first size at which it appears. The number of items per stage is exactly the growth in cells — 1, 1, 2, 2, 3, 3, 8, 10, 18, 15, 17 = 80 — and no two items whose stages have been reached ever fall in one cell. Together those make every board full at every size, and mean nothing that appeared at a smaller size is ever pushed out at a larger one.

Points are not free. Going from 6×8 to 7×9 merges cells of an 8×10 grid that 6×8 keeps apart (rows 3–4 and columns 4–5 of 8×10 fall in one 7×9 cell, but in four 6×8 cells), so no layout that puts words on 8×10 cell centres can keep every size full: that was the first design, and it is provably impossible. The fix: a word lives in an atom, one rectangle of the common refinement of all eleven sizes' cell boundaries (22 × 26 atoms), which never straddles a cell boundary of any size. pslib/grid.py has the rule; pslib/solve.py the search.

The first boards are designed; the rest is solved

The boards a beginning communicator sees first are designed by hand, as anchors in growing-core.yaml, and the solver must keep them exactly:

1x2:  stop | more
2x2:  go   | more        2x3:  go   | like | more
      stop | help              stop | not  | help

3x3:  I    | want | more            3x4:  I    | you  | want | more
      go   | like | all done              what | go   | like | all done
      stop | not  | help                  stop | that | not  | help

4x5:  I    | you  | want | more     | Social ▸
      what | go   | like | all done | Food ▸
      it   | look | yes  | no       | in
      stop | that | not  | help     | up

Why these:

  • 1×1 "more" and 1×2 "stop | more": a request to continue and a way to end. Both are in Universal Core, and "more" is in Banajee et al. (2003); they work in every activity, which is the point of a first word (Project Core's principle: core words usable everywhere, no nouns).
  • 2×2 adds "go" and "help": starting something, and asking for a person.
  • 2×3 adds "like" and "not": a comment and its negation.
  • 3×3: the top row reads as a sentence, "I want more"; each word added since 2×2 stayed in the region it had.
  • 3×4 adds "you", "that" and "what": the other person, pointing, asking.
  • 4×5 adds yes/no side by side in the middle, "it", "look", two place words, and the first two pages — Social (greetings and repairs) and Food — on the right edge, where every page key will be.

Each anchor fixes a rectangle of points; their intersection, for every word, is non-empty (the solver refuses anchors that contradict each other).

From 5×6 on, the solver places the remaining 60 items in their regions: Fitzgerald Key order left to right, as in an English sentence — questions, people, actions, describing words, little words and place words — with yes/no/not near the top and every page key on the right edge (regions in the design). A region is a target, weighted more for items that appear earlier (they appear at more sizes); the hard rules are the anchors and fullness.

Stage New Words (U: Universal Core, B: Banajee et al. 2003, #: spoken rank)
1x1 1 more (U, B, #103)
1x2 1 stop (U, #151)
2x2 2 go (U, B, #42); help (U, B, #132)
2x3 2 like (U, #39); not (U, #25)
3x3 3 I (U, B, #2); want (U, B, #56); all done (U, B, #–)
3x4 3 you (U, B, #1); that (U, B, #8); what (U, B, #12)
4x5 8 it (U, B, #6); yes (B, #73); no (B, #24); up (U, #48); in (U, B, #11); look (U, #78); Social ▸; Food ▸
5x6 10 do (U, #22); make (U, #106); get (U, #40); put (U, #161); open (U, #323); turn (U, #332); on (U, B, #19); good (U, #67); People ▸; Feelings ▸
6x8 18 all (U, #33); can (U, #30); different (U, #393); same (U, #229); he (U, #16); she (U, #41); here (U, B, #37); some (U, B, #93); when (U, #74); where (U, #82); who (U, #68); why (U, #69); my (B, #18); eat (#353); play (#316); out (B, #46); Places ▸; Actions ▸
7x9 15 is (B, #10); will (#61); see (#65); have (#20); need (#99); me (#14); your (#21); we (#13); they (#38); the (B, #3); a (B, #5); and (#7); to (#4); off (B, #121); Things ▸
8x10 17 this (#15); know (#29); come (#54); now (#51); again (#145); there (#36); back (#77); little (#113); with (#31); for (#17); of (#9); down (#105); don't (#28); how (#59); Describe ▸; Time ▸; Word forms ▸

The boards at every size (▸ opens a page):

1x1

| more |

1x2

| stop         | more |

2x2

| go           | more |
| stop         | help |

2x3

| go           | like         | more |
| stop         | not          | help |

3x3

| I            | want         | more |
| go           | like         | all done |
| stop         | not          | help |

3x4

| I            | you          | want         | more |
| what         | go           | like         | all done |
| stop         | that         | not          | help |

4x5

| I            | you          | want         | more         | Social▸ |
| what         | go           | like         | all done     | Food▸ |
| it           | look         | yes          | no           | in |
| stop         | that         | not          | help         | up |

5x6

| I            | you          | good         | want         | more         | Social▸ |
| what         | go           | get          | like         | all done     | Feelings▸ |
| turn         | put          | do           | yes          | on           | Food▸ |
| it           | that         | look         | no           | in           | People▸ |
| open         | stop         | make         | not          | help         | up |

6x8

| where        | he           | you          | good         | want         | all          | more         | Social▸ |
| why          | I            | my           | get          | some         | same         | Feelings▸    | Actions▸ |
| what         | when         | go           | do           | like         | different    | all done     | Food▸ |
| who          | turn         | put          | look         | yes          | on           | in           | People▸ |
| it           | stop         | that         | eat          | not          | no           | help         | Places▸ |
| she          | open         | can          | make         | play         | here         | up           | out |

7x9

| where        | he           | you          | is           | want         | all          | more         | the          | Things▸ |
| why          | I            | my           | get          | good         | some         | same         | Feelings▸    | Social▸ |
| what         | me           | go           | do           | like         | different    | all done     | a            | Actions▸ |
| who          | when         | they         | will         | see          | yes          | on           | and          | Food▸ |
| it           | turn         | put          | look         | eat          | need         | to           | in           | People▸ |
| we           | stop         | that         | make         | not          | no           | help         | up           | Places▸ |
| she          | open         | your         | can          | have         | play         | here         | out          | off |

8x10

| where        | he           | don't        | is           | back         | want         | all          | the          | Word forms▸  | Things▸ |
| why          | I            | you          | again        | good         | some         | same         | more         | for          | Social▸ |
| what         | know         | my           | go           | get          | like         | down         | all done     | Feelings▸    | Actions▸ |
| how          | when         | me           | do           | see          | now          | different    | a            | Time▸        | Food▸ |
| who          | turn         | they         | put          | will         | yes          | there        | on           | and          | People▸ |
| we           | it           | come         | look         | eat          | need         | no           | to           | in           | Describe▸ |
| this         | stop         | that         | make         | have         | not          | of           | help         | up           | Places▸ |
| she          | open         | your         | can          | little       | play         | with         | here         | out          | off |

Hide and reveal at a fixed size

Location-centred growth — start at the largest grid a person can see and reach, show a few words, reveal more over time — needs nothing new: a word's reveal step is its stage. A person on the 8×10 board "at the 3×3 stage" sees exactly the nine 3×3 words, each in the region it had at 3×3, and every other cell hidden in place (SPEC §3 item 3, §3.1 item 3). Revealing the next stage shows the three 3×4 words, then the eight of 4×5, and so on. Every button carries its stage (ext_aurasense_pageset.stage), so the app reveals any stage without another file: the chooser's "Start with fewer words on a bigger board" picks a size and a stage, and aac_core::pagesets::reveal sets Cell.hidden from each button's stage before the boards are added (the test holds it to the generator's own reveal packages, two of which ship as examples for other OBF apps). Track B's "Show hidden words for now" shows every word in its place and hides them again; Edit mode reveals a word for good.

2. The words

Sources

Only open sources, each cited in sources/catalog.yaml and in every package's manifest:

  • Universal Core (UNC CLDS; CC BY 4.0 per UNC, CC BY-SA 4.0 per Project Core — treated as BY-SA): all 36 words are on the core by 6×8 ("finished" as "all done", the app's word that has a gloss and a symbol). Its symbols and its 6×6 layout are not used.
  • Banajee, DiCarlo & Buras Stricklin (2003), the 23 words all 50 toddlers used across activities: all but "mine" on the core by 7×9 ("mine" is on People).
  • Spoken frequency: FrequencyWords 2018 (OpenSubtitles dialogue, CC BY-SA 4.0), the best open proxy for conversation; the first 5,000 words are committed in sources/. The "top N spoken" metrics use it with clitic fragments ('s, 't), disfluencies, abbreviations and profanity left out and contraction stems read as the contraction ("don" → "don't").
  • The app's own vocabulary.rs (which cites Banajee 2003, Cross et al. 2006 and Yorkston et al. 2010): word classes, which agree with the app's everywhere but one word (below).
  • Project Core (CC BY-SA 4.0): the principle for the small grids.

The app's English pack (wordfreq) is not used for choice: it mixes Wikipedia, news and books with speech, so "government" outranks "help".

Why a word is at its stage

Small sizes are built from Universal Core and Banajee words — usable in every activity, mostly verbs and little words, no nouns. Larger sizes add what speech needs most by spoken frequency: the pronouns (he, she, we, they, me, your), the copula and modals (is, will, can, have, need), articles and connectors (the, a, and, to, of, for, with). At 8×10, 24 of the 25 most-spoken words are on the core itself ("was" is on Word forms), and 86 of the top 100 are in reach, 54 of them on the core (table in §6). Function words come late on purpose: early communicators combine core words first, and the grammar words matter most once sentences do.

Colours (Fitzgerald Key)

The Fitzgerald Key (1954) is a public method. aac-core gives every word class its colour (WordCategory::fitzgerald: the app's own defaults.rs hues, with text that reads at 4.5:1 or more on each, tested): yellow people, green actions, blue describing words, orange things, pink social words, white questions, red negation, and brown for the little words — prepositions and conjunctions, the key's "other" colour, which the app's editor calls "Little words". The sets use light tints of those hues with a strong border of the same hue and black text (contrast 13:1 or more on every tint), so colour carries the class without carrying the legibility. The class itself travels as ext_aurasense_word_class, so a high-contrast theme can recolour by class.

Role Words Background Border
people pronouns, possessives, this/that, people #FFF4C2 #A67C00
action verbs #DDF3D8 #2E7D32
describe adjectives, adverbs, some/all, feelings, time #DCEBFF #1565C0
thing nouns, places #FFE3C4 #C25E00
social social words and messages #FCE1EC #AD1457
question what, where, who, when, why, how #FFFFFF #6A1B9A
little prepositions, conjunctions, articles, endings #EFE6E1 #6D4C41
negation no, not, don't, can't, won't, didn't, never #FFD9D9 #C62828
control Back, Home #E0E0E0 #37474F

Word classes written are the app's own names, conjunction among them (added to aac-core with this work: "and", "but", "or", "because", "if", "so" are conjunctions in vocabulary.rs now); adverbs are written as "adjective", as vocabulary.rs does. Where these sets and vocabulary.rs differ:

Word These sets The app's vocabulary.rs Why
back adjective core_noun back again, as in come back or give it back (not the body part, which is what the app's glosses of back are)
clean verb adjective to clean (the verb)

Senses

The app glosses a word by its English spelling, and its glosses were audited in the sense vocabulary.rs gives each word (gloss_audit_2026-10-01). Every word here is used in that sense; the lexicon records the sense of each homograph ("right" = correct, "close" = shut, "can" = able to, "watch" = look at, "orange" = the colour), and words whose meaning a gloss would get wrong are left out ("mean", "kind", "light", "well" as an adverb).

"Back" as in "come back" (the 77th most-spoken word) joins the core at 8×10, in place of "big" (which is on Describe). Its glosses are the body part, so its cell carries sense (aac-core Cell::sense, OBF ext_aurasense_sense): its words are English only, never glossed, and in another language it is hidden in place until someone gives it a word (§4). It may sit on a page beside the Back control because the control has no words on screen: the app draws it as its arrow, with the control's word as its accessible name ("Go back", or the word in the person's language).

Symbols

Every button names the symbol the app draws for it (Mulberry first, then OpenMoji, then Bliss — the app's lookup_for_cell); the test checks each one resolves in the app's index and is the one the app draws. Page keys whose label is not a concept show an exemplar's picture (key_symbols), written as Track B's ext_aurasense_symbol. No symbol id is invented. These words and messages have no symbol yet (they show their words; adding them is the symbol track's work):

+'s, +ed, +ing, +s, ?, already, am, an, are, as, at, been, by, can't, could, did, didn't, does, excuse me, from, good morning, good night, got, had, has, hey, him, how are you, I don't feel good, I don't like it, I feel good, I like it, I need a break, I need help, I'm not finished, jump, let me think, let me try, man, mine, my turn, nervous, never mind, not +, of, oh, ouch, said, say it again, see you later, slow down, something, talk, that's not what I meant, them, then, uh oh, us, was, well, went, were, will +, won't, would, yay, yeah, your turn (68)

3. Pages of more words

Ten pages, opened from keys on the right edge of the core: Social, Food (from 4×5), People, Feelings (5×6), Places, Actions (6×8), Things (7×9), Describe, Time and Word forms (8×10). A page is the size of the core it opens from (the same target size and motor scale), and grows by the same rule: its words, in priority order, appear at its first size and then in their own places as it grows. Cells left over at the larger sizes stay empty, for the person's own words (Track B's editor places a new word only in an empty cell, so space must be left on purpose).

Page Opens from Words First words (they appear at the page's first size)
Social 4x5 37 hi, bye, please, thank you, wait, I'm not finished, that's not what I meant, sorry, okay, I don't know, say it again, how are you, …
Food 4x5 30 eat, drink, food, water, milk, juice, snack, hungry, thirsty, breakfast, lunch, dinner, …
People 5x6 38 mom, dad, friend, teacher, he, she, we, they, me, my, your, brother, …
Feelings 5x6 29 feel, happy, sad, angry, scared, tired, sick, hurt, good, bad, excited, bored, …
Places 6x8 19 home, school, outside, inside, bathroom, bedroom, kitchen, park, store, playground, pool, beach, …
Actions 6x8 78 come, think, take, tell, say, love, give, find, work, wait, call, talk, …
Things 7x9 56 toy, ball, book, game, music, TV, phone, picture, car, bed, chair, table, …
Describe 8x10 68 big, little, hot, cold, good, bad, new, old, fast, slow, different, same, …
Time 8x10 30 now, later, today, tomorrow, yesterday, morning, afternoon, night, day, week, year, time, …
Word forms 8x10 22 +s, +ed, +ing, will +, +'s, not +, ?, is, am, are, was, were, …

The price of the rule on pages: at 8×10 a page with 30 words spreads them over the whole board with gaps between, because each stays in the region it had at 4×5. A packed page would read faster but move every word when the person moves up a size. The words people say most are on the core, not on pages, so this design keeps the rule everywhere; see the decisions below.

A Back cell on every page

Every page has Back in the top-left corner, at every size; it goes to the core. The app already offers Back, Home and Help beside the board, scanned and dwelt on (SPEC §5.6), so a page does not need its own Back to be escapable. It has one anyway, for four reasons:

  1. Scanning cost. The navigation is scanned after the board by default, so leaving a page by it costs a full pass of the rows first; the top-left cell is the first a row-column scan reaches (2 steps).
  2. One place, every page. The way back is in the same place on every page and every size: a motor plan of its own.
  3. Open Board Format. The sets are for any OBF app; most do not scan or dwell on their own back button.
  4. Paper. A printed page needs its way back on the page.

It costs one cell per page. The top-left corner is the worst place for a webcam gaze user (the edge), who has the navigation bar instead. It is drawn as its arrow (the app's nav:back symbol, mirrored in right-to-left languages), with no words on screen; its accessible name is the control's word in the person's language where both readers agreed on it (aac-core/src/nav_labels.json), "Go back" otherwise — never the gloss of "back", which is the body part (SPEC §5.6 item 5). The navigation words moved from aac-web into aac-core with this work, so the app and its Open Board Format export share them: Back and Home cells are exported with the control's word in every language, never a gloss.

Social messages

Greetings (hi, bye, how are you, see you later, good morning, good night), politeness (please, thank you, sorry, excuse me, you're welcome), feelings as messages (I feel good, I don't feel good, I like it, I don't like it, I love you), turn-taking (my turn, your turn, let me try, let me think) and repairs first: wait, I'm not finished, that's not what I meant, say it again, I don't know, never mind, slow down, I need a break, I need help. Wait, I'm not finished, that's not what I meant, say it again and I don't know are among the page's first nineteen words, so they are there from 4×5; the rest of the repairs come at 5×6. These speak at once like any cell; a message bar that would let them skip the message (a "say now" action) is a Track B/C decision, not a page-set one.

Word forms

What the app has today: grammar endings that act on the last word of the message (GrammarModifier: +s, +ed, +ing, will, 's, not, ?), English-regular only (D11). The Word forms page (8×10) has those seven and, until irregular forms exist, the irregular forms people say most as whole words: is, am, are, was, were, be, been, has, had, did, does, didn't, got, went, said.

Where the endings get the sets' own words wrong (the lexicon records the right form for every word whose ending is irregular or changes its spelling; this table is computed against the app's apply_modifier):

Word Ending The app says Correct
be present-progressive bing being
bring past bringed brought
build past builded built
buy past buyed bought
carry past carryed carried
catch past catched caught
choose past choosed chose
come past comed came
cut past cuted cut
cut present-progressive cuting cutting
do past doed did
draw past drawed drew
drink past drinked drank
drive past drived drove
eat past eated ate
feel past feeled felt
find past finded found
fish plural fishes fish
foot plural foots feet
forget past forgeted forgot
forget present-progressive forgeting forgetting
get past geted got
get present-progressive geting getting
give past gived gave
go past goed went
have past haved had
hear past heared heard
hold past holded held
hug past huged hugged
hug present-progressive huging hugging
hurt past hurted hurt
keep past keeped kept
know past knowed knew
leave past leaved left
let past leted let
let present-progressive leting letting
lose past losed lost
make past maked made
man plural mans men
pay past payed paid
put past puted put
put present-progressive puting putting
read past readed read
ride past rided rode
run past runed ran
run present-progressive runing running
say past sayed said
see past seed saw
see present-progressive seing seeing
send past sended sent
sing past singed sang
sit past sited sat
sit present-progressive siting sitting
sleep past sleeped slept
stand past standed stood
stop past stoped stopped
stop present-progressive stoping stopping
swim past swimed swam
swim present-progressive swiming swimming
take past taked took
teach past teached taught
tell past telled told
think past thinked thought
throw past throwed threw
try past tryed tried
understand past understanded understood
wake up past wake uped woke up
wake up present-progressive wake uping waking up
win past wined won
win present-progressive wining winning
worry past worryed worried
write past writed wrote

Plan for irregular forms (UniMorph):

  1. Data: per language, a table lemma → {feature bundle → form}, from UniMorph (https://github.com/unimorph; English is CC BY-SA 3.0, adaptable under 4.0; check each language's licence, most are Wiktionary-derived). Ship only the lemmas of the person's vocabulary (a few thousand rows per language), content-hashed beside the language packs.
  2. Mapping: GrammarModifier → UniMorph features — Plural → N;PL, PastTense → V;PST, PresentProgressive → V;V.PTCP;PRS (English adds "be"), FutureTense → V;FUT where the language inflects it (Spanish irá) and the periphrasis where it does not (English will), Possessive → the language's own construction. Fall back to today's regular rule only where the table has no row, and say so.
  3. A Word Forms page that re-inflects the last word: show that word's forms from the table as cells (went, gone, going, goes), so a person picks the form instead of an ending; the endings stay for words the table lacks.
  4. The lexicon's forms here become the English test vectors.
  5. Order: English plus the ten largest languages first, as the gap report says (§4 item 16).

4. Languages

The sets are English (ValidatedNativeCorpus). In every other language the app shows its glosses of the English words: GlossOnly (SPEC §4.1), never that language's core vocabulary, and the chooser says so before a set is added, with the share of the set's words that have words in the language.

On these sets, a word with no word in the person's language is hidden in place (SPEC §4.1 item 4, proposed): they are made to be glossed, and their cells carry ext_aurasense_pageset. Nowhere else is a word hidden for want of a gloss: the app's own boards, the person's own and imported boards and the phrase sets show such a word in English, marked lang="en" and said by an English voice (aac-web translate::cell_words). The gaps are mostly English function words that many languages do not have as words ("is", "the", "of", "and"), which is exactly why a gloss is not a core; and the social messages, which have no whole-phrase glosses yet. In Edit mode such a cell shows "No Spanish word yet" (in the language's name) over its English key, so a partner can give it their own words there (Track B's lang: the person's own words, never glossed); showing hidden words for now does not show it, since there is nothing to show. A page key is never blank: with no name of its own in the language it shows the name of the board it opens there, else its English name, marked as English (lang="en", said by an English voice) — hiding is for words, never for the way around. build.py --out writes languages.json: per language, every word and message without a gloss, the page keys without a name, the control words, and the work needed.

Code Language Core status Prediction pack Growing Core words glossed Fixed Paths words glossed Published native core list exists
en English ValidatedNativeCorpus multi_source source source –
es Spanish GlossOnly multi_source 90% (87% by use) 88% (83% by use)
fr French GlossOnly multi_source 90% (87% by use) 88% (83% by use)
de German GlossOnly multi_source 90% (87% by use) 88% (83% by use)
pt Portuguese GlossOnly multi_source 90% (87% by use) 88% (83% by use)
it Italian GlossOnly multi_source 90% (87% by use) 88% (83% by use)
nl Dutch GlossOnly multi_source 90% (87% by use) 88% (83% by use)
zh Chinese (Simplified) GlossOnly multi_source 90% (82% by use) 88% (78% by use) yes
ja Japanese GlossOnly multi_source 89% (78% by use) 88% (75% by use)
ko Korean GlossOnly single_source 89% (78% by use) 88% (75% by use) yes
ar Arabic GlossOnly multi_source 89% (82% by use) 88% (78% by use) yes
he Hebrew GlossOnly multi_source 89% (81% by use) 87% (78% by use) yes
ur Urdu GlossOnly multi_source 90% (87% by use) 88% (83% by use)
fa Persian GlossOnly multi_source 90% (87% by use) 88% (83% by use)
hi Hindi GlossOnly multi_source 90% (82% by use) 88% (78% by use)
bn Bengali GlossOnly multi_source 90% (87% by use) 88% (83% by use)
ta Tamil GlossOnly multi_source 90% (87% by use) 88% (83% by use)
te Telugu GlossOnly single_source 90% (87% by use) 88% (83% by use)
ml Malayalam GlossOnly single_source 90% (87% by use) 88% (83% by use)
mr Marathi GlossOnly sparse 90% (87% by use) 88% (83% by use)
kn Kannada GlossOnly none 90% (87% by use) 88% (83% by use)
gu Gujarati GlossOnly none 90% (87% by use) 88% (83% by use)
pa Punjabi GlossOnly single_source 90% (87% by use) 88% (83% by use)
th Thai GlossOnly single_source 90% (87% by use) 88% (83% by use)
vi Vietnamese GlossOnly multi_source 90% (87% by use) 88% (83% by use)
id Indonesian GlossOnly multi_source 90% (87% by use) 88% (83% by use)
ms Malay GlossOnly multi_source 90% (87% by use) 88% (83% by use)
tl Filipino GlossOnly multi_source 90% (87% by use) 88% (83% by use)
ru Russian GlossOnly multi_source 89% (76% by use) 87% (73% by use)
pl Polish GlossOnly multi_source 90% (82% by use) 88% (78% by use)
uk Ukrainian GlossOnly multi_source 90% (82% by use) 88% (78% by use)
ro Romanian GlossOnly multi_source 90% (82% by use) 88% (78% by use)
cs Czech GlossOnly multi_source 90% (87% by use) 88% (83% by use)
sv Swedish GlossOnly multi_source 90% (87% by use) 88% (83% by use)
da Danish GlossOnly multi_source 90% (87% by use) 88% (83% by use)
nb Norwegian GlossOnly multi_source 90% (87% by use) 88% (83% by use)
fi Finnish GlossOnly multi_source 90% (87% by use) 88% (83% by use)
sw Swahili GlossOnly single_source 90% (87% by use) 88% (83% by use)
am Amharic GlossOnly sparse 90% (87% by use) 88% (83% by use)
ha Hausa GlossOnly sparse 90% (87% by use) 88% (83% by use)
yo Yoruba GlossOnly sparse 90% (87% by use) 88% (83% by use)
zu Zulu GlossOnly sparse 89% (79% by use) 87% (75% by use)
tr Turkish GlossOnly multi_source 89% (80% by use) 88% (76% by use)
el Greek GlossOnly multi_source 90% (87% by use) 88% (83% by use)
hu Hungarian GlossOnly multi_source 90% (87% by use) 88% (83% by use)

Every one of the 44 needs native core-vocabulary work before its set is that language's core: a list from its speakers (SPEC §4.1 StakeholderValidated or ValidatedNativeCorpus), laid out by the same rule. Order of work:

  1. Korean, Chinese, Hebrew, Arabic: a published native core list exists (cited in vocabulary.rs CORE_COVERAGE_EVIDENCE); adopt it where its licence allows. Korean counts morphemes, not words: its core will not be a word-for-word grid.
  2. Languages with the largest gaps by use (Japanese, Korean, Russian at 72–75% of spoken use glossed; Chinese, Hindi, Romanian, Turkish at 75–78%): the missing words are grammar the language expresses differently (particles, case, no articles).
  3. Kannada and Gujarati (no prediction pack), Amharic, Hausa, Yoruba, Zulu, Marathi (sparse packs): need frequency data before any core.
  4. Everyone: native review of the glosses (model-read only so far), and whole-phrase translations of the social messages.

5. How the app offers it

At setup ("Words to start with") and in Settings → Words and boards, the catalogue's families sit beside the built-in sets (aac-web pagesets.rs, components/panels/catalogue_sets.rs):

  1. What it is: the set's description, its sources and licence, and, when the person's language is not English, what that language gets (§4).
  2. The size: eleven buttons, each saying what it holds ("9 words", "18 words and 2 pages of more", …). When a size gives targets under the 10 mm a finger needs on this screen, the chooser says so with the measured size ("about 6 × 12 mm") and lets the person choose it anyway. (A browser does not say how big its screen is: the estimate takes the board's size in CSS pixels and a phone's, a tablet's or a desktop's millimetres per pixel, and says it is an estimate.)
  3. "Start with fewer words on a bigger board": a size and the stage whose words show first; the rest are hidden in their places, and Track B's "Show hidden words for now" (partner menu and edit bar, scanned) shows them.
  4. Adding downloads the package the first time only (from /app/models/pagesets/, checked against the catalogue's size and SHA-256, then kept in IndexedDB — never Cache Storage, which iPad Safari evicts — so the set can be added again offline), imports it with fresh ids (another copy is another set), and adds its boards beside the person's as one change Undo takes away (editing::add_boards_as_page_set). At setup on a first start it replaces the unused defaults, as the built-in sets do.
  5. Supported navigation below 3×3: the 1×1 to 2×3 boards have no pages; the partner changes size from the chooser.
  6. What the import says is shown, as for any import (SPEC §8): the status line in Settings, a notice after setup. Each board's licence is kept with it (aac_board_licenses), so an export re-shares it with its attribution.

The chooser is the catalogue's, not these two sets': any family a generator in generators.json writes appears in it. A family with a package per language (the phrase sets) is resolved by aac_core::pagesets::Family::for_person(size, variant, lang, speaker_form): the person's language (the exact tag, then its base), and where its words change with the speaker's gender ("cansado" / "cansada") their speaker form — never assumed: with none it returns Pick::AskSpeakerForm, and Family::speaker_form_matters(lang) lets the chooser ask first — else the glossed or English package. A family with one size shows no size to choose.

6. Metrics

What the sets reach at each size (words said directly; "top N spoken" from the subtitle list; Universal Core and Banajee counted when on the core itself):

Size Cells Core words (1 hit) Pages Words in reach Top 25 spoken Top 50 Top 100 Top 200 Spoken tokens covered Universal Core on the core Banajee on the core
1x1 1 1 0 1 0/25 0/50 0/100 1/200 0% 1/36 1/23
1x2 2 2 0 2 0/25 0/50 0/100 2/200 0% 2/36 1/23
2x2 4 4 0 4 0/25 1/50 1/100 4/200 1% 4/36 3/23
2x3 6 6 0 6 1/25 3/50 3/100 6/200 2% 6/36 3/23
3x3 9 9 0 9 2/25 4/50 5/100 8/200 7% 9/36 6/23
3x4 12 12 0 12 5/25 7/50 8/100 11/200 14% 12/36 9/23
4x5 20 18 2 56 8/25 11/50 15/100 21/200 19% 16/36 13/23
5x6 30 26 4 139 15/25 22/50 32/100 44/200 30% 24/36 14/23
6x8 48 42 6 231 15/25 26/50 49/100 71/200 38% 36/36 18/23
7x9 63 56 7 311 21/25 32/50 59/100 84/200 52% 36/36 22/23
8x10 80 70 10 438 25/25 44/50 86/100 136/200 68% 36/36 22/23

Frequency-weighted cost of saying a word, over the words in reach (hits: 1 on the core, 2 on a page; scan steps: row-column from the top left; touch: Fitts' index of difficulty from a hand resting below the board; gaze: distance from the board's centre, 0–1 — definitions in pslib/costs.py and DESIGN-motor.md):

Size Hits per word Row-column scan steps Touch (Fitts ID, bits) Gaze (eccentricity)
1x1 1.0 2.0 0.665 0.0
1x2 1.0 2.638 0.892 0.354
2x2 1.0 2.585 1.416 0.5
2x3 1.0 3.316 1.221 0.45
3x3 1.0 2.711 1.878 0.576
3x4 1.0 3.255 1.816 0.553
4x5 1.046 4.381 2.259 0.628
5x6 1.297 7.905 3.122 0.764
6x8 1.301 9.708 3.437 0.741
7x9 1.178 9.97 3.318 0.686
8x10 1.268 12.306 3.786 0.73

Size of a cell (millimetres, width × height) after the app's message bar, suggestion row and navigation bar, against the app's own recommended minimums (touch 10 mm, switch 15 mm, head 18 mm, gaze 20 mm):

Size 10.2" tablet, landscape (mm) tablet, portrait 6.1" phone, portrait phone, landscape Meets on the tablet (landscape) Meets on the phone (portrait)
1x1 206×121 154×173 63×97 123×31 touch, switch, head, gaze touch, switch, head, gaze
1x2 103×121 77×173 31×97 61×31 touch, switch, head, gaze touch, switch, head, gaze
2x2 103×60 77×86 31×48 61×15 touch, switch, head, gaze touch, switch, head, gaze
2x3 68×60 51×86 21×48 40×15 touch, switch, head, gaze touch, switch, head, gaze
3x3 68×40 51×57 21×32 40×10 touch, switch, head, gaze touch, switch, head, gaze
3x4 51×40 38×57 15×32 30×10 touch, switch, head, gaze touch, switch
4x5 41×30 30×43 12×24 24×7 touch, switch, head, gaze touch
5x6 34×24 25×34 10×19 20×6 touch, switch, head, gaze none
6x8 25×20 19×28 7×16 15×5 touch, switch, head none
7x9 22×17 16×24 6×13 13×4 touch, switch none
8x10 20×14 15×21 6×12 12×3 touch none

A 6.1-inch phone held upright holds the core up to 4×5 for touch (5×6 is a fraction of a millimetre under the 10 mm minimum); a 10.2-inch tablet in landscape holds every size for touch, and up to 5×6 for gaze.

Stability. For every core item present at two sizes:

  • Pairs of sizes compared (an item present at both): 545.
  • Mean shift of a button's centre: 0.111 of the board's width or height.
  • Largest shift: 0.85 cells of the smaller board (it, 7x9 → 8x10: 0.094 across, 0.045 down). Threshold: less than one cell of the smaller board — met.
  • Largest shift between neighbouring sizes of the ladder: 0.250 of the board.
  • Every item's buttons, at every size, share one point of the screen: yes.
  • Pages: Social ok; Food ok; People ok; Feelings ok; Places ok; Actions ok; Things ok; Describe ok; Time ok; Word forms ok.

The rule makes the one-cell bound hold by construction; the test checks it again on the imported boards.

7. Decisions (2026-10-05)

Taken by the coordinator for the founder, and reversible:

  1. Pages keep their words in place (gaps at the larger sizes), for a motor plan that never changes.
  2. A word with no word in the person's language is hidden in place on these glossed sets only; Edit mode says so, and a partner can give it their own words (§4). Elsewhere it is shown in English, marked.
  3. Conjunctions are a word class in aac-core, with the Fitzgerald Key's "other" colour (brown, white text at 7:1), as the app's "Little words".
  4. The navigation words live in aac-core, so the app and the Open Board Format export share them: Back and Home cells never carry a gloss.
  5. "Back", the word, has its place (on the core at 8×10), and the Back control is drawn as its arrow, named "Go back" or the control's word.
  6. Phones are not restricted: the chooser says when a size's targets come under 10 mm on the screen, with the measured size.

Still open: a gloss review by native speakers, and native core vocabularies (§4); the UniMorph plan (§3).