ucode 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +72 -0
- data/Gemfile.lock +2 -2
- data/TODO.full/00-README.md +116 -0
- data/TODO.full/01-panglyph-vision.md +112 -0
- data/TODO.full/02-panglyph-repo-bootstrap.md +184 -0
- data/TODO.full/03-panglyph-font-builder.md +201 -0
- data/TODO.full/04-panglyph-publish-pipeline.md +126 -0
- data/TODO.full/05-ucode-0-1-1-release.md +139 -0
- data/TODO.full/06-fontisan-remove-audit.md +142 -0
- data/TODO.full/07-fontisan-remove-ucd.md +125 -0
- data/TODO.full/08-archive-private-bin-build.md +143 -0
- data/TODO.full/09-archive-public-structure.md +164 -0
- data/TODO.full/10-fontist-org-woff-glyphs.md +131 -0
- data/TODO.full/11-fontist-org-audit-coverage.md +140 -0
- data/TODO.full/12-implementation-order.md +216 -0
- data/TODO.full/13-fontisan-font-writer-api.md +189 -0
- data/TODO.full/14-fontisan-table-writers.md +66 -0
- data/TODO.full/15-panglyph-builder-real.md +82 -0
- data/TODO.full/16-archive-public-sync-workflows.md +167 -0
- data/TODO.full/17-fontist-org-font-picker.md +73 -0
- data/TODO.full/18-comprehensive-spec-coverage.md +64 -0
- data/TODO.full/19-ucode-0-1-2-patch.md +32 -0
- data/TODO.full/20-fontisan-0-2-23-release.md +52 -0
- data/TODO.new/00-README.md +30 -0
- data/TODO.new/23-universal-glyph-set-source-map.md +312 -0
- data/TODO.new/24-universal-glyph-set-build.md +189 -0
- data/TODO.new/25-font-audit-against-universal-set.md +195 -0
- data/TODO.new/26-missing-glyph-reporter.md +189 -0
- data/TODO.new/27-fontist-org-consumer-integration.md +200 -0
- data/TODO.new/28-implementation-order-update.md +187 -0
- data/TODO.new/29-universal-set-curation-uc17.md +312 -0
- data/TODO.new/30-tier1-font-acquisition.md +241 -0
- data/TODO.new/31-universal-set-production-build.md +205 -0
- data/TODO.new/32-uc17-coverage-matrix.md +165 -0
- data/TODO.new/33-specialist-font-acquisition-refresh.md +138 -0
- data/TODO.new/34-pillar2-content-stream-correlator.md +147 -0
- data/TODO.new/35-universal-set-production-run.md +160 -0
- data/TODO.new/36-per-font-coverage-audit.md +145 -0
- data/TODO.new/37-coverage-highlight-reporter.md +125 -0
- data/TODO.new/38-fontist-org-glyph-consumer.md +141 -0
- data/TODO.new/39-implementation-order-update-32-38.md +258 -0
- data/TODO.new/40-archive-private-uses-ucode-audit.md +124 -0
- data/TODO.new/41-ucode-unicode-archive-bridge.md +160 -0
- data/config/specialist_fonts.yml +102 -0
- data/config/unicode17_tier1_fonts.yml +42 -0
- data/config/unicode17_universal_glyph_set.yml +293 -0
- data/lib/ucode/audit/block_aggregator.rb +57 -29
- data/lib/ucode/audit/browser/face_page.rb +128 -0
- data/lib/ucode/audit/browser/glyph_panel.rb +124 -0
- data/lib/ucode/audit/browser/library_page.rb +74 -0
- data/lib/ucode/audit/browser/missing_glyph_page.rb +87 -0
- data/lib/ucode/audit/browser/template.rb +47 -0
- data/lib/ucode/audit/browser/templates/face.css +200 -0
- data/lib/ucode/audit/browser/templates/face.html.erb +41 -0
- data/lib/ucode/audit/browser/templates/face.js +298 -0
- data/lib/ucode/audit/browser/templates/library.css +119 -0
- data/lib/ucode/audit/browser/templates/library.html.erb +42 -0
- data/lib/ucode/audit/browser/templates/library.js +99 -0
- data/lib/ucode/audit/browser/templates/missing_glyph_page.css +119 -0
- data/lib/ucode/audit/browser/templates/missing_glyph_page.html.erb +58 -0
- data/lib/ucode/audit/browser/templates/missing_glyph_page.js +2 -0
- data/lib/ucode/audit/browser.rb +32 -0
- data/lib/ucode/audit/context.rb +27 -1
- data/lib/ucode/audit/coverage_reference.rb +103 -0
- data/lib/ucode/audit/differ.rb +121 -0
- data/lib/ucode/audit/emitter/block_emitter.rb +52 -0
- data/lib/ucode/audit/emitter/codepoint_emitter.rb +87 -0
- data/lib/ucode/audit/emitter/collection_emitter.rb +80 -0
- data/lib/ucode/audit/emitter/face_directory.rb +212 -0
- data/lib/ucode/audit/emitter/glyph_emitter.rb +48 -0
- data/lib/ucode/audit/emitter/index_emitter.rb +149 -0
- data/lib/ucode/audit/emitter/library_emitter.rb +96 -0
- data/lib/ucode/audit/emitter/paths.rb +312 -0
- data/lib/ucode/audit/emitter/plane_emitter.rb +29 -0
- data/lib/ucode/audit/emitter/script_emitter.rb +29 -0
- data/lib/ucode/audit/emitter.rb +29 -0
- data/lib/ucode/audit/extractors/aggregations.rb +31 -2
- data/lib/ucode/audit/face_auditor.rb +86 -0
- data/lib/ucode/audit/formatters/audit_diff_text.rb +112 -0
- data/lib/ucode/audit/formatters/audit_text.rb +411 -0
- data/lib/ucode/audit/formatters/color.rb +48 -0
- data/lib/ucode/audit/formatters/library_summary_text.rb +98 -0
- data/lib/ucode/audit/formatters/text_formatter.rb +83 -0
- data/lib/ucode/audit/formatters.rb +23 -0
- data/lib/ucode/audit/library_aggregator.rb +86 -0
- data/lib/ucode/audit/library_auditor.rb +105 -0
- data/lib/ucode/audit/release/emitter.rb +152 -0
- data/lib/ucode/audit/release/face_card.rb +93 -0
- data/lib/ucode/audit/release/formula_audits.rb +50 -0
- data/lib/ucode/audit/release/library_index_builder.rb +78 -0
- data/lib/ucode/audit/release/manifest_builder.rb +127 -0
- data/lib/ucode/audit/release.rb +42 -0
- data/lib/ucode/audit/ucd_only_reference.rb +81 -0
- data/lib/ucode/audit/universal_set_reference.rb +136 -0
- data/lib/ucode/audit.rb +31 -0
- data/lib/ucode/cli.rb +339 -33
- data/lib/ucode/commands/audit/browser_command.rb +82 -0
- data/lib/ucode/commands/audit/collection_command.rb +103 -0
- data/lib/ucode/commands/audit/compare_command.rb +188 -0
- data/lib/ucode/commands/audit/font_command.rb +140 -0
- data/lib/ucode/commands/audit/library_command.rb +87 -0
- data/lib/ucode/commands/audit/reference_builder.rb +64 -0
- data/lib/ucode/commands/audit.rb +20 -0
- data/lib/ucode/commands/block_feed.rb +73 -0
- data/lib/ucode/commands/canonical_build.rb +138 -0
- data/lib/ucode/commands/fetch.rb +37 -1
- data/lib/ucode/commands/release.rb +115 -0
- data/lib/ucode/commands/universal_set.rb +211 -0
- data/lib/ucode/commands.rb +5 -0
- data/lib/ucode/coordinator/indices.rb +11 -0
- data/lib/ucode/coordinator.rb +138 -5
- data/lib/ucode/error.rb +30 -2
- data/lib/ucode/fetch/font_fetcher/result.rb +39 -0
- data/lib/ucode/fetch/font_fetcher.rb +16 -0
- data/lib/ucode/fetch/specialist_font_fetcher.rb +280 -0
- data/lib/ucode/fetch.rb +7 -3
- data/lib/ucode/glyphs/real_fonts/cmap_cache.rb +74 -0
- data/lib/ucode/glyphs/real_fonts.rb +1 -0
- data/lib/ucode/glyphs/resolver.rb +62 -0
- data/lib/ucode/glyphs/source.rb +48 -0
- data/lib/ucode/glyphs/source_builder.rb +61 -0
- data/lib/ucode/glyphs/source_config/coverage_assertion.rb +79 -0
- data/lib/ucode/glyphs/source_config/gap_report.rb +54 -0
- data/lib/ucode/glyphs/source_config.rb +104 -0
- data/lib/ucode/glyphs/sources/pillar1_embedded_tounicode.rb +63 -0
- data/lib/ucode/glyphs/sources/pillar3_last_resort.rb +51 -0
- data/lib/ucode/glyphs/sources/tier1_real_font.rb +104 -0
- data/lib/ucode/glyphs/sources.rb +20 -0
- data/lib/ucode/glyphs/universal_set/builder.rb +161 -0
- data/lib/ucode/glyphs/universal_set/coverage_report.rb +139 -0
- data/lib/ucode/glyphs/universal_set/idempotency.rb +86 -0
- data/lib/ucode/glyphs/universal_set/manifest_accumulator.rb +195 -0
- data/lib/ucode/glyphs/universal_set/manifest_writer.rb +61 -0
- data/lib/ucode/glyphs/universal_set/pre_build_check.rb +197 -0
- data/lib/ucode/glyphs/universal_set/validator.rb +204 -0
- data/lib/ucode/glyphs/universal_set.rb +45 -0
- data/lib/ucode/glyphs.rb +6 -0
- data/lib/ucode/models/audit/baseline.rb +6 -0
- data/lib/ucode/models/audit/block_summary.rb +7 -0
- data/lib/ucode/models/audit/codepoint_provenance.rb +39 -0
- data/lib/ucode/models/audit/release_face.rb +42 -0
- data/lib/ucode/models/audit/release_formula.rb +33 -0
- data/lib/ucode/models/audit/release_manifest.rb +43 -0
- data/lib/ucode/models/audit/release_universal_set.rb +37 -0
- data/lib/ucode/models/audit.rb +9 -0
- data/lib/ucode/models/block.rb +2 -0
- data/lib/ucode/models/build_report.rb +109 -0
- data/lib/ucode/models/codepoint/glyph.rb +42 -0
- data/lib/ucode/models/codepoint.rb +3 -0
- data/lib/ucode/models/glyph_source.rb +86 -0
- data/lib/ucode/models/glyph_source_map.rb +138 -0
- data/lib/ucode/models/specialist_font.rb +70 -0
- data/lib/ucode/models/specialist_font_manifest.rb +48 -0
- data/lib/ucode/models/unihan_entry.rb +81 -9
- data/lib/ucode/models/unihan_field.rb +21 -0
- data/lib/ucode/models/universal_set_entry.rb +47 -0
- data/lib/ucode/models/universal_set_manifest.rb +78 -0
- data/lib/ucode/models/validation_report.rb +99 -0
- data/lib/ucode/models.rb +9 -0
- data/lib/ucode/parsers/named_sequences.rb +5 -5
- data/lib/ucode/parsers/unihan.rb +50 -19
- data/lib/ucode/repo/aggregate_writer.rb +34 -2
- data/lib/ucode/repo/block_feed_emitter.rb +153 -0
- data/lib/ucode/repo/build_report_accumulator.rb +138 -0
- data/lib/ucode/repo/build_report_writer.rb +46 -0
- data/lib/ucode/repo/build_validator.rb +229 -0
- data/lib/ucode/repo/codepoint_writer.rb +50 -1
- data/lib/ucode/repo/paths.rb +8 -0
- data/lib/ucode/repo.rb +4 -0
- data/lib/ucode/version.rb +1 -1
- data/schema/block-feed.output.schema.yml +134 -0
- metadata +143 -2
- data/ucode.gemspec +0 -56
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# 16 — archive-public: three sync workflows (GHA)
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Add the three GitHub Actions workflows that sync `fontist-archive-public`
|
|
6
|
+
from its three upstream sources:
|
|
7
|
+
|
|
8
|
+
1. `sync-private.yml` — pulls from `fontist-archive-private` on push
|
|
9
|
+
2. `sync-ucode.yml` — pulls from `fontist/ucode` publish workflow
|
|
10
|
+
3. `sync-panglyph.yml` — pulls from `fontist/panglyph` tag pushes
|
|
11
|
+
|
|
12
|
+
Each writes to a disjoint directory (`coverage/`, `unicode/`, `panglyph/`),
|
|
13
|
+
so concurrent runs don't conflict.
|
|
14
|
+
|
|
15
|
+
## Why this is a separate TODO
|
|
16
|
+
|
|
17
|
+
The directory placeholders exist (committed in the
|
|
18
|
+
`audit/add-unicode-and-panglyph-dirs` branch). The sync workflows are
|
|
19
|
+
the actual machinery. Without them, the directories stay empty.
|
|
20
|
+
|
|
21
|
+
## Scope
|
|
22
|
+
|
|
23
|
+
### sync-private.yml
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
name: Sync from fontist-archive-private
|
|
27
|
+
|
|
28
|
+
on:
|
|
29
|
+
repository_dispatch:
|
|
30
|
+
types: [archive-private-updated]
|
|
31
|
+
workflow_dispatch:
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
sync:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- name: Clone private (read-only deploy key)
|
|
39
|
+
env:
|
|
40
|
+
SSH_KEY: ${{ secrets.ARCHIVE_PRIVATE_DEPLOY_KEY }}
|
|
41
|
+
run: |
|
|
42
|
+
mkdir -p ~/.ssh && echo "$SSH_KEY" > ~/.ssh/id_ed25519 && chmod 600 ~/.ssh/id_ed25519
|
|
43
|
+
git clone --depth 1 git@github.com:fontist/fontist-archive-private.git /tmp/private
|
|
44
|
+
- name: Sync coverage/
|
|
45
|
+
run: |
|
|
46
|
+
rm -rf coverage
|
|
47
|
+
cp -r /tmp/private/coverage .
|
|
48
|
+
- name: Sync woff/ (open-license only)
|
|
49
|
+
run: |
|
|
50
|
+
rm -rf woff
|
|
51
|
+
mkdir -p woff
|
|
52
|
+
for d in /tmp/private/woff/*; do
|
|
53
|
+
base=$(basename "$d")
|
|
54
|
+
[ "$base" != "macos" ] && cp -r "$d" "woff/"
|
|
55
|
+
done
|
|
56
|
+
- name: Sync fonts.json + font-metadata.json
|
|
57
|
+
run: cp /tmp/private/fonts.json /tmp/private/font-metadata.json . || true
|
|
58
|
+
- name: Commit
|
|
59
|
+
run: |
|
|
60
|
+
git config user.email "archive-bot@fontist.org"
|
|
61
|
+
git config user.name "archive-bot"
|
|
62
|
+
git add -A
|
|
63
|
+
git diff --quiet HEAD || git commit -m "Sync from fontist-archive-private @ $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
64
|
+
git push
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### sync-ucode.yml
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
name: Sync from fontist/ucode
|
|
71
|
+
|
|
72
|
+
on:
|
|
73
|
+
workflow_run:
|
|
74
|
+
workflows: [publish-unicode-archive]
|
|
75
|
+
types: [completed]
|
|
76
|
+
branches: [main]
|
|
77
|
+
workflow_dispatch:
|
|
78
|
+
|
|
79
|
+
jobs:
|
|
80
|
+
sync:
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
if: github.event.workflow_run.conclusion == 'success'
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/checkout@v4
|
|
85
|
+
- name: Download ucode artifacts
|
|
86
|
+
uses: actions/github-script@v7
|
|
87
|
+
with:
|
|
88
|
+
script: |
|
|
89
|
+
const runId = context.payload.workflow_run.id
|
|
90
|
+
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
|
91
|
+
owner: 'fontist', repo: 'ucode', run_id: runId
|
|
92
|
+
})
|
|
93
|
+
// download unicode-block-feed.tar.gz + universal-glyph-set.tar.gz
|
|
94
|
+
// ...
|
|
95
|
+
- name: Sync unicode/
|
|
96
|
+
run: |
|
|
97
|
+
rm -rf unicode/block-feed unicode/universal-glyph-set
|
|
98
|
+
mkdir -p unicode/block-feed unicode/universal-glyph-set
|
|
99
|
+
tar xzf /tmp/block-feed.tar.gz -C unicode/block-feed
|
|
100
|
+
tar xzf /tmp/universal-glyph-set.tar.gz -C unicode/universal-glyph-set
|
|
101
|
+
- name: Commit
|
|
102
|
+
run: |
|
|
103
|
+
git config user.email "archive-bot@fontist.org"
|
|
104
|
+
git config user.name "archive-bot"
|
|
105
|
+
git add -A unicode/
|
|
106
|
+
git diff --quiet HEAD -- unicode/ || git commit -m "Sync unicode/ from fontist/ucode"
|
|
107
|
+
git push
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### sync-panglyph.yml
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
name: Sync from fontist/panglyph
|
|
114
|
+
|
|
115
|
+
on:
|
|
116
|
+
repository_dispatch:
|
|
117
|
+
types: [panglyph-released]
|
|
118
|
+
workflow_dispatch:
|
|
119
|
+
inputs:
|
|
120
|
+
version:
|
|
121
|
+
description: 'panglyph version (e.g. 17.0.0)'
|
|
122
|
+
required: true
|
|
123
|
+
|
|
124
|
+
jobs:
|
|
125
|
+
sync:
|
|
126
|
+
runs-on: ubuntu-latest
|
|
127
|
+
steps:
|
|
128
|
+
- uses: actions/checkout@v4
|
|
129
|
+
- name: Download panglyph release
|
|
130
|
+
env:
|
|
131
|
+
GH_TOKEN: ${{ secrets.ARCHIVE_PUBLIC_BOT_TOKEN }}
|
|
132
|
+
run: |
|
|
133
|
+
VERSION="${{ inputs.version || github.event.client_payload.version }}"
|
|
134
|
+
gh release download "v${VERSION}" \
|
|
135
|
+
--repo fontist/panglyph \
|
|
136
|
+
--pattern "panglyph-unicode*.{ttf,woff2,otf}" \
|
|
137
|
+
--pattern "coverage-report.json" \
|
|
138
|
+
--pattern "source-manifest.json" \
|
|
139
|
+
--dir "/tmp/v${VERSION}"
|
|
140
|
+
- name: Sync panglyph/
|
|
141
|
+
run: |
|
|
142
|
+
mkdir -p "panglyph/v${VERSION}"
|
|
143
|
+
cp /tmp/v${VERSION}/* "panglyph/v${VERSION}/"
|
|
144
|
+
# Update top-level manifest.json (script in bin/update-panglyph-manifest.rb)
|
|
145
|
+
ruby bin/update-panglyph-manifest.rb "${VERSION}"
|
|
146
|
+
- name: Commit
|
|
147
|
+
run: |
|
|
148
|
+
git config user.email "archive-bot@fontist.org"
|
|
149
|
+
git config user.name "archive-bot"
|
|
150
|
+
git add -A panglyph/
|
|
151
|
+
git diff --quiet HEAD -- panglyph/ || git commit -m "Sync panglyph v${VERSION}"
|
|
152
|
+
git push
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Acceptance
|
|
156
|
+
|
|
157
|
+
- [ ] All three workflows exist + are syntactically valid YAML
|
|
158
|
+
- [ ] Each writes to a disjoint directory
|
|
159
|
+
- [ ] Manual dispatch works (`workflow_dispatch`)
|
|
160
|
+
- [ ] Trigger-based dispatch works (`repository_dispatch` / `workflow_run`)
|
|
161
|
+
- [ ] Bot commits identify as `archive-bot@fontist.org`
|
|
162
|
+
|
|
163
|
+
## References
|
|
164
|
+
|
|
165
|
+
- [TODO.full/09](09-archive-public-structure.md) — target structure
|
|
166
|
+
- [TODO.full/04](04-panglyph-publish-pipeline.md) — panglyph publish trigger
|
|
167
|
+
- [TODO.new/41](../TODO.new/41-ucode-unicode-archive-bridge.md) — ucode publish trigger
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# 17 — fontist.org: font picker on the universal Unicode browser
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Add a font picker to the standalone `/unicode` page so users can browse
|
|
6
|
+
Unicode with a specific font active. Today the universal browser uses
|
|
7
|
+
system fallback fonts; selecting a font from `public/fonts/*.woff2`
|
|
8
|
+
injects `@font-face` and renders every glyph in that font.
|
|
9
|
+
|
|
10
|
+
Pairs with the existing `/fonts/{slug}/unicode` page (FontUnicodePage),
|
|
11
|
+
which already does this — but only for one font at a time. The universal
|
|
12
|
+
browser should let users switch fonts without leaving `/unicode`.
|
|
13
|
+
|
|
14
|
+
## Why this is a separate TODO
|
|
15
|
+
|
|
16
|
+
TODO.full/10 covered the rendering primitives (useFontFace composable,
|
|
17
|
+
FontPicker component, etc.). The integration work — wiring the picker
|
|
18
|
+
into `/unicode`, persisting selection, surfacing on the block + char
|
|
19
|
+
pages — is separate.
|
|
20
|
+
|
|
21
|
+
## Scope
|
|
22
|
+
|
|
23
|
+
### Phase A — Reuse the existing FontPicker
|
|
24
|
+
|
|
25
|
+
1. The `FontStyleUnicodePage` already injects `@font-face` via
|
|
26
|
+
`injectFontFace(slug, 'fonts/${slug}.woff2', true)`. Extract this
|
|
27
|
+
into a global composable that any page can call.
|
|
28
|
+
|
|
29
|
+
2. Add a `<FontPicker>` component to `/unicode` (top of page, sticky).
|
|
30
|
+
|
|
31
|
+
3. On font selection: set a global Pinia store (or provide/inject)
|
|
32
|
+
so all child routes inherit the active font.
|
|
33
|
+
|
|
34
|
+
### Phase B — Coverage overlay
|
|
35
|
+
|
|
36
|
+
4. When a font is active on `/unicode`:
|
|
37
|
+
- Each block row shows: `[coverage bar: 128/128 = 100%]` next to the name
|
|
38
|
+
- Color-coded: green ≥95%, yellow 50-95%, red <50%
|
|
39
|
+
- Click → navigates to `/unicode/block/<slug>?font=<active-slug>`
|
|
40
|
+
|
|
41
|
+
5. On `/unicode/block/<slug>`:
|
|
42
|
+
- If `?font=X` is set, inject X's WOFF + show coverage overlay on each cell
|
|
43
|
+
- Cells with chars the font covers: render in WOFF
|
|
44
|
+
- Cells with chars the font misses: gray out + tooltip "Not in X"
|
|
45
|
+
|
|
46
|
+
### Phase C — Persistence
|
|
47
|
+
|
|
48
|
+
6. Active font persists across page navigation via `localStorage`.
|
|
49
|
+
|
|
50
|
+
7. URL parameter `?font=X` overrides localStorage. Useful for sharing
|
|
51
|
+
links like "view this block in Noto Sans".
|
|
52
|
+
|
|
53
|
+
### Phase D — "Best font per block" page
|
|
54
|
+
|
|
55
|
+
8. New route `/unicode/best-fonts/{block-slug}`: lists fonts sorted by
|
|
56
|
+
fill ratio for that block. Top result is the canonical Tier 1 font
|
|
57
|
+
from ucode's universal-set manifest.
|
|
58
|
+
|
|
59
|
+
## Acceptance
|
|
60
|
+
|
|
61
|
+
- [ ] `/unicode` shows FontPicker at top
|
|
62
|
+
- [ ] Selecting a font injects `@font-face` and re-renders the page
|
|
63
|
+
- [ ] Block list shows coverage bars when a font is active
|
|
64
|
+
- [ ] Block detail page respects `?font=X`
|
|
65
|
+
- [ ] Active font persists in localStorage
|
|
66
|
+
- [ ] `/unicode/best-fonts/{block}` exists
|
|
67
|
+
|
|
68
|
+
## References
|
|
69
|
+
|
|
70
|
+
- [TODO.full/10](10-fontist-org-woff-glyphs.md) — rendering primitives
|
|
71
|
+
- [TODO.full/11](11-fontist-org-audit-coverage.md) — coverage data layer
|
|
72
|
+
- `src/pages/FontUnicodePage.vue` — existing per-font page (pattern source)
|
|
73
|
+
- `src/composables/useFontFace.ts` — existing composable
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# 18 — Comprehensive spec coverage for new code
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Every class added in TODO.full/13–17 must have specs covering:
|
|
6
|
+
- Public API behavior
|
|
7
|
+
- Edge cases (empty input, malformed input, boundary values)
|
|
8
|
+
- Round-trip serialization (write → read = same data)
|
|
9
|
+
- Performance (no obvious pathological cases for 299k codepoints)
|
|
10
|
+
|
|
11
|
+
## Why a separate TODO
|
|
12
|
+
|
|
13
|
+
Quality bar per global rules: "Good specs throughout. Every public
|
|
14
|
+
method should have specs. Every behavioral edge case should be covered.
|
|
15
|
+
Specs use real model instances — never doubles."
|
|
16
|
+
|
|
17
|
+
The new code (FontWriter, panglyph Builder, font picker integration)
|
|
18
|
+
touches core paths. Without specs, regressions slip silently.
|
|
19
|
+
|
|
20
|
+
## Scope
|
|
21
|
+
|
|
22
|
+
### fontisan FontWriter (TODO.full/13, 14)
|
|
23
|
+
|
|
24
|
+
- `FontWriter#set_cmap` — empty, single entry, full BMP, supplementary
|
|
25
|
+
- `FontWriter#add_glyph` — simple outline, composite outline, no instructions
|
|
26
|
+
- `FontWriter#set_name_records` — all 6 standard name_ids
|
|
27
|
+
- `FontWriter#write_to` — round-trip: write → reopen via Fontisan::Font.open
|
|
28
|
+
- Per-table specs:
|
|
29
|
+
- `Tables::Head` — byte-exact comparison with a known fixture
|
|
30
|
+
- `Tables::Cmap` — format 4 BMP, format 12 supplementary, both
|
|
31
|
+
- `Tables::Glyf` — simple glyph, composite glyph, empty glyph (.notdef)
|
|
32
|
+
- etc.
|
|
33
|
+
|
|
34
|
+
### panglyph (TODO.full/15)
|
|
35
|
+
|
|
36
|
+
- `Builder#call` — full pipeline with a 5-codepoint fixture
|
|
37
|
+
- `OutlineExtractor#extract_many` — real font, 3 codepoints
|
|
38
|
+
- `FontAssembler#assemble` — output TTF opens via Fontisan::Font.open
|
|
39
|
+
- `CoverageReport#validate_font` — known gap → reported in missing_codepoints
|
|
40
|
+
- `Publisher#call` — atomic sync to temp git repo fixture
|
|
41
|
+
|
|
42
|
+
### fontist.org (TODO.full/17)
|
|
43
|
+
|
|
44
|
+
- `FontPicker.vue` — emits selection event
|
|
45
|
+
- `useActiveFont` composable — persists to localStorage
|
|
46
|
+
- `/unicode/best-fonts/{block}` — sorts by fill_ratio desc
|
|
47
|
+
|
|
48
|
+
### Integration specs
|
|
49
|
+
|
|
50
|
+
- End-to-end: ucode parse → universal-set build → panglyph build → archive sync → fontist.org fetch
|
|
51
|
+
- Smoke test: built panglyph TTF renders U+0041 in a headless browser
|
|
52
|
+
|
|
53
|
+
## Acceptance
|
|
54
|
+
|
|
55
|
+
- [ ] Every new public class has a corresponding spec file
|
|
56
|
+
- [ ] Every public method has at least one happy-path + one edge-case spec
|
|
57
|
+
- [ ] Round-trip specs exist for any serialization path
|
|
58
|
+
- [ ] `bundle exec rspec` passes on all repos
|
|
59
|
+
- [ ] No `double()` usage (per global rule)
|
|
60
|
+
|
|
61
|
+
## References
|
|
62
|
+
|
|
63
|
+
- Global rule: "Good specs throughout"
|
|
64
|
+
- `spec/support/model_round_trip.rb` — shared example for round-trip models
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# 19 — ucode 0.1.2 patch: include FontWriter + universal-set fixes
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
After TODO.full/13 (FontWriter) lands in fontisan, bump ucode to 0.1.2
|
|
6
|
+
with whatever fixes accumulated. Keep the gem install path stable for
|
|
7
|
+
fontist-archive-private CI.
|
|
8
|
+
|
|
9
|
+
## Why a separate TODO
|
|
10
|
+
|
|
11
|
+
ucode 0.1.1 (TODO.full/05) ships the audit subsystem + BlockFeedEmitter.
|
|
12
|
+
0.1.2 is a routine patch — no SemVer drama, just iteration. Bundles
|
|
13
|
+
whatever real-data fixes surface when CI actually runs against all
|
|
14
|
+
formulas.
|
|
15
|
+
|
|
16
|
+
## Scope
|
|
17
|
+
|
|
18
|
+
- Bump `lib/ucode/version.rb` to `0.1.2`
|
|
19
|
+
- Add CHANGELOG entry (typically: 1-2 fixes)
|
|
20
|
+
- Run full test suite + rubocop
|
|
21
|
+
- Open PR + tag + release per standard release process
|
|
22
|
+
|
|
23
|
+
## Acceptance
|
|
24
|
+
|
|
25
|
+
- [ ] Version bumped
|
|
26
|
+
- [ ] CHANGELOG documents 0.1.2
|
|
27
|
+
- [ ] Specs green
|
|
28
|
+
- [ ] Tag v0.1.2 + `rake release` (with explicit user authorization)
|
|
29
|
+
|
|
30
|
+
## References
|
|
31
|
+
|
|
32
|
+
- [TODO.full/05](05-ucode-0-1-1-release.md) — prior release process
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 20 — fontisan 0.2.23: ship FontWriter
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Once TODO.full/13 (FontWriter API) + TODO.full/14 (table writers) are
|
|
6
|
+
merged to main, ship fontisan 0.2.23 with the new capability. Stays
|
|
7
|
+
on 0.2.x because the removal of audit + UCD was framed as dead-code
|
|
8
|
+
cleanup, not a SemVer event.
|
|
9
|
+
|
|
10
|
+
## Why this is a separate TODO
|
|
11
|
+
|
|
12
|
+
panglyph's gemspec depends on `fontisan, "~> 0.3"` today (the bootstrap
|
|
13
|
+
commit assumed the 0.3.0 bump). After your correction (no bump), the
|
|
14
|
+
constraint needs to relax to `~> 0.2` to pick up FontWriter in 0.2.23.
|
|
15
|
+
|
|
16
|
+
## Scope
|
|
17
|
+
|
|
18
|
+
1. Verify TODO.full/13 + 14 are merged to main.
|
|
19
|
+
2. Bump `lib/fontisan/version.rb` to `0.2.23`.
|
|
20
|
+
3. Add CHANGELOG entry:
|
|
21
|
+
```markdown
|
|
22
|
+
## [0.2.23] — 2026-XX-XX
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- `Fontisan::FontWriter` — new API for assembling fonts from scratch
|
|
27
|
+
(cmap + glyf + name + metrics). Pairs with the existing font-reading
|
|
28
|
+
API. Enables downstream consumers (panglyph) to build new fonts
|
|
29
|
+
from extracted outlines.
|
|
30
|
+
- `Fontisan::FontWriter::Tables::*` — one writer class per OpenType
|
|
31
|
+
table (Head, Cmap, Hmtx, Hhea, Glyf, Loca, Maxp, Os2, Post, Name).
|
|
32
|
+
- Typed structs: `Outline`, `Point`, `NameRecord`, `Metrics`,
|
|
33
|
+
`GlyphEntry`, `FontModel`.
|
|
34
|
+
```
|
|
35
|
+
4. Update panglyph gemspec: `gem "fontisan", "~> 0.2"` (was `~> 0.3`).
|
|
36
|
+
5. Run full test suite + rubocop.
|
|
37
|
+
6. Open PR + tag + release.
|
|
38
|
+
|
|
39
|
+
## Acceptance
|
|
40
|
+
|
|
41
|
+
- [ ] Version bumped to 0.2.23
|
|
42
|
+
- [ ] CHANGELOG entry documents FontWriter addition
|
|
43
|
+
- [ ] panglyph.gemspec constraint relaxed to `~> 0.2`
|
|
44
|
+
- [ ] `bundle exec panglyph version` works against the new fontisan
|
|
45
|
+
- [ ] Tag v0.2.23 + `rake release` (with explicit user authorization)
|
|
46
|
+
|
|
47
|
+
## References
|
|
48
|
+
|
|
49
|
+
- [TODO.full/06](06-fontisan-remove-audit.md) — why we stayed on 0.2.x
|
|
50
|
+
- [TODO.full/07](07-fontisan-remove-ucd.md) — same reasoning
|
|
51
|
+
- [TODO.full/13](13-fontisan-font-writer-api.md) — what 0.2.23 ships
|
|
52
|
+
- [TODO.full/14](14-fontisan-table-writers.md) — companion
|
data/TODO.new/00-README.md
CHANGED
|
@@ -46,9 +46,39 @@ first; these TODOs reference sections of it.
|
|
|
46
46
|
- [20 — Canonical 4-tier resolver](20-canonical-resolver-4-tier.md)
|
|
47
47
|
- [21 — Canonical Unicode 17 dataset build](21-canonical-unicode17-build.md)
|
|
48
48
|
|
|
49
|
+
### Universal glyph set + UC17 curation
|
|
50
|
+
|
|
51
|
+
- [23 — Universal glyph set: Tier 1 source map](23-universal-glyph-set-source-map.md)
|
|
52
|
+
- [24 — Universal glyph set build](24-universal-glyph-set-build.md)
|
|
53
|
+
- [25 — Font audit against universal set](25-font-audit-against-universal-set.md)
|
|
54
|
+
- [26 — Missing glyph reporter (drill-down view)](26-missing-glyph-reporter.md)
|
|
55
|
+
- [27 — fontist.org consumer integration](27-fontist-org-consumer-integration.md)
|
|
56
|
+
- [29 — Universal glyph set: full Unicode 17 curation (Part 1)](29-universal-set-curation-uc17.md)
|
|
57
|
+
- [30 — Tier 1 font acquisition: specialist fonts](30-tier1-font-acquisition.md)
|
|
58
|
+
- [31 — Universal set production build + coverage validation](31-universal-set-production-build.md)
|
|
59
|
+
|
|
60
|
+
### Full UC17 coverage + per-font audit (Part 1 close + Part 2)
|
|
61
|
+
|
|
62
|
+
- [32 — Universal glyph set: full UC17 coverage matrix (Part 1 master)](32-uc17-coverage-matrix.md)
|
|
63
|
+
- [33 — Specialist font acquisition refresh](33-specialist-font-acquisition-refresh.md)
|
|
64
|
+
- [34 — Pillar 2 ContentStreamCorrelator (generalize correlate-v4)](34-pillar2-content-stream-correlator.md)
|
|
65
|
+
- [35 — Universal set production run + glyph provenance (Part 1 close)](35-universal-set-production-run.md)
|
|
66
|
+
- [36 — Per-font coverage audit against universal set (Part 2 master)](36-per-font-coverage-audit.md)
|
|
67
|
+
- [37 — Coverage highlight reporter (missing-glyph visualizer)](37-coverage-highlight-reporter.md)
|
|
68
|
+
- [38 — fontist.org glyph consumer + provenance display](38-fontist-org-glyph-consumer.md)
|
|
69
|
+
|
|
70
|
+
### Pipeline wiring (archive integration)
|
|
71
|
+
|
|
72
|
+
- [40 — fontist-archive-private bin/build uses ucode audit](40-archive-private-uses-ucode-audit.md)
|
|
73
|
+
- [41 — ucode Unicode artifacts → fontist-archive-public bridge](41-ucode-unicode-archive-bridge.md)
|
|
74
|
+
- [30 — Tier 1 font acquisition: specialist fonts](30-tier1-font-acquisition.md)
|
|
75
|
+
- [31 — Universal set production build + coverage validation](31-universal-set-production-build.md)
|
|
76
|
+
|
|
49
77
|
### Sequencing
|
|
50
78
|
|
|
51
79
|
- [22 — Implementation order](22-implementation-order.md)
|
|
80
|
+
- [28 — Implementation order update (TODOs 23-31)](28-implementation-order-update.md)
|
|
81
|
+
- [39 — Implementation order update (TODOs 32-38)](39-implementation-order-update-32-38.md)
|
|
52
82
|
|
|
53
83
|
## Conventions
|
|
54
84
|
|