[feat](trx-frontend-http): render APRS symbols as glyphs #37

Merged
sjg merged 3 commits from feat/aprs-symbol-glyphs into main 2026-08-03 20:12:50 +02:00
Owner

APRS position reports were rendering their raw symbol character in a bordered box, because the stylesheet had sprite rules (background-size: 384px 192px) for a sheet that was never added to the repo.

What changed

  • Vendored rev H of hessu/aprs-symbols: the primary, alternate and overlay 24px sheets plus their retina variants, embedded and served under /vendor with immutable cache headers.
  • Rendering moved to a shared aprsSymbolSprite() helper used by the APRS list, the HF APRS list and the map markers. / and \ select a sheet; any other table identifier is an overlay character stacked on top of the alternate symbol, per the APRS spec. Codes outside 0x21..0x7E keep the old character box.
  • Sheet URLs stay in CSS so a min-resolution: 2dppx query swaps in the retina sheets; only the cell offset is inline.

Licensing

The symbol set carries no single license — individual symbols are variously vectorizations of the original WA8LMF bitmaps with unknown terms, new CC BY-SA work by OH7LZB, public-domain or CC sources, and a few brand logos owned by their companies. It is recorded as LicenseRef-APRS-Symbols with the upstream per-symbol catalogue copied verbatim into LICENSES/, plus the attribution pointer upstream asks for in the README.

Testing

  • tests/aprs-symbols.test.mjs pins the cell indexing, the three table modes, overlay layer order, the fallback, and that the stylesheet serves all six sheets locally at the sprite geometry.
  • A Rust test parses each embedded PNG's IHDR, so a re-vendored sheet at a different size can't silently shift every symbol onto a neighbouring icon.
  • cargo test -p trx-frontend-http (56), cargo clippy -p trx-frontend-http --all-targets, frontend typecheck / build / lint / test (39) all clean.
  • Rendered in headless Chromium at 2x against the real stylesheet and sheets: /> a car, /- a house, /_ a WX circle, /& an igate diamond, \n a red triangle, and the overlays S> / 7# / An carrying their character on the alternate symbol.

Not included

trx-aprs only extracts symbol_table / symbol_code for Position packets, so Mic-E, Object and Item reports still render no symbol. They carry symbols too, in different field positions — left for a follow-up.

APRS position reports were rendering their raw symbol character in a bordered box, because the stylesheet had sprite rules (`background-size: 384px 192px`) for a sheet that was never added to the repo. ## What changed - **Vendored** rev H of [hessu/aprs-symbols](https://github.com/hessu/aprs-symbols): the primary, alternate and overlay 24px sheets plus their retina variants, embedded and served under `/vendor` with immutable cache headers. - **Rendering** moved to a shared `aprsSymbolSprite()` helper used by the APRS list, the HF APRS list and the map markers. `/` and `\` select a sheet; any other table identifier is an overlay character stacked on top of the alternate symbol, per the APRS spec. Codes outside `0x21..0x7E` keep the old character box. - Sheet URLs stay in CSS so a `min-resolution: 2dppx` query swaps in the retina sheets; only the cell offset is inline. ## Licensing The symbol set carries no single license — individual symbols are variously vectorizations of the original WA8LMF bitmaps with unknown terms, new CC BY-SA work by OH7LZB, public-domain or CC sources, and a few brand logos owned by their companies. It is recorded as `LicenseRef-APRS-Symbols` with the upstream per-symbol catalogue copied verbatim into `LICENSES/`, plus the attribution pointer upstream asks for in the README. ## Testing - `tests/aprs-symbols.test.mjs` pins the cell indexing, the three table modes, overlay layer order, the fallback, and that the stylesheet serves all six sheets locally at the sprite geometry. - A Rust test parses each embedded PNG's IHDR, so a re-vendored sheet at a different size can't silently shift every symbol onto a neighbouring icon. - `cargo test -p trx-frontend-http` (56), `cargo clippy -p trx-frontend-http --all-targets`, frontend `typecheck` / `build` / `lint` / `test` (39) all clean. - Rendered in headless Chromium at 2x against the real stylesheet and sheets: `/>` a car, `/-` a house, `/_` a WX circle, `/&` an igate diamond, `\n` a red triangle, and the overlays `S>` / `7#` / `An` carrying their character on the alternate symbol. ## Not included `trx-aprs` only extracts `symbol_table` / `symbol_code` for `Position` packets, so Mic-E, Object and Item reports still render no symbol. They carry symbols too, in different field positions — left for a follow-up.
sjg added 1 commit 2026-08-03 19:37:19 +02:00
The web UI had no symbol graphics at all, so a position report rendered
its raw symbol character in a bordered box.  Vendor rev H of the
hessu/aprs-symbols set: three 24px sheets (primary, alternate, and the
overlay characters) plus their retina variants.

