Site: review round — panel fixes, camera frame, and a guided setup page - #119
Merged
Conversation
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
Deploying lenslink with
|
| Latest commit: |
a0fbcb6
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://cab8b8d6.lenslink.pages.dev |
| Branch Preview URL: | https://claude-lenslink-site-review.lenslink.pages.dev |
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
"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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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'tdrift 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 shorterthan 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: noneso a future squeeze can't be absorbed by silentlyshrinking 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/orhero-feed-portrait.*intostatic/img/and the build puts them behind thepanel, 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. Thedesign 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./setup/?os=macos&link=wifi&mode=screen&app=sideload.cable rather than charge-only, iTunes on Windows, the weekly re-install a
sideload costs.
the page is keyboard- and screen-reader-native and works unstyled.
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.macOS/Wi-Fi/screen/sideload): correct steps, correct order, correct
"what you'll need", no page errors, and the URL round-trips.
the radios still usable.
checking which file each viewport actually fetches.
Release-Skip: true;site/matches none of the release paths.🤖 Generated with Claude Code
https://claude.ai/code/session_01PSuQicA9NrKWwpgzY6SvhA