Skip to content

Commit 4b9b47b

Browse files
Themes, fonts, reader typography, weave membership, Study hub (v0.49.0) (#26)
* UAT round: hymnal bar, read gates, plan chip + pause, viz grouping, portrait weave map (v0.49.0) Reader & reading map: - A destination no longer wears the reader's passage: the header subtitle hides off the Read screen (the Hymnal advertised "1 Corinthians 7"). - Reading is tracked only with the text in front of the reader: Android now also gates on Present and the map overlays (web already did). - A chapter completes at 85% dwell AND the last verse reached — the snap is a tolerance on the clock, not permission to skip the end of the chapter. - Overscroll (last line to the top of the pane) is a phone affordance: web keeps it under the 700px breakpoint and stops it AT the last line, so the text can never slide off entirely; Android same stop, all its modes. Plans (web UI; core+ABI shared): - The nav-strip chip retires for the rest of the day once a full plan-day finishes today — even when it was yesterday's leftovers (plan::done_today, doneToday on the plans wire, dated by the chapters' last_read). - Plans pause and resume (paused in the plan file, additive; new plan_set_paused ABI fn): a paused plan keeps its progress and class but asks nothing — no chip, no today card — and its card reads name + start day ("Started 3 Aug 2026 · paused"). Study hub: - One ≡ above 700px: the ScreenBar's menu hides where the app header (with its own ≡) is still visible — two stacked menus in different colours. - Constellation and Weave map fold under one expanding Visualizations card (both shells) — two views of one thing, not two more tools. Maps & boot: - The weave map flips in a portrait viewport (both shells): canon axis down the left edge, ribbons bulging right, taps mapped y→book. - The canon strip carries its own background from the first frame and fades its detail in — no more differently-coloured bar the minimap pops onto. Also: README rearrange + the themeable screenshot (maintainer), version to 0.49.0, FEATURE-MANIFEST updates, EN+DE strings, bindings regenerated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Lint: clippy useless-vec in the new reading test + rustfmt reflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Notes copy, theme roster rework, Atkinson Hyperlegible (stacked on #26) - Notes card copy (pick C): "Browse every note you've left in the text." ("search" trimmed — the notes browser has no search field yet, and the card must not promise one.) EN + DE. - Darcula retired as a near-duplicate of One Dark. Both parses ALIAS the stored token to one-dark, so an existing config opens on its nearest neighbour instead of snapping to System. Pinned by test. - Four house themes, none of them editor ports, all clearing the same WCAG-AA contrast test as the rest (18 themes now): scriptorium — parchment, iron-gall ink, RUBRICATED accents (light) blueprint — cyanotype: Prussian blue, chalk ink, gold divine name phosphor — green CRT with the classic amber second phosphor high-contrast — pure black on white, the deliberate low-vision option - Atkinson Hyperlegible (Braille Institute, OFL) as the fifth face, both shells, optical scale 0.90 (x-height 0.496, same half-correction as the others). It is the one STATIC family, so Font::static_bold enters the vocabulary: the web declares each face at its single weight (a static 400 declared 400-700 paints bold text regular), keeps the 700s out of the engine worker's measurement list, and precaches them via the new FONT_ALL_FILES; Android's FontSpec carries bold/boldItalic asset paths. Whole family: 87 KB woff2. - BIBLIOGRAPHY credits all five faces; FEATURE-MANIFEST updated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Verse-number + supplied-word-italics switches, and weave membership on a verse Three asks, and the first two are NOT the same kind of thing — which is most of the work here: - VERSE NUMBERS OFF is a LAYOUT input (`LayoutConfig.verse_numbers`, and +4 bytes on the by-value `PlumblineLayoutConfig`). A shell that merely declined to paint them would flow every verse around an invisible marker: the number's box AND the gap after it belong to the line. So the core emits no number items and reclaims the width, and the field joins both turn-cache keys (`engine.worker.ts`, Android's `ChapterKey`) while staying out of `font_identity` — like `verse_break`, it moves boxes, never a glyph's advance. The web hand-marshals the struct, so its size moved 28 → 32 in lockstep. - SUPPLIED-WORD ITALICS OFF is PAINT ONLY. The measure callback is font-blind, so the engine already measures those words upright and the layout is untouched: deliberately absent from both cache keys, present in Android's ChapterPaintKey (the Picture bakes the face) and named as an explicit dependency of the web's paint effect. That last one was a real bug the new e2e caught: `draw` runs in a rAF callback, outside the effect's tracking scope, so reading the flag down there registered nothing and the italics stayed on screen until something else happened to repaint. - A VERSE NOW NAMES THE WEAVES IT IS IN, above the partner list and separate from it. The two answer different questions and the partner list buries the first: a verse with six links into one weave read as six rows repeating a name, and a verse in three weaves gave no way to see the three at all. Both switches default ON and are written as explicit booleans, so every read is `!== false` — an absent key is a config from before they existed, not an opt-out. Tests, each mutation-tested against the defect it describes: - core: numbers off emits no boxes AND reclaims their width (the mutation that keeps the gap moves the first word to x=4, and the test fails); - core: membership dedupes by name across an interleaved partner list, is singular at one and absent at none; - web e2e: both switches driven through Settings › Advanced, asserting the display list for numbers and the CANVAS PIXELS for italics — dropping the paint dependency or the cache-key field each kills exactly its own test. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Study hub: an In-progress band, live counts, and the reading map as a bar The hub was eight identical rectangles of FIXED text — the same on install day as after a year of study. Plans tells you today's chapters; the Hymnal is full of hymns; this screen had nothing that could change, which is what "a bunch of boring brown cards, not like the other pages" was describing. Informative first, per the ask: - an IN PROGRESS band, drawing only rows that have something to say (a hub reading "0 due · 0 to review" every day would be the fixed text again): the running plan with today's chapters, the memorize queue when anything is due, the review queue when anything waits. Nothing running at all gets one invitation rather than an empty box, and a PAUSED plan says so and names no chapters — promising chapters it is not asking for reads as asking for them. - a count on every card that holds a collection, absent at zero so an empty tool reads as quiet rather than as a score of nought. Plans and Memorize carry none: they are activities, and the band speaks for them. Visual, as the bonus and where it costs nothing: the reading map as one number and one bar — chapters read of 1,189, the map's own readDone over a faint readUnread track, so it is correct in all eighteen themes for free and taps through to the navigator. The first cut used the unread gold at 22% and an unread reader's empty bar looked FULL; it is 12% with a hairline now. No new engine calls: every number is a query another screen already makes, so the web reads them through the session cache and they move on an authoring write. That is the failure worth pinning — a count fetched once looks perfect until the reader writes something — so the e2e writes first and then looks, and the mutation that snapshots the counts instead of deriving them kills exactly that test and no other. Two traps this hit, both worth the note: the band first rendered as EXPLORE.INPROGRESS because the i18n catalogue lives in the ENGINE and only the bundle had been rebuilt; and the "quiet at zero" assertion first passed because `q` answers null before its fetch lands, which is indistinguishable from an empty tool — it now waits on the stock set's own weave count as the signal that the queries have resolved, and asserts a DELTA where the stock set seeds data. Android gets the same band and counts (plans stay web-only, per the manifest's shell deltas), refetching on the note epoch and on every entry to the hub. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent 8b03aa1 commit 4b9b47b

70 files changed

Lines changed: 2503 additions & 232 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

BIBLIOGRAPHY.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,8 @@ what promotes it out of the queue into the library.
9494

9595
Scripture renders in **EB Garamond** (SIL Open Font License), bundled with the
9696
web shell under `apps/web/public/fonts/`; the Compose shell asks for the same
97-
family from `assets/fonts/` and falls back to the platform serif.
97+
family from `assets/fonts/` and falls back to the platform serif. The picker
98+
offers four more faces, all bundled the same way and all OFL: **Literata**
99+
(Type Together, for Google Fonts), **Inter** (Rasmus Andersson), **Fira Code**
100+
(Nikita Prokopov et al.), and **Atkinson Hyperlegible** (Braille Institute of
101+
America — the low-vision face).

Cargo.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ default-members = [
2121
# shells — About renders it as `engine ` + this number. The workflow refuses a tag
2222
# whose version disagrees with this line (and with apps/web/package.json), so a
2323
# release ships one number, not three.
24-
version = "0.48.0"
24+
version = "0.49.0"
2525
edition = "2021"
2626
license = "MIT"
2727
authors = ["Glendon Klassen <gjklassen@proton.me>"]

README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ canon](assets/readme/reader-weaves.png)
3838
- German language support
3939
- Canon strip "minimap" under the reader to show where you're at in the Bible
4040

41+
![Acts 7 and Genesis 15 side by side in a deep indigo theme, weave connectors
42+
between the quoted passages, and the weave's own note with its cited verses
43+
in the study panel — the same reader, re-inked by a
44+
theme](assets/readme/themeable.png)
45+
4146
### Study
4247

4348
- Add notes to words/verses
@@ -116,7 +121,7 @@ steps, all on the phone.
116121
open **Plumbline** from your app drawer: the whole Bible is inside the file
117122
you just installed, so it opens with the network off.
118123

119-
## Getting started (60 seconds)
124+
## Getting started
120125

121126
First launch asks who's opening the Book — **new in the faith** (a welcome
122127
with next steps, landing in John), **curious about the Bible** (for someone
@@ -233,13 +238,6 @@ public-domain Textus Receptus tagging; cross-references from the TSK via
233238
openbible.info. Full credits and licenses: **[BIBLIOGRAPHY.md](BIBLIOGRAPHY.md)**.
234239
Scripture renders in EB Garamond (OFL, bundled).
235240

236-
## License
237-
238-
The code is MIT — **[LICENSE](LICENSE)**. The text and the lexical data keep
239-
their own terms (public domain, CC-BY 4.0, CC-BY-SA); the carve-out at the end
240-
of LICENSE names them directory by directory, and
241-
[BIBLIOGRAPHY.md](BIBLIOGRAPHY.md) has it file by file.
242-
243241
## Translation selection
244242

245243
This application is built with the 1769 King James Version of the Bible, which
@@ -312,7 +310,14 @@ additions:
312310
- John 7:53–8:11
313311
- 1 John 5:7–8
314312

313+
## License
314+
315+
The code is MIT — **[LICENSE](LICENSE)**. The text and the lexical data keep
316+
their own terms (public domain, CC-BY 4.0, CC-BY-SA); the carve-out at the end
317+
of LICENSE names them directory by directory, and
318+
[BIBLIOGRAPHY.md](BIBLIOGRAPHY.md) has it file by file.
319+
315320
## Final note
316321

317-
May God bless you as you read his Word, whether here or elsewhere, and don't
322+
May God bless you as you read His Word, whether here or elsewhere, and don't
318323
fail to share it with others.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
Copyright 2020 Braille Institute of America, Inc.
2+
3+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
4+
This license is copied below, and is also available with a FAQ at:
5+
http://scripts.sil.org/OFL
6+
7+
-----------------------------------------------------------
8+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9+
-----------------------------------------------------------
10+
11+
PREAMBLE
12+
The goals of the Open Font License (OFL) are to stimulate worldwide
13+
development of collaborative font projects, to support the font creation
14+
efforts of academic and linguistic communities, and to provide a free and
15+
open framework in which fonts may be shared and improved in partnership
16+
with others.
17+
18+
The OFL allows the licensed fonts to be used, studied, modified and
19+
redistributed freely as long as they are not sold by themselves. The
20+
fonts, including any derivative works, can be bundled, embedded,
21+
redistributed and/or sold with any software provided that any reserved
22+
names are not used by derivative works. The fonts and derivatives,
23+
however, cannot be released under any other type of license. The
24+
requirement for fonts to remain under this license does not apply
25+
to any document created using the fonts or their derivatives.
26+
27+
DEFINITIONS
28+
"Font Software" refers to the set of files released by the Copyright
29+
Holder(s) under this license and clearly marked as such. This may
30+
include source files, build scripts and documentation.
31+
32+
"Reserved Font Name" refers to any names specified as such after the
33+
copyright statement(s).
34+
35+
"Original Version" refers to the collection of Font Software components as
36+
distributed by the Copyright Holder(s).
37+
38+
"Modified Version" refers to any derivative made by adding to, deleting,
39+
or substituting -- in part or in whole -- any of the components of the
40+
Original Version, by changing formats or by porting the Font Software to a
41+
new environment.
42+
43+
"Author" refers to any designer, engineer, programmer, technical
44+
writer or other person who contributed to the Font Software.
45+
46+
PERMISSION & CONDITIONS
47+
Permission is hereby granted, free of charge, to any person obtaining
48+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
49+
redistribute, and sell modified and unmodified copies of the Font
50+
Software, subject to the following conditions:
51+
52+
1) Neither the Font Software nor any of its individual components,
53+
in Original or Modified Versions, may be sold by itself.
54+
55+
2) Original or Modified Versions of the Font Software may be bundled,
56+
redistributed and/or sold with any software, provided that each copy
57+
contains the above copyright notice and this license. These can be
58+
included either as stand-alone text files, human-readable headers or
59+
in the appropriate machine-readable metadata fields within text or
60+
binary files as long as those fields can be easily viewed by the user.
61+
62+
3) No Modified Version of the Font Software may use the Reserved Font
63+
Name(s) unless explicit written permission is granted by the corresponding
64+
Copyright Holder. This restriction only applies to the primary font name as
65+
presented to the users.
66+
67+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68+
Software shall not be used to promote, endorse or advertise any
69+
Modified Version, except to acknowledge the contribution(s) of the
70+
Copyright Holder(s) and the Author(s) or with their explicit written
71+
permission.
72+
73+
5) The Font Software, modified or unmodified, in part or in whole,
74+
must be distributed entirely under this license, and must not be
75+
distributed under any other license. The requirement for fonts to
76+
remain under this license does not apply to any document created
77+
using the Font Software.
78+
79+
TERMINATION
80+
This license becomes null and void if any of the above conditions are
81+
not met.
82+
83+
DISCLAIMER
84+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92+
OTHER DEALINGS IN THE FONT SOFTWARE.

apps/android/app/src/main/java/dev/plumbline/Wire.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,11 @@ data class ConfigState(
478478
val firstRun: Boolean = false,
479479
// Frozen additive field shared with GTK's config.json — must round-trip.
480480
val versePerLine: Boolean = false,
481+
// The two reader-typography switches (additive). Defaulted TRUE, not false:
482+
// an absent key is an engine or a config from before they existed, and
483+
// reading that as "off" would strip a chapter of its numbers.
484+
val verseNumbers: Boolean = true,
485+
val addedItalics: Boolean = true,
481486
// Colour theme choice: "system" | "light" | "dark" | "night". Additive.
482487
val theme: String = "system",
483488
// The two TYPE axes (additive, core::font tokens): the face scripture is

0 commit comments

Comments
 (0)