Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ jobs:
node-version: "22"
cache: npm
- run: npm ci
- name: Validate release tag and notes
if: startsWith(github.ref, 'refs/tags/v')
env:
RELEASE_TAG: ${{ github.ref_name }}
run: |
node --input-type=module -e 'import { readFileSync, accessSync } from "node:fs"; const { version } = JSON.parse(readFileSync("package.json")); if (process.env.RELEASE_TAG !== `v${version}`) throw new Error("Tag does not match package version"); accessSync(`docs/releases/${process.env.RELEASE_TAG}.md`);'
- run: npm test
- run: npm run build
- run: npm run lint:firefox
Expand All @@ -34,6 +40,11 @@ jobs:
echo "CHROME_KEY_PATH=$RUNNER_TEMP/fontify.pem" >> "$GITHUB_ENV"
fi
- run: npm run package
- name: Package human-readable review source
if: startsWith(github.ref, 'refs/tags/v')
run: |
VERSION=$(node -p "require('./package.json').version")
git archive --format=zip --output="artifacts/fontify-$VERSION-source.zip" HEAD src public scripts data tests docs package.json package-lock.json README.md LICENSE THIRD_PARTY_NOTICES.md
- name: Sign Firefox XPI for unlisted distribution
if: startsWith(github.ref, 'refs/tags/v')
env:
Expand All @@ -42,7 +53,8 @@ jobs:
shell: bash
run: |
if [ -n "$AMO_JWT_ISSUER" ] && [ -n "$AMO_JWT_SECRET" ]; then
npx web-ext sign --source-dir dist/firefox --artifacts-dir artifacts/signed --channel unlisted --api-key "$AMO_JWT_ISSUER" --api-secret "$AMO_JWT_SECRET"
VERSION=$(node -p "require('./package.json').version")
npx web-ext sign --source-dir dist/firefox --artifacts-dir artifacts/signed --channel unlisted --upload-source-code "artifacts/fontify-$VERSION-source.zip" --api-key "$AMO_JWT_ISSUER" --api-secret "$AMO_JWT_SECRET"
else
echo 'AMO credentials are not configured. The unsigned XPI is available for development.'
fi
Expand All @@ -68,13 +80,15 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: fontify-packages
path: packages
- uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
body_path: docs/releases/${{ github.ref_name }}.md
files: |
packages/*.zip
packages/*.crx
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Download the latest **fontify-packages** artifact from [Actions](https://github.

### Chrome / Chromium

1. Extract `fontify-1.1.0-chrome.zip`.
1. Extract `fontify-1.1.1-chrome.zip`.
2. Open `chrome://extensions` and enable **Developer mode**.
3. Choose **Load unpacked** and select the folder containing `manifest.json`.
4. Refresh any already-open websites once after installation. Later settings changes apply live.
Expand All @@ -42,7 +42,7 @@ A CRX3 package is also built. A self-signed CRX is useful for compatible develop

### Firefox

1. Extract `fontify-1.1.0-firefox.zip`.
1. Extract `fontify-1.1.1-firefox.zip`.
2. Open `about:debugging#/runtime/this-firefox`.
3. Choose **Load Temporary Add-on** and select `manifest.json`.
4. Refresh already-open websites once after installation.
Expand All @@ -69,10 +69,11 @@ Output:
| -------------------------------------- | ------------------------------------------------------ |
| `dist/chrome/` | Unpacked Chromium MV3 build; service worker background |
| `dist/firefox/` | Firefox MV3 build; event-page background |
| `artifacts/fontify-1.1.0-chrome.zip` | Chrome development/store upload package |
| `artifacts/fontify-1.1.0-firefox.zip` | Firefox source package |
| `artifacts/fontify-1.1.0.crx` | Self-signed CRX3 |
| `artifacts/fontify-1.1.0-unsigned.xpi` | Unsigned Firefox development package |
| `artifacts/fontify-1.1.1-chrome.zip` | Chrome development/store upload package |
| `artifacts/fontify-1.1.1-firefox.zip` | Firefox extension package |
| `artifacts/fontify-1.1.1.crx` | Self-signed CRX3 |
| `artifacts/fontify-1.1.1-unsigned.xpi` | Unsigned Firefox development package |
| `artifacts/fontify-1.1.1-source.zip` | Human-readable source for release review |

`npm run catalogue:update` refreshes the Google Fonts metadata snapshot. Catalogue access is never needed during an ordinary build. Fonts themselves download on demand through the background extension context and are cached in IndexedDB. All executable code and UI assets are bundled locally.

Expand All @@ -82,7 +83,7 @@ Mozilla's linter currently reports one `UNSAFE_VAR_ASSIGNMENT` warning in the bu

## Automated builds and signing

Every push to `main` and every pull request builds, tests, validates, packages, and uploads artifacts. Tags matching `v*` also create GitHub Releases.
Every push to `main` and every pull request builds, tests, validates, packages, and uploads artifacts. Tags matching `v*` also sign an unlisted Firefox XPI when credentials are configured and publish GitHub release assets. Unlisted signing does not publish a Mozilla Add-ons store listing. See the [1.1.1 release notes](docs/releases/v1.1.1.md).

Optional repository **Actions secrets**:

Expand Down
2 changes: 2 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ Fontify is MIT licensed. It uses @m3e/web (MIT, copyright 2025–2026 matraic),
The Google Fonts catalogue contains family names and metadata retrieved from Google's public metadata endpoint. Individual font files retain their own licences; selected Google fonts are downloaded at runtime, not redistributed in this repository. Outfit is bundled for the interface under SIL Open Font License 1.1; see public/fonts/OFL.txt.

Custom fonts are supplied by the user and stored only on their device. Users should have permission to use their uploaded fonts.

Sidebar symbols are Google's Material Symbols Rounded, weight 700, in outlined and filled variants, from https://github.com/google/material-design-icons. They are bundled under Apache License 2.0; see public/symbols/LICENSE.
130 changes: 130 additions & 0 deletions anti-slop/delivery-2026-10-12.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Fontify Anti Slop delivery

Applied the Anti Slop plugin in during mode. Direction comes from Fontify's existing lavender M3E tonal palette, expressive selected shapes, and browser-extension workflow, plus the owner's request for interface-wide font application, a wider popup, a larger sidebar, thick rounded icons, and micro-interaction morphs. Outfit remains the loading/error fallback. ENERGY 2 / RHYTHM 2 / MOTION 2.

## Changes and reasons

- Retain Outfit as the fallback, the existing app icon, and M3E components: these are Fontify's established identity.
- Apply the selected sans-serif/default profile across the interface, including native inputs and M3E shadow-root labels; apply the bold and italic profiles to their text styles: the extension itself now demonstrates the saved choices. Fonts apply after loading, with Outfit as a fallback on failure.
- Increase the desktop sidebar from 195px to 260px, with 76px navigation rows and 30px symbols: the controls are easier to read and target.
- Bundle Google's Material Symbols Rounded at weight 700 in outlined/filled pairs: typography, library, exclusion, tuning, and settings symbols describe each section, keep their shape when the interface font changes, and meet the owner's explicit icon direction.
- Morph navigation/icon corners and crossfade outlined/filled selection states; soften button/filter/icon press shapes and animate the picker entrance: short motion communicates actions and hierarchy. M3E expressive motion is enabled; reduced-motion preferences remove the added motion. Background colours switch immediately to avoid low-contrast transitional pairings.
- Set native toolbar popup width explicitly to 520px, while ordinary-tab previews remain responsive: viewport-relative width caused the native Chrome popup to shrink to 25px in a reproduced test. The actual toolbar popup now measures 520px, with quick settings visible before the specimen.
- Retain lavender as the primary accent: it marks selected controls and the working font specimen.
- Remove repeated slogan eyebrows and decorative hero blobs: settings titles should identify the task, and the specimen should demonstrate the fonts.
- Keep the typography page's existing pun: it gives Fontify a recognisable voice without obscuring the functional navigation labels.
- Replace vague library, override, upload, and preference copy with action names: users can identify where to change a setting.
- Use a pangram, numerals, bold, and italic in the specimen: users can compare actual letterforms and styles.
- Apply selected families to the profile-card glyphs: those samples previously showed the interface font rather than the selected profile.
- Place preview controls beside the specimen in reading order: changes have an immediate, nearby result.
- Put popup site actions and All settings above the specimen: quick controls stay reachable before the longer preview.
- Use 18px profile-card corners, larger grouping surfaces, and the existing asymmetric specimen/selected-navigation shapes: radius communicates hierarchy while preserving M3E character.
- Use plain empty-state text rather than repeated decorative icons and dashed cards: the next useful action is easier to read.
- Wrap navigation at narrow widths and constrain grid tracks: settings remain accessible without horizontal page scrolling.
- Give buttons, filters, icons, and the size slider at least 44px target height: the compact extension remains usable by touch.
- Keep native control borders at the outline token and remove text opacity reductions: boundaries and text remain distinguishable in both themes.
- Make the main shell inert while dialogs are open, focus the editor, and restore its trigger after closing: keyboard users stay in the task and return to their place.
- Resolve the system theme before choosing the corner toggle's action: clicking it now switches to the opposite visible theme.
- Add a persistent startup error and retry action: a failed catalogue load no longer leaves a loading screen with a disappearing toast.
- Ignore outdated asynchronous preview results and clear recovered errors: a slow previous selection cannot overwrite a later specimen.

No new logo, navigation destinations, dependencies, or settings-schema changes. Requested sidebar symbols are bundled with Google's Apache-2.0 licence and attribution.

## Validation

- `npm test`: 8 tests passed.
- `npm run build`: Chrome and Firefox builds passed.
- `npm run lint:firefox`: 0 errors, 0 notices, 1 existing `UNSAFE_VAR_ASSIGNMENT` warning from Lit's bundled template parser, already documented in README.md.
- `npm run test:browser`: passed using Playwright 1.55.1 and Chromium 140 with the actual unpacked extension. Google font responses use a deterministic bundled-font fixture, so these tests validate loading and application behaviour rather than the visual appearance of each remote family.
- Every settings section checked in light and dark at 1240, 768, 390, and 320px. Document overflow, rendered text contrast using the WCAG luminance formula, and control target height assertions passed. The popup tab preview also passed light/dark checks at 320px and was captured at 520px.
- Actual native Chromium toolbar popup opened through `chrome.action.openPopup`; its DevTools target measured 520px body/content width, no horizontal overflow, and All settings within the visible height. Native viewport width can also include platform scrollbar space. This validates native sizing separately from opening popup.html in a tab.
- Selecting independent Bungee/Lora/Roboto regular/bold/italic profiles changes computed interface font families, including inputs, section headings, and M3E shadow-root labels. This checks propagation while keeping deterministic font data in the integration suite.
- All ten local outlined/filled SVG variants fetch successfully. Reduced-motion emulation reports no picker animation and zero navigation-icon transition duration.
- Screenshots recorded for all 40 settings/theme/width combinations and the popup. Desktop typography, narrow typography/preferences, and popup captures were visually inspected.
- Keyboard tests verify initial editor focus, nested picker/editor Escape handling, restored trigger focus, and focus remaining in the popup dialog while tabbing. Source review confirms native focus outlines and M3E strong-focus remain enabled.
- Firefox interactive behaviour and physical mobile keyboards were not tested. Firefox validation is build/lint only. The builds remain unsigned development packages.

## Recorded interaction checks

- Regular, serif, sans-serif, bold, italic, and monospace font choices open a picker and select a profile; live page typography changes. Regular/bold/italic card glyphs load the selected face.
- Style weights render their defaults; override weight changes persist after Save changes.
- Global enable switches pause and restore page typography, including original inline priorities. Code replacement changes fixed-width text while protecting icons.
- Preview text updates the specimen; size changes update the specimen and its px output.
- Picker search filters results; all category filters change their selected state; Show more expands the list; saving and unsaving a favourite changes Saved results; unmatched searches show an empty state.
- Picker Close, Done, and Escape close it. Closing a nested picker returns focus inside the override editor. Closing the editor returns focus to Edit.
- Each navigation button opens its real section; narrow navigation wraps visibly.
- Upload accepts the bundled TTF; Use applies it; Remove confirms deletion and restores the empty library state.
- Exception type selection works; an invalid hostname shows validation; selector exceptions preserve page text; font exceptions can be added and removed.
- A context-menu-equivalent block request opens the composer; Save override persists across reloads; Edit, Save changes, Cancel, and Remove work.
- Theme controls change light/dark mode. System light and system dark each make the corner button switch to the opposite visible mode.
- Download permission toggles; Clear cache confirms completion while keeping custom fonts.
- Export produces a JSON backup; Import restores it after confirmation; Reset clears settings while retaining uploaded fonts.
- Popup Pause here and Resume here update the site's exception. All settings opens the options page.
- Failed catalogue startup shows a persistent error; Try again recovers the interface.
- Interface-wide fonts change with the profiles; real native toolbar sizing is 520px; icon states load locally; added animations are disabled with reduced motion.
- Runtime page-error collection is empty. Existing external Source & feedback and M3E links retain their real destinations and explicit new-tab arrows; no new links were introduced.

## Delivery gate

Each PASS below is limited to the Chromium runtime, source review, and build/lint evidence above.

### Hard gate

- R-02 PASS: UI source scan has no em dashes in authored copy.
- R-03 PASS: overflow and 44px target assertions pass at the four recorded widths in both themes.
- R-17 PASS: catalogue totals, result counts, and file sizes derive from real stored data.
- R-18 PASS: no testimonial or avatar content exists in the interface.
- R-23 PASS: existing app assets and navigation reused; owner's requested rounded symbols bundled with their licence.
- R-24 PASS: all five navigation controls open existing settings views.
- R-25 PASS: rendered text passes computed WCAG AA contrast in the recorded views/themes and picker filters.
- R-26 PASS: shared control actions exercised in the interaction record; no placeholder controls added.
- R-27 PASS: loading status, collection/search empty states, font errors, and persistent startup error/retry exist; failure recovery exercised.
- R-28 PASS: no FAQ exists or was added.
- R-32 PASS: native outlines and M3E strong focus retained; dialog keyboard/focus assertions pass.
- R-33 PASS: edits made directly in UI source and CSS; no source-rewriting helper scripts added.
- R-34 PASS: light, dark, and system-toggle behaviour verified; both rendered themes pass layout and contrast assertions.
- R-35 PASS: both browser builds run; real Chromium extension interaction suite passes with no page errors.
- R-36 PASS: no new security, compliance, performance, or customer claims.
- R-37 PASS: existing brand direction and explicit dials declared before edits.
- R-38 PASS: product copy describes existing implemented behaviour; no invented features or content.

### Purpose gate

- R-01 PASS: existing lavender tonal tokens retained for state and specimen hierarchy; no gradients/glows added.
- R-04 PASS: Material Symbols Rounded text_fields, collections_bookmark, block, tune, and settings identify their sections; theme and favourite marks denote real actions.
- R-06 PASS: Outfit retained for established identity; labels now use normal case without wide tracking.
- R-07 PASS: no background grid or ornamental texture.
- R-08 PASS: existing external/new-tab arrows retained for destination behaviour; no new decorative arrows.
- R-09 PASS: author badge removed; remaining counts reflect actual exception/result data.
- R-10 PASS: no glassmorphism.
- R-12 PASS: shadows limited to the modal layer and transient status message.
- R-13 PASS: no glow treatment.
- R-14 PASS: equivalent profile cards remain comparable; category controls, specimen, settings rows, and library lists use distinct layouts for their tasks.
- R-19 PASS: short selection/press morphs and picker entrance communicate actual interaction; no looping animation; reduced-motion assertions pass.
- R-22 PASS: no illustrations created.

### Liveliness

- Dials PASS: ENERGY 2 / RHYTHM 2 / MOTION 2 declared and maintained.
- Focal point PASS: the working specimen anchors typography; other screens use task titles and the relevant action/list.
- Whitespace PASS: settings groups, profile controls, specimen, and explanation use distinct spacing levels.
- Accent PASS: lavender identifies selection, primary actions, and the specimen.
- Motif PASS: Outfit letterforms and existing asymmetric M3E selected/specimen shapes remain.
- Design Read PASS: browser typography utility with Fontify's existing M3E language declared before generation.

### Craftsmanship and quality locks

- C-1 PASS: major visual decisions have written reasons above.
- C-2 PASS: shared interactive control actions verified in the recorded suite.
- C-3 PASS: all sections serve real extension functions; repeated decorative headings removed.
- C-4 PASS: layout, theme, error recovery, and keyboard dialog tests pass within the stated coverage.
- C-5 PASS: no fabricated testimonials, statistics, or claims.
- R-05 PASS: task-oriented settings structure retained; specimen, profile grids, rows, and lists reflect their content.
- R-11 PASS: profile cards, grouping panels, controls, and asymmetric selected shapes have distinct radii.
- R-15 PASS: library action now says Choose regular font; other actions name their behaviour.
- R-16 PASS: vague promotional UI copy replaced by specific setting descriptions.
- R-20 PASS: existing Fontify icon, Outfit fallback, lavender M3E palette, and typography specimen retain identity while the interface demonstrates the user's font choices.
- R-21 PASS: existing light/dark/system controls remain functional; system toggle corrected.
- R-29 PASS: existing coherent M3E tonal palette retained without additional core colours.
- R-30 PASS: no unrelated product's visual design copied.
- R-31 PASS: palette, layout, typography, spacing, surfaces, and icon purposes documented above.
Loading
Loading