Commit Graph

5 Commits

Author SHA1 Message Date
1d2cbda50d Ship a signed release APK
The release build type reuses the debug signing config, so a downloaded APK
installs over an existing one instead of demanding an uninstall. This never
goes to Play, which rejects debug keys anyway, so there is no private key
worth safeguarding for years and no way to strand anyone on a version that
can no longer be updated.

That choice is load-bearing in one direction: a release build is not
DEBUGGABLE, so adb shell run-as stops reading app data back out, and there is
no in-app restore. A signature change would have cost the drill progress.

npm run release stages release/404-Layers-<version>.apk with a checksum and
verifies the signature, since an unsigned APK builds fine and only fails at
install time, on someone else's phone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 21:51:01 +03:00
2b28f27e79 Close the keystore gitignore trap, and ship the font licences
.gitignore had "*.keystore" followed by "!debug.keystore", which
deliberately un-ignored a signing key. Nothing leaked - no keystore has
ever been in the tree - but had one landed there it would have been
committed silently. The negation is gone and *.jks is covered too.

public/fonts/ redistributes Space Grotesk and Space Mono, and the SIL
Open Font License requires its text to accompany the fonts. Both are
included, fetched from each typeface's own repository rather than
written from memory, and kept as separate files because the copyright
lines differ: Space Grotesk 2020, Space Mono 2016.

Added a README there recording which file is which family, why only the
latin subsets are shipped, and the two glyphs that fall outside them and
so render from a system fallback - which is why the pickers draw their
caret as SVG instead of typing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 21:27:48 +03:00
956dc57763 Phase 2: React scaffolding, self-hosted fonts, design tokens
Vite builds to dist/, deliberately not www/. www/ is still produced by
sync-www.sh for the Phase 1 APK, which stays installable throughout the
port; cutover is a one-line webDir change in capacitor.config.json.
base is relative because Capacitor serves the bundle from the APK, where
absolute asset paths would 404.

index.html omits viewport-fit=cover on purpose. That string is what
makes Capacitor's SystemBars plugin pass insets through to the page;
without it the plugin pads the decor view and the layout is always
between the status and gesture bars. Phase 1 learned this the hard way.

Fonts are self-hosted for offline use, latin subsets only: three files
at 68K, against the 133K Barlow costs today. Space Grotesk is variable,
so one file covers 400-700. Dropped latin-ext and vietnamese.

Carets are drawn as SVG, not typed. U+25BE and U+23EE sit outside every
Latin subset and would fall back to a system font mid-label.

base.css carries the settled palette and the measured vertical budget as
tokens, so a component cannot quietly exceed it:
  8 + 44 + 8 + 525 + 8 + 84 + 8 + 50 = 735

Verified: typecheck clean, 103 tests, vite build emits with the fonts
copied, and www/ is untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 01:05:09 +03:00
091bdc2a96 Add design canvas: two TE-inspired directions before the React port
Design inspiration is the Teenage Engineering EP-133 manual: flat fills,
heavy outlines, hard zero-blur offset shadows, one orange accent,
uppercase technical type, monospaced numerals.

Six artboards drawn at the real measured 360x735 with the actual
vertical budget (44px pickers, 485px panel, 116px info, 58px tabs), so
a mockup cannot fit in a way the device won't:

- Current       the app as it stands, for comparison
- A Manual      light ground, 2px black outlines, black pads
- B Blueprint   pure black, 1px white hairlines, no fills
- Specimen      type candidates and palette, incl. which orange

Type is identical across both directions so the light/dark choice is
not confounded with the font choice. Green/red drill feedback is
replaced by orange fill vs dashed outline - neither exists in this
palette.

The seeded canvas payload is gitignored; these files are its source.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 23:56:04 +03:00
1a8a12f7f3 Phase 1: wrap the reference web app in Capacitor for Android
Wraps reference/sp404-layers as a sideloadable APK without editing the
reference, which stays the frozen spec for the Phase 2 React port.

- sync-www.sh builds www/ from reference/ + native/, asserting each patch
  anchor so a reference change fails loudly rather than shipping broken
- drops the service worker (would serve a stale app after an APK update)
- haptics via a navigator.vibrate override, so buzz() needs no change
- localStorage mirrored into Preferences; sync load()/save() untouched
- hardware back: sheet -> Explore tab -> exit
- edge-to-edge handled in MainActivity: Android 16 + targetSdk 36 removes
  the opt-out, and a WebView never fills env(safe-area-inset-*), so insets
  are pushed into CSS custom properties instead

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 00:26:35 +03:00