0
0

Compare commits

...

6 Commits

5 changed files with 74 additions and 31 deletions

39
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install fonts-liberation
run: |
sudo apt-get update
sudo apt-get install -y fonts-liberation
- name: Set up uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Build assets
run: make
- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: |
dist/qrfont-1L.ttf
dist/qrfont-2L.ttf
dist/qrfont-3L.ttf
dist/index.html
dist/favicon.ico

View File

@@ -9,12 +9,13 @@ text as QR Code symbols while keeping surrounding text readable. The generated
font is a Modified Version of Liberation Sans Regular and is licensed under the
SIL Open Font License 1.1.
The current bounded QR target is:
The bounded QR targets are:
- QR Code Version 3-L
- **QR Code Version 1-L** (up to 17 characters per block)
- **QR Code Version 2-L** (up to 32 characters per block)
- **QR Code Version 3-L** (up to 53 characters per block)
- byte mode
- fixed mask pattern 0
- printable ASCII payloads up to 53 characters per bracketed block
- `[` and `]` delimiters
Example:
@@ -32,8 +33,9 @@ Use `uv` for Python commands and dependency management.
make
```
`make` runs the full Reed-Solomon parity build, then copies the font, demo,
reference page, license, and notice into `~/Downloads/qrfont/`.
`make` runs the full Reed-Solomon parity build and compiles the fonts and `index.html` demo into the `dist/` directory.
Use `make deploy` to synchronize the built `dist/` assets directly to `psy:/www/qr/` (which cleans up stale/experimental remote files via `--delete`).
Do not use the placeholder parity path for normal verification. It exists only
as a legacy layout-debug target:
@@ -87,13 +89,7 @@ Browser rendering is useful but time-consuming. The user asked to skip routine
Firefox rendering for now. If visual alignment regresses, inspect recent
screenshots in `~/Downloads`.
## Larger QR Codes
The current font is fixed to Version 3-L, which supports 53 byte-mode
characters. Supporting multiple QR versions in one font is possible, but would
require branching by payload length at close-delimiter time and emitting
version-specific base patterns, coordinate maps, RS parity circuits, and
advances. The current simpler strategy is one fixed QR version for all payloads.
We build three separate font families (`1-L`, `2-L`, `3-L`), each fixed to its respective QR version. Supporting multiple QR versions dynamically in a single font file is possible, but would require branching by payload length at close-delimiter time and emitting version-specific base patterns, coordinate maps, RS parity circuits, and advances. The current strategy compiles separate fonts for each version.
## Browser Layout, Alignment, and Line-Breaking Details

View File

@@ -1,6 +1,11 @@
# QR Font
# Jim's TrueType QR Code Font
**Live Demo:** [https://qr.jim.sh/](https://qr.jim.sh/)
Live Demo: https://qr.jim.sh/
Downloads:
- [qrfont-1L.ttf](https://github.com/jimparis/qr-font/releases/latest/download/qrfont-1L.ttf) (21x21 modules, up to 17 characters)
- [qrfont-2L.ttf](https://github.com/jimparis/qr-font/releases/latest/download/qrfont-2L.ttf) (25x25 modules, up to 32 characters)
- [qrfont-3L.ttf](https://github.com/jimparis/qr-font/releases/latest/download/qrfont-3L.ttf) (29x29 modules, up to 53 characters)
This repo generates an experimental OpenType font that turns bracket-delimited
text into a QR Code symbol while leaving surrounding text readable.
@@ -9,23 +14,21 @@ text into a QR Code symbol while leaving surrounding text readable.
abc[hello]ghi
```
The first target is intentionally bounded:
- QR Code Version 3-L, 29 by 29 modules
- byte mode
- printable ASCII input, up to 53 characters
- fixed mask pattern 0
All fonts use:
- Byte mode
- Printable ASCII input
- Fixed mask pattern 0
- `[` and `]` as delimiters
The font is generated rather than hand-authored. The build script emits glyph
outlines and GSUB feature logic, then compiles them into `dist/qrfont.ttf`.
The fonts are generated rather than hand-authored. The build script emits glyph
outlines and GSUB feature logic, then compiles them into `dist/qrfont-*.ttf`.
The default build compiles the delimiter parser, byte expansion, Reed-Solomon
parity circuit, QR module placement, and fixed mask rendering.
Printable ASCII glyphs are copied from Liberation Sans Regular, scaled into the
QR Font em square, so text outside bracketed QR blocks renders as ordinary text
in the same font. `Liberation` is a reserved font name under the source font
license, so the generated family is named `QR Font`.
license, so the generated families are named `QR Font 1-L`, `QR Font 2-L`, and `QR Font 3-L`.
## Build
@@ -75,11 +78,11 @@ uv run tools/shape_debug.py '[a]' '[b]'
Outputs:
- `dist/qrfont.ttf`
- `dist/demo.html`
- `build/qrfont.fea`
- `dist/qrfont-*.ttf` (1-L, 2-L, and 3-L font files)
- `dist/index.html` (interactive web demo)
- `build/qrfont-*.fea` (generated OpenType feature files)
Open `dist/demo.html` in a browser and type bracketed text such as `[hello]`.
Open `dist/index.html` in a browser and type bracketed text such as `[hello]`.
Mixed text such as `abc[def]ghi` should render as normal text, then a QR code
for `def`, then normal text.
@@ -93,4 +96,5 @@ licensed under the SIL Open Font License, Version 1.1. See
This is a proof-of-concept font. It relies on OpenType shaping, so it needs an
environment that applies GSUB features to the font. Inputs inside a QR block
are bounded to printable ASCII, up to 53 characters.
are bounded to printable ASCII, up to 17, 32, or 53 characters depending on the
selected font version.

View File

@@ -2,7 +2,7 @@ import argparse
from pathlib import Path
import hashlib
DIST = Path("/home/jim/git/qr-font/dist")
DIST = Path(__file__).resolve().parent.parent / "dist"
def file_hash(filepath: Path) -> str:
if not filepath.exists():

View File

@@ -3,8 +3,12 @@ import subprocess
from pathlib import Path
import shutil
DIST = Path("/home/jim/git/qr-font/dist")
ARTIFACTS = Path("/home/jim/.gemini/antigravity-cli/brain/b99818b3-5da0-4033-8da1-3a74b472fb71")
DIST = Path(__file__).resolve().parent.parent / "dist"
# Fallback for artifacts folder if home directory is different
home_dir = Path.home()
ARTIFACTS = home_dir / ".gemini/antigravity-cli/brain/b99818b3-5da0-4033-8da1-3a74b472fb71"
if not ARTIFACTS.exists():
ARTIFACTS = Path("/tmp")
PROFILE_DIR = Path("/tmp/ff_test_prof")
TEST_HTML_PATH = Path("/tmp/test_visual.html")