Skip to content

Commit efd8b7e

Browse files
ehsun-shclaude
andcommitted
Refresh the mockup to the full library, and write DESIGN.md
The mockup had gone stale: it embedded 26 manifests while the registry had 32, so the six blocks added since -- Splitter, PolarizationCombiner, PolarizationRotator, DualPolarizationReceiver, ButterflyEqualizer, DifferentialDecoder -- were missing from the palette. Its schematic also predated pulse shaping and differential encoding. Both are now current: 14 blocks, 18 links, 32 components in the palette. DESIGN.md is the record the mockup's own direction contract promised and never delivered. It carries the two grounds and why paper is the default, the spectral port identity, the measured ink ladder, the layout numbers with their reasons, the plot language, and -- most usefully -- what is verified on each publish and how. Including the two verification findings worth not relearning: an audit run while the browser pane was not compositing reported a clean result that meant nothing, because the page had laid out at its narrow breakpoint where the palette and inspector are display:none and were never checked; and an empty result from a degraded detector is an undercount, not a pass. Refreshing the export surfaced two real defects in it. The sensitivity sweep swept BPSK through a differentially encoded mapper, which correctly refuses: quadrant encoding needs a quadrant to difference and a two-point constellation has none. BPSK is dropped from that sweep with the reason stated, rather than the mapper being made to cope silently. The sweep also overrode only the first of the two mappers, leaving the reference arm on the old format. Both are overridden now. And one design defect, found the same way the eye-histogram banding was found -- by building the interface against real output. An analyser placed after the differential decoder reported an EVM of exactly zero however bad the link was, because that block emits decisions rather than soft symbols. The mockup now carries two analysers: EVM before the decoder where the measurement is soft, the error count after it where the data exists. The decoder's docstring says so. Measured, full chain with shaping, matched filtering, carrier recovery and differential encoding: 16-QAM at 128 Gb/s, EVM 4.17%, SNR 27.59 dB, zero symbol errors in 3968. The EVM improvement from 5.75% is the matched filter earning its place. Verified: zero contrast failures across four dock tabs in both grounds, 16 of 16 clusters inked, no stray geometry outside the viewBox, no horizontal overflow. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent bedc662 commit efd8b7e

5 files changed

Lines changed: 6091 additions & 5476 deletions

File tree

