# Reconstruction findings and reproducibility

## Result

The selected reconstruction uses **ClarendonLTStd.otf, Regular**, with global scaling, a small rotation, and three measured origin advances.
No glyph-specific scale, rotation, vertical offset, or outline edit is applied.
The source SVG remains unchanged.

The geometry is very close but not identical: contour RMS is **0.149379 SVG units**, and raster IoU is **98.396611%**.
This supports a consistent “Bygger” extension. It does not establish historically exact spacing or custom contours for letters absent from the reference.

## Coordinate rules

- Font units per em: 1000.
- Local scale: x = `0.160677063690360`, y = `0.160971301777546` SVG units per font unit.
- Equivalent SVG font size: `160.971301777546`, followed by horizontal scaling `0.998172108420`.
- Rotation: `-0.237928331343` degrees. Negative angles rise to the right in SVG coordinates.
- B baseline origin: `[18.816718044107336, 117.9427579177128]`.
- Fill: `#154840`.
- Original root viewBox retained in both reconstruction SVGs: `13 10 638 217`.

For a glyph outline point `(u, v)` in native font coordinates (y up) and glyph origin `o` in font units:

```text
x_svg = a * (u + o) + c * v + e
y_svg = b * (u + o) + d * v + f
[a, b, c, d, e, f] = [0.16067567830587562, -0.0006672309217133212, -0.0006684527809233856, -0.16096991385609147, 18.816718044107336, 117.9427579177128]
```

Glyph origins along the untransformed baseline are `[0.0, 661.5475346823724, 1187.7162335238447, 1784.8484388495922]` font units.
The JSON includes all four final SVG baseline positions and the baseline equation.
An absolute historical font size is not identifiable independently from the SVG scaling; the stated size is a reproducible convention.

## Exact fitted spacing

Native GPOS kerning for these pairs is zero.
Each origin advance is the distance between glyph origins, not the distance between ink bounding boxes.

| Pair | Native advance (FU) | Fitted advance (FU) | Total adjustment (FU) | Residual after estimated tracking (FU) | Advance along baseline (SVG units) |
| --- | --- | --- | --- | --- | --- |
| B-y | 722 | 661.547534682 | -60.452465318 | 11.264721733 | 106.295515364 |
| y-g | 611 | 526.168698841 | -84.831301159 | -13.114114108 | 84.543241536 |
| g-g | 667 | 597.132205326 | -69.867794674 | 1.849392376 | 95.945449387 |

FU means font units. The measured total adjustments are authoritative for this reconstruction.
Tracking and pair corrections are not independently identifiable from three observed gaps.

## Extension to “Bygger”: explicit inference

Preserve the existing pair advances exactly. Preserve font, scale, rotation, baseline, and fill.
For the new pairs, use native advance plus native kerning plus estimated tracking.
The chosen tracking estimate is **-71.717187050 font units**, the arithmetic mean of the three existing adjustments.
The JSON decomposes existing adjustments into this estimate and pair-specific residuals. That decomposition is a convention, not a recovered historical setting.

- g→e: `667 + 0 + (-71.717187050) = 595.282812950` font units.
- e→r: `500 + 0 + (-71.717187050) = 428.282812950` font units.
- Continue the same rotated baseline for both added letters.
- Do not copy g-specific counter differences into new letters.

Every existing pair is tighter than native spacing, which supports a tightening policy for new pairs.
However, the existing adjustments range from -84.831301 to -60.452465 font units.
One common tracking value alone does not explain them. Optical spacing or manual corrections remain possible explanations.
The proposed g-e and e-r positions therefore require visual review when that extension is commissioned.
No “Bygger” SVG was generated in this task.

## Model selection and remaining outline error

| Model | Free parameters | RMS (SVG units) | Sampled maximum |
| --- | --- | --- | --- |
| Uniform scale, common horizontal baseline, custom pairs | 6 | 0.379782 | 1.443840 |
| Separate x/y scale, common horizontal baseline, custom pairs | 7 | 0.379368 | 1.439534 |
| Separate x/y scale, independent glyph y positions | 10 | 0.168875 | 1.019374 |
| Uniform scale + rotation, common baseline, custom pairs | 7 | 0.153253 | 1.073635 |
| x/y scale + rotation, common baseline, custom pairs (SELECTED) | 8 | 0.149379 | 1.108511 |
| Global affine, common baseline, custom pairs | 9 | 0.148656 | 1.088286 |
| Global affine, independent glyph x/y positions | 12 | 0.147386 | 1.089093 |
| x/y scale + rotation, common baseline, ONE tracking value | 6 | 0.553156 | 1.858460 |
| Independent affine per glyph (experimental) | 24 | 0.134247 (balanced) | 1.134849 |

