CMMS fork: re-vendor all runtime deps locally, strip analytics

Upstream loads zip.js, OpenCV.js, WireBender (JS+WASM) and Google Fonts
from CDNs at runtime, and includes a Google Tag / gtag.js snippet. The
CMMS deployment forbids external requests. Changes:

- docs/vendor/ — local copies of opencv.js (Apache-2.0), zip.min.js
  (BSD-3-Clause), WireBender.{js,wasm} (AGPL-3.0/commercial, source at
  github.com/dev-lab/WireBender), and the three Google fonts (OFL, latin
  subset). SOURCE.txt records provenance.
- studio.html / schema.html — zip.js + opencv.js + fonts @import point at
  docs/vendor/.
- inspect-traces.js / schema/layout.js — WireBender import() + locateFile
  point at docs/vendor/wirebender/.
- every *.html — Google Tag / gtag.js snippet removed.

No behaviour change; kicad-symbols zip was already bundled + local.
CMMS embedding hooks (window.PCBRETRACE_CONFIG, save-back, AI bridge)
land in a later commit.
This commit is contained in:
Stuart 2026-09-03 14:02:16 +10:00
commit 5e4c7245b6
22 changed files with 172 additions and 36 deletions

View file

@ -7,10 +7,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted"});gtag("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",region:"AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE,IS,LI,NO,GB,CH,UA".split(",")});</script> <!-- CMMS fork: Google Tag / analytics removed (no external requests) -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-X1MKL6C4B0"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date());gtag("config","G-X1MKL6C4B0");</script>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="favicon.ico"> <link rel="icon" href="favicon.ico">

View file

@ -7,10 +7,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted"});gtag("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",region:"AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE,IS,LI,NO,GB,CH,UA".split(",")});</script> <!-- CMMS fork: Google Tag / analytics removed (no external requests) -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-X1MKL6C4B0"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date());gtag("config","G-X1MKL6C4B0");</script>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="favicon.ico"> <link rel="icon" href="favicon.ico">

View file

@ -7,10 +7,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted"});gtag("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",region:"AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE,IS,LI,NO,GB,CH,UA".split(",")});</script> <!-- CMMS fork: Google Tag / analytics removed (no external requests) -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-X1MKL6C4B0"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date());gtag("config","G-X1MKL6C4B0");</script>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="favicon.ico"> <link rel="icon" href="favicon.ico">

View file

@ -7,10 +7,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted"});gtag("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",region:"AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE,IS,LI,NO,GB,CH,UA".split(",")});</script> <!-- CMMS fork: Google Tag / analytics removed (no external requests) -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-X1MKL6C4B0"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date());gtag("config","G-X1MKL6C4B0");</script>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="favicon.ico"> <link rel="icon" href="favicon.ico">

View file

