347 lines
19 KiB
Markdown
347 lines
19 KiB
Markdown
# Fixed Paths — design
|
||
|
||
A motor-plan vocabulary: every word has one place to be reached from, by the
|
||
same 1, 2 or 3 movements every time, starting from Home. It is designed from
|
||
first principles — frequency times motor cost — and is ours: it does not
|
||
reproduce LAMP Words for Life's, Speak for Yourself's or Unity's layout,
|
||
category scheme or names, and it uses no multi-meaning icon sequences.
|
||
|
||
- Source: `data/fixed-paths.yaml` (the words, the page each belongs to, the
|
||
groups pages fall back on), `data/fixed-paths.layout.yaml` (where
|
||
everything sits, solved once and reviewed), `data/lexicon.en.yaml`.
|
||
- Output: `fixed-paths-{30,60,84}.obz`, and each with the starter filter;
|
||
built by `catalog.py` wherever they are served, never committed (see
|
||
DESIGN-core.md for the catalogue, `aac-rs/data/pagesets/index.json`).
|
||
- Check: `python3 tools/pagesets/build.py --check`,
|
||
`python3 tools/pagesets/catalog.py --check` and
|
||
`cargo test -p aac-core --test pagesets`.
|
||
- Rebuild: `python3 tools/pagesets/build.py` and `catalog.py --write` (Python
|
||
3.11+ and PyYAML, no network). Re-solve the layout:
|
||
`python3 tools/pagesets/solve.py motor`, 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`.
|
||
|
||
## 1. Rules
|
||
|
||
1. **One meaning per location.** A location says one word, or opens one page.
|
||
Every button shows the word it says or the name of the page it opens.
|
||
2. **One path per word**, at each size: Home → word (1 hit), Home → page →
|
||
word (2), or Home → page → group → word (3). The test walks every package
|
||
and fails on a word reachable twice or in more than three hits.
|
||
3. **Every selection returns Home.** The app has this as the person's setting
|
||
("go back to Home after a word", `access.return_home`); SPEC §5.6 item 6
|
||
makes it the person's choice, never the board's. So the set does not turn
|
||
it on: its manifest says it is made for it
|
||
(`ext_aurasense_pageset.recommends.return_home_after_word`), and the
|
||
chooser asks when the set is added.
|
||
4. **The place that opened a page closes it.** On a page, the cell in the
|
||
place of the key that opened it is **Back**, to the board that key is on
|
||
(from a group, its page; from a page, Home). A wrong page is undone by
|
||
pressing the same place again — the most automatic movement there is — at
|
||
no cost of a separate location, and it is the same rule on every page and
|
||
group at every size. It is labelled Back, not Home, with the app's arrow and
|
||
the control's word in each language: the Places page has the word *home*,
|
||
and two buttons reading alike must never mean two things on one page (a
|
||
build check; it is also why the body part *back* is not in the set).
|
||
5. **The same 472 words at every size**: 30, 60 and 84 locations differ only
|
||
in how many words are one hit away.
|
||
|
||
### The patent constraint
|
||
|
||
Three PRC patents on multi-meaning symbol sequences are listed as active to
|
||
about 2033–34 (US 9,202,298; 9,183,655; 9,239,824). Fixed Paths has no
|
||
multi-meaning icons and no icon sequences:
|
||
|
||
- No picture stands for different words depending on what was pressed before
|
||
it. A word's button shows that word; a page key shows the page's name.
|
||
- A page key's picture is an exemplar of the words behind it (Family shows
|
||
"mom"), as folders do in every grid app; no two keys share a picture, and a
|
||
key's label is never a word on the page it sits on (build check).
|
||
- A location's meaning never depends on a previous selection: on Home it means
|
||
one thing; on a page, that page's cell means one thing.
|
||
|
||
This is the ordinary navigation of every dynamic-display AAC app (pages of
|
||
words), not semantic compaction. It is a design statement, not legal advice;
|
||
a freedom-to-operate review is still the founder's call before anything like
|
||
icon sequences is ever added.
|
||
|
||
### Not LAMP, not Speak for Yourself
|
||
|
||
- **LAMP and Unity** reach words by sequences of multi-meaning icons on one
|
||
fixed keyboard. Fixed Paths has none: two-hit words sit on pages of explicit
|
||
words.
|
||
- **Speak for Yourself** gives each core word its own secondary page of
|
||
related words. Fixed Paths groups by meaning (twelve pages: Social, People,
|
||
Actions, Describe, Little words, Feelings, Food, Places, Things, Body, Time,
|
||
Word forms), and which words are on Home is computed from frequency, not
|
||
chosen as a set of keys.
|
||
- **TD Snap Motor Plan** is taxonomic too; its layouts and words are not used.
|
||
Its published averages (2.3 hits on 30 locations, 2.0 on 66) are a
|
||
reference point: Fixed Paths averages 2.36 on 30, 2.00 on 60, 1.86 on 84
|
||
(unweighted, §5).
|
||
- Every position comes from the optimiser below and the committed layout; the
|
||
page and group names are plain English.
|
||
|
||
## 2. Frequency × motor cost
|
||
|
||
### Weight of a word
|
||
|
||
A word's weight is how often it is likely to be chosen: its spoken frequency
|
||
(FrequencyWords 2018, OpenSubtitles dialogue, CC BY-SA 4.0), times 4
|
||
(`aac_boost` 3) if it is in Universal Core or Banajee et al. (2003). Pure
|
||
adult spoken frequency would put "the", "of" and "to" ahead of "want", "more"
|
||
and "help"; the boost is the evidence that early communicators need the
|
||
latter, from the two open lists made for them. A message (a phrase) weighs a
|
||
quarter of its proxy word ("I'm not finished" → "finished"). The metrics show
|
||
both weights.
|
||
|
||
**Home at 30 locations is for a person starting out** (decision of
|
||
2026-10-05): its 18 words are the ones that carry a message on their own, from
|
||
Universal Core and Banajee et al. (2003) — I, you, it, that, what, want, more,
|
||
go, help, stop, not, like, all done, yes, no, my, look, do — and the most
|
||
frequent function words ("the", "a", "to", "is", "in", "on") are one page away
|
||
(Little words). **At 60 and 84** Home keeps those 18 where they are and adds
|
||
the heaviest of the rest by weight, to 48 and 72. The sets nest: a word on
|
||
Home at 30 is on Home at 60 and 84.
|
||
|
||
What the beginners' Home costs, measured on the 30-location set (by spoken
|
||
frequency; § 5): a spoken word takes 1.84 hits on average instead of 1.67
|
||
with the heaviest words on Home, and 9 of the 25 most-spoken words are one hit
|
||
instead of 16 — the words a fluent speaker uses most, for the words a person
|
||
starting out needs most. At 60 and 84 the difference is under 2% (the
|
||
beginners' words are among the heaviest there anyway).
|
||
|
||
### What "easy" means
|
||
|
||
Each model is scaled 0–1 over the grid and blended per size
|
||
(`pslib/costs.py`); none is a measurement of a person.
|
||
|
||
- **Touch**: Fitts' index of difficulty, log2(1 + D/W), from a hand resting
|
||
at the bottom centre below the board to the cell, W the cell's smaller side,
|
||
on a 10.2-inch tablet in landscape. Easy: low and central.
|
||
- **Scanning**: row-column steps from the top left (rows highlighted until the
|
||
row, then cells until the cell, both presses counted). Easy: the top left.
|
||
The app's opt-in adaptive scan order (SPEC §5.4) can put heavy rows first
|
||
without moving a cell, so position matters less here than for touch.
|
||
- **Gaze**: distance from the centre of the board, 0 at the centre, 1 at a
|
||
corner. A webcam's gaze estimate is least accurate towards the edges, and a
|
||
target at the edge has nowhere to put an overshoot. Easy: central, large.
|
||
|
||
They disagree: touch wants the bottom centre, scanning the top left, gaze the
|
||
middle. Blends: **30 locations** (the gaze size) gaze 0.5, touch 0.25, scan
|
||
0.25; **60 and 84** touch 0.5, scan 0.25, gaze 0.25.
|
||
|
||
### Placement
|
||
|
||
Home items live at points, like the Growing Core's words (DESIGN-core.md §1),
|
||
on the ladder 5×6 → 6×10 → 7×12, so an item on Home at 30 stays in the same
|
||
region at 60 and 84 and a person moving up keeps their Home motor plan. The
|
||
solver (`pslib/solve.py`) minimises Σ weight × blended cost over the three
|
||
sizes; a page key weighs the sum of the words behind it at that size. Pages
|
||
are then laid out per size: heaviest words in the cheapest cells, the Back
|
||
cell where the key was.
|
||
|
||
**Groups.** When a page has more words than places (always at 30), it frees
|
||
places one at a time at the least weight: opening a group moves that group's
|
||
two lightest words behind its key (two words out, one key in), and an open
|
||
group takes its next lightest. So the heaviest words stay on the page whatever
|
||
their group, the lightest of a meaning (Family, Moving, Colors, …) go behind
|
||
its key, and no key ever stands for a single word. The Social page keeps its
|
||
*repairs* on the page at every size, however full: *wait*, *I'm not finished*,
|
||
*that's not what I meant*, *say it again*, *I don't know*.
|
||
|
||
<!-- table:motor-pages -->
|
||
| Page | Words | Groups (by meaning) | Groups in use, by size |
|
||
|---|---|---|---|
|
||
| Social | 41 | Answers, Manners, Greetings, Turn taking, Likes, Pauses, Exclamations | 30: Exclamations, Greetings, Pauses, Turn taking; 60: none; 84: none |
|
||
| People | 43 | Pronouns, Owners, Family, Helpers, Others | 30: Family, Helpers; 60: none; 84: none |
|
||
| Actions | 101 | Wanting, Doing, Trying, Moving, Thinking, Talking, Daily | 30: Daily, Doing, Moving, Talking, Thinking, Trying, Wanting; 60: Daily, Doing, Moving, Talking, Thinking, Trying; 84: Daily, Moving |
|
||
| Describe | 72 | Amount, Opinions, Size and feel, Colors, Numbers | 30: Colors, Numbers, Opinions, Size and feel; 60: Colors, Size and feel; 84: none |
|
||
| Little words | 51 | Questions, Joining, Linking, Position, Negatives | 30: Joining, Linking, Negatives, Position; 60: none; 84: none |
|
||
| Feelings | 24 | – | 30: none; 60: none; 84: none |
|
||
| Food | 26 | Flavors | 30: none; 60: none; 84: none |
|
||
| Places | 17 | – | 30: none; 60: none; 84: none |
|
||
| Things | 45 | Play things, Home things, Clothes, Animals, Outside things | 30: Animals, Clothes, Home things, Outside things, Play things; 60: none; 84: none |
|
||
| Body | 14 | – | 30: none; 60: none; 84: none |
|
||
| Time | 25 | – | 30: none; 60: none; 84: none |
|
||
| Word forms | 21 | – | 30: none; 60: none; 84: none |
|
||
<!-- /table -->
|
||
|
||
Home at each size (▸ opens a page):
|
||
|
||
<!-- table:motor-grids -->
|
||
**30 (5x6)**
|
||
|
||
```
|
||
| help | Time▸ | yes | Things▸ | stop | Body▸ |
|
||
| more | my | People▸ | Word forms▸ | like | Feelings▸ |
|
||
| not | Describe▸ | Little wor~ | Actions▸ | Social▸ | Places▸ |
|
||
| go | what | you | I | no | all done |
|
||
| look | do | that | it | want | Food▸ |
|
||
```
|
||
|
||
**60 (6x10)**
|
||
|
||
```
|
||
| help | have | this | we | yes | up | Things▸ | stop | was | Body▸ |
|
||
| more | good | Time▸ | my | here | Word forms▸ | like | when | your | Feelings▸ |
|
||
| why | she | can | People▸ | in | Actions▸ | Social▸ | and | for | Places▸ |
|
||
| out | not | Describe▸ | what | Little wor~ | I | on | get | who | be |
|
||
| of | go | all | is | you | a | he | no | where | all done |
|
||
| me | look | do | that | the | it | to | want | some | Food▸ |
|
||
```
|
||
|
||
**84 (7x12)**
|
||
|
||
```
|
||
| help | have | now | this | we | yes | him | one | stop | got | her | Body▸ |
|
||
| more | good | Time▸ | there | off | just | up | Things▸ | when | was | your | Feelings▸ |
|
||
| why | they | she | my | People▸ | here | with | Word forms▸ | like | at | come | Places▸ |
|
||
| out | not | Describe▸ | can | don't | in | Actions▸ | know | Social▸ | and | for | well |
|
||
| of | go | all | what | are | Little wor~ | I | on | get | who | where | be |
|
||
| right | look | but | do | is | you | a | he | no | if | put | all done |
|
||
| oh | me | so | make | that | the | it | to | want | about | some | Food▸ |
|
||
```
|
||
<!-- /table -->
|
||
|
||
Stability of Home across sizes:
|
||
|
||
<!-- table:motor-stability -->
|
||
Home items present at two sizes: 120 pairs; mean shift 0.072 of the board; largest 0.79 cells of the smaller board (`Things`, 6x10 → 7x12); every item's buttons share a point: yes.
|
||
<!-- /table -->
|
||
|
||
### The trade-offs, measured
|
||
|
||
Each size, laid out four more ways — the blend alone (this size only, no tie to
|
||
the other sizes), and each access method alone — then every layout measured
|
||
under every method (design-weighted mean per word; hits are the same for all,
|
||
since which words are on Home does not depend on where):
|
||
|
||
<!-- table:motor-tradeoffs -->
|
||
| Locations | Layout | Hits | Scan steps | Touch (bits) | Gaze |
|
||
|---|---|---|---|---|---|
|
||
| 30 | chosen | 1.614 | 10.488 | 3.208 | 0.502 |
|
||
| 30 | blend alone | 1.614 | 10.272 | 3.292 | 0.483 |
|
||
| 30 | touch only | 1.614 | 12.351 | 2.646 | 0.798 |
|
||
| 30 | scan only | 1.614 | 6.314 | 4.152 | 0.997 |
|
||
| 30 | gaze only | 1.614 | 10.498 | 3.324 | 0.478 |
|
||
| 60 | chosen | 1.178 | 11.149 | 2.371 | 0.486 |
|
||
| 60 | blend alone | 1.178 | 11.203 | 2.312 | 0.512 |
|
||
| 60 | touch only | 1.178 | 12.314 | 2.225 | 0.597 |
|
||
| 60 | scan only | 1.178 | 6.555 | 3.228 | 0.717 |
|
||
| 60 | gaze only | 1.178 | 10.543 | 2.739 | 0.383 |
|
||
| 84 | chosen | 1.113 | 12.455 | 2.383 | 0.486 |
|
||
| 84 | blend alone | 1.113 | 12.604 | 2.298 | 0.49 |
|
||
| 84 | touch only | 1.113 | 13.699 | 2.21 | 0.576 |
|
||
| 84 | scan only | 1.113 | 6.692 | 3.33 | 0.704 |
|
||
| 84 | gaze only | 1.113 | 11.687 | 2.796 | 0.331 |
|
||
<!-- /table -->
|
||
|
||
What it shows:
|
||
|
||
- A **scan-only** layout needs 40–46% fewer scan steps than the chosen one
|
||
(6.3–6.7 against 10.5–12.5) and is the worst for touch and gaze.
|
||
- A **touch-only** layout is 6–18% cheaper to touch and the worst to scan.
|
||
- **Gaze-only** is within 5% of the chosen layout at 30 locations, where gaze
|
||
weighs most; at 60 and 84 it would be 21–32% better for gaze and 16–17%
|
||
worse for touch.
|
||
- **Tying the three sizes together** (chosen against the blend alone) costs at
|
||
most 4% on one measure (gaze at 30, touch at 84) and is better on others.
|
||
|
||
**One layout for every access method** (decision of 2026-10-05): the layout is
|
||
the motor plan, and stays; a person who scans can opt into the app's adaptive
|
||
scan order (SPEC §5.4), which puts the rows they use first without moving a
|
||
cell.
|
||
|
||
## 3. Vocabulary filter, and "show everything for now"
|
||
|
||
A filter shows only its words, each in its place; every other word is hidden
|
||
in place (OBF `hidden: true`, the app's `Cell.hidden`). A page or group key shows while any word behind it shows; Back
|
||
cells always show. Positions never change (test). The
|
||
**starter** filter is Universal Core ∪ Banajee et al. (2003): 45 words for a
|
||
person starting out. Filters are lists in `fixed-paths.yaml`, so a team can
|
||
write its own; the chooser could also build one from the words a person used
|
||
(the app's usage counts), never by moving anything.
|
||
|
||
"Show everything for now" (Babble, in other apps' words) is Track B's "Show
|
||
hidden words for now", in the partner menu and the edit bar, and scanned
|
||
(decision of 2026-10-05): it shows every hidden word in its place until it is
|
||
turned off, and changes nothing on the board. A word hidden because it has no
|
||
word in the person's language stays hidden (DESIGN-core.md §4).
|
||
|
||
## 4. How the app offers it
|
||
|
||
As for the Growing Core (DESIGN-core.md §5): at setup and in Settings → Words
|
||
and boards, downloaded once, checked, kept on the device, and added as one
|
||
undoable change. Then:
|
||
|
||
1. Choose **30** places (the largest targets, for eye gaze and head pointers),
|
||
**60** or **84**; when a size's targets come under 10 mm on this screen, the
|
||
chooser says so with the measured size.
|
||
2. "Start with the 45 first words" picks the starter package (the filter's
|
||
hidden flags are in it: `fixed-paths-<n>-starter.obz`).
|
||
3. Its Home **becomes the person's home board** (going back to Home goes
|
||
there), and the app **asks once**, in words: "Fixed Paths is made to go
|
||
back to Home after each word … Turn that on?" — at setup as part of the
|
||
choice, in Settings after the set is added; `access.return_home` is set
|
||
only on yes, and the question is not asked again (SPEC §5.6 item 6).
|
||
|
||
## 5. Metrics
|
||
|
||
<!-- table:motor-reach -->
|
||
| Locations | Grid | Words on Home | Pages | Groups | Words | 1 hit | 2 hits | 3 hits | Mean hits | Hits per word, spoken weight | Hits, design weight | Top 25 in 1 hit | Top 100 in 1 hit | Top 100 in reach | Top 200 in reach | Spoken tokens covered |
|
||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||
| 30 | 5x6 | 18 | 12 | 26 | 473 | 18 | 268 | 187 | 2.357 | 1.837 | 1.614 | 9/25 | 14/100 | 99/100 | 156/200 | 73% |
|
||
| 60 | 6x10 | 48 | 12 | 8 | 473 | 48 | 377 | 48 | 2.0 | 1.397 | 1.178 | 25/25 | 44/100 | 99/100 | 156/200 | 73% |
|
||
| 84 | 7x12 | 72 | 12 | 2 | 473 | 72 | 395 | 6 | 1.86 | 1.259 | 1.113 | 25/25 | 65/100 | 99/100 | 156/200 | 73% |
|
||
<!-- /table -->
|
||
|
||
"Top 100 in reach" counts words the set holds as words: 99 of the 100.
|
||
"Going" is "go" and the -ing ending. Beyond the top 100,
|
||
`metrics.json` lists every size's coverage of the top 25 to 400.
|
||
|
||
Spoken-weighted cost per word, by method:
|
||
|
||
<!-- table:motor-costs -->
|
||
| Locations | Hits per word | Row-column scan steps | Touch (Fitts ID, bits) | Gaze (eccentricity) |
|
||
|---|---|---|---|---|
|
||
| 30 | 1.837 | 11.636 | 3.78 | 0.605 |
|
||
| 60 | 1.397 | 12.961 | 2.936 | 0.566 |
|
||
| 84 | 1.259 | 13.826 | 2.862 | 0.548 |
|
||
<!-- /table -->
|
||
|
||
Target sizes (mm, width × height), against the app's minimums (touch 10, switch
|
||
15, head 18, gaze 20):
|
||
|
||
<!-- table:motor-targets -->
|
||
| Locations | Grid | 10.2" tablet, landscape (mm) | tablet, portrait | 6.1" phone, portrait | phone, landscape | Meets on the tablet (landscape) | Meets on the phone (portrait) |
|
||
|---|---|---|---|---|---|---|---|
|
||
| 30 | 5x6 | 34×24 | 25×34 | 10×19 | 20×6 | touch, switch, head, gaze | none |
|
||
| 60 | 6x10 | 20×20 | 15×28 | 6×16 | 12×5 | touch, switch, head | none |
|
||
| 84 | 7x12 | 16×17 | 12×24 | 5×13 | 10×4 | touch, switch | none |
|
||
<!-- /table -->
|
||
|
||
30 locations meets the app's 20 mm gaze minimum on a 10.2-inch tablet in
|
||
landscape; 60 and 84 do not. No size meets touch's 10 mm on a 6.1-inch phone
|
||
held upright (30 locations misses by a fraction of a millimetre): Fixed Paths
|
||
is a tablet set.
|
||
|
||
## 6. Decisions (2026-10-05)
|
||
|
||
Taken by the coordinator for the founder, and reversible:
|
||
|
||
1. **Home at 30 is for beginners** (§2), with the frequency × 4 weighting kept
|
||
for 60 and 84.
|
||
2. **One layout for every access method**, with the adaptive scan order for
|
||
scanners (§2).
|
||
3. **"Show everything for now" is Track B's "Show hidden words for now"** (§3).
|
||
4. **"Back", the word, has its place** (Little words → Position at 30, Little
|
||
words at 60 and 84, by its weight): the Back control is drawn as its arrow,
|
||
so the two never read alike. Its glosses are the body part, so it is English only and
|
||
hidden in place in other languages (DESIGN-core.md §2).
|
||
|
||
Still open: irregular forms sit on the Word forms page as words until the
|
||
UniMorph plan (DESIGN-core.md §3) gives a Word Forms page that re-inflects;
|
||
until then "went" is two hits and "goed" is what the ending says.
|