docs(handoff): state after the 2026-11-11 audit session; /simple mockups

Spec 008 is approved and on hold at the owner's request; its mockups and
screenshots move into mockups/ so they outlive the session.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Fable 5.2 committed 2026-11-11 10:48:46 +01:00
1 parent 4ddc79e9f4
commit 3c094522f2
10 files changed
+207 -46

No files matched your search

+95 -43
View File
@@ -1,53 +1,105 @@
# Handoff — 2026-11-11 (live; audit in progress)
# Handoff — 2026-11-11 (after the audit session)
Where development stopped, and how to pick it up. Delete or rewrite this file when the next session starts.
Everything a new agent needs from the 2026-11-11 session is in this file or in a file it points to.
## State
## State in one paragraph
- **The site is live** at `lucaswinther.info` (behind Cloudflare) since the DNS cutover on 2026-11-10; the 2021 site is at
`old.lucaswinther.info`. On 2026-11-11 `/status` reported all four sources ok. Older lines below that say "not
deployed" or "never run live" describe the state before that.
- **Audit 2026-11-11**: `docs/audits/2026-11-11-audit.md` lists 24 findings with a status each. Fixed so far on
`fix/audit-quick-wins`: 2, 6, 7, 18, 19, 21; on `feat/start-page-without-react` (spec 006, stacked on it): 3.
On `feat/link-previews-sitemap-feed` (spec 007, stacked on that): 8 and 9. The image and its smoke test were not
rebuilt after spec 007 (`SITE_URL` is a new image default). Finding 5 waits in a git stash
for the owner's look. None of these branches is merged.
The site is **live** at `lucaswinther.info` (behind Cloudflare) since the DNS cutover on 2026-11-10; the 2021 site is at
`old.lucaswinther.info`. `main` (`0462ab8`) is what runs in production. On 2026-11-11 the whole app was audited
(`docs/audits/2026-11-11-audit.md`, 24 findings, a status on each row) and a stack of five unmerged, **unpushed**
branches fixes nine of them and adds two built specs and one unbuilt spec. Nothing below is on `main` or on Gitea yet:
it exists only in this working copy.
- **Spec 005 is merged and pushed** (2026-11-10): the start page cassette shows a strip of the song cover with title
and artist; the collage stacks (polaroid over cassette and note); the grain is a pre-rendered tile mask. The owner's
hover-lag feel is written up in `docs/TODO.md` (his browser caps at ~70–80 fps).
- **Specs 003 and 004 are merged into `main` and pushed** (2026-11-10, owner-approved): last film from Trakt and the
week's top track from ListenBrainz in the "right now" strip, alternating film posters, 4:3 band photo, song cards
without the record. `bun test` 184 pass, Playwright 129 pass / 9 skipped. Production needs
`LISTENBRAINZ_USER=stereotypicalcat` (`docs/DEPLOY.md`). The Trakt history/ratings requests haven't run live yet.
Content repo `main` is at `2b89137` (Summer Blooms Without You plays from Spotify).
- **Spec 002 (items in more than one interest, soundtrack tray, band photo, whole-cover comics) is merged into `main`
and pushed** (2026-11-10, owner-approved). `bun test` 168 pass, typecheck clean.
- **Content repo** `portfolio-next-content` (`~/portfolio-next-content`) merged into `main` and **pushed** (head `dd325d6`):
`contract: 2`, five new items (Dear Evan Hansen, A Whisker Away, Always Never, Summer Blooms Without You,
Saltlakridserne: photo only, no link, as the owner said the Facebook URL isn't important; a landscape header photo
would crop better than the portrait one).
Dear Evan Hansen's tray plays "Part Of Me" (Broadway Cast Recording, Deluxe) on Spotify, the owner's pick. Deploy order: app first, then this content (`docs/DEPLOY.md`).
- Spec 001 and its follow-ups are merged into `main` and pushed; not deployed (owner wires homelab, OpenBao, DNS).
## The branch stack (each builds on the one above; merging the last brings everything)
## Next steps
| # | Branch | What it holds | Verified |
|---|---|---|---|
| 1 | `chore/audit-2026-11-11` | The audit report; a pointer in `docs/TODO.md` | docs only |
| 2 | `fix/audit-quick-wins` | Findings 2 (no fonts inlined into CSS), 6 (Ghost fetched page by page), 7, 18, 19, 21 | typecheck, `bun test` 189 |
| 3 | `chore/specs-006-007` | Specs 006 and 007 | docs only |
| 4 | `feat/start-page-without-react` | Spec 006: the start page ships no React; one plain preference switch on every page (finding 3) | typecheck, `bun test` 201, Playwright 133 passed / 9 skipped |
| 5 | `feat/link-previews-sitemap-feed` | Spec 007: canonical + Open Graph tags, `/sitemap.xml`, three Atom feeds, `SITE_URL` (findings 8, 9) | typecheck, `bun test` 236, Playwright 133 / 9 |
| 6 | `feat/simple-side-index` | Spec 008 and its plan (**not built**), the `/simple` mockups, this handoff | docs and mockups only |
1. Owner works through `docs/TODO.md` → "Before go-live (owner)": real project dates, years, `intro` and
`personal_intro`, AU projects' AI levels and un-drafting, comic images, Junkwraith quote check, CV PDF,
Ghost/Trakt/Hardcover keys (and a public Trakt profile), DNS cutover, the blog-redirect decision.
2. First live build with real keys: check `/status` → `sources`. The Ghost, Trakt and Hardcover modules
(`src/sources/`) have never run against the live APIs. `HARDCOVER_QUERY` is the most likely to need fixing.
3. Agent-doable backlog: `docs/TODO.md` → "Next" and "Review follow-ups".
Specs 006 and 007 were implemented by Opus 5.5 subagents from the specs; the main session re-ran typecheck and
`bun test` on each branch and checked the built output. The Playwright numbers are the subagents' runs.
If Playwright shows "Page crashed", the machine is short of memory: rerun with `--workers=2`.
**Not verified anywhere:** the Docker image and `scripts/smoke-test.sh` after spec 007 (`SITE_URL` is a new image default;
the smoke test now sets it and checks `/sitemap.xml`); how LinkedIn and Bluesky render the previews; the cassette's play
button (no fixture or real song has an audio file; it was checked by hand in a browser).
## Before merging to `main` (only when the owner says so)
1. `git rm docs/plans/006-start-page-without-react.md docs/plans/007-link-previews-sitemap-feed.md` (plans are removed
before a merge; keep `docs/plans/008-simple-side-index.md`, its spec is not built).
2. Run `bun run typecheck`, `bun test`, `bunx playwright test` on the tip.
3. Merge locally, no pull requests, never force-push. The owner approves each merge and each push himself; an approval
for one branch does not cover the next.
4. After the merge CI builds the image: watch the smoke test (first real check of `SITE_URL`).
5. Deploying is the owner's (homelab config repo `~/lucwin-config/config`, off limits to agents without asking).
## Waiting for the owner
- **Merge and push** of the stack above. He has not been asked to push; nothing is on Gitea.
- **Finding 5, `color-scheme: dark` on the work theme.** A one-line change, kept out of the branches because he looks
at visual changes before they are committed. It is in `git stash` (`stash@{0}`, "audit #5 …") and is exactly this, in
`src/site/styles/work.css` line 2: `[data-theme='work'] { scroll-padding-top: 72px; color-scheme: dark; }`.
Headless Chrome does not draw scrollbars, so the screenshots (`~/work-color-scheme-before.png`, `-after.png`) only
show that the page content is unchanged; he has to look at `/work/` in a real browser (scrollbar, search field).
- **A changed Playwright check from spec 006.** The "The 2021 site was all by hand →" line is now always in the HTML but
`hidden`; the test in `e2e/preference.spec.ts` that asserted the link was absent now asserts it is not visible and not
in the accessibility tree. Equivalent for visitors, but beyond what the spec allowed ("adapted only where they wait
for an island"), so he was asked to confirm. No answer yet.
- **Spec 007 extras beyond the spec:** an SVG is never used as `og:image` (social sites take raster images only),
`og:image:alt` is written when there is alt text, a malformed `SITE_URL` fails the build. Reported to him; no objection, no explicit yes.
- **Spec 008 calls** (in the spec, marked [call]): no `contract` bump for the optional `pins` block although
`docs/CONTENT-CONTRACT.md` asks for one on a format change; off-the-clock pins are items only; project rows show the AI
level instead of a date; the AI preference hides rows on `/simple` too. He answered "sounds good" to the summary.
- **Owner-only audit findings:** 1 (`www.lucaswinther.info` returns a Cloudflare 525) and 4 (Cloudflare raises `/media/`
browser caching to 20 h; fix in Cloudflare or by hashing media URLs in the app).
## Spec 008 — `/simple` side index with pins: approved, on hold
- The owner chose mockup **A** and asked for pins; then said: "Write the spec and commit it, but dont complete it."
A build that had just started was stopped; only the plan was committed (`docs/plans/008-simple-side-index.md`,
nothing ticked, no code). **Do not start it until he says so.**
- Design truth: `mockups/simple-side-a.html` (a fragment, see its header comment) and
`mockups/shots/simple-side-a-1440.png`, `-390.png`. The mockup has no project rows; the spec adds up to three under
"work". Its label colour `#a8927f` on the oxblood `#3a1d1a` has not been contrast-checked.
- When it is built: he looks at the rendered page before the page and its CSS are committed (the plan says which parts
may be committed first). Preview with a temporary copy of the real content that has the two pins
(`gacha-event-tracker`, `saltlakridserne`); the real content repo gets its `pins` block from the owner afterwards.
## Open audit findings (see the audit file for evidence and fixes)
Open and agent-doable: 10 (print styles for `/simple`, visual), 11 (CI check in the content repo), 12 (publish on push;
touches deployment, ask first), 13 (hover lag hypothesis, to try in the hover lab), 14 (prerender on hover),
15 (`theme-color`), 16 (refresh race: needs a test seam in `src/runtime/refresh.ts`, none was found without one),
17, 20, 22, 23. Waiting or owner-only: 1, 4, 5, 24.
## How the owner works (learned or confirmed this session)
- Once he approves a design, carry it through spec → plan → execution without review stops and report the decisions
at the end. **Exception he set himself:** visual changes are rendered and shown before they are committed.
- On 2026-11-11 he said: "Once specs are written, use Opus 5.5 to complete them." The main session wrote the specs and
the briefs, Opus 5.5 subagents built them (one at a time, stacked branches, because they share `Base.astro`), and the
main session checked each result before starting the next.
- He judges by eye and reacts best to real rendered mockups on a build of the real content. He reaches this machine
over WireGuard at `10.20.20.2`; previews are served with `bun src/cli.ts preview <dir> 4392` and screenshots go in `~/`.
- Never invent facts about him. The 13 projects' dates are placeholders (2021-01-07…19), so nothing should present a
"latest project" by date as fact.
- The real content is `~/portfolio-next-content` (separate repo, head `2b89137`); agents do not change it unasked.
Build it locally with `SOURCES_FIXTURES=fixtures/sources bun src/cli.ts build ~/portfolio-next-content <out> <cache>`.
## Where things are
- Decisions and why: `docs/DECISIONS.md`. Map and invariants: `docs/ARCHITECTURE.md`. Agent rules and commands: `AGENTS.md`. Content format: `docs/CONTENT-CONTRACT.md`. Taste log and every mockup verdict: `docs/inspiration.md`.
- Chosen mockups (visual truth): `mockups/nav-d.html`, `mockups/tech-r3-c.html`, `mockups/personal-r2-b.html`. The sister repo `~/commission-compass` is the pattern for runtime, CI and deploy.
- Local scratch, git-ignored, safe to delete: `.superpowers/` (brainstorm mockup sessions and the finished plan's ledger `sdd/001-site/`; the repo's permission rules block agents from `rm -r`, so delete it by hand). Same for old build output in `.tmp/`.
## Working with the owner
- Once he approves a design, carry it through spec → plan → execution without review stops, and report decisions at the end.
- He reacts best to real mockups; taste lines: calm until touched, no loading screens or game feel, nothing selling, no AI-default look. Not too sleek: he picked `tech-r3-c` over the polished round 4.
- Never invent facts about him; unknowns stay out or go in as drafts.
- He reaches this machine over WireGuard at `10.20.20.2` (the visual companion was served there).
- Decisions and why: `docs/DECISIONS.md`. Map and invariants: `docs/ARCHITECTURE.md`. Rules and commands: `AGENTS.md`.
Content format: `docs/CONTENT-CONTRACT.md`. Deploy: `docs/DEPLOY.md`. Taste log and every mockup verdict:
`docs/inspiration.md`. Backlog: `docs/TODO.md` (its "Before go-live (owner)" list is still his).
- Chosen mockups (visual truth): `mockups/nav-d.html`, `mockups/tech-r3-c.html`, `mockups/personal-r2-b.html`; for
spec 008 also `mockups/simple-side-a.html`. The sister repo `~/commission-compass` is the pattern for runtime, CI and deploy.
- Local scratch, git-ignored, safe to delete: `.superpowers/`, `.tmp/` (including the subagents' `spec006-*` and
`spec007-*` builds). Screenshots from this session are in `~/` (`spec006-*.png`, `simple-mock-*.png`,
`work-color-scheme-*.png`); the ones that matter are also in `mockups/shots/`.
+10
View File
@@ -210,6 +210,16 @@ he moved and cropped the cover himself; using the cover's own lettering was trie
became a stack: the polaroid tilted further (7°) over the cassette, the life note tucked underneath the polaroid
("fine for now", though its LIFE label is partly covered); hovering any scrap brings it to the front.
## `/simple` side panel (2026-11-11)
The owner asked for the left side of `/simple` to be more useful: it only had the two links and the (currently unused)
"everything at once". Two rendered variants on a build of the real content: **A** each way in shows what is behind it
(counts with the by-hand / AI split, newest writing, newest on the wall, reading / listening / last film) and **B** a
dated "Lately" list across both sides (`mockups/simple-side-a.html`, `simple-side-b.html`, shots in `mockups/shots/`).
**Picked: A** ("Simple-a works best"). He added: "Would be nice to be able to pin some stuff that should show … e.g. the
gacha-event-tracker for work and Saltlakridserne for off-the-clock, and then have the app fill in the rest by newest."
That is `docs/specs/008-simple-side-index.md` (approved, not built yet on his request).
## Decisions so far (summary, 2026-11-09)
- **Start page:** `mockups/nav-d.html`, with two gates (work on the left, off the clock on the right) and a small "wander through everything at once" link to the garden (`nav-c.html` idea).
+4 -2
View File
@@ -1,10 +1,12 @@
---
status: in-progress
status: approved
---
# Plan 008 — `/simple` side index with pins
Spec: `docs/specs/008-simple-side-index.md`. Mockup: `~/simple-mock-a-1440.png`, `~/simple-mock-a-390.png`.
Spec: `docs/specs/008-simple-side-index.md`. Mockup: `mockups/simple-side-a.html`,
`mockups/shots/simple-side-a-1440.png`, `mockups/shots/simple-side-a-390.png`.
**On hold:** the owner asked on 2026-11-11 for the spec to be committed but not built yet. Start only when he says so.
Commands: `bun test`, `bun run typecheck`, `bunx playwright test`.
## 1. Pins in `site.yml` (committed)
+5 -1
View File
@@ -5,11 +5,15 @@ status: approved
# 008 — `/simple`: the side becomes an index, with pins
Designed with the owner on 2026-11-11 from two rendered mockups of the side panel; he chose variant A ("each way in
shows what's behind it"; screenshots `~/simple-mock-a-1440.png`, `~/simple-mock-a-390.png`) and asked for pins:
shows what's behind it"; mockup `mockups/simple-side-a.html`, screenshots
`mockups/shots/simple-side-a-1440.png` and `-390.png`; the rejected variant B is beside them) and asked for pins:
"pin some stuff … e.g. the gacha-event-tracker for work and Saltlakridserne for off-the-clock, and then have the app
fill in the rest by newest". Extends `docs/specs/001-site.md` §9. Choices marked **[call]** were made while writing
the spec, not by the owner.
**Not built yet.** The owner approved the design and this spec on 2026-11-11 ("sounds good") and asked for it to be
written and committed but not completed for now. The plan is `docs/plans/008-simple-side-index.md`, nothing ticked.
## Why
The left side of `/simple` held two links and a lot of empty oxblood. It should say what is behind each link, with
real things from the site, and let the owner choose which things lead. The page stays the short, static one:
Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

+48
View File
@@ -0,0 +1,48 @@
<!-- /simple side panel, variant A (2026-11-11). CHOSEN by the owner (spec 008).
A fragment, not a page: the <aside> replaces .sm-side in a BUILT /simple/index.html and the <style> goes before </head>
(it sits on top of src/site/styles/simple.css). Screenshots: mockups/shots/simple-side-a-1440.png, -390.png.
Throwaway markup: match the look, do not copy the code. "[newest post title]" is a stand-in; the reading / listening /
last film values were copied from the live site on 2026-11-11. -->
<style>
.sm-ways{margin-top:40px;gap:22px}
.way{display:grid}
.sm-in{list-style:none;margin:6px 0 0 42px;padding:0;font-size:14px;line-height:1.45;color:var(--cream-dim)}
.sm-in li{padding:3px 0}
.sm-in li.k{margin-top:8px;font:600 10.5px var(--sans);letter-spacing:.12em;text-transform:uppercase;color:#a8927f}
.sm-in a,.sm-late a{color:var(--cream);text-decoration:none;border-bottom:1px solid rgba(242,231,215,.28)}
.sm-in time{margin-left:8px;font-size:12.5px;color:#a8927f;font-variant-numeric:tabular-nums}
.sm-in span{color:var(--cream)}
.mk{display:inline-block;width:.62em;height:.62em;border-radius:50%;border:1.4px solid var(--cream-dim);margin:0 .3em 0 .7em;vertical-align:.02em}
.mk.ai{background:var(--cream-dim)}
.sm-rn{display:grid;grid-template-columns:84px minmax(0,1fr);gap:6px 14px;margin:36px 0 0 42px;font-size:14px}
.sm-rn dt{font:600 10.5px/1.9 var(--sans);letter-spacing:.12em;text-transform:uppercase;color:#a8927f}
.sm-rn dd{margin:0;color:var(--cream)} .sm-rn dd span{color:var(--cream-dim);margin-left:6px;font-size:13px}
.sm-late{margin:40px 0 0}
.sm-late h2{display:flex;align-items:center;gap:12px;margin:0 0 10px;font:600 11px var(--sans);letter-spacing:.12em;text-transform:uppercase;color:#a8927f}
.sm-late h2::after{content:"";flex:1;height:1px;background:rgba(242,231,215,.18)}
.sm-late ol{list-style:none;margin:0;padding:0}
.sm-late li{display:grid;grid-template-columns:58px minmax(0,1fr) auto;gap:12px;align-items:baseline;padding:8px 0;border-bottom:1px solid rgba(242,231,215,.12);font-size:15.5px}
.sm-late li a{justify-self:start;font-family:var(--serif);font-size:17px}
.sm-late time,.sm-late li span{font-size:12.5px;color:#a8927f;font-variant-numeric:tabular-nums}
.sm-rnl{margin:16px 0 0;font-size:14px;line-height:1.55;color:var(--cream-dim);max-width:30em} .sm-rnl b{font-weight:400;color:var(--cream)}
@media (hover:hover){.sm-in a:hover,.sm-late a:hover{border-color:var(--saffron)}}
@media (max-width:900px){.sm-rn,.sm-in{margin-left:42px}}
.sm-ways .sm-in a{display:inline;padding:0}.sm-ways .sm-in a::before{content:none}.sm-in li{display:flex;justify-content:space-between;gap:12px;align-items:baseline}.sm-in li:first-child{justify-content:flex-start;gap:0}.sm-rn{margin-top:28px}</style>
<aside class="sm-side"><h1>Lucas Winther</h1><p class="sm-line">Computer Scientist with passion for development.</p>
<nav class="sm-ways" aria-label="The two spaces">
<div class="way"><a href="/work/"><span class="n">work</span><span class="d">projects, writing, the CV in full</span></a>
<ul class="sm-in">
<li><span>13 projects</span> <i class="mk hand" aria-hidden="true"></i> 11 by hand <i class="mk ai" aria-hidden="true"></i> 2 made with AI</li>
<li class="k">latest writing</li>
<li><a href="/work/writing/synthetic-work-post/">[newest post title]</a> <time>14 Mar</time></li>
</ul></div>
<div class="way"><a href="/off-the-clock/"><span class="n">off the clock</span><span class="d">things I love and things I think</span></a>
<ul class="sm-in">
<li class="k">newest on the wall</li>
<li><a href="/off-the-clock/a-whisker-away/">A Whisker Away</a> <time>film · 10 Nov</time></li>
<li><a href="/off-the-clock/always-never/">Always Never</a> <time>comic · 10 Nov</time></li>
<li><a href="/off-the-clock/saltlakridserne/">Saltlakridserne</a> <time>music · 10 Nov</time></li>
</ul></div>
</nav>
<dl class="sm-rn"><dt>reading</dt><dd>Wolvenheart, Vol. 1 <span>Mark London</span></dd><dt>listening</dt><dd>New Commandments <span>Moon Walker</span></dd><dt>last film</dt><dd>Backrooms <span>7 Aug</span></dd></dl>
<p class="sm-more"><a href="/">the start page</a> · <a href="/everything/">everything in one list</a></p></aside>
+45
View File
@@ -0,0 +1,45 @@
<!-- /simple side panel, variant B (2026-11-11). Rejected (owner chose A).
A fragment, not a page: the <aside> replaces .sm-side in a BUILT /simple/index.html and the <style> goes before </head>
(it sits on top of src/site/styles/simple.css). Screenshots: mockups/shots/simple-side-b-1440.png, -390.png.
Throwaway markup: match the look, do not copy the code. "[newest post title]" is a stand-in; the reading / listening /
last film values were copied from the live site on 2026-11-11. -->
<style>
.sm-ways{margin-top:40px;gap:22px}
.way{display:grid}
.sm-in{list-style:none;margin:6px 0 0 42px;padding:0;font-size:14px;line-height:1.45;color:var(--cream-dim)}
.sm-in li{padding:3px 0}
.sm-in li.k{margin-top:8px;font:600 10.5px var(--sans);letter-spacing:.12em;text-transform:uppercase;color:#a8927f}
.sm-in a,.sm-late a{color:var(--cream);text-decoration:none;border-bottom:1px solid rgba(242,231,215,.28)}
.sm-in time{margin-left:8px;font-size:12.5px;color:#a8927f;font-variant-numeric:tabular-nums}
.sm-in span{color:var(--cream)}
.mk{display:inline-block;width:.62em;height:.62em;border-radius:50%;border:1.4px solid var(--cream-dim);margin:0 .3em 0 .7em;vertical-align:.02em}
.mk.ai{background:var(--cream-dim)}
.sm-rn{display:grid;grid-template-columns:84px minmax(0,1fr);gap:6px 14px;margin:36px 0 0 42px;font-size:14px}
.sm-rn dt{font:600 10.5px/1.9 var(--sans);letter-spacing:.12em;text-transform:uppercase;color:#a8927f}
.sm-rn dd{margin:0;color:var(--cream)} .sm-rn dd span{color:var(--cream-dim);margin-left:6px;font-size:13px}
.sm-late{margin:40px 0 0}
.sm-late h2{display:flex;align-items:center;gap:12px;margin:0 0 10px;font:600 11px var(--sans);letter-spacing:.12em;text-transform:uppercase;color:#a8927f}
.sm-late h2::after{content:"";flex:1;height:1px;background:rgba(242,231,215,.18)}
.sm-late ol{list-style:none;margin:0;padding:0}
.sm-late li{display:grid;grid-template-columns:58px minmax(0,1fr) auto;gap:12px;align-items:baseline;padding:8px 0;border-bottom:1px solid rgba(242,231,215,.12);font-size:15.5px}
.sm-late li a{justify-self:start;font-family:var(--serif);font-size:17px}
.sm-late time,.sm-late li span{font-size:12.5px;color:#a8927f;font-variant-numeric:tabular-nums}
.sm-rnl{margin:16px 0 0;font-size:14px;line-height:1.55;color:var(--cream-dim);max-width:30em} .sm-rnl b{font-weight:400;color:var(--cream)}
@media (hover:hover){.sm-in a:hover,.sm-late a:hover{border-color:var(--saffron)}}
@media (max-width:900px){.sm-rn,.sm-in{margin-left:42px}}
</style>
<aside class="sm-side"><h1>Lucas Winther</h1><p class="sm-line">Computer Scientist with passion for development.</p>
<nav class="sm-ways" aria-label="The two spaces">
<a href="/work/"><span class="n">work</span><span class="d">13 projects, 11 of them by hand · writing · the CV in full</span></a>
<a href="/off-the-clock/"><span class="n">off the clock</span><span class="d">5 things on the wall this year · things I love and things I think</span></a>
</nav>
<section class="sm-late" aria-labelledby="late"><h2 id="late">Lately</h2>
<ol>
<li><time>10 Nov</time><a href="/off-the-clock/a-whisker-away/">A Whisker Away</a><span>film</span></li>
<li><time>10 Nov</time><a href="/off-the-clock/always-never/">Always Never</a><span>comic</span></li>
<li><time>10 Nov</time><a href="/off-the-clock/saltlakridserne/">Saltlakridserne</a><span>music</span></li>
<li><time>14 Mar</time><a href="/work/writing/synthetic-work-post/">[newest post title]</a><span>writing</span></li>
</ol>
<p class="sm-rnl">Reading <b>Wolvenheart, Vol. 1</b>, listening to <b>New Commandments</b>, last watched <b>Backrooms</b>.</p>
</section>
<p class="sm-more"><a href="/">the start page</a> · <a href="/everything/">everything in one list</a></p></aside>