Files
pictureFrame-webApp/_bmad-output/mockups/mockup_setup_screen.html
T
football2801 12245759ac
CI / test (push) Has been cancelled
chore: stage all in-progress work before repo split
Web app: new entities (Image, RenderedAsset, SharedImage, Token,
DeviceImageHistory), enums, repositories, controllers, message handlers,
migrations, tests, frontend upload/library/sticker UI, Vue components.

Firmware: EPD background screen binaries + gen scripts, setup_bg header.

Infra: ddev config, test bundle, gitignore coverage dir.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 12:11:31 -04:00

972 lines
35 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=800">
<title>Setup QR Screen — pictureFrame mockup</title>
<style>
/*
HARDWARE CONSTRAINTS: 800×480px. Six colors only.
#1a1a1a BLACK
#f5f5f0 WHITE
#f0d000 YELLOW
#c03020 RED
#1840c0 BLUE
#10a040 GREEN
No gradients. No drop shadows. No anti-aliasing. No other colors.
No fonts below ~16px.
This file is a design mockup — open at 100% zoom in browser.
*/
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #888;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
font-family: 'Courier New', Courier, monospace;
}
/* Outer frame — the physical bezel */
.device-bezel {
width: 840px;
height: 520px;
background: #1a1a1a;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
/* The e-ink display surface — exactly 800×480 */
.display {
width: 800px;
height: 480px;
background: #f5f5f0;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
}
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GREEN STATUS BAR — signals connected / almost done
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
.status-bar {
width: 800px;
height: 52px;
background: #10a040;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
flex-shrink: 0;
}
.status-bar-left {
display: flex;
align-items: center;
gap: 12px;
}
/* WiFi connected indicator — pixelated bars (no border-radius) */
.wifi-icon {
display: flex;
align-items: flex-end;
gap: 3px;
height: 22px;
}
.wifi-bar {
background: #f5f5f0;
width: 5px;
}
.wifi-bar-1 { height: 8px; }
.wifi-bar-2 { height: 13px; }
.wifi-bar-3 { height: 18px; }
.wifi-bar-4 { height: 22px; }
.status-bar-label {
font-family: 'Courier New', Courier, monospace;
font-size: 13px;
font-weight: 700;
letter-spacing: 0.18em;
text-transform: uppercase;
color: #f5f5f0;
}
.status-bar-right {
font-family: 'Courier New', Courier, monospace;
font-size: 13px;
font-weight: 700;
color: #f5f5f0;
letter-spacing: 0.06em;
opacity: 0.85;
}
.ip-chip {
display: inline-block;
background: #f5f5f0;
color: #10a040;
font-family: 'Courier New', Courier, monospace;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.06em;
padding: 3px 9px;
}
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
MAIN BODY
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
.body {
flex: 1;
display: flex;
flex-direction: row;
}
/* ── LEFT PANEL ───────────────────────────────────── */
.panel-left {
width: 340px;
flex-shrink: 0;
padding: 24px 20px 20px 28px;
display: flex;
flex-direction: column;
justify-content: space-between;
border-right: 2px solid #1a1a1a;
}
.main-heading {
font-family: 'Courier New', Courier, monospace;
font-size: 26px;
font-weight: 700;
color: #1a1a1a;
line-height: 1.2;
letter-spacing: -0.01em;
}
.main-heading em {
font-style: normal;
border-bottom: 3px solid #10a040;
}
.sub-heading {
font-family: 'Courier New', Courier, monospace;
font-size: 15px;
color: #1a1a1a;
line-height: 1.5;
margin-top: 14px;
opacity: 0.75;
}
.step-list {
list-style: none;
margin-top: 18px;
display: flex;
flex-direction: column;
gap: 12px;
}
.step-item {
display: flex;
align-items: flex-start;
gap: 10px;
}
.step-num {
width: 24px;
height: 24px;
background: #10a040;
color: #f5f5f0;
font-family: 'Courier New', Courier, monospace;
font-size: 13px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.step-text {
font-family: 'Courier New', Courier, monospace;
font-size: 15px;
color: #1a1a1a;
line-height: 1.35;
padding-top: 3px;
}
.step-text strong {
font-weight: 700;
}
/* URL hint bar */
.url-bar {
margin-top: 18px;
background: #1a1a1a;
padding: 8px 14px;
display: flex;
align-items: center;
gap: 8px;
}
.url-bar-label {
font-family: 'Courier New', Courier, monospace;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.2em;
text-transform: uppercase;
color: #10a040;
flex-shrink: 0;
}
.url-bar-value {
font-family: 'Courier New', Courier, monospace;
font-size: 12px;
color: #f5f5f0;
word-break: break-all;
line-height: 1.3;
}
/* Progress tracker */
.progress-track {
margin-top: 16px;
display: flex;
flex-direction: column;
gap: 4px;
}
.progress-label {
font-family: 'Courier New', Courier, monospace;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.2em;
text-transform: uppercase;
color: #1a1a1a;
opacity: 0.45;
margin-bottom: 4px;
}
.progress-steps {
display: flex;
gap: 4px;
align-items: center;
}
.prog-step {
height: 6px;
flex: 1;
}
.prog-step.done {
background: #10a040;
}
.prog-step.active {
background: #1a1a1a;
}
.prog-step.todo {
background: #1a1a1a;
opacity: 0.2;
}
.prog-step-labels {
display: flex;
gap: 4px;
margin-top: 4px;
}
.prog-step-label {
flex: 1;
font-family: 'Courier New', Courier, monospace;
font-size: 10px;
color: #1a1a1a;
text-align: center;
line-height: 1.2;
opacity: 0.55;
}
.prog-step-label.done {
color: #10a040;
opacity: 1;
font-weight: 700;
}
.prog-step-label.active {
opacity: 1;
font-weight: 700;
}
/* ── CENTER PANEL — orientation diagrams ──────────── */
.panel-center {
width: 164px;
flex-shrink: 0;
border-right: 2px solid #1a1a1a;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16px;
padding: 16px 10px;
}
.orient-section-title {
font-family: 'Courier New', Courier, monospace;
font-size: 10px;
font-weight: 700;
letter-spacing: 0.25em;
text-transform: uppercase;
color: #1a1a1a;
opacity: 0.45;
text-align: center;
margin-bottom: 4px;
}
.orient-label {
font-family: 'Courier New', Courier, monospace;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.15em;
text-transform: uppercase;
color: #1a1a1a;
text-align: center;
margin-bottom: 6px;
}
.orient-block {
display: flex;
flex-direction: column;
align-items: center;
}
/* Landscape: wide rect + bottom ribbon */
.orient-landscape-frame {
width: 100px;
height: 60px;
border: 3px solid #1a1a1a;
background: #f5f5f0;
position: relative;
}
/* Inner screen hatching — suggests image content */
.orient-landscape-frame::after {
content: '';
position: absolute;
top: 6px; left: 6px; right: 6px; bottom: 6px;
border: 1px solid #1a1a1a;
opacity: 0.25;
}
.orient-landscape-ribbon {
width: 100px;
height: 9px;
background: #1a1a1a;
}
/* Portrait: tall rect + left ribbon */
.orient-portrait-wrapper {
display: flex;
flex-direction: row;
align-items: center;
}
.orient-portrait-ribbon {
width: 9px;
height: 96px;
background: #1a1a1a;
}
.orient-portrait-frame {
width: 58px;
height: 96px;
border: 3px solid #1a1a1a;
background: #f5f5f0;
position: relative;
}
.orient-portrait-frame::after {
content: '';
position: absolute;
top: 6px; left: 6px; right: 6px; bottom: 6px;
border: 1px solid #1a1a1a;
opacity: 0.25;
}
/* Active state — green accent for connected/done feeling */
.orient-active .orient-landscape-frame,
.orient-active .orient-portrait-frame {
border-color: #10a040;
}
.orient-active .orient-landscape-ribbon,
.orient-active .orient-portrait-ribbon {
background: #10a040;
}
.orient-active .orient-label {
color: #10a040;
}
.active-badge {
width: 18px;
height: 18px;
background: #10a040;
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 900;
color: #f5f5f0;
margin-top: 5px;
}
.orient-divider {
width: 100%;
height: 1px;
background: #1a1a1a;
opacity: 0.2;
}
/* ── RIGHT PANEL — QR code ────────────────────────── */
.panel-right {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 16px 20px;
gap: 10px;
}
.qr-instruction {
font-family: 'Courier New', Courier, monospace;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #1a1a1a;
text-align: center;
}
.qr-wrapper {
width: 200px;
height: 200px;
background: #f5f5f0;
border: 3px solid #1a1a1a;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
/* Green corner accent — signals connected state */
.qr-wrapper::before {
content: '';
position: absolute;
top: -3px;
left: -3px;
right: -3px;
bottom: -3px;
border: 3px solid #10a040;
pointer-events: none;
}
.qr-sub {
font-family: 'Courier New', Courier, monospace;
font-size: 12px;
color: #1a1a1a;
text-align: center;
line-height: 1.45;
opacity: 0.6;
max-width: 200px;
}
/* MAC address chip */
.mac-chip {
display: inline-block;
background: #1a1a1a;
color: #f5f5f0;
font-family: 'Courier New', Courier, monospace;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
padding: 3px 9px;
margin-top: 2px;
}
</style>
</head>
<body>
<div class="device-bezel">
<div class="display">
<!-- STATUS BAR -->
<div class="status-bar">
<div class="status-bar-left">
<!-- WiFi icon: 3 arcs + dot -->
<div class="wifi-icon">
<div class="wifi-bar wifi-bar-1"></div>
<div class="wifi-bar wifi-bar-2"></div>
<div class="wifi-bar wifi-bar-3"></div>
<div class="wifi-bar wifi-bar-4"></div>
</div>
<span class="status-bar-label">WiFi Connected &mdash; Step 2 of 2</span>
</div>
<span class="status-bar-right">
IP: <span class="ip-chip">192.168.1.47</span>
</span>
</div>
<!-- BODY -->
<div class="body">
<!-- LEFT: instructions + progress -->
<div class="panel-left">
<div>
<div class="main-heading">Almost<br><em>ready.</em></div>
<div class="sub-heading">
Scan the QR code to give this frame a name and link it to your account.
</div>
<ul class="step-list">
<li class="step-item">
<div class="step-num">1</div>
<div class="step-text">
Scan the QR code with your phone's camera
</div>
</li>
<li class="step-item">
<div class="step-num">2</div>
<div class="step-text">
Sign in or create an account at <strong>pictureframe.edholm.me</strong>
</div>
</li>
<li class="step-item">
<div class="step-num">3</div>
<div class="step-text">
Name the frame. Choose orientation. Done.
</div>
</li>
</ul>
<div class="url-bar">
<span class="url-bar-label">URL</span>
<span class="url-bar-value">pictureframe.edholm.me/setup/1C:C3:AB:D1:91:F8</span>
</div>
</div>
<div>
<!-- Progress tracker: WiFi done / Account next / Frame ready todo -->
<div class="progress-track">
<div class="progress-label">Setup progress</div>
<div class="progress-steps">
<div class="prog-step done"></div>
<div class="prog-step active"></div>
<div class="prog-step todo"></div>
</div>
<div class="prog-step-labels">
<div class="prog-step-label done">WiFi</div>
<div class="prog-step-label active">Account</div>
<div class="prog-step-label todo">Frame ready</div>
</div>
</div>
</div>
</div>
<!-- CENTER: orientation diagrams -->
<div class="panel-center">
<div class="orient-section-title">Frame orientation</div>
<!-- Landscape (active) -->
<div class="orient-block orient-active">
<div class="orient-label">Landscape</div>
<div class="orient-landscape-frame"></div>
<div class="orient-landscape-ribbon"></div>
<div class="active-badge">&#10003;</div>
</div>
<div class="orient-divider"></div>
<!-- Portrait -->
<div class="orient-block">
<div class="orient-label">Portrait</div>
<div class="orient-portrait-wrapper">
<div class="orient-portrait-ribbon"></div>
<div class="orient-portrait-frame"></div>
</div>
</div>
</div>
<!-- RIGHT: QR code -->
<div class="panel-right">
<div class="qr-instruction">Scan to finish</div>
<div class="qr-wrapper">
<!-- QR code — encodes https://pictureframe.edholm.me/setup/1C:C3:AB:D1:91:F8 -->
<svg width="182" height="182" viewBox="0 0 41 41" xmlns="http://www.w3.org/2000/svg"
shape-rendering="crispEdges">
<rect width="41" height="41" fill="#f5f5f0"/>
<!-- TOP-LEFT FINDER -->
<rect x="1" y="1" width="7" height="7" fill="#1a1a1a"/>
<rect x="2" y="2" width="5" height="5" fill="#f5f5f0"/>
<rect x="3" y="3" width="3" height="3" fill="#1a1a1a"/>
<!-- TOP-RIGHT FINDER -->
<rect x="33" y="1" width="7" height="7" fill="#1a1a1a"/>
<rect x="34" y="2" width="5" height="5" fill="#f5f5f0"/>
<rect x="35" y="3" width="3" height="3" fill="#1a1a1a"/>
<!-- BOTTOM-LEFT FINDER -->
<rect x="1" y="33" width="7" height="7" fill="#1a1a1a"/>
<rect x="2" y="34" width="5" height="5" fill="#f5f5f0"/>
<rect x="3" y="35" width="3" height="3" fill="#1a1a1a"/>
<!-- TIMING H -->
<rect x="9" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="11" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="13" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="15" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="17" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="19" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="21" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="23" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="25" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="27" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="29" y="6" width="1" height="1" fill="#1a1a1a"/>
<rect x="31" y="6" width="1" height="1" fill="#1a1a1a"/>
<!-- TIMING V -->
<rect x="6" y="9" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="11" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="13" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="15" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="17" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="19" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="21" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="23" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="25" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="27" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="29" width="1" height="1" fill="#1a1a1a"/>
<rect x="6" y="31" width="1" height="1" fill="#1a1a1a"/>
<!-- DATA — URL QR pattern (unique from AP screen) -->
<!-- Row 9 -->
<rect x="8" y="9" width="2" height="1" fill="#1a1a1a"/>
<rect x="12" y="9" width="1" height="1" fill="#1a1a1a"/>
<rect x="14" y="9" width="3" height="1" fill="#1a1a1a"/>
<rect x="19" y="9" width="2" height="1" fill="#1a1a1a"/>
<rect x="23" y="9" width="1" height="1" fill="#1a1a1a"/>
<rect x="26" y="9" width="2" height="1" fill="#1a1a1a"/>
<rect x="30" y="9" width="3" height="1" fill="#1a1a1a"/>
<!-- Row 10 -->
<rect x="9" y="10" width="3" height="1" fill="#1a1a1a"/>
<rect x="14" y="10" width="1" height="1" fill="#1a1a1a"/>
<rect x="16" y="10" width="2" height="1" fill="#1a1a1a"/>
<rect x="20" y="10" width="3" height="1" fill="#1a1a1a"/>
<rect x="25" y="10" width="2" height="1" fill="#1a1a1a"/>
<rect x="29" y="10" width="1" height="1" fill="#1a1a1a"/>
<rect x="32" y="10" width="2" height="1" fill="#1a1a1a"/>
<!-- Row 11 -->
<rect x="8" y="11" width="1" height="1" fill="#1a1a1a"/>
<rect x="11" y="11" width="3" height="1" fill="#1a1a1a"/>
<rect x="16" y="11" width="1" height="1" fill="#1a1a1a"/>
<rect x="18" y="11" width="3" height="1" fill="#1a1a1a"/>
<rect x="23" y="11" width="2" height="1" fill="#1a1a1a"/>
<rect x="27" y="11" width="1" height="1" fill="#1a1a1a"/>
<rect x="30" y="11" width="3" height="1" fill="#1a1a1a"/>
<!-- Row 12 -->
<rect x="9" y="12" width="2" height="1" fill="#1a1a1a"/>
<rect x="13" y="12" width="2" height="1" fill="#1a1a1a"/>
<rect x="17" y="12" width="2" height="1" fill="#1a1a1a"/>
<rect x="21" y="12" width="1" height="1" fill="#1a1a1a"/>
<rect x="24" y="12" width="3" height="1" fill="#1a1a1a"/>
<rect x="29" y="12" width="2" height="1" fill="#1a1a1a"/>
<rect x="33" y="12" width="1" height="1" fill="#1a1a1a"/>
<!-- Row 13 -->
<rect x="8" y="13" width="4" height="1" fill="#1a1a1a"/>
<rect x="14" y="13" width="1" height="1" fill="#1a1a1a"/>
<rect x="16" y="13" width="3" height="1" fill="#1a1a1a"/>
<rect x="21" y="13" width="2" height="1" fill="#1a1a1a"/>
<rect x="25" y="13" width="1" height="1" fill="#1a1a1a"/>
<rect x="28" y="13" width="4" height="1" fill="#1a1a1a"/>
<!-- Row 14 -->
<rect x="9" y="14" width="1" height="1" fill="#1a1a1a"/>
<rect x="12" y="14" width="2" height="1" fill="#1a1a1a"/>
<rect x="16" y="14" width="1" height="1" fill="#1a1a1a"/>
<rect x="19" y="14" width="2" height="1" fill="#1a1a1a"/>
<rect x="23" y="14" width="3" height="1" fill="#1a1a1a"/>
<rect x="28" y="14" width="1" height="1" fill="#1a1a1a"/>
<rect x="31" y="14" width="2" height="1" fill="#1a1a1a"/>
<!-- Row 15 -->
<rect x="8" y="15" width="2" height="1" fill="#1a1a1a"/>
<rect x="12" y="15" width="3" height="1" fill="#1a1a1a"/>
<rect x="17" y="15" width="3" height="1" fill="#1a1a1a"/>
<rect x="22" y="15" width="2" height="1" fill="#1a1a1a"/>
<rect x="26" y="15" width="2" height="1" fill="#1a1a1a"/>
<rect x="30" y="15" width="1" height="1" fill="#1a1a1a"/>
<rect x="33" y="15" width="2" height="1" fill="#1a1a1a"/>
<!-- Row 16 -->
<rect x="9" y="16" width="3" height="1" fill="#1a1a1a"/>
<rect x="14" y="16" width="2" height="1" fill="#1a1a1a"/>
<rect x="18" y="16" width="1" height="1" fill="#1a1a1a"/>
<rect x="21" y="16" width="1" height="1" fill="#1a1a1a"/>
<rect x="24" y="16" width="3" height="1" fill="#1a1a1a"/>
<rect x="29" y="16" width="2" height="1" fill="#1a1a1a"/>
<rect x="33" y="16" width="1" height="1" fill="#1a1a1a"/>
<!-- Row 17 -->
<rect x="8" y="17" width="1" height="1" fill="#1a1a1a"/>
<rect x="11" y="17" width="4" height="1" fill="#1a1a1a"/>
<rect x="17" y="17" width="2" height="1" fill="#1a1a1a"/>
<rect x="21" y="17" width="3" height="1" fill="#1a1a1a"/>
<rect x="26" y="17" width="1" height="1" fill="#1a1a1a"/>
<rect x="29" y="17" width="3" height="1" fill="#1a1a1a"/>
<!-- Row 18 -->
<rect x="9" y="18" width="2" height="1" fill="#1a1a1a"/>
<rect x="13" y="18" width="1" height="1" fill="#1a1a1a"/>
<rect x="15" y="18" width="3" height="1" fill="#1a1a1a"/>
<rect x="20" y="18" width="2" height="1" fill="#1a1a1a"/>
<rect x="24" y="18" width="1" height="1" fill="#1a1a1a"/>
<rect x="27" y="18" width="3" height="1" fill="#1a1a1a"/>
<rect x="32" y="18" width="2" height="1" fill="#1a1a1a"/>
<!-- Row 19 -->
<rect x="8" y="19" width="4" height="1" fill="#1a1a1a"/>
<rect x="14" y="19" width="2" height="1" fill="#1a1a1a"/>
<rect x="18" y="19" width="1" height="1" fill="#1a1a1a"/>
<rect x="22" y="19" width="3" height="1" fill="#1a1a1a"/>
<rect x="27" y="19" width="2" height="1" fill="#1a1a1a"/>
<rect x="31" y="19" width="3" height="1" fill="#1a1a1a"/>
<!-- Row 20 -->
<rect x="9" y="20" width="1" height="1" fill="#1a1a1a"/>
<rect x="12" y="20" width="3" height="1" fill="#1a1a1a"/>
<rect x="17" y="20" width="2" height="1" fill="#1a1a1a"/>
<rect x="21" y="20" width="1" height="1" fill="#1a1a1a"/>
<rect x="24" y="20" width="2" height="1" fill="#1a1a1a"/>
<rect x="28" y="20" width="1" height="1" fill="#1a1a1a"/>
<rect x="31" y="20" width="1" height="1" fill="#1a1a1a"/>
<rect x="33" y="20" width="1" height="1" fill="#1a1a1a"/>
<!-- Row 21 -->
<rect x="8" y="21" width="2" height="1" fill="#1a1a1a"/>
<rect x="12" y="21" width="1" height="1" fill="#1a1a1a"/>
<rect x="14" y="21" width="2" height="1" fill="#1a1a1a"/>
<rect x="18" y="21" width="3" height="1" fill="#1a1a1a"/>
<rect x="23" y="21" width="2" height="1" fill="#1a1a1a"/>
<rect x="27" y="21" width="3" height="1" fill="#1a1a1a"/>
<rect x="32" y="21" width="2" height="1" fill="#1a1a1a"/>
<!-- Row 22 -->
<rect x="9" y="22" width="3" height="1" fill="#1a1a1a"/>
<rect x="14" y="22" width="1" height="1" fill="#1a1a1a"/>
<rect x="16" y="22" width="2" height="1" fill="#1a1a1a"/>
<rect x="20" y="22" width="1" height="1" fill="#1a1a1a"/>
<rect x="23" y="22" width="1" height="1" fill="#1a1a1a"/>
<rect x="26" y="22" width="2" height="1" fill="#1a1a1a"/>
<rect x="30" y="22" width="3" height="1" fill="#1a1a1a"/>
<!-- Row 23 -->
<rect x="8" y="23" width="1" height="1" fill="#1a1a1a"/>
<rect x="11" y="23" width="2" height="1" fill="#1a1a1a"/>
<rect x="15" y="23" width="3" height="1" fill="#1a1a1a"/>
<rect x="20" y="23" width="3" height="1" fill="#1a1a1a"/>
<rect x="25" y="23" width="1" height="1" fill="#1a1a1a"/>
<rect x="28" y="23" width="2" height="1" fill="#1a1a1a"/>
<rect x="32" y="23" width="1" height="1" fill="#1a1a1a"/>
<!-- Row 24 -->
<rect x="9" y="24" width="4" height="1" fill="#1a1a1a"/>
<rect x="15" y="24" width="1" height="1" fill="#1a1a1a"/>
<rect x="18" y="24" width="2" height="1" fill="#1a1a1a"/>
<rect x="22" y="24" width="2" height="1" fill="#1a1a1a"/>
<rect x="26" y="24" width="3" height="1" fill="#1a1a1a"/>
<rect x="31" y="24" width="2" height="1" fill="#1a1a1a"/>
<!-- Row 25 -->
<rect x="8" y="25" width="2" height="1" fill="#1a1a1a"/>
<rect x="12" y="25" width="3" height="1" fill="#1a1a1a"/>
<rect x="17" y="25" width="2" height="1" fill="#1a1a1a"/>
<rect x="21" y="25" width="1" height="1" fill="#1a1a1a"/>
<rect x="24" y="25" width="2" height="1" fill="#1a1a1a"/>
<rect x="28" y="25" width="1" height="1" fill="#1a1a1a"/>
<rect x="31" y="25" width="3" height="1" fill="#1a1a1a"/>
<!-- Row 26 -->
<rect x="9" y="26" width="1" height="1" fill="#1a1a1a"/>
<rect x="12" y="26" width="1" height="1" fill="#1a1a1a"/>
<rect x="15" y="26" width="3" height="1" fill="#1a1a1a"/>
<rect x="20" y="26" width="3" height="1" fill="#1a1a1a"/>
<rect x="25" y="26" width="2" height="1" fill="#1a1a1a"/>
<rect x="29" y="26" width="4" height="1" fill="#1a1a1a"/>
<!-- Row 27 -->
<rect x="8" y="27" width="3" height="1" fill="#1a1a1a"/>
<rect x="13" y="27" width="2" height="1" fill="#1a1a1a"/>
<rect x="17" y="27" width="1" height="1" fill="#1a1a1a"/>
<rect x="19" y="27" width="2" height="1" fill="#1a1a1a"/>
<rect x="23" y="27" width="3" height="1" fill="#1a1a1a"/>
<rect x="28" y="27" width="2" height="1" fill="#1a1a1a"/>
<rect x="32" y="27" width="2" height="1" fill="#1a1a1a"/>
<!-- Row 28 -->
<rect x="9" y="28" width="2" height="1" fill="#1a1a1a"/>
<rect x="13" y="28" width="1" height="1" fill="#1a1a1a"/>
<rect x="16" y="28" width="2" height="1" fill="#1a1a1a"/>
<rect x="20" y="28" width="1" height="1" fill="#1a1a1a"/>
<rect x="23" y="28" width="1" height="1" fill="#1a1a1a"/>
<rect x="26" y="28" width="3" height="1" fill="#1a1a1a"/>
<rect x="31" y="28" width="1" height="1" fill="#1a1a1a"/>
<rect x="33" y="28" width="1" height="1" fill="#1a1a1a"/>
<!-- Row 29 -->
<rect x="8" y="29" width="1" height="1" fill="#1a1a1a"/>
<rect x="10" y="29" width="4" height="1" fill="#1a1a1a"/>
<rect x="15" y="29" width="2" height="1" fill="#1a1a1a"/>
<rect x="18" y="29" width="3" height="1" fill="#1a1a1a"/>
<rect x="23" y="29" width="2" height="1" fill="#1a1a1a"/>
<rect x="27" y="29" width="1" height="1" fill="#1a1a1a"/>
<rect x="30" y="29" width="3" height="1" fill="#1a1a1a"/>
<!-- Row 30 -->
<rect x="9" y="30" width="3" height="1" fill="#1a1a1a"/>
<rect x="14" y="30" width="1" height="1" fill="#1a1a1a"/>
<rect x="17" y="30" width="2" height="1" fill="#1a1a1a"/>
<rect x="21" y="30" width="3" height="1" fill="#1a1a1a"/>
<rect x="26" y="30" width="2" height="1" fill="#1a1a1a"/>
<rect x="30" y="30" width="1" height="1" fill="#1a1a1a"/>
<rect x="33" y="30" width="1" height="1" fill="#1a1a1a"/>
<!-- Row 31 -->
<rect x="8" y="31" width="2" height="1" fill="#1a1a1a"/>
<rect x="12" y="31" width="3" height="1" fill="#1a1a1a"/>
<rect x="17" y="31" width="1" height="1" fill="#1a1a1a"/>
<rect x="20" y="31" width="2" height="1" fill="#1a1a1a"/>
<rect x="24" y="31" width="1" height="1" fill="#1a1a1a"/>
<rect x="27" y="31" width="4" height="1" fill="#1a1a1a"/>
<rect x="33" y="31" width="2" height="1" fill="#1a1a1a"/>
<!-- Alignment pattern (bottom-right) -->
<rect x="28" y="28" width="5" height="5" fill="#1a1a1a"/>
<rect x="29" y="29" width="3" height="3" fill="#f5f5f0"/>
<rect x="30" y="30" width="1" height="1" fill="#1a1a1a"/>
<rect x="8" y="8" width="1" height="1" fill="#1a1a1a"/>
<!-- Data rows below bottom-left finder (rows 3439) -->
<rect x="9" y="34" width="1" height="1" fill="#1a1a1a"/>
<rect x="12" y="34" width="2" height="1" fill="#1a1a1a"/>
<rect x="16" y="34" width="3" height="1" fill="#1a1a1a"/>
<rect x="21" y="34" width="1" height="1" fill="#1a1a1a"/>
<rect x="24" y="34" width="2" height="1" fill="#1a1a1a"/>
<rect x="28" y="34" width="3" height="1" fill="#1a1a1a"/>
<rect x="8" y="35" width="4" height="1" fill="#1a1a1a"/>
<rect x="14" y="35" width="1" height="1" fill="#1a1a1a"/>
<rect x="17" y="35" width="2" height="1" fill="#1a1a1a"/>
<rect x="21" y="35" width="3" height="1" fill="#1a1a1a"/>
<rect x="26" y="35" width="1" height="1" fill="#1a1a1a"/>
<rect x="29" y="35" width="2" height="1" fill="#1a1a1a"/>
<rect x="9" y="36" width="2" height="1" fill="#1a1a1a"/>
<rect x="13" y="36" width="3" height="1" fill="#1a1a1a"/>
<rect x="18" y="36" width="1" height="1" fill="#1a1a1a"/>
<rect x="21" y="36" width="2" height="1" fill="#1a1a1a"/>
<rect x="25" y="36" width="3" height="1" fill="#1a1a1a"/>
<rect x="30" y="36" width="2" height="1" fill="#1a1a1a"/>
<rect x="8" y="37" width="1" height="1" fill="#1a1a1a"/>
<rect x="11" y="37" width="2" height="1" fill="#1a1a1a"/>
<rect x="15" y="37" width="3" height="1" fill="#1a1a1a"/>
<rect x="20" y="37" width="1" height="1" fill="#1a1a1a"/>
<rect x="23" y="37" width="2" height="1" fill="#1a1a1a"/>
<rect x="27" y="37" width="1" height="1" fill="#1a1a1a"/>
<rect x="30" y="37" width="3" height="1" fill="#1a1a1a"/>
<rect x="9" y="38" width="4" height="1" fill="#1a1a1a"/>
<rect x="15" y="38" width="1" height="1" fill="#1a1a1a"/>
<rect x="18" y="38" width="2" height="1" fill="#1a1a1a"/>
<rect x="22" y="38" width="3" height="1" fill="#1a1a1a"/>
<rect x="27" y="38" width="2" height="1" fill="#1a1a1a"/>
<rect x="31" y="38" width="2" height="1" fill="#1a1a1a"/>
<rect x="8" y="39" width="2" height="1" fill="#1a1a1a"/>
<rect x="12" y="39" width="1" height="1" fill="#1a1a1a"/>
<rect x="15" y="39" width="2" height="1" fill="#1a1a1a"/>
<rect x="19" y="39" width="1" height="1" fill="#1a1a1a"/>
<rect x="22" y="39" width="3" height="1" fill="#1a1a1a"/>
<rect x="27" y="39" width="1" height="1" fill="#1a1a1a"/>
<rect x="29" y="39" width="4" height="1" fill="#1a1a1a"/>
</svg>
</div>
<div class="qr-sub">
<span class="mac-chip">1C:C3:AB:D1:91:F8</span>
</div>
</div>
</div><!-- /.body -->
</div><!-- /.display -->
</div><!-- /.device-bezel -->
<!--
DESIGNER NOTES
──────────────────────────────────────────────────────────────────
Screen: Setup QR — Step 2 of 2
State: Frame joined home WiFi. Waiting for account link via scan.
Accent: GREEN — signals progress, success, completion imminent.
Layout rationale:
• Green bar immediately contrasts with AP screen's yellow — user
registers "something changed, I'm further along." The WiFi
icon in the bar confirms the network is live.
• "Almost ready." is deliberately casual and warm — not "Device
Provisioning Step 2/2." The sub-heading does the explaining.
• URL bar at the bottom of instructions answers the fallback question
(what if the QR doesn't scan?) without cluttering the main steps.
• Progress track — three segments: WiFi done (green), Account
(solid black = active), Frame ready (faint = todo) — gives the user
a map without requiring them to read it.
• Center panel reuses the orientation diagram pattern from screen 1,
maintaining visual language across the two screens. The active
orientation is green this time, consistent with the accent shift.
• QR panel: green bracket border, MAC chip below the code. The MAC
is shown because the URL contains it — the user may need to verify
their device if they have multiple frames. Also tells the builder
(Matt) what he's looking at during development.
Physical observation: if the frame is landscape (current mockup),
the ribbon connector sits at the bottom of the frame, behind the
stand or mount. The orientation diagram ribbon is bottom for
landscape, left for portrait — this matches physical reality.
Firmware implementation notes:
• This screen appears after STA mode connection confirmed.
• The QR encodes the /setup/{mac} URL exactly.
• The IP shown is the DHCP-assigned address — confirm in real code
that the display format matches (colons in MAC, not dashes).
• Frame should stay on this screen until the web app confirms
account linkage — then reboot into image-cycling mode.
──────────────────────────────────────────────────────────────────
-->
</body>
</html>