@ -44,9 +44,9 @@ const TraceConfig = {
*/ */
RECALC_MODE: 'single', RECALC_MODE: 'single',
/** WireBender WASM module entry point. */ /** WireBender WASM module entry point. */
WASM_URL: 'https://dev-lab.github.io/WireBender/latest/WireBender.js', WASM_URL: 'vendor/wirebender/WireBender.js',
/** WireBender WASM binary. */ /** WireBender WASM binary. */
WASM_BINARY_URL: 'https://dev-lab.github.io/WireBender/latest/WireBender.wasm', WASM_BINARY_URL: 'vendor/wirebender/WireBender.wasm',
}; };
/** /**

View file

@ -7,10 +7,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted"});gtag("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",region:"AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE,IS,LI,NO,GB,CH,UA".split(",")});</script> <!-- CMMS fork: Google Tag / analytics removed (no external requests) -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-X1MKL6C4B0"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date());gtag("config","G-X1MKL6C4B0");</script>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="favicon.ico"> <link rel="icon" href="favicon.ico">

View file

@ -7,17 +7,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted"});gtag("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",region:"AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE,IS,LI,NO,GB,CH,UA".split(",")});</script> <!-- CMMS fork: Google Tag / analytics removed (no external requests) -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-X1MKL6C4B0"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date());gtag("config","G-X1MKL6C4B0");</script>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Schematic ReTrace</title> <title>Schematic ReTrace</title>
<script src="https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.8.26/dist/zip.min.js"></script> <script src="vendor/zip.min.js"></script>
<script src="db-core.js"></script> <script src="db-core.js"></script>
<style> <style>
@import url('https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Rajdhani:wght@400;500;600;700&family=Space+Mono:wght@400;700&display=swap'); @import url('vendor/fonts/fonts.css');
:root { :root {
--bg:#0d1117; --surface:#161b22; --surface2:#1c2230; --border:#30363d; --bg:#0d1117; --surface:#161b22; --surface2:#1c2230; --border:#30363d;
--accent:#00e5a0; --accent2:#00a8ff; --accent3:#ff6b35; --warn:#f0c040; --accent:#00e5a0; --accent2:#00a8ff; --accent3:#ff6b35; --warn:#f0c040;

View file

@ -47,9 +47,9 @@ let _modulePromise = null;
*/ */
export function initWireBender() { export function initWireBender() {
if (_modulePromise) return _modulePromise; if (_modulePromise) return _modulePromise;
_modulePromise = import('https://dev-lab.github.io/WireBender/latest/WireBender.js') _modulePromise = import('../vendor/wirebender/WireBender.js')
.then(m => m.default({ .then(m => m.default({
locateFile: f => f === 'WireBender.wasm' ? 'https://dev-lab.github.io/WireBender/latest/WireBender.wasm' : f, locateFile: f => f === 'WireBender.wasm' ? new URL('../vendor/wirebender/WireBender.wasm', import.meta.url).href : f,
})) }))
.then(module => { .then(module => {
_WB = module; _WB = module;

View file

@ -7,18 +7,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted"});gtag("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",region:"AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE,IS,LI,NO,GB,CH,UA".split(",")});</script> <!-- CMMS fork: Google Tag / analytics removed (no external requests) -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-X1MKL6C4B0"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date());gtag("config","G-X1MKL6C4B0");</script>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="favicon.ico"> <link rel="icon" href="favicon.ico">
<title>PCB ReTrace Studio</title> <title>PCB ReTrace Studio</title>
<script src="https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.8.26/dist/zip.min.js"></script> <script src="vendor/zip.min.js"></script>
<!-- LIBRARIES --> <!-- LIBRARIES -->
<script async src="https://docs.opencv.org/4.x/opencv.js" type="text/javascript"></script> <script async src="vendor/opencv.js" type="text/javascript"></script>
<script src="spyglass.js"></script> <script src="spyglass.js"></script>
<!-- CORE LOGIC --> <!-- CORE LOGIC -->

36
docs/vendor/SOURCE.txt vendored Normal file
View file

@ -0,0 +1,36 @@
Third-party runtime dependencies, vendored locally for the CMMS fork
==================================================================
Upstream pcb-retrace loads these from CDNs at runtime. The CMMS deployment
forbids external requests (CSP + offline-capable), so they are copied here and
the references in ../studio.html, ../schema.html, ../inspect-traces.js and
../schema/layout.js are rewritten to these local paths. Fetched 2026-09-03.
opencv.js
https://docs.opencv.org/4.x/opencv.js (OpenCV 4.x prebuilt, single-file,
wasm embedded as a base64 data URI — no separate .wasm)
License: Apache-2.0. Used by cv-core.js for ORB feature matching / photo
alignment only.
zip.min.js
https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.8.26/dist/zip.min.js
License: BSD-3-Clause (Gildas Lormeau). Project-ZIP + kicad-symbols-zip
read/write.
wirebender/WireBender.js + WireBender.wasm
https://dev-lab.github.io/WireBender/latest/{WireBender.js,WireBender.wasm}
License: dual AGPL-3.0-only OR commercial (Taras Greben). Corresponding
source: https://github.com/dev-lab/WireBender (not modified here — the
published binary is redistributed as-is alongside this AGPL fork).
Cosmetic net-trace routing for the Inspect view + Schema ReTrace layout.
ES module (uses import.meta.url); the .wasm is resolved by emscripten's
default locateFile relative to the module, or via the explicit URL() in
schema/layout.js.
fonts/ (Rajdhani v17, Share Tech Mono v16, Space Mono v17 — latin subset only)
https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Rajdhani:wght@400;500;600;700&family=Space+Mono:wght@400;700
License: SIL Open Font License 1.1. Used by schema.html only. fonts.css
replaces the external @import.
../assets/kicad-symbols-master.zip is bundled by upstream itself (KiCad symbol
libraries, CC-BY-SA-4.0 + KiCad library exception) — not added here.

56
docs/vendor/fonts/fonts.css vendored Normal file
View file

@ -0,0 +1,56 @@
/*
* Local copies of the Google Fonts used by schema.html (Schema ReTrace).
* Latin subset only. Fetched 2026-09-03 from fonts.googleapis.com /
* fonts.gstatic.com. Rajdhani v17, Share Tech Mono v16, Space Mono v17.
* All three are licensed under the SIL Open Font License 1.1.
* Replaces an external @import so the app makes no cross-origin requests.
*/
@font-face {
font-family: 'Rajdhani';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(./rajdhani-400.woff2) format('woff2');
}
@font-face {
font-family: 'Rajdhani';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(./rajdhani-500.woff2) format('woff2');
}
@font-face {
font-family: 'Rajdhani';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(./rajdhani-600.woff2) format('woff2');
}
@font-face {
font-family: 'Rajdhani';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(./rajdhani-700.woff2) format('woff2');
}
@font-face {
font-family: 'Share Tech Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(./sharetechmono-400.woff2) format('woff2');
}
@font-face {
font-family: 'Space Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(./spacemono-400.woff2) format('woff2');
}
@font-face {
font-family: 'Space Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(./spacemono-700.woff2) format('woff2');
}

BIN
docs/vendor/fonts/rajdhani-400.woff2 vendored Normal file

Binary file not shown.

BIN
docs/vendor/fonts/rajdhani-500.woff2 vendored Normal file

Binary file not shown.

BIN
docs/vendor/fonts/rajdhani-600.woff2 vendored Normal file

Binary file not shown.

BIN
docs/vendor/fonts/rajdhani-700.woff2 vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
docs/vendor/fonts/spacemono-400.woff2 vendored Normal file

Binary file not shown.

BIN
docs/vendor/fonts/spacemono-700.woff2 vendored Normal file

Binary file not shown.

48
docs/vendor/opencv.js vendored Normal file

File diff suppressed because one or more lines are too long

16
docs/vendor/wirebender/WireBender.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
docs/vendor/wirebender/WireBender.wasm vendored Normal file

Binary file not shown.

1
docs/vendor/zip.min.js vendored Normal file

File diff suppressed because one or more lines are too long