DESIGN.md

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# Design
2+
3+
The visual and interaction record for OpenOptiSim's interface. It exists because
4+
[`docs/ui-mockup.html`](docs/ui-mockup.html) is a *build*, and a build without a
5+
written rationale is a set of numbers nobody can argue with later. Everything
6+
here was decided against the audience and use scene in [PRODUCT.md](PRODUCT.md);
7+
where a decision was made by measurement rather than judgement, the measurement
8+
is given.
9+
10+
---
11+
12+
## 1. What the surface is
13+
14+
An **Operate** surface: a schematic editor, used to complete a task rather than
15+
to be admired or read through. Scanability, consistency and the real usage scene
16+
outrank expression. Brand lives in precise details, not in gestures.
17+
18+
The engineer is *iterating* — change a parameter, run, look at the constellation,
19+
change it again — dozens of times an hour. Three consequences follow, and they
20+
decide most of what is below:
21+
22+
1. **Density beats generosity.** Screen space spent on decoration is space not
23+
spent on the schematic or the plot.
24+
2. **Recognition beats novelty.** The layout is the one this audience already
25+
knows from Blender, VS Code and EDA tools. Nothing is moved to be different.
26+
3. **Nothing on screen may be invented.** Every number, every parameter, every
27+
port comes from a real engine run. See §7.
28+
29+
---
30+
31+
## 2. Two grounds
32+
33+
The interface ships **paper** and **graphite**, and defaults to paper.
34+
35+
A schematic is a document before it is a screen. Its plots leave the tool for
36+
reports, theses and papers, where a screenshot off a black canvas is the wrong
37+
artefact. Graphite is one click away for the night session beside a terminal.
38+
39+
Neither is a skin over the other:
40+
41+
| | paper | graphite |
42+
| :--- | :--- | :--- |
43+
| ground | `#e9edf3` bed under white panels | `#0b0e13` under `#11151c` panels |
44+
| a block | white card on a grey bed | raised panel on a dark one |
45+
| hover | adds **ink** (darker) | adds **light** |
46+
| plot bed | `#ffffff` — a plot is on paper | `#080b10` |
47+
48+
The port hues are the identity and survive both, but their **values are
49+
re-derived per ground rather than inverted** — on paper the spectrum darkens to
50+
hold contrast against a light bed.
51+
52+
**Structure.** The bare `:root` block carries the complete paper palette. The
53+
graphite tokens appear twice: once under
54+
`@media (prefers-color-scheme: dark)` guarded as `:root:not([data-theme="light"])`,
55+
and once under `:root[data-theme="dark"]` so an explicit choice wins in both
56+
directions. No colour is ever defined *only* inside a media or `[data-theme]`
57+
block — that is the classic unreadable-page bug, and it is checked rather than
58+
assumed (§8).
59+
60+
---
61+
62+
## 3. The spectral port identity
63+
64+
**Every port colour is a wavelength, not a preference.** A wire's colour tells
65+
you what travels down it.
66+
67+
| port type | paper | graphite |
68+
| :--- | :--- | :--- |
69+
| optical (C-band) | `#0a8279` | `#22d3c5` |
70+
| electrical | `#a35f00` | `#f0a030` |
71+
| binary | `#5a6474` | `#7c86a0` |
72+
| symbol | `#6539cc` | `#9b7cf6` |
73+
| metric | `#bc2668` | `#e85d9b` |
74+
75+
This is the one place the interface is allowed to be memorable, and it earns its
76+
place by being *information*: a typed-port system that refuses invalid wiring at
77+
edit time is meaningless if the types are invisible.
78+
79+
The shown project is chosen so that **all five types appear on the canvas at
80+
once**. That is why it is a coherent link rather than an on-off-keyed one: only
81+
a coherent chain carries binary into symbols, symbols into two electrical
82+
drives, an optical field, two photocurrents back, and symbols out again.
83+
84+
Accent is `--optical`, because the tool is an optical simulator. Semantic colour
85+
(`--good` / `--warn` / `--bad`) is kept separate from it and does not count as
86+
the accent.
87+
88+
---
89+
90+
## 4. The ink ladder
91+
92+
Four layers, spaced so hierarchy comes from the **distance between them** rather
93+
than from pushing the weakest below readability.
94+
95+
| token | paper | vs white | graphite | role |
96+
| :--- | :--- | ---: | :--- | :--- |
97+
| `--ink` | `#0f141c` | 18.5 | `#e6ecf5` | values, headings |
98+
| `--ink-2` | `#333d4b` | 11.0 | `#a8b4c6` | labels, body |
99+
| `--ink-3` | `#4c5666` | 7.4 | `#8e9bb0` | section titles, axes |
100+
| `--ink-4` | `#5f6a79` | 5.5 | `#7a869b` | units, ranges, disabled |
101+
102+
The bottom rung is set by the **tinted grounds it actually lands on** — a unit
103+
inside an input well, a disabled toolbar label — not by white, where it would
104+
look too pale. Against the darkest surface it still clears 4.5:1.
105+
106+
---
107+
108+
## 5. Layout
109+
110+
Four regions, top to bottom:
111+
112+
```
113+
menu bar 34px File / Edit / Simulate / View / Help, ground switch, engine state
114+
action toolbar 40px Run, Stop, Sweep · select/pan/align · zoom · run context
115+
body 1fr palette 216px | node canvas 1fr | inspector 260px
116+
results dock 292px tabs + metric strip, plot + side readouts
117+
status bar 24px block and link counts, selection, sample count, precision
118+
```
119+
120+
**Run sits leftmost in the toolbar**, where the eye lands first, because it is
121+
the action taken dozens of times an hour.
122+
123+
**The dock is 292px** because the constellation's plot is square and therefore
124+
sized by the dock's *height*, not its width. A shorter dock wastes the width it
125+
has.
126+
127+
Below 940px the palette and inspector collapse and a note says so. This is a
128+
desktop tool; the real build would dock them as overlays rather than dropping
129+
them, and the note says that too rather than pretending the narrow layout is the
130+
intended one.
131+
132+
---
133+
134+
## 6. Plots
135+
136+
Two reduced result types, and they share a visual language because they mean the
137+
same thing: **distance from the page is how many landed there**.
138+
139+
- **Eye diagram** — density ramp bed → cyan → far stop.
140+
- **Constellation** — the same ramp; axes through the origin, because a
141+
constellation is read relative to zero and not to the corner of a box; ideal
142+
points marked with **crosses rather than filled dots**, so a cluster's own
143+
centre stays visible underneath and a bias offset reads instead of being
144+
covered by the marker meant to locate it.
145+
- **Sensitivity** — one curve per format, each labelled where it crosses the FEC
146+
threshold rather than in a legend box. The threshold is 1e-3, not Q = 6:
147+
nobody operates an error-free channel any more, they operate one a
148+
soft-decision code can close.
149+
150+
The ramp's mid stop is placed by **luminance**, at roughly the same fraction of
151+
each ground's span, which is what keeps sparse outliers subordinate to the dense
152+
regions on both.
153+
154+
A canvas has no cascade, so the plots read the same tokens as everything else at
155+
draw time and are redrawn when the ground changes. Nothing below the token block
156+
names a colour.
157+
158+
---
159+
160+
## 7. Real data, always
161+
162+
The palette is generated from `manifests()` — the same call the real GUI will
163+
make. The inspector shows true parameters, units, ranges and docstrings. The
164+
constellation, eye and sweep are a real run, exported by
165+
[`examples/export_ui_data.py`](examples/export_ui_data.py).
166+
167+
This is not a purity exercise. Building the mockup against real data has twice
168+
found engine defects that the test suite missed:
169+
170+
- `eye_histogram` accepted any `time_bins` and rendered a 32-sample trace across
171+
96 columns as **vertical banding**. Time resolution is now capped at one
172+
column per sample.
173+
- Placing an analyser after the differential decoder reported **EVM of exactly
174+
zero** however bad the link was, because that block emits decisions. The
175+
mockup now carries two analysers — soft measurement before the decoder, error
176+
count after — which is also how a bench does it.
177+
178+
---
179+
180+
## 8. What is verified, and how
181+
182+
Not by looking at downscaled screenshots. Each publish is checked by
183+
measurement, in **both grounds**:
184+
185+
- **Contrast** — every text node's computed colour against its resolved
186+
background; ~110 elements per dock tab. Target 4.5:1 (3:1 for large text).
187+
Current status: **zero failures**, both grounds, all four tabs.
188+
- **Token completeness** — every `var(--…)` the stylesheet references must
189+
resolve from bare `:root` alone. Current: 34/34.
190+
- **Theme-block drift** — the two graphite blocks are compared key by key.
191+
- **Canvas repaint** — plot beds are sampled after switching, in both
192+
directions.
193+
- **Geometry** — no SVG element may stray outside the viewBox; no horizontal
194+
page overflow at 1440px.
195+
196+
Two findings worth keeping:
197+
198+
- A contrast audit run while the browser pane was not compositing reported a
199+
clean result that **meant nothing** — the page had laid out at its narrow
200+
breakpoint, where the palette and inspector are `display: none` and were never
201+
checked. Verify the viewport before trusting the audit.
202+
- The design detector once ran degraded and returned `[]`. An empty result from
203+
a degraded tool is an undercount, not a pass.
204+
205+
---
206+
207+
## 9. Decisions worth not re-litigating
208+
209+
- **Paper is the default**, and it is stamped before first paint so a dark host
210+
never flashes through. The stylesheet still answers `prefers-color-scheme` on
211+
its own for the no-script case.
212+
- **A backward wire is the schematic wrapping**, not a mistake. It needs a
213+
*tighter* bezier control offset than a forward one; scaling the offset with
214+
the span throws the curve outside the canvas on exactly the wire that already
215+
travels furthest.
216+
- **Node labels truncate with the full name in a tooltip.** A fixed-width box
217+
that lets long names spill across neighbours is worse than one that clips.
218+
- **Hover on paper adds ink, not light.** Lightening a hover on a white ground
219+
moves it towards invisible.
220+
221+
---
222+
223+
## 10. Not done
224+
225+
- The mockup shows a single-carrier link. The dual-polarization link is in
226+
[`examples/dualpol_link.py`](examples/dualpol_link.py) and is not on the
227+
canvas: at ~20 blocks the node text stops being readable at this canvas size,
228+
and a schematic nobody can read is not a better demonstration.
229+
- No motion beyond the run pulse and the control transitions.
230+
- No empty, loading or error states — there is no session server yet to produce
231+
them.

0 commit comments

Comments
 (0)