File size: 15,918 Bytes
176941f 98410e9 176941f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | <!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Data Centre Nameplates — read & verify equipment nameplates</title>
<meta name="description" content="Photograph an equipment nameplate and read it in your browser: model, serial, voltage and rating checked against your equipment schedule, with an asset register CSV. Nothing is uploaded." />
<meta name="robots" content="index, follow" />
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22><rect width=%2224%22 height=%2224%22 rx=%225%22 fill=%22%230f2547%22/><rect x=%225%22 y=%227%22 width=%2214%22 height=%2210%22 rx=%221.5%22 fill=%22none%22 stroke=%22white%22 stroke-width=%221.8%22/><path d=%22M8 11h8M8 14h5%22 stroke=%22white%22 stroke-width=%221.6%22/></svg>" />
<meta name="theme-color" content="#0f2547" />
<meta name="author" content="Constructelligence" />
<meta name="keywords" content="nameplate OCR, equipment nameplate reader, data centre nameplate, data center commissioning, UPS nameplate, PDU nameplate, switchgear, generator nameplate, transformer nameplate, equipment schedule verification, asset register, CRAH, chiller, MEP commissioning, browser OCR, BuildVision" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="BuildVision" />
<meta property="og:title" content="Nameplates — read & verify equipment nameplates in the browser" />
<meta property="og:description" content="Photograph a data centre equipment nameplate and read it in your browser: model, serial, voltage and rating checked against your equipment schedule, with an asset register CSV. Nothing is uploaded." />
<meta property="og:image" content="og-nameplates.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="BuildVision Nameplates — read and verify data centre equipment nameplates against the equipment schedule" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Nameplates — read & verify equipment nameplates in the browser" />
<meta name="twitter:description" content="Photograph a UPS, PDU, switchgear or chiller nameplate and check model, serial, voltage and rating against the equipment schedule. Runs in your browser; nothing is uploaded." />
<meta name="twitter:image" content="og-nameplates.png" />
<meta name="twitter:image:alt" content="BuildVision Nameplates — equipment-nameplate OCR checked against the equipment schedule" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebApplication",
"name": "BuildVision Nameplates",
"description": "Browser tool that reads an equipment nameplate (UPS, PDU, switchgear, generator, transformer, battery, CRAH, chiller) with in-browser OCR and checks model, serial, voltage, phase, Hz, kVA, kW, amps, MCA, MOCP and refrigerant against the equipment schedule, then exports an asset register CSV. Photos never leave the device.",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Any (runs in a modern web browser)",
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
"featureList": [
"On-device nameplate OCR (nothing uploaded)",
"13 equipment types: UPS, generator, ATS, switchgear, transformer, PDU, panelboard, busway, battery, CDU, chiller, CRAH/CRAC, pump",
"Field-by-field check against the equipment schedule",
"Flags wrong voltage, rating or model instead of a silent pass",
"Asset register with duplicate-serial and missing-tag detection, exported as CSV"
]
}
</script>
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
<link rel="stylesheet" href="style.css" />
<style>
body { min-height: 100%; }
.np-wrap { display: grid; grid-template-columns: 320px minmax(0, 1fr); flex: 1; min-height: 0; }
.np-side { border-right: 1px solid var(--border); padding: 18px 18px 28px; display: flex; flex-direction: column; gap: 18px; background: var(--bg-panel-2); overflow-y: auto; }
.np-side h2, .np-main h2 { font-size: 0.78rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-dim); margin: 0 0 8px; }
.np-side p, .np-note { font-size: 0.82rem; color: var(--text-dim); line-height: 1.45; margin: 0; }
.np-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.np-btn { border: 1px solid var(--border); background: var(--bg); color: var(--text); padding: 8px 12px; border-radius: var(--radius-sm); font-weight: 600; font-size: 0.84rem; cursor: pointer; }
.np-btn:hover { border-color: var(--accent); }
.np-btn.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.np-btn.primary:hover { background: var(--accent-hover); }
.np-btn:disabled { opacity: 0.5; cursor: default; }
.np-btn.link { border: none; background: none; padding: 4px 6px; color: var(--text-dim); font-weight: 500; }
.np-drop { display: block; border: 1.5px dashed var(--border); border-radius: var(--radius); padding: 16px; text-align: center; font-size: 0.84rem; color: var(--text-dim); background: var(--bg); cursor: pointer; }
.np-drop.over { border-color: var(--accent); background: var(--accent-soft); }
.np-status { font-size: 0.82rem; min-height: 1.2em; color: var(--text-dim); }
.np-status.err { color: var(--danger); }
.np-bar { height: 4px; background: var(--border); border-radius: 2px; overflow: hidden; }
.np-bar > i { display: block; height: 100%; width: 0; background: var(--accent); transition: width 0.15s; }
.np-main { display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow-y: auto; }
.np-top { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(300px, 1fr); border-bottom: 1px solid var(--border); }
.np-stage { position: relative; min-height: 340px; background: var(--bg-subtle); display: grid; place-items: center; padding: 12px; }
.np-stage canvas { max-width: 100%; max-height: 62vh; height: auto; display: block; border-radius: var(--radius-sm); }
.np-empty { text-align: center; color: var(--text-dim); font-size: 0.9rem; padding: 24px; }
.np-reading { padding: 16px 18px 20px; border-left: 1px solid var(--border); display: flex; flex-direction: column; gap: 12px; }
.np-fields { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px 10px; align-items: center; font-size: 0.84rem; }
.np-fields label { color: var(--text-dim); font-weight: 600; white-space: nowrap; display: flex; align-items: center; gap: 6px; }
.np-fields input, .np-fields select, .np-tag select { width: 100%; padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: 16px; background: var(--bg); color: var(--text); min-width: 0; }
.np-fields input.low { border-color: var(--warning, #c98a00); background: color-mix(in srgb, var(--warning, #c98a00) 8%, var(--bg)); }
.np-key { display: inline-block; width: 9px; height: 9px; border-radius: 2px; flex: none; }
.np-tag { display: flex; flex-direction: column; gap: 6px; font-size: 0.84rem; font-weight: 600; }
.np-checks { list-style: none; margin: 0; padding: 0; font-size: 0.84rem; display: flex; flex-direction: column; gap: 4px; }
.np-checks li { display: flex; gap: 8px; align-items: baseline; }
.np-checks .ok { color: var(--success, #1f8a4c); }
.np-checks .mismatch { color: var(--danger); font-weight: 600; }
.np-checks .unread { color: var(--text-dim); }
.np-verdict { padding: 8px 10px; border-radius: var(--radius-sm); font-size: 0.86rem; font-weight: 600; }
.np-verdict.verified { background: color-mix(in srgb, var(--success, #1f8a4c) 12%, transparent); color: var(--success, #1f8a4c); }
.np-verdict.mismatch { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger); }
.np-verdict.partial, .np-verdict.unmatched { background: var(--bg-subtle); color: var(--text); }
.np-register { padding: 14px 18px 24px; }
.np-summary { display: flex; gap: 18px; flex-wrap: wrap; margin-bottom: 10px; font-size: 0.86rem; }
.np-summary b { font-size: 1.05rem; }
table.np-table { border-collapse: collapse; width: 100%; font-size: 0.82rem; }
.np-table th, .np-table td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--border); vertical-align: top; }
.np-table th { color: var(--text-dim); font-weight: 600; font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.04em; }
.np-table tr[data-id] { cursor: pointer; }
.np-table tr[data-id]:hover td { background: var(--bg-subtle); }
.np-table tr.sel td { background: var(--accent-soft); }
.np-table img { width: 56px; height: 40px; object-fit: cover; border-radius: 3px; display: block; }
.np-chip { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 0.74rem; font-weight: 600; white-space: nowrap; background: var(--bg-subtle); }
.np-chip.verified { background: color-mix(in srgb, var(--success, #1f8a4c) 14%, transparent); color: var(--success, #1f8a4c); }
.np-chip.mismatch { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }
.np-missing { font-size: 0.82rem; color: var(--text-dim); margin-top: 10px; }
@media (max-width: 980px) {
.np-top { grid-template-columns: 1fr; }
.np-reading { border-left: none; border-top: 1px solid var(--border); }
}
@media (max-width: 820px) {
/* One column that scrolls as a page, not panels that each scroll (they overlapped the photo). */
html, body { height: auto; }
.np-wrap { display: block; }
.np-side, .np-main { overflow: visible; }
.np-side { border-right: none; border-bottom: 1px solid var(--border); padding: 16px; }
.np-stage { min-height: 220px; }
.np-reading, .np-register { padding: 14px 16px; }
.np-table .np-hide-sm { display: none; }
}
</style>
</head>
<body>
<header class="app-header">
<div class="brand">
<a class="brand-home" href="https://huggingface.co/constructelligence/data-centre-nameplates" title="Model card on Hugging Face" style="text-decoration:none;color:inherit;display:flex;align-items:center;gap:8px">
<h1 class="brand-name">BuildVision</h1>
</a>
</div>
<nav class="mode-switch" aria-label="Page">
<a class="mode-link" href="https://huggingface.co/constructelligence/data-centre-nameplates" target="_blank" rel="noopener">Model card</a>
<a class="mode-link" href="https://constructelligence.co" target="_blank" rel="noopener">constructelligence.co</a>
<span class="mode-link active" aria-current="page">Nameplates</span>
</nav>
<div class="header-status"><span id="npModel" class="status-pill model-status">OCR idle</span></div>
</header>
<main class="np-wrap">
<aside class="np-side">
<section>
<h2>1. Equipment schedule</h2>
<label id="npSchedDrop" class="np-drop" tabindex="0">
<input id="npSchedFile" type="file" accept=".csv,.tsv,.txt,text/csv" hidden />
<span>Drop the equipment schedule as CSV, or click to choose</span>
</label>
<div class="np-row" style="margin-top:8px">
<button id="npSchedSample" class="np-btn" type="button">Use sample schedule</button>
<button id="npSchedClear" class="np-btn link" type="button" hidden>Remove</button>
</div>
<p id="npSchedStatus" class="np-status" style="margin-top:8px" aria-live="polite"></p>
<p style="margin-top:6px">Optional. Needs a Tag or Model column; Manufacturer, Voltage, Phase, kVA, kW, Amps, Refrigerant, Serial and Location are checked when present.</p>
</section>
<section>
<h2>2. Nameplate photo</h2>
<label id="npDrop" class="np-drop" tabindex="0">
<input id="npFile" type="file" accept="image/*" multiple hidden />
<span>Take or drop a nameplate photo, or a batch from a walk</span>
</label>
<div class="np-row" style="margin-top:8px">
<button id="npSample" class="np-btn" type="button">Try a sample nameplate</button>
<button id="npRotate" class="np-btn" type="button" disabled title="Rotate the photo 90°">Rotate</button>
</div>
<p style="margin-top:8px">Fill the frame with the plate, without glare across the text. Tilted shots are straightened automatically. Pick several photos at once to read a whole walk into the register, then click a row to review it.</p>
</section>
<section>
<button id="npRun" class="np-btn primary" type="button" disabled>Read nameplate</button>
<div class="np-bar" style="margin-top:10px"><i id="npProg"></i></div>
<div id="npStatus" class="np-status" role="status" aria-live="polite"></div>
</section>
<section>
<p class="np-note">Runs in your browser: photos never leave this device. The first read downloads the OCR engine and English text model (about 11 MB) from a public CDN. OCR misreads happen, so fields with low confidence are highlighted for you to check against the plate.</p>
</section>
</aside>
<section class="np-main">
<div class="np-top">
<div class="np-stage">
<canvas id="npCanvas" width="0" height="0" hidden></canvas>
<div id="npEmpty" class="np-empty">Load a nameplate photo to begin.</div>
</div>
<div id="npReading" class="np-reading" hidden>
<h2>Reading</h2>
<div id="npVerdict" class="np-verdict" aria-live="polite"></div>
<div class="np-fields" id="npFields"></div>
<div class="np-tag">
<span>Schedule tag</span>
<select id="npTag"></select>
<span id="npTagNote" class="np-note" style="font-weight:400"></span>
</div>
<ul id="npChecks" class="np-checks" aria-label="Checks against the schedule"></ul>
<div class="np-row">
<button id="npAdd" class="np-btn primary" type="button">Add to register</button>
<details style="font-size:0.8rem;color:var(--text-dim)"><summary>OCR text</summary><pre id="npText" style="white-space:pre-wrap;font-size:0.78rem;margin:6px 0 0"></pre></details>
</div>
</div>
</div>
<div class="np-register">
<h2>Asset register</h2>
<div id="npSummary" class="np-summary"></div>
<div class="np-row" style="margin-bottom:10px">
<button id="npCsv" class="np-btn" type="button" disabled>Download register CSV</button>
<button id="npClearReg" class="np-btn link" type="button" disabled>Clear register</button>
</div>
<table class="np-table">
<thead><tr><th class="np-hide-sm">Photo</th><th>Tag</th><th>Status</th><th>Model</th><th class="np-hide-sm">Serial</th><th class="np-hide-sm">Voltage</th><th>Issues</th><th></th></tr></thead>
<tbody id="npRows"></tbody>
</table>
<p id="npEmptyReg" class="np-note" style="margin-top:10px">Nothing scanned yet. Each plate you add appears here with its check result.</p>
<p id="npMissing" class="np-missing"></p>
</div>
</section>
</main>
<script type="module" src="nameplates-app.js"></script>
</body>
</html>
|