The set carries no single license.  Individual symbols are variously
vectorizations of the original WA8LMF bitmaps with unknown terms, new
CC BY-SA work by OH7LZB, public-domain or CC sources, and a handful of
brand logos owned by their companies.  Record that as
LicenseRef-APRS-Symbols with the upstream per-symbol catalogue copied
verbatim, and carry the attribution pointer upstream asks for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018huL1ELyr86yVqfAabtioA
Signed-off-by: Stan Grams <sjg@haxx.space>
sjg added 2 commits 2026-08-03 19:56:04 +02:00
Embed the six sheets alongside the other vendored assets and serve them
under /vendor with the same immutable cache headers.

The browser computes a symbol's cell from a 16x6 grid of 24px cells, so
a re-vendored sheet at any other size would shift every station onto a
neighbouring icon -- wrong on every packet, and invisible unless you
know which glyph to expect.  Pin the geometry by parsing each embedded
PNG's IHDR in a test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018huL1ELyr86yVqfAabtioA
Signed-off-by: Stan Grams <sjg@haxx.space>
[feat](trx-frontend-http): draw APRS symbols from the sprite sheets
CI / lint (pull_request) Successful in 2m16s
CI / test (pull_request) Successful in 8m12s
CI / frontend (pull_request) Successful in 3m2s
CI / reuse (pull_request) Successful in 3s
CI / lint (push) Successful in 2m24s
CI / test (push) Successful in 7m28s
CI / frontend (push) Successful in 2m11s
CI / reuse (push) Successful in 3s
5b7dd493d4
Resolve a table/code pair to a sprite cell in aprs-shared, and use it
from both the packet lists and the map markers, which had each been
printing the raw symbol character in a bordered box.

A table identifier of / or \ selects the primary or alternate sheet
directly.  Anything else is an overlay character, which the APRS spec
draws on top of the alternate symbol -- so those stack the overlay sheet
over the alternate one rather than picking a sheet.  Codes outside
0x21..0x7E have no cell and keep the old character box.

The sheet URLs stay in the stylesheet so a min-resolution query can swap
in the retina sheets; only the cell offset is computed and set inline.
Map markers share the helper through the plugin chunk, so the map stays
free of any remote symbol fetch.

Verified in a browser against the real stylesheet and sheets: /> is a
car, /_ a WX circle, /& an igate diamond, \n a red triangle, and the
overlays S> and 7# carry their character on the alternate symbol.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018huL1ELyr86yVqfAabtioA
Signed-off-by: Stan Grams <sjg@haxx.space>
sjg force-pushed feat/aprs-symbol-glyphs from 597ba031f3 to 5b7dd493d4 2026-08-03 19:56:04 +02:00 Compare
sjg merged commit 5b7dd493d4 into main 2026-08-03 20:12:50 +02:00
sjg deleted branch feat/aprs-symbol-glyphs 2026-08-03 20:12:50 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sjg/trx-rs#37