An event companion and onboarding experience for the ATmosphere (alpha) atmo.quest
6

Configure Feed

Select the types of activity you want to include in your feed.

docs: design spec for mobile open-camera button

Mobile-only camera-launch button on profile and event screens.
Captures via <input capture="environment">; no QR decode (v1 stub).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Brittany Ellich (May 31, 2026, 2:49 PM -0700) d18f7dc9 26b98f70

+94
+94
docs/superpowers/specs/2026-05-31-mobile-camera-button-design.md
··· 1 + # Design: Mobile "Open Camera" Button 2 + 3 + **Date:** 2026-05-31 4 + **Status:** Approved, pending implementation plan 5 + 6 + ## Summary 7 + 8 + Add a button to both the **profile screen** and the **event screen** that, on 9 + mobile devices only, opens the device's rear camera when tapped. The button is 10 + a camera-launch affordance — it pops the native camera capture sheet and does 11 + not process the captured image. 12 + 13 + ## Motivation 14 + 15 + atmo.quest's connect flow relies on scanning a QR code (each profile exposes a 16 + QR encoding `/c/{did}`). Today users scan with their phone's standalone camera 17 + app. This feature adds an in-page shortcut to open the camera from the profile 18 + and event screens on mobile. 19 + 20 + ## Scope and explicit non-goals 21 + 22 + **In scope:** a mobile-only button that opens the native camera capture sheet. 23 + 24 + **Explicit non-goal — no QR decode.** Per the product decision during 25 + brainstorming, the page does **not** process the captured photo. The button is 26 + a v1 stub / camera-launch affordance, **not a working scanner**. Tapping it 27 + opens the camera; whatever photo the user takes is discarded. 28 + 29 + > Web reality that drove this decision: the only no-dependency way for a web 30 + > page to open the camera is `<input type="file" capture="environment">`, which 31 + > opens the **photo-capture sheet**. That sheet takes a still photo and returns 32 + > it to the input — it does **not** do the live QR detection of the standalone 33 + > Camera app, and there is no web API to launch that standalone app. Making the 34 + > button actually connect someone would require adding a decode step (client- 35 + > side JS QR decode, then redirect to the connect URL). That is a deliberate 36 + > future enhancement, not part of this work. 37 + 38 + ## Behavior 39 + 40 + - Rendered as a `<label class="btn …">` wrapping a hidden 41 + `<input type="file" accept="image/*" capture="environment">`. 42 + - `capture="environment"` requests the rear camera. 43 + - Tapping the label opens the native camera capture sheet. 44 + - The input has **no** change handler — the captured image is not read, 45 + uploaded, or decoded. 46 + 47 + ## Mobile-only visibility 48 + 49 + Pure CSS, mirroring the existing `.bottom-nav` convention: 50 + 51 + - The button's container class defaults to `display: none`. 52 + - Inside `@media (max-width: 768px)` it becomes visible. 53 + 54 + 768px is the app's established mobile breakpoint (see `.bottom-nav` in 55 + `web/resources/static/css/terminal.css`). No JavaScript, no user-agent 56 + sniffing. The element is always present in the HTML and simply hidden on 57 + desktop. 58 + 59 + ## Reuse 60 + 61 + A single shared templ component, `CameraScanButton`, lives in 62 + `features/common/layouts` alongside `TopNav` / `BottomNav`. Both 63 + `profile.templ` and `event.templ` invoke it so the markup is defined once. 64 + 65 + ## Placement 66 + 67 + - **Profile** (`features/profile/pages/profile.templ`): directly under the QR 68 + flip card (`.profile-flip`), near the top of `.profile-card`. 69 + - **Event** (`features/event/pages/event.templ`): near the top of 70 + `.event-card`, just under the event meta lines. 71 + 72 + ## Label 73 + 74 + `📷 open camera` — honest about what happens, since it does not decode a QR. 75 + 76 + ## Files touched 77 + 78 + - `features/common/layouts/` — new `CameraScanButton` templ component 79 + (+ regenerated `*_templ.go`). 80 + - `features/profile/pages/profile.templ` — invoke the component. 81 + - `features/event/pages/event.templ` — invoke the component. 82 + - `web/resources/static/css/terminal.css` — new mobile-only button class. 83 + - templ regeneration via the project's `templ generate` task. 84 + 85 + No Go handler/route changes. No new dependencies. 86 + 87 + ## Testing 88 + 89 + - Verify the button is hidden on desktop widths (> 768px) and visible at 90 + ≤ 768px on both screens. 91 + - On a mobile device / emulated mobile, verify tapping opens the camera capture 92 + sheet. 93 + - Verify existing profile flip and event check-in behavior are unaffected. 94 + - `templ generate` runs clean; `go build` / existing checks pass.