Loading…
a327ex.com

Anchor Website 1

Fable 5

Opus 4.8

Summary

Started, from scratch, an Anchor 2 reimplementation of the personal website a327ex.com — rendered in the RICOCHET visual theme, desktop-first — living at a327ex-site/renderer/ (a fork of ricochet-template). Built the engine support, the markdown→element converter, article rendering, the sidebar + in-app navigation, and the homepage shell + feed. Full status/roadmap saved to renderer/PLAN.md.

Task framing & strategy (A vs B):

  • Restart of the earlier Anchor2/site effort. Goal: render everything the live site renders, inside Anchor 2, in the Ricochet theme, as close as possible to the site's structure while respecting Ricochet.
  • Debated "copy the site CSS first, then fix" (A) vs "start from Ricochet, fix toward the site" (B). Chose B: A's gravity is the bland default theme we're replacing (silent omissions that linger); B's errors are concrete/visible and converge. The real resolution: source of truth is per-dimension — site dictates structure (what renders, column width, feed/sidebar), Ricochet dictates look; spacing takes the site's relationships but Ricochet's magnitudes. Also: the site CSS is explicitly throwaway bridge code.

Setup decisions:

  • Project folder a327ex-site/renderer/, tracked inside the a327ex-site repo (no separate git repo). Old /posts/* must eventually render in their EXACT original dark theme (deferred; old CSS is in static/old-blog*.css). Font handled the thorough way (engine change), not a hack.

Engine — dynamic glyph atlas (shared Anchor2/engine/src/anchor.c):

  • Replaced the fixed ASCII-96 baked atlas with a lazy, multi-page, codepoint→GlyphInfo cache. On a glyph miss: FT_Load_Char, pack at a shelf cursor, glTexSubImage2D just that sub-rect (from a tight buffer — no GL_UNPACK_ROW_LENGTH, WebGL-safe), open-addressing hash cache, 1024² pages (cap 8), .notdef for missing. ASCII pre-warmed at load. FT_Face + font_data now kept alive (not freed after bake).
  • Result: any codepoint the font file contains renders (Latin-1, punctuation, CJK e.g. LanaPixel). Caveats noted: font must actually contain the glyph; CJK line-breaking and cross-font fallback are separate renderer-layer concerns.
  • Later added a font_get_ascent Lua binding + self.ascent on the framework font object (both Anchor2/framework/anchor/font.lua and renderer/anchor/font.lua) to baseline-align mixed-font lines (inline code was sitting above the body baseline because tokens were top-aligned). Engine built; patched binary at renderer/anchor.exe.

Scaffold: lean fork — the ricochet/ package + framework + fresh patched anchor.exe + smooth assets (Oswald / IBM Plex Reg+Italic+Medium / Cascadia) + Tabler icons; skipped rough-mode pixel assets and dev galleries. Proof-of-life main.lua that doubled as a live non-ASCII font test; verified the file is real UTF-8.

Phase 1 — article renderer:

  • theme.lua (prose): type scale (Oswald title; Plex Medium h2/h3 — condensed caps too loud for in-article subheads; Plex 18 body; Cascadia code), light color roles, spacing.
  • elements.lua + canvas.lua adapted from the old Anchor2/site extraction: styled runs, word-wrap, image fit, scroll (mouse wheel + arrows/j-k), chrome (crumb + Oswald title + hairline). Reads data files via dofile (engine _chdirs into the game dir).

Spacing iteration:

  • Started flat (14px gap); user pushed to source values from the real CSS. Transcribed new-theme.css margins (p 16, .entry headings mt40/mb8.8, etc.) with CSS-style margin collapse — then user chose to revert to the Ricochet baseline (strategy B) and tune by eye.
  • Built an F1 spacing tuner (live sliders + COPY VALUES → clipboard + console). Baked article values: element_gap 14, line_gap 6, gap_before h2 28 / h3 24 / image 20 (image carries an equal gap below via gap_after + max-collapse).

Converter (tools/convert.lua):

  • markdown + Blot frontmatter + ::directivesdata/<slug>.lua element files. Inline parser (**bold** / *italic* / `code` / [text](url) links → blue, non-interactive), block line-scanner, ::image (URL-decode + /media../media), other ::TYPE → dim [TYPE] placeholder, blockquotes → body paragraphs. Serializes with %q.
  • --all converts + indexes notes/logs/posts/messages = 328 pagesdata/index.lua (globally date-sorted, message content previews). Fixed a crash on lines starting with :: but no directive name (require non-space after ::).

Phase 2 — sidebar + navigation (sidebar.lua):

  • Content tree from the index (notes/logs), collapsible (collapsed by default), date-sorted, truncated rows (text_truncate, UTF-8 safe, in elements.lua), HOME pin, stencil-clipped scroll, active row = inverted ink fill + blue tick.
  • In-app navigation: clicking loads + lays out that page (load_page), two independent scroll panes (wheel routes to the pane under the cursor).
  • Explored the nav design against the Ricochet reference sheets; offered "open rail" vs "framed panel" via an F2 toggle, user chose open; removed the edge-hugging corner brackets and fixed the header rule that was striking through the section label.

Perf: added off-screen culling in canvas_draw (long logs only pay draw cost for the visible screenful). Open-click layout hitch for huge logs still pending (caching).

Phase 4 — homepage (homepage.lua):

  • Crumb (social links + email) + ARTIFACTS banner (It Follows / SNKRX / BYTEPATH) + separator + unified feed (all four types interleaved by date, tagged NOTE/AI LOG/POST/MSG, clickable). Initial view; HOME pin returns to it.
  • After user flagged ratios as "very off" vs the live site, reworked to compact UI-scale type (like the sidebar, not the article prose scale), dense rows, full timestamps, and a small mono ARTIFACTS label (was a giant Oswald title). Made the F1 panel contextual (HOME SPACING vs SPACING) with hp live-tunable, immediate-mode.

Wrap-up: plan + status written to renderer/PLAN.md and a project memory pointer added. Next steps (priority): (1) inline message content in the feed, (2) content fidelity — code blocks/lists/blockquotes/embeds/spoilers and the rough-rendering logs (raw HTML), (3) old-theme /posts/*, (4) search + theme toggle + interactive links, (5) styling polish (STYLING_TODO.md), (6) infra/perf + eventual web delivery, (7) the renderer is still uncommitted. Controls: F1 spacing tuner; wheel / ↑↓ / j-k scroll.

🔒 Only the summary of this log is public. Private because it contains too many website internal details.