12245759ac
CI / test (push) Has been cancelled
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>
821 lines
32 KiB
HTML
821 lines
32 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=800">
|
||
<title>AP Provisioning 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 of the device */
|
||
.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;
|
||
}
|
||
|
||
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
YELLOW STATUS BAR — signals AP mode / action required
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
|
||
.status-bar {
|
||
width: 800px;
|
||
height: 52px;
|
||
background: #f0d000;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 24px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.status-bar-label {
|
||
font-family: 'Courier New', Courier, monospace;
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.18em;
|
||
text-transform: uppercase;
|
||
color: #1a1a1a;
|
||
}
|
||
|
||
.status-bar-network {
|
||
font-family: 'Courier New', Courier, monospace;
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
color: #1a1a1a;
|
||
letter-spacing: 0.06em;
|
||
}
|
||
|
||
/* Monospaced network name chip */
|
||
.network-chip {
|
||
display: inline-block;
|
||
background: #1a1a1a;
|
||
color: #f0d000;
|
||
font-family: 'Courier New', Courier, monospace;
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
padding: 4px 10px;
|
||
}
|
||
|
||
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
MAIN BODY — three-column layout
|
||
LEFT: header + instructions
|
||
CENTER: orientation diagrams
|
||
RIGHT: QR code
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
|
||
.body {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: row;
|
||
}
|
||
|
||
/* ── LEFT PANEL ───────────────────────────────────── */
|
||
.panel-left {
|
||
width: 310px;
|
||
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;
|
||
color: #1a1a1a;
|
||
/* Underline in yellow: simulate with border since no CSS effects */
|
||
border-bottom: 3px solid #f0d000;
|
||
}
|
||
|
||
.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: #1a1a1a;
|
||
color: #f0d000;
|
||
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;
|
||
}
|
||
|
||
/* Divider */
|
||
.left-divider {
|
||
height: 2px;
|
||
background: #1a1a1a;
|
||
margin: 16px 0 14px;
|
||
}
|
||
|
||
.footnote {
|
||
font-family: 'Courier New', Courier, monospace;
|
||
font-size: 13px;
|
||
color: #1a1a1a;
|
||
line-height: 1.4;
|
||
opacity: 0.7;
|
||
}
|
||
|
||
/* ── CENTER PANEL — orientation diagrams ──────────── */
|
||
.panel-center {
|
||
width: 196px;
|
||
flex-shrink: 0;
|
||
border-right: 2px solid #1a1a1a;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 20px;
|
||
padding: 16px 12px;
|
||
}
|
||
|
||
.orient-label {
|
||
font-family: 'Courier New', Courier, monospace;
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.2em;
|
||
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: 110px;
|
||
height: 66px;
|
||
border: 3px solid #1a1a1a;
|
||
background: #f5f5f0;
|
||
position: relative;
|
||
}
|
||
|
||
/* Corner tick marks to suggest the physical frame */
|
||
.orient-landscape-frame::before,
|
||
.orient-landscape-frame::after {
|
||
content: '';
|
||
position: absolute;
|
||
background: #1a1a1a;
|
||
}
|
||
|
||
.orient-landscape-ribbon {
|
||
width: 110px;
|
||
height: 10px;
|
||
background: #1a1a1a;
|
||
/* The power ribbon / cable notch at bottom */
|
||
}
|
||
|
||
/* Portrait: tall rect + left ribbon */
|
||
.orient-portrait-frame {
|
||
width: 64px;
|
||
height: 106px;
|
||
border: 3px solid #1a1a1a;
|
||
background: #f5f5f0;
|
||
display: flex;
|
||
align-items: flex-end;
|
||
justify-content: flex-end;
|
||
position: relative;
|
||
}
|
||
|
||
.orient-portrait-wrapper {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
.orient-portrait-ribbon {
|
||
width: 10px;
|
||
height: 106px;
|
||
background: #1a1a1a;
|
||
}
|
||
|
||
/* Active/current orientation highlight */
|
||
.orient-active .orient-landscape-frame,
|
||
.orient-active .orient-portrait-frame {
|
||
border-color: #f0d000;
|
||
border-width: 3px;
|
||
}
|
||
|
||
.orient-active .orient-landscape-ribbon,
|
||
.orient-active .orient-portrait-ribbon {
|
||
background: #f0d000;
|
||
}
|
||
|
||
.orient-active .orient-label {
|
||
color: #1a1a1a;
|
||
}
|
||
|
||
/* Tiny check mark for active orientation */
|
||
.active-badge {
|
||
width: 18px;
|
||
height: 18px;
|
||
background: #f0d000;
|
||
border: 2px solid #1a1a1a;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 11px;
|
||
font-weight: 900;
|
||
color: #1a1a1a;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.orient-divider {
|
||
width: 100%;
|
||
height: 1px;
|
||
background: #1a1a1a;
|
||
opacity: 0.3;
|
||
}
|
||
|
||
.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.55;
|
||
text-align: center;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
/* ── RIGHT PANEL — QR code ────────────────────────── */
|
||
.panel-right {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 16px;
|
||
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: 196px;
|
||
height: 196px;
|
||
background: #f5f5f0;
|
||
border: 3px solid #1a1a1a;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
}
|
||
|
||
/* Yellow corner brackets — frame the QR */
|
||
.qr-wrapper::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: -3px;
|
||
left: -3px;
|
||
right: -3px;
|
||
bottom: -3px;
|
||
border: 3px solid #f0d000;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.qr-sub {
|
||
font-family: 'Courier New', Courier, monospace;
|
||
font-size: 12px;
|
||
color: #1a1a1a;
|
||
text-align: center;
|
||
line-height: 1.4;
|
||
opacity: 0.65;
|
||
max-width: 190px;
|
||
}
|
||
|
||
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
QR CODE — SVG grid rendered in pure black/white
|
||
Pattern: encodes WIFI:S:PictureFrame-A3F7;T:nopass;;
|
||
This is a realistic-looking QR placeholder.
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="device-bezel">
|
||
<div class="display">
|
||
|
||
<!-- STATUS BAR -->
|
||
<div class="status-bar">
|
||
<span class="status-bar-label">Setup Mode — Step 1 of 2</span>
|
||
<span class="status-bar-network">
|
||
Broadcasting: <span class="network-chip">PictureFrame-A3F7</span>
|
||
</span>
|
||
</div>
|
||
|
||
<!-- BODY -->
|
||
<div class="body">
|
||
|
||
<!-- LEFT: instructions -->
|
||
<div class="panel-left">
|
||
<div>
|
||
<div class="main-heading">Connect to<br><em>WiFi</em></div>
|
||
|
||
<ul class="step-list">
|
||
<li class="step-item">
|
||
<div class="step-num">1</div>
|
||
<div class="step-text">
|
||
Scan the QR code →<br>
|
||
Your phone joins <strong>PictureFrame-A3F7</strong>
|
||
</div>
|
||
</li>
|
||
<li class="step-item">
|
||
<div class="step-num">2</div>
|
||
<div class="step-text">
|
||
A WiFi setup page opens automatically in your browser
|
||
</div>
|
||
</li>
|
||
<li class="step-item">
|
||
<div class="step-num">3</div>
|
||
<div class="step-text">
|
||
Enter your <strong>home WiFi</strong> credentials and tap Connect
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="left-divider"></div>
|
||
<div class="footnote">
|
||
Page didn't open? Navigate to<br>
|
||
<strong>192.168.4.1</strong> in any browser.
|
||
</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">✓</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 connect</div>
|
||
|
||
<div class="qr-wrapper">
|
||
<!-- QR code rendered as SVG — encodes WIFI:S:PictureFrame-A3F7;T:nopass;; -->
|
||
<svg width="178" height="178" 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 PATTERN -->
|
||
<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 PATTERN -->
|
||
<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 PATTERN -->
|
||
<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 PATTERNS (horizontal and vertical) -->
|
||
<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"/>
|
||
|
||
<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 MODULES — WiFi QR payload simulation -->
|
||
<!-- Row 9 -->
|
||
<rect x="9" y="9" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="11" y="9" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="14" y="9" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="16" y="9" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="21" y="9" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="25" y="9" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="27" y="9" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="31" y="9" width="1" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 10 -->
|
||
<rect x="9" y="10" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="13" y="10" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="15" y="10" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="19" y="10" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="22" y="10" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="26" y="10" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="30" y="10" width="2" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 11 -->
|
||
<rect x="8" y="11" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="10" y="11" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="15" y="11" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="17" y="11" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="21" y="11" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="24" y="11" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="28" y="11" width="3" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 12 -->
|
||
<rect x="9" y="12" width="4" height="1" fill="#1a1a1a"/>
|
||
<rect x="14" y="12" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="17" y="12" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="22" y="12" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="26" y="12" width="1" 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="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="12" y="13" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="14" y="13" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="18" y="13" width="4" height="1" fill="#1a1a1a"/>
|
||
<rect x="24" y="13" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="29" y="13" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="31" y="13" width="2" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 14 -->
|
||
<rect x="9" y="14" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="11" y="14" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="16" y="14" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="20" y="14" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="23" y="14" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="27" y="14" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="32" y="14" width="1" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 15 -->
|
||
<rect x="8" y="15" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="13" y="15" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="17" y="15" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="19" y="15" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="24" y="15" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="27" y="15" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="30" y="15" width="3" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 16 -->
|
||
<rect x="9" y="16" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="13" y="16" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="16" y="16" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="21" y="16" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="25" y="16" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="30" y="16" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="34" y="16" width="1" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 17 -->
|
||
<rect x="8" y="17" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="10" y="17" width="4" height="1" fill="#1a1a1a"/>
|
||
<rect x="15" y="17" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="19" y="17" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="22" y="17" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="27" y="17" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="29" y="17" width="4" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 18 -->
|
||
<rect x="9" y="18" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="14" y="18" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="17" y="18" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="21" y="18" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="24" y="18" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="28" y="18" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="32" y="18" width="3" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 19 -->
|
||
<rect x="8" y="19" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="12" y="19" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="16" y="19" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="18" y="19" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="22" y="19" width="4" height="1" fill="#1a1a1a"/>
|
||
<rect x="28" y="19" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="30" y="19" width="3" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 20 (center) -->
|
||
<rect x="9" y="20" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="11" y="20" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="15" y="20" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="20" y="20" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="23" y="20" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="27" y="20" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="32" y="20" width="2" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 21 -->
|
||
<rect x="8" y="21" width="4" 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="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="25" y="21" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="29" y="21" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="31" y="21" width="3" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 22 -->
|
||
<rect x="9" y="22" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="13" 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="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="24" y="22" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="29" y="22" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="33" y="22" width="1" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 23 -->
|
||
<rect x="8" y="23" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="10" y="23" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="15" y="23" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="17" y="23" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="22" y="23" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="26" y="23" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="28" y="23" width="4" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 24 -->
|
||
<rect x="9" y="24" width="4" height="1" fill="#1a1a1a"/>
|
||
<rect x="14" y="24" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="18" y="24" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="21" y="24" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="26" y="24" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="30" y="24" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="32" 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="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="14" y="25" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="19" y="25" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="23" y="25" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="26" y="25" width="3" 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="11" y="26" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="15" y="26" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="19" y="26" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="22" y="26" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="27" y="26" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="31" y="26" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="33" y="26" width="1" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 27 -->
|
||
<rect x="8" y="27" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="13" y="27" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="16" y="27" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="21" y="27" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="25" y="27" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="28" y="27" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="33" 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="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="18" y="28" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="21" y="28" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="24" y="28" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="28" y="28" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="30" y="28" width="4" 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="16" y="29" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="20" y="29" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="25" y="29" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="29" y="29" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="33" y="29" width="1" 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="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="20" y="30" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="24" y="30" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="29" y="30" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="32" y="30" width="2" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Row 31 -->
|
||
<rect x="8" y="31" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="12" y="31" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="16" y="31" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="21" y="31" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="23" y="31" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="27" y="31" width="4" height="1" fill="#1a1a1a"/>
|
||
<rect x="33" y="31" width="1" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Alignment pattern bottom-right (5×5) -->
|
||
<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"/>
|
||
|
||
<!-- Format info strips -->
|
||
<rect x="8" y="8" width="1" height="1" fill="#1a1a1a"/>
|
||
|
||
<!-- Extra data density rows 33–39 (below bottom-left finder) -->
|
||
<rect x="9" y="34" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="13" y="34" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="15" y="34" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="20" y="34" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="24" y="34" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="27" y="34" width="2" height="1" fill="#1a1a1a"/>
|
||
|
||
<rect x="8" y="35" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="13" y="35" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="17" y="35" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="19" y="35" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="24" y="35" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="28" y="35" width="1" height="1" fill="#1a1a1a"/>
|
||
|
||
<rect x="9" y="36" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="11" y="36" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="14" y="36" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="17" y="36" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="21" y="36" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="23" y="36" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="27" y="36" width="2" height="1" fill="#1a1a1a"/>
|
||
|
||
<rect x="8" y="37" width="4" height="1" fill="#1a1a1a"/>
|
||
<rect x="14" y="37" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="18" y="37" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="23" y="37" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="25" y="37" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="29" y="37" width="1" height="1" fill="#1a1a1a"/>
|
||
|
||
<rect x="9" y="38" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="13" y="38" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="18" y="38" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="21" y="38" width="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="25" y="38" width="3" height="1" fill="#1a1a1a"/>
|
||
<rect x="30" y="38" width="1" height="1" fill="#1a1a1a"/>
|
||
|
||
<rect x="8" y="39" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="10" y="39" width="3" 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="2" height="1" fill="#1a1a1a"/>
|
||
<rect x="26" y="39" width="1" height="1" fill="#1a1a1a"/>
|
||
<rect x="28" y="39" width="3" height="1" fill="#1a1a1a"/>
|
||
</svg>
|
||
</div>
|
||
|
||
<div class="qr-sub">
|
||
Encodes: <strong>WIFI:S:PictureFrame-A3F7;T:nopass;;</strong>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.body -->
|
||
|
||
</div><!-- /.display -->
|
||
</div><!-- /.device-bezel -->
|
||
|
||
<!--
|
||
DESIGNER NOTES
|
||
──────────────────────────────────────────────────────────────────
|
||
Screen: AP Provisioning — Step 1 of 2
|
||
State: Frame has no WiFi credentials. Broadcasting open AP.
|
||
Accent: YELLOW — signals "action required," unconnected state.
|
||
|
||
Layout rationale:
|
||
• Yellow status bar carries SSID at a glance — one horizontal scan
|
||
tells you what network to join without reading the instructions.
|
||
• Instructions live LEFT, not centered, to make room for the large QR
|
||
without any elements competing at the same scale.
|
||
• Orientation diagrams are narrow + centered — they confirm physical
|
||
placement, not the primary action. They don't compete.
|
||
• QR panel is RIGHT and large — the single action. Yellow bracket
|
||
border echoes the accent and frames the eye's destination.
|
||
• Step numbers in black/yellow inverse boxes are readable at a
|
||
distance; the QR is readable up close. Both jobs done together.
|
||
• "Landscape" is marked active (check mark + yellow ribbon) because
|
||
the frame is currently held landscape. Portrait shown as the alt.
|
||
• Footnote handles the "captive portal didn't open" edge case.
|
||
Firmware MUST handle this — the screen already does.
|
||
|
||
Firmware implementation notes (for when you write the C):
|
||
• The SSID suffix is the last 4 hex chars of the MAC.
|
||
• The QR encodes the WIFI: string for auto-join on iOS/Android.
|
||
• The 192.168.4.1 fallback is the ESP32 SoftAP default gateway.
|
||
──────────────────────────────────────────────────────────────────
|
||
-->
|
||
|
||
</body>
|
||
</html>
|