Rebrand infra and docs from M1730 to E440; bump version to 1.0
This commit is contained in:
@@ -4,24 +4,30 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
SVG scale artwork for M1730 analog meters. The scales are designed in Inkscape (v1.4.3) using the **ГОСТ тип А** (GOST type A) font, a Russian technical drafting standard typeface.
|
SVG scale artwork for E440-style round-dial analog meters. The scales are designed in Inkscape (v1.4.3) using **Alte DIN 1451 Mittelschrift**, a German technical drafting standard typeface.
|
||||||
|
|
||||||
All canvas dimensions are **157.18373 mm × 26.683672 mm**. The coordinate origin is offset: `transform="translate(-37.352226,-90.454928)"` is applied to `layer1` in all files, so absolute SVG coordinates start around x=37, y=90 rather than 0,0.
|
The canvas is **93.824249 mm × 57.215687 mm**. The coordinate origin is offset: `transform="translate(-60.717741,-107.14126)"` is applied to `layer1` in all files, so absolute SVG coordinates start around x=61, y=107 rather than 0,0.
|
||||||
|
|
||||||
## File Roles
|
## File Roles
|
||||||
|
|
||||||
The three SVG files represent layers of the same design, intended to be combined or used separately:
|
The three SVG files represent layers of the same design, intended to be combined or used separately:
|
||||||
|
|
||||||
- **`M1730-Scale_template.svg`** — Inkscape working template. Contains the background rect+cutout path, the zero tick mark, an end tick mark, the "U" axis label, numeric labels `0` and `X` (placeholder for the full-scale value), and a `5mA` range label. Also contains a `<rect id="rect5">` inside `<defs>` used as a text flow shape (`shape-inside:url(#rect5)`) for the title text block (`id="text5"`).
|
- **`E440-Scale_template.svg`** — Inkscape working template. Contains the case body path (with mounting ears and rim cutout), the pivot guide circle, tick marks, numeric labels `0`–`50`, the `uA` unit label, and `Text`/`Left` and `Text`/`Right` corner label placeholders.
|
||||||
- **`M1730-Scale_paths.svg`** — Paths-only version: all tick marks as `<path>` elements, no text nodes (or text converted to paths). Used for cutting/printing workflows where fonts must not be embedded as live text.
|
- **`E440-Scale_paths.svg`** — Paths-only version: all tick marks and text as `<path>`/`<line>` elements, no live text. Used for cutting/printing workflows where fonts must not be embedded as live text.
|
||||||
- **`M1730-Scale_text.svg`** — Text-overlay version: tick mark paths plus live `<text>` elements for numeric labels. The `sodipodi:docname` is `M1730-Scale.svg`, suggesting this is the "final" named file.
|
- **`E440-Scale_text.svg`** — Text-overlay version: tick mark lines plus live `<text>` elements for numeric/unit/corner labels, font embedded as base64.
|
||||||
|
|
||||||
## Key Design Parameters
|
## Key Design Parameters
|
||||||
|
|
||||||
- Stroke colors: `#1a1a1a` (dark near-black) for all scale lines and text; fill `#f9f9f9` for the background panel, `#ffffff` for tick mark strokes.
|
- Stroke colors: `#1a1a1a` (dark near-black) for tick marks, numeric/unit/corner text; fill `#f9f9f9` for the case body; `#000000` for the rim arc stroke; `#b3b3b3` for the pivot guide circle.
|
||||||
- Major tick stroke-width: `0.555`; border stroke-width: `0.184`.
|
- Fixed case geometry (identical across every generated scale — only tick/label/text content varies):
|
||||||
- Scale bar (the colored strip below tick marks): `y` range 107.547–113.746 mm absolute, `x` range 58.444–183.644.
|
- Pivot point (local, pre-translate frame): `(107.42845, 162.62819)`
|
||||||
- Zero tick at absolute x=60.844; full-scale tick at x=180.251.
|
- Rim / inner-tick radius: `43.842751` mm
|
||||||
|
- Angular sweep: `±45.667193°` from vertical, clockwise-positive (low value on the left)
|
||||||
|
- Tick radial lengths: major `4.7839203` mm, medium `3.1215858` mm, small `1.8121802` mm
|
||||||
|
- Tick stroke widths: major `0.79658329`, medium `0.37985462`, small `0.27478597`
|
||||||
|
- Label radius: `49.862` mm
|
||||||
|
- Tick tiers: major ticks at each labeled interval boundary; a medium tick appears only when the minor-tick count per interval is odd, at the exact midpoint subdivision; all other subdivisions render as small ticks.
|
||||||
|
- Numeric labels rotate to follow the arc (radial orientation), matching their tick's angle.
|
||||||
|
|
||||||
## Web Generator (`web/`)
|
## Web Generator (`web/`)
|
||||||
|
|
||||||
@@ -32,23 +38,23 @@ source .venv/bin/activate
|
|||||||
cd web && python app.py # runs on http://localhost:5000
|
cd web && python app.py # runs on http://localhost:5000
|
||||||
```
|
```
|
||||||
|
|
||||||
`app.py` has one route (`GET /`) serving the form and one (`POST /generate`) that returns SVG. All SVG geometry is computed in `generate_svg()` using the same coordinate constants as the hand-drawn files. The form exposes: unit label, min/max values, major tick intervals, minor ticks per interval, number of numeric labels, and range label.
|
`app.py` has one route (`GET /`) serving the form and one (`POST /generate`) that returns SVG. All SVG geometry is computed in `generate_svg()` using the same coordinate constants as the hand-drawn files: ticks and labels are positioned "as if angle=0" (straight up from the pivot) and given an SVG `rotate(angle, PIVOT_X, PIVOT_Y)` transform. The form exposes: unit label, min/max values, scale mapping, major tick intervals, minor ticks per interval, number of numeric labels, custom labels, label size, font, output mode, and left/right corner labels (up to 2 lines each).
|
||||||
|
|
||||||
The ГОСТ тип А font is loaded at startup from `/usr/local/share/fonts/г/ГОСТ_тип_А.ttf` and embedded as base64 in every generated SVG so output files are self-contained.
|
Fonts are loaded at startup from every `.ttf` in `fonts/` and embedded as base64 in every generated SVG (text output mode) so output files are self-contained. The default font is `alte-din-1451-mittelschrift.regular`.
|
||||||
|
|
||||||
## Container & Kubernetes
|
## Container & Kubernetes
|
||||||
|
|
||||||
```
|
```
|
||||||
docker build -t m1730-scale:latest .
|
docker build -t e440-scale:latest .
|
||||||
```
|
```
|
||||||
|
|
||||||
`fonts/ГОСТ_тип_А.ttf` must exist in the repo root before building (copy from `/usr/local/share/fonts/г/`). The image runs gunicorn on port 5000.
|
`fonts/` must contain the required TTF files before building.
|
||||||
|
|
||||||
```
|
```
|
||||||
kubectl apply -f k8s/
|
kubectl apply -f k8s/
|
||||||
```
|
```
|
||||||
|
|
||||||
`k8s/ingress.yaml` adds a Traefik `IngressRoute` for `works.baumann.gr/M1730-generator` and a `stripPrefix` middleware. Adjust `certResolver` in the file if your Traefik instance uses a different name.
|
`k8s/ingress.yaml` adds a Traefik `IngressRoute` for `works.baumann.gr/E440-generator` and a `stripPrefix` middleware. Adjust `certResolver` in the file if your Traefik instance uses a different name.
|
||||||
|
|
||||||
## Editing SVG files directly
|
## Editing SVG files directly
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
# M1730-Scale
|
# E440-Scale
|
||||||
|
|
||||||
SVG scale artwork and web generator for M1730 analog panel meters. Scales are typeset in **ГОСТ тип А** (GOST type A), the Russian technical drafting standard typeface.
|
SVG scale artwork and web generator for E440-style round-dial analog panel
|
||||||
|
meters. Scales are typeset in **Alte DIN 1451 Mittelschrift**.
|
||||||
|
|
||||||
## Repository layout
|
## Repository layout
|
||||||
|
|
||||||
```
|
```
|
||||||
M1730-Scale_template.svg Inkscape working file (background, tick marks, labels)
|
E440-Scale_template.svg Inkscape working file (case body, tick marks, labels)
|
||||||
M1730-Scale_paths.svg Paths-only export — text converted to outlines
|
E440-Scale_paths.svg Paths-only export — text converted to outlines
|
||||||
M1730-Scale_text.svg Live-text export — embedded font, editable labels
|
E440-Scale_text.svg Live-text export — embedded font, editable labels
|
||||||
fonts/ ГОСТ тип А TTF (required for Docker build)
|
fonts/ TTF fonts (required for Docker build)
|
||||||
web/ Flask web generator
|
web/ Flask web generator
|
||||||
k8s/ Kubernetes manifests
|
k8s/ Kubernetes manifests
|
||||||
Dockerfile Container build
|
Dockerfile Container build
|
||||||
@@ -16,22 +17,33 @@ Dockerfile Container build
|
|||||||
|
|
||||||
## SVG files
|
## SVG files
|
||||||
|
|
||||||
All canvases are **157.18 × 26.68 mm**. The coordinate origin is offset: layer 1 carries `transform="translate(-37.352226,-90.454928)"`, so absolute SVG coordinates begin around x=37, y=90.
|
The canvas is **93.824249 × 57.215687 mm**. The coordinate origin is
|
||||||
|
offset: layer 1 carries `transform="translate(-60.717741,-107.14126)"`, so
|
||||||
|
absolute SVG coordinates begin around x=61, y=107.
|
||||||
|
|
||||||
|
The dial's case geometry — body outline, mounting ears, pivot point
|
||||||
|
(local `107.42845, 162.62819`), rim radius (`43.842751` mm), and angular
|
||||||
|
sweep (`±45.667°` from vertical) — is fixed across every generated scale.
|
||||||
|
Only the tick marks, numeric labels, unit label, and corner text vary.
|
||||||
|
|
||||||
| File | Purpose |
|
| File | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `M1730-Scale_template.svg` | Master Inkscape file. Contains background path, tick marks, unit label, numeric labels, and range label. Edit this one. |
|
| `E440-Scale_template.svg` | Master Inkscape file. Edit this one. |
|
||||||
| `M1730-Scale_paths.svg` | All text converted to outlines. Use for cutting plotters, laser engravers, or any workflow where fonts must not be embedded as live text. |
|
| `E440-Scale_paths.svg` | All text converted to outlines. Use for cutting plotters, laser engravers, or any workflow where fonts must not be embedded as live text. |
|
||||||
| `M1730-Scale_text.svg` | Live `<text>` nodes with the font embedded as base64. Smaller file; requires an SVG viewer that supports embedded fonts. |
|
| `E440-Scale_text.svg` | Live `<text>` nodes with the font embedded as base64. Smaller file; requires an SVG viewer that supports embedded fonts. |
|
||||||
|
|
||||||
Open files in **Inkscape** (developed with v1.4.3). There is no build step — edit the SVG directly or use the web generator.
|
Open files in **Inkscape** (developed with v1.4.3). There is no build step
|
||||||
|
— edit the SVG directly or use the web generator.
|
||||||
|
|
||||||
## Web generator
|
## Web generator
|
||||||
|
|
||||||
A Flask app that generates scale SVGs from a form. Supports two output modes switchable in the UI:
|
A Flask app that generates arc-dial scale SVGs from a form. Supports two
|
||||||
|
output modes switchable in the UI:
|
||||||
|
|
||||||
- **Paths** — glyphs rendered as outlines via fontTools; opens cleanly in Inkscape, Illustrator, and cutting software
|
- **Paths** — glyphs rendered as outlines via fontTools; opens cleanly in
|
||||||
- **Text** — live `<text>` elements with the GOST font embedded as base64
|
Inkscape, Illustrator, and cutting software
|
||||||
|
- **Text** — live `<text>` elements with the selected font embedded as
|
||||||
|
base64
|
||||||
|
|
||||||
### Run locally
|
### Run locally
|
||||||
|
|
||||||
@@ -46,17 +58,15 @@ Fonts are loaded at startup from the `fonts/` directory in the repo root.
|
|||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Unit | Symbol shown in the left panel (e.g. `U`, `mA`, `%`). Supports inline markup — see below |
|
| Unit | Symbol shown centered above the arc (e.g. `uA`, `V`, `%`). Supports inline markup — see below |
|
||||||
| Range label | Text inside the coloured bar on the right (e.g. `5mA`) |
|
| Left label / Right label | Up to 2 lines each, placed in the bottom-left/bottom-right corners of the dial |
|
||||||
| Mapping | **Linear**, **√** (square root), or **Log**. Major ticks are always evenly spaced physically; the mapping controls their values and how minor ticks are placed within each interval. See below. |
|
| Mapping | **Linear**, **√** (square root), **Log**, or **1/x** (reciprocal). Major ticks are always evenly spaced angularly; the mapping controls their values and how minor ticks are placed within each interval. |
|
||||||
| Min / Max | Numeric range of the scale |
|
| Min / Max | Numeric range of the scale |
|
||||||
| Major intervals | Number of major tick intervals |
|
| Major intervals | Number of major tick intervals |
|
||||||
| Minor per interval | Minor ticks between each pair of major ticks |
|
| Minor per interval | Minor ticks between each pair of major ticks. When odd, the exact midpoint subdivision is drawn as a taller "medium" tick, matching the reference dial's 3-tier tick scheme |
|
||||||
| Labels | Number of numeric labels; Labels − 1 should divide evenly into Major intervals |
|
| Labels | Number of numeric labels; Labels − 1 should divide evenly into Major intervals |
|
||||||
| Custom labels | Optional comma-separated labels that override the calculated numbers; their count sets the number of labels. Leave blank to auto-calculate |
|
| Custom labels | Optional comma-separated labels that override the calculated numbers |
|
||||||
| Label size (mm) | Font size of the numeric labels, in millimetres (default `9`) |
|
| Label size (mm) | Font size of the numeric labels, in millimetres (default `5.1126`) |
|
||||||
|
|
||||||
Calculated numbers are rendered in fixed-point notation at 4 significant figures — never scientific (e.g. `10000`, not `1e+04`).
|
|
||||||
|
|
||||||
### Scale mappings
|
### Scale mappings
|
||||||
|
|
||||||
@@ -65,13 +75,12 @@ Calculated numbers are rendered in fixed-point notation at 4 significant figures
|
|||||||
| Linear | Evenly spaced | Uniform | None |
|
| Linear | Evenly spaced | Uniform | None |
|
||||||
| √ | Quadratic (0, 1, 4, 9 … × max) — compresses low values | Crowded toward the low end of each interval | Min ≥ 0 |
|
| √ | Quadratic (0, 1, 4, 9 … × max) — compresses low values | Crowded toward the low end of each interval | Min ≥ 0 |
|
||||||
| Log | Geometric (min × r⁰, r¹, r² …) — each interval spans the same ratio | Crowded toward the high end of each interval | Min and Max > 0 |
|
| Log | Geometric (min × r⁰, r¹, r² …) — each interval spans the same ratio | Crowded toward the high end of each interval | Min and Max > 0 |
|
||||||
| 1/x | Harmonic (values decrease left → right, e.g. ∞, 10, 5, 2, 1) — compresses high values | Uniform (in position space, i.e. proportional to 1/v) | Min and Max > 0; Max may be ∞ |
|
| 1/x | Harmonic (values decrease left → right, e.g. ∞, 10, 5, 2, 1) — compresses high values | Uniform (in angle space, i.e. proportional to 1/v) | Min and Max > 0; Max may be ∞ |
|
||||||
|
|
||||||
The √ mapping is typical for AC RMS current and power meters, where needle deflection is proportional to the square of the measured quantity. The 1/x mapping is used for ohms/resistance scales, where values decrease from left (high resistance / ∞) to right (low resistance).
|
|
||||||
|
|
||||||
### Unit markup
|
### Unit markup
|
||||||
|
|
||||||
The Unit field accepts a lightweight shorthand (no LaTeX engine — everything is drawn as glyph paths in the ГОСТ тип А font and auto-sized to fit the panel):
|
The Unit field accepts a lightweight shorthand (no LaTeX engine — everything
|
||||||
|
is drawn as glyph paths and auto-sized to fit above the arc):
|
||||||
|
|
||||||
| Markup | Result |
|
| Markup | Result |
|
||||||
|---|---|
|
|---|---|
|
||||||
@@ -79,29 +88,33 @@ The Unit field accepts a lightweight shorthand (no LaTeX engine — everything i
|
|||||||
| `H_2O` | subscript (`_{...}` for multiple characters) |
|
| `H_2O` | subscript (`_{...}` for multiple characters) |
|
||||||
| `{1/2}` | stacked fraction with a horizontal rule; a bare `/` stays inline |
|
| `{1/2}` | stacked fraction with a horizontal rule; a bare `/` stays inline |
|
||||||
|
|
||||||
Constructs nest: `{m/s^2}` is a fraction with a superscript in the denominator, `x^{1/2}` a superscripted fraction. A unit containing markup is always emitted as paths, even in text-output mode, since it is a composite of glyphs and a rule.
|
Constructs nest: `{m/s^2}` is a fraction with a superscript in the
|
||||||
|
denominator, `x^{1/2}` a superscripted fraction.
|
||||||
|
|
||||||
## Container
|
## Container
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build -t m1730-scale:latest .
|
docker build -t e440-scale:latest .
|
||||||
docker run -p 5000:5000 m1730-scale:latest
|
docker run -p 5000:5000 e440-scale:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Fonts are loaded from `fonts/` in the repo root; they are bundled into the image at build time.
|
Fonts are loaded from `fonts/` in the repo root; they are bundled into the
|
||||||
|
image at build time.
|
||||||
|
|
||||||
The production image is at `git.baumann.gr/adebaumann/m1730-generator`.
|
The production image is at `git.baumann.gr/adebaumann/e440-generator`.
|
||||||
|
|
||||||
## Kubernetes
|
## Kubernetes
|
||||||
|
|
||||||
Manifests in `k8s/` deploy to the `works` namespace with a Traefik v2 IngressRoute at `works.baumann.gr/M1730-generator`.
|
Manifests in `k8s/` deploy to the `works` namespace with a Traefik v2
|
||||||
|
IngressRoute at `works.baumann.gr/E440-generator`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Managed by ArgoCD — push to git to deploy
|
# Managed by ArgoCD — push to git to deploy
|
||||||
git push
|
git push
|
||||||
```
|
```
|
||||||
|
|
||||||
Resources: namespace, deployment (1 replica, gunicorn), ClusterIP service, Traefik IngressRoute + stripPrefix middleware.
|
Resources: namespace, deployment (1 replica, gunicorn), ClusterIP service,
|
||||||
|
Traefik IngressRoute + stripPrefix middleware.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -1,21 +1,21 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: m1730-generator
|
name: e440-generator
|
||||||
namespace: works
|
namespace: works
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: m1730-generator
|
app: e440-generator
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: m1730-generator
|
app: e440-generator
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: m1730-generator
|
- name: e440-generator
|
||||||
image: git.baumann.gr/adebaumann/m1730-generator:0.87
|
image: git.baumann.gr/adebaumann/e440-generator:1.0
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 5000
|
- containerPort: 5000
|
||||||
|
|||||||
+6
-6
@@ -1,27 +1,27 @@
|
|||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
kind: Middleware
|
kind: Middleware
|
||||||
metadata:
|
metadata:
|
||||||
name: m1730-strip-prefix
|
name: e440-strip-prefix
|
||||||
namespace: works
|
namespace: works
|
||||||
spec:
|
spec:
|
||||||
stripPrefix:
|
stripPrefix:
|
||||||
prefixes:
|
prefixes:
|
||||||
- /M1730-generator
|
- /E440-generator
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: m1730-generator
|
name: e440-generator
|
||||||
namespace: works
|
namespace: works
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- web
|
- web
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`works.baumann.gr`) && PathPrefix(`/M1730-generator`)
|
- match: Host(`works.baumann.gr`) && PathPrefix(`/E440-generator`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: m1730-strip-prefix
|
- name: e440-strip-prefix
|
||||||
services:
|
services:
|
||||||
- name: m1730-generator
|
- name: e440-generator
|
||||||
port: 80
|
port: 80
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: m1730-generator
|
name: e440-generator
|
||||||
namespace: works
|
namespace: works
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: m1730-generator
|
app: e440-generator
|
||||||
ports:
|
ports:
|
||||||
- port: 80
|
- port: 80
|
||||||
targetPort: 5000
|
targetPort: 5000
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ from fontTools.pens.svgPathPen import SVGPathPen
|
|||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
VERSION = "0.87"
|
VERSION = "1.0"
|
||||||
|
|
||||||
_LOGO_PATH = pathlib.Path(__file__).parent / 'static' / 'logo.png'
|
_LOGO_PATH = pathlib.Path(__file__).parent / 'static' / 'logo.png'
|
||||||
_LOGO_B64 = base64.b64encode(_LOGO_PATH.read_bytes()).decode()
|
_LOGO_B64 = base64.b64encode(_LOGO_PATH.read_bytes()).decode()
|
||||||
|
|||||||
Reference in New Issue
Block a user