The rotation explains the source baseline slope without four independent y positions.
The selected x/y scales differ by about 0.1831%; this small anisotropy is a fitting choice, not proof of deliberate stretching.
Adding shear lowers RMS by only 0.000723 units.
Independent affine glyph transforms lower balanced RMS to 0.134247, but require 24 parameters and still cannot recover the source contours.
Their fitted scales and rotations are retained in `fits.json`; the experimental SVG provides a reviewable alternative.
The simpler global model is the main reconstruction because it supports consistent new letters.

Largest errors occur at small sharp-to-rounded transitions and contour details.
`metrics.json` gives each worst-error coordinate, both distance directions, and counter-specific errors.
The differing g counters demonstrate that no placement of a single unchanged g outline can exactly reproduce both source glyphs.
Possible causes include retracing, cleanup, or a different font revision. Deliberate manual editing cannot be proven from these files.

### Uniform outline expansion experiment

The source's filled area is slightly larger than the fitted font's area.
Holding the main typography fixed, a uniform outward expansion of **0.092661 SVG units** improves raster IoU to **98.719792%**.
The experimental SVG implements this with a 0.185321-unit centered stroke and round joins, after transforming the font paths.
The radius minimizes antialiased alpha coverage difference at 16× resolution over the interval 0…0.25 units; a second narrower search checks its plateau.
This is a reproducible, slightly closer **raster-area approximation**. It is not a recovered historical stroke setting or a vector-distance optimum.
It may compensate for edge expansion from tracing or rasterization. It does not remove the differing counters or local contour deviations.
The main SVGs retain unmodified font outlines for typography reuse; `experimental_ink_expansion.svg` makes the closer area approximation available separately.
The measured expansion is small enough that either version needs the enlarged diagnostics to assess the difference.

## Validation and stopping criterion

The fit minimizes symmetric contour distances, with equal weight for each glyph and each distance direction.
Distances are measured to sampled polylines by projecting onto segments adjacent to the nearest sample.
This approximates vector-curve distance; the sampled maximum is Hausdorff-style, not a certified exact Hausdorff distance.
Counters participate in the objective. Raster overlap is a separate validation and does not drive font selection.

Final reference sampling: 0.04 SVG units. Font sampling: 0.25 font units (about 0.04 SVG units after scaling).
Increasing resolution fourfold changed RMS from 0.149488626 to 0.149378928 units.
Repeating optimization from that solution changed the objective by 0.
All selected fit runs reported convergence. This establishes a local numerical plateau, not a formal global-optimum proof.
The bbox-initialized independent candidate fits and the simpler-to-more-flexible model sequence reduce alignment ambiguity.

- Mean contour distance: 0.121376150 units.
- RMS contour distance: 0.149378928 units.
- 95th percentile contour distance: 0.267671541 units.
- Sampled maximum contour distance: 1.108511032 units.
- 16× raster IoU: 98.396610760%.
- XOR / union: 1.603389240%.
- XOR area: 349.992187500 square SVG units.
- 8× raster IoU: 98.404870210%.

Raster comparison uses alpha masks thresholded at 128, no post-render alignment, identical padded viewports, and transparent backgrounds.
The full word is included. Quantitative 16× masks use 6512 × 2528 pixels.
Diagnostic colors: magenta = original-only ink; blue = reconstruction-only ink; shared ink = dark gray (overlay) or pale gray (difference).
`comparison.png` shows side-by-side words at one pixel per SVG unit. High-resolution and per-glyph diagnostics expose the residuals.
`difference_amplified.png` expands difference locations by three pixels at 8× (0.375 SVG units) for visibility; it is not used for measurement.

## Reproduce

From the workspace root:

```sh
uv sync --locked
uv run python analyze.py
uv run python refine.py
uv run python deliver.py
```

To regenerate only the two production SVGs from the saved parameters:

```sh
uv run python reconstruct.py
```

For a future approved extension using the documented policy:

```sh
uv run python reconstruct.py --word Bygger --output-prefix results/bygger
```

The construction SVG embeds the supplied OTF in a CSS font face and positions each character explicitly.
It disables automatic kerning and ligatures because positions already include the measured spacing.
Browsers must support embedded SVG web fonts. Some image libraries, including CairoSVG, do not honor these fonts.
The original-versus-reconstruction diagnostics therefore render the portable outlined SVG.
Browser validation: **Rendered in Chromium (separate shell invocations)**.
At 4× resolution, the construction and outlined forms have 99.819570% binary ink overlap in Chromium.
Text hinting and path rasterization can cause small raster differences even with the same font outlines and placement.
The browser screenshots and `browser_validation.json` record this separate check.
Both forms come from the same font, matrix, and positions. The outlined form is the authoritative portable geometry.

Dependencies are recorded in `pyproject.toml` and pinned in `uv.lock`.
Diagnostics use DejaVu Sans for labels and the system Cairo library through CairoSVG.
Do not modify the reference or source fonts between runs; hashes in the rules identify the analyzed inputs.
