Skip to content

Site: review round — panel fixes, camera frame, and a guided setup page - #119

Merged
MyNamesEMurray merged 11 commits into
mainfrom
claude/lenslink-site-review-round
Sep 8, 2026
Merged

Site: review round — panel fixes, camera frame, and a guided setup page#119
MyNamesEMurray merged 11 commits into
mainfrom
claude/lenslink-site-review-round

Conversation

@MyNamesEMurray

@MyNamesEMurray MyNamesEMurray commented Sep 8, 2026

Copy link
Copy Markdown
Owner

What & why

A running branch for the site review. Not to be merged until the round is
done
— commits get added as each item is settled, and this description tracks
them.

1. The hero device panel clipped on phones

The panel is not a screenshot: it's the app's Live screen rebuilt from the
design tokens in docs/UI_DESIGN.md, so it stays crisp at any size and can't
drift out of date. It was laid out wrong on a narrow screen, though — the box
was pinned to aspect-ratio: 16 / 10, which at phone widths computes shorter
than the control rows need, and the box hides its overflow. The AF / Lock row
was sliced in half: 44px of overflow at 390px, none at 768px and above,
which is why desktop checks never caught it.

16:10 only has room for the controls once the screen is ~382px wide (a ~470px
viewport), so below that the ratio gives way and content sets the height. The
children are flex: none so a future squeeze can't be absorbed by silently
shrinking a row. Verified across 18 widths from 320 to 1920: no clipping, and
the crossover is 1.64 → 1.60.

2. A camera frame behind the panel, chosen by orientation

The controls looked like a widget rather than a camera app with nothing behind
them. Now: drop static/img/hero-feed-landscape.* and/or
hero-feed-portrait.* into static/img/ and the build puts them behind the
panel, the way the app draws controls over live video.

The stylesheet picks by viewport, on a seam that already exists — portrait
below 470px, where the panel drops 16:10 and stands tall (and where a phone
held upright is what the app looks like anyway); landscape above it. Either
orientation stands in for a missing one, and only the one in use is
downloaded
. With neither file the panel keeps its tinted glow and the page
requests nothing extra — which is the state this PR ships in, pending real
frames.

The gradient layer doubles as a scrim when a photo is present, so white
controls stay legible over any image.

3. A setup guide that filters itself

Setup branches more than a linear page can serve: 3 operating systems × 2
transports × 3 app-install routes × camera-or-screen = 36 combinations, of
which any one reader needs about a dozen steps and has to skip the rest.

/setup/ asks those four questions and shows only the matching steps. The
design choice worth keeping: it filters rather than generates. Every step is
in the HTML with its conditions attached, so with JavaScript off nothing is
hidden and the page is still a complete, correctly ordered guide — which is
also what search engines index. There's no template to drift from the docs, and
steps renumber themselves because a hidden <li> takes no CSS counter.

  • Answers live in the query string, so a configuration is a shareable link:
    /setup/?os=macos&link=wifi&mode=screen&app=sideload.
  • A "what you'll need" box names what's easy to discover too late — a data
    cable rather than charge-only, iTunes on Windows, the weekly re-install a
    sideload costs.
  • The questions are real radio inputs styled as the app's segmented control, so
    the page is keyboard- and screen-reader-native and works unstyled.
  • Linked from the home hero, the docs index and the install page.

Also in this commit: heading anchors are now documentation-only. They earn
their place where headings are destinations people link to; on the marketing
pages they were a stray # on hover.

How it was tested

  • python3 build.py → 16 pages; python3 check-links.py → 0 broken links.
  • Two full configurations walked end to end (Windows/USB/camera/TestFlight and
    macOS/Wi-Fi/screen/sideload): correct steps, correct order, correct
    "what you'll need", no page errors, and the URL round-trips.
  • JavaScript disabled: all 22 steps present, the explanatory notice visible,
    the radios still usable.
  • Feed layer verified in all three states — both images, one image, neither —
    checking which file each viewport actually fetches.
  • Rendered at 390px and 1280px: no horizontal overflow.

Release-Skip: true; site/ matches none of the release paths.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA

The home page's device panel is not a screenshot — it is the app's Live
screen rebuilt from the design tokens, so it stays crisp and cannot drift
out of date. Its screen box was pinned to 16:10, which at phone widths
computes shorter than the control rows need, and the box hides its
overflow: the AF / Lock row was sliced in half. Measured 44px of overflow
at 390px, none at 768px and above.

16:10 only fits once the screen is about 382px wide — a ~470px viewport —
so below that the ratio now gives way and the content sets the height.
The children are also flex: none, so a squeeze can never be absorbed by
shrinking a row instead.

Swept 18 viewport widths from 320px to 1920px: no clipping at any of them,
and the crossover at the breakpoint is 1.64 to 1.60, which is invisible.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 8, 2026

Copy link
Copy Markdown

Deploying lenslink with  Cloudflare Pages  Cloudflare Pages

Latest commit: a0fbcb6
Status: ✅  Deploy successful!
Preview URL: https://cab8b8d6.lenslink.pages.dev
Branch Preview URL: https://claude-lenslink-site-review.lenslink.pages.dev

View logs

The panel reads oddly with nothing behind it: the app's controls are drawn
over live video, so a flat gradient makes them look like a widget rather
than a camera app. This adds the missing layer while keeping the panel
itself HTML and CSS, which is what keeps it crisp and in step with the app.

Drop a landscape image at static/img/hero-feed.jpg and build.py marks the
panel `has-feed` and points a --feed custom property at it. Absent that
file — the state this commit ships in — nothing references it, so there is
no failed request and no broken-image box; the panel keeps the tinted glow
it has now. The same ::before layer that draws that glow becomes the scrim
when a photo is present, so white controls stay legible over whatever the
photo is doing, and the panel and pills are lifted above it.

Verified both ways: with a generated stand-in the frame shows through the
scrim with every control readable and no failed requests; with the file
removed the markup is exactly as before.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
Takes both a landscape and a portrait still and chooses between them by
viewport, rather than stretching one to fit both. The seam is one that
already exists: below 470px the panel drops 16:10 and stands tall, which
is a portrait frame's shape — and a phone held upright is what the app
looks like there anyway — while above it the panel is a wide screen.

Either orientation stands in for a missing one, so one file is enough, and
with neither the panel keeps its tinted glow. Because the choice is made in
a media query, the browser downloads only the frame it will actually show.

Verified with stand-ins: 390px picks portrait, 471px and 1440px pick
landscape, each fetching that file alone; with the portrait removed, 390px
falls back to landscape with no failed request; with both removed the
markup carries no reference at all.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
Setup branches more than a linear page can serve: three operating systems,
two transports, three ways to install the app, and camera or screen — 36
combinations, of which any one reader needs a dozen steps and has to skip
the rest.

/setup/ asks those four questions and shows only the matching steps. It
filters rather than generates: every step is in the HTML with the setups it
belongs to attached, so with JavaScript off nothing is hidden and the page
is still a complete, correctly ordered guide — which is also what search
engines see. There is no template to drift from the documentation, and the
steps renumber themselves because a hidden item takes no CSS counter.

The answers are in the query string, so a working configuration is a link
you can send someone, and a "what you'll need" box names the parts that are
easy to discover too late — a data cable rather than a charge-only one,
iTunes on Windows, the weekly re-install a sideload costs.

The questions are real radio inputs styled as the app's segmented control,
so the page is keyboard- and screen-reader-native and works unstyled.

Also: heading anchors are now documentation-only. They earn their place
where headings are destinations; on the marketing pages they were a stray #
appearing on hover.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
@MyNamesEMurray MyNamesEMurray changed the title Site: review-round fixes Site: review round — panel fixes, camera frame, and a guided setup page Sep 8, 2026
"The camera" and "The phone's screen" were an odd pair — one leaned on the
question for its subject, the other repeated it. Both now name the thing
being chosen, in the same shape, which also reads correctly if the question
scrolls out of view on a phone.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
…ning

Two of the four questions have a real answer behind them — USB and
TestFlight are what the documentation recommends everywhere — so they now
carry a quiet "Recommended" badge rather than leaving the reader to infer
it from a note underneath. The other two questions are facts about the
reader, not choices to steer, and are left unmarked.

The badge deliberately does not introduce a second accent: it is the
accent at low opacity, and inverts to white-on-accent when its option is
selected so it stays legible either way.

Icons go where they depict something — a cable, a Wi-Fi fan, a lens, a
phone, a download arrow. The operating systems get none: there is nothing
to draw for them but trademarks, and a generic box beside each of three
names would carry no information.

Both are the first things to go when space runs out. Under 560px the badge
collapses to an accent dot, keeping the word for screen readers; under
400px the icons drop entirely, which is what stops "USB cable" and "Phone
camera" wrapping onto a second line at 320px. Swept nine widths from 320
to 1280: no wrapping, no overflow, at any of them.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
USB or Wi-Fi is the one question in the guide that asks the reader for a
decision rather than a fact, and it is the one a newcomer is least equipped
to make — the tradeoff only makes sense once you have run both.

"Not sure" takes the USB path, and says so: an answer box explains that the
steps below are the USB ones, why that is the safe default, and when to
switch. The guide chooses, rather than quietly picking for them or leaving
them stuck on the question. The general note arguing for USB hides while
that box is up, since together they said the same thing twice.

The URL keeps `link=unsure` rather than rewriting it to `usb`, so a shared
link preserves what the reader actually answered.

Icons now drop below 479px rather than 400px: three options plus a cable
glyph do not fit a 430px row, which the sweep caught. Sixteen widths from
320 to 1280 are clean.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
Anyone setting up a capture pipeline knows what a cable and a wireless
network are; the sentence explained the difference to nobody who needed it.
The "Recommended" badge already carries the only part that was a claim.

The "Not sure" answer keeps a shorter version — one line saying which
steps it picked and when to switch — because that one is not explaining
USB, it is explaining what the guide just did on the reader's behalf.

Removes the now-unused .q-note rule and the JavaScript that toggled it.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
It was a pill beside the label — a pill inside a pill, and wide enough to
make the recommended option noticeably fatter than its neighbours. Now it
sits on its own line under the label at 9.5px, as letterspaced small caps
rather than a second filled shape, so the options keep a common outline and
the marker reads as an annotation instead of a badge competing with the
selection.

flex-basis carries it to the second line, so no extra markup, and the spans
fill their labels: every pill in a row matches height whether or not it is
the one being recommended.

It also no longer has to collapse to a dot on a phone. On its own line the
word fits down to 320px, so the marker now says the same thing at every
width. Checked at eleven widths from 320 to 1280: rows even, nothing
overflowing.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
Checked against the plugin rather than memory, and the site was wrong on one
point: it said USB needs "nothing extra on macOS or Linux". macOS is right —
the usbmuxd socket is part of the OS — but on Linux the plugin connects to
/var/run/usbmuxd (usbmux.c), which is a daemon a distribution may or may not
have installed. That is the same class of prerequisite as iTunes on Windows,
and it was documented as no prerequisite at all.

So: the install page gains a table of the real differences, the download
page's note is corrected, and the setup guide grows a Linux + USB step
beside the Windows + iTunes one, with the matching line in "what you'll
need".

The differences are narrower than they look, and the table says so: the app,
the protocol and every camera feature are identical everywhere. What changes
is the USB helper, the hardware-decode backend (D3D11VA/DXVA2, VideoToolbox,
VAAPI/VDPAU), what the GPU pipeline requires, and one real feature gap —
10-bit on the GPU pipeline, which macOS cannot do because VideoToolbox
converts to 8-bit BGRA before the plugin sees the frame (gpu-frame.c), so
HDR and Apple Log render through the standard path there. That last one is
now in the performance page's platform notes as well.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
The README said USB needs iTunes on Windows and "nothing extra on macOS",
which quietly omitted Linux — where the plugin connects to
/var/run/usbmuxd, a daemon a distribution may not have installed. Both the
requirements list and the troubleshooting entry now name what supplies the
usbmuxd protocol on each system, because that is the actual dependency:
Apple Mobile Device Service on Windows, the usbmuxd package on Linux, the
OS itself on macOS.

The site's performance page also gains a short answer to "does the GPU
brand matter": barely, except on Linux, where Intel and AMD get VAAPI from
Mesa and NVIDIA needs nvidia-vaapi-driver before the GPU pipeline can
engage at all. Also worth saying out loud for multi-phone setups — this is
a decode workload, so NVIDIA's NVENC session limit is irrelevant — and that
the benchmark table came from a single Windows/NVIDIA machine, which is
part of why the pipeline is still beta.

Release-Skip: true

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA
@MyNamesEMurray
MyNamesEMurray merged commit de6836f into main Sep 8, 2026
8 checks passed
@MyNamesEMurray
MyNamesEMurray deleted the claude/lenslink-site-review-round branch September 8, 2026 05:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants