@meltemi/diagrams-cli 1.9.0 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/agent-setup/prompt.md +83 -0
  2. package/dist/assets-command.d.ts.map +1 -1
  3. package/dist/assets-command.js +15 -0
  4. package/dist/assets-command.js.map +1 -1
  5. package/dist/cli.d.ts +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +11 -1
  8. package/dist/cli.js.map +1 -1
  9. package/dist/export-command.d.ts.map +1 -1
  10. package/dist/export-command.js +16 -3
  11. package/dist/export-command.js.map +1 -1
  12. package/dist/init-command.d.ts.map +1 -1
  13. package/dist/init-command.js +6 -3
  14. package/dist/init-command.js.map +1 -1
  15. package/dist/messages/en.d.ts +45 -7
  16. package/dist/messages/en.d.ts.map +1 -1
  17. package/dist/messages/en.js +82 -9
  18. package/dist/messages/en.js.map +1 -1
  19. package/dist/messages/es.d.ts.map +1 -1
  20. package/dist/messages/es.js +79 -8
  21. package/dist/messages/es.js.map +1 -1
  22. package/dist/messages/index.d.ts +41 -6
  23. package/dist/messages/index.d.ts.map +1 -1
  24. package/dist/skill-command.d.ts +48 -0
  25. package/dist/skill-command.d.ts.map +1 -0
  26. package/dist/skill-command.js +148 -0
  27. package/dist/skill-command.js.map +1 -0
  28. package/package.json +25 -18
  29. package/skills/.skills-sync.json +5 -0
  30. package/skills/meltemi-diagrams/SKILL.md +232 -0
  31. package/skills/meltemi-diagrams/examples/architecture.meltemi +73 -0
  32. package/skills/meltemi-diagrams/examples/platform.meltemi +139 -0
  33. package/skills/meltemi-diagrams/examples/sequence.meltemi +52 -0
  34. package/skills/meltemi-diagrams/examples/slide.meltemi +60 -0
  35. package/skills/meltemi-diagrams/examples/story.meltemi +53 -0
  36. package/skills/meltemi-diagrams/reference/c4.md +92 -0
  37. package/skills/meltemi-diagrams/reference/cloud.md +19 -0
  38. package/skills/meltemi-diagrams/reference/converting.md +101 -0
  39. package/skills/meltemi-diagrams/reference/free.md +327 -0
  40. package/skills/meltemi-diagrams/reference/language.md +245 -0
  41. package/skills/meltemi-diagrams/reference/layout.md +165 -0
  42. package/skills/meltemi-diagrams/reference/sequence.md +143 -0
  43. package/skills/meltemi-diagrams/reference/stories.md +94 -0
  44. package/skills/meltemi-diagrams/reference/themes.md +148 -0
  45. package/templates/kanban/diagrams/board.meltemi +57 -0
  46. package/templates/whiteboard/diagrams/whiteboard.meltemi +59 -0
@@ -0,0 +1,73 @@
1
+ language "0.2"
2
+
3
+ // Shared model and views from the product proposal ("Modelos y vistas"), with a context view and
4
+ // a component view that lift and combine the model's relations.
5
+ model commerce {
6
+ person customer "Cliente" { description "Compra en línea" }
7
+
8
+ system shop "Commerce" {
9
+ description "Tienda en línea"
10
+ container web "Web" { technology "React" }
11
+ container api "API" {
12
+ technology "HTTP"
13
+ component orders "Pedidos" { technology "Kotlin" }
14
+ component payments "Pagos" { technology "Kotlin" }
15
+ }
16
+ datastore db "Pedidos" { technology "PostgreSQL" }
17
+ api.orders -> db: "Guarda" as store
18
+ }
19
+ system bank "Banco" {
20
+ description "Autoriza tarjetas"
21
+ external
22
+ }
23
+
24
+ customer -> shop.web: "Compra" as visit
25
+ shop.web -> shop.api: "HTTPS" as request { technology "JSON/HTTPS" }
26
+ shop.api -> shop.db: "SQL" as persist
27
+ shop.api.payments -> bank: "Autoriza" as authorize
28
+ shop.web -> shop.api.orders: "Pedidos" as orders
29
+ }
30
+
31
+ diagram context: c4 using commerce {
32
+ level context
33
+ layout assisted
34
+ title "Commerce en contexto"
35
+
36
+ placement {
37
+ place customer at (92, 64)
38
+ place shop at (456, 64)
39
+ place bank at (833, 64)
40
+ }
41
+ }
42
+
43
+ diagram containers: c4 using commerce {
44
+ level container
45
+ scope shop
46
+ include customer, shop.web, shop.api, shop.db
47
+ layout assisted
48
+ direction LR
49
+ theme "editorial.light"
50
+ label shop.api "API de pedidos"
51
+
52
+ placement {
53
+ place customer at (92, 93)
54
+ place shop.web at (473, 93)
55
+ place shop.api at (855, 93)
56
+ place shop.db at (1214, 94)
57
+ }
58
+ }
59
+
60
+ diagram components: c4 using commerce {
61
+ level component
62
+ scope shop.api
63
+ layout assisted
64
+ shop.web -> shop.api.orders: "Usa" as uses
65
+
66
+ placement {
67
+ place shop.web at (97, 88)
68
+ place shop.api.orders at (459, 88)
69
+ place shop.api.payments at (459, 200)
70
+ place shop.db at (845, 88)
71
+ place bank at (850, 210)
72
+ }
73
+ }
@@ -0,0 +1,139 @@
1
+ language "0.2"
2
+
3
+ // A complete sheet using every construct of the flow profile: bands, nodes with descriptions,
4
+ // data stores, a decision, notes, tags, named relations with numbered steps, waypoints, shared
5
+ // styles for a palette and for "proposed" pieces, a legend and a file theme with the brand frame.
6
+
7
+ theme acme {
8
+ extends "technical.light"
9
+ accent "#1D4ED8"
10
+ accentEnd "#0891B2"
11
+ brand "Acme · Meltemi Diagrams"
12
+ }
13
+
14
+ diagram paymentsPlatform: flow {
15
+ title "Payments platform"
16
+ description "Target architecture of the payments platform: edge, services, approval and data."
17
+ layout manual
18
+ theme "acme"
19
+
20
+ // ---- Bands --------------------------------------------------------------------------------
21
+ group identity "Identity" {
22
+ node login "Login + PKCE" { description "customers" }
23
+ node obo "Token exchange" { description "on behalf of" }
24
+ note identityLimits "To validate\nrate limits\ntoken lifetimes"
25
+ }
26
+
27
+ group services "Services" {
28
+ node orders "Orders" { description "Go · gRPC" }
29
+ node payments "Payments" { description "Go · gRPC" }
30
+ decision risky "Manual approval?"
31
+ node approvals "Approvals" { description "Temporal workflow" }
32
+ }
33
+
34
+ group data "Data" {
35
+ data documents "Documents" { description "S3" }
36
+ data ledger "Ledger" { description "PostgreSQL" }
37
+ data cache "Cache" { description "Redis · TTL" }
38
+ }
39
+
40
+ // ---- Edge and partners --------------------------------------------------------------------
41
+ node app "Mobile app" { description "signed-in user" }
42
+ node gateway "API Gateway" { description "validates JWT · routes" }
43
+ node partner "Partner API" { description "banks and PSPs" }
44
+
45
+ // ---- Tags: capability that acts at that point ---------------------------------------------
46
+ tag tPkce "PKCE"
47
+ tag tJwt "JWT"
48
+ tag tObo "OBO"
49
+
50
+ // ---- Main path (the numbers are the steps) ------------------------------------------------
51
+ // 1. The user signs in and the app calls the gateway with the user's JWT.
52
+ app -> gateway: "1" as r1
53
+ // 2. The gateway validates the token and routes to Orders.
54
+ gateway -> orders: "2" as r2
55
+ // 3. Orders asks Payments to charge.
56
+ orders -> payments: "3" as r3
57
+ // 4. Payments decides whether a human must approve.
58
+ payments -> risky: "4" as r4
59
+ // 5. Risky payments wait for approval in a durable workflow; the rest settle at once.
60
+ risky -> approvals: "yes" as r5
61
+ risky -> ledger: "no" as r6
62
+ approvals -> ledger as r7
63
+ approvals -> documents as r10
64
+ // Partners are called with a token exchanged on behalf of the user.
65
+ payments -> partner as r8
66
+ payments -> cache as r9
67
+
68
+ // ---- Legend --------------------------------------------------------------------------------
69
+ tag lgIdentity "Identity"
70
+ tag lgServices "Services"
71
+ tag lgData "Data"
72
+ tag lgDashed "Dashed: proposed"
73
+
74
+ placement {
75
+ // Bands
76
+ place identity at (120, 250); size identity (200, 460)
77
+ place services at (560, 340); size services (520, 280)
78
+ place data at (640, 620); size data (600, 160)
79
+
80
+ // Identity
81
+ place login at (120, 98); size login (160, 56)
82
+ place obo at (120, 178); size obo (160, 56)
83
+ place identityLimits at (118, 290); size identityLimits (150, 54)
84
+
85
+ // Edge and partners
86
+ place app at (380, 60); size app (180, 56)
87
+ place gateway at (560, 160); size gateway (420, 50)
88
+ place partner at (980, 160); size partner (160, 56)
89
+
90
+ // Services
91
+ place orders at (440, 300); size orders (160, 56)
92
+ place payments at (660, 300); size payments (160, 56)
93
+ place risky at (660, 410); size risky (180, 80)
94
+ place approvals at (440, 410); size approvals (160, 56)
95
+
96
+ // Data
97
+ place documents at (440, 640)
98
+ place ledger at (620, 640)
99
+ place cache at (840, 640)
100
+
101
+ // Tags on box corners
102
+ place tPkce at (470, 32)
103
+ place tJwt at (770, 135)
104
+ place tObo at (740, 272)
105
+
106
+ // Steps beside the arrows
107
+ label r1 at 50% offset (16, 0)
108
+ label r2 at 50% offset (16, 0)
109
+ label r3 at 50% offset (0, -16)
110
+ label r4 at 50% offset (16, 0)
111
+ label r5 at 50% offset (0, -16)
112
+ label r6 at 50% offset (16, 0)
113
+
114
+ // Bends: one waypoint per corner
115
+ route r7 from approvals.south to ledger.north via [(480, 520), (600, 520)]
116
+ route r8 from payments.east to partner.south via [(980, 300)]
117
+ route r9 from payments.south to cache.north via [(720, 345), (840, 345)]
118
+
119
+ // Legend
120
+ place lgIdentity at (80, 760)
121
+ place lgServices at (180, 760)
122
+ place lgData at (266, 760)
123
+ place lgDashed at (402, 760)
124
+ }
125
+
126
+ // ---- Palette -------------------------------------------------------------------------------
127
+ style identity, lgIdentity { fill "#f6f3fe"; stroke "#6a4fd0"; color "#33247a" }
128
+ style login, obo { fill "#ebe5fd"; stroke "#6a4fd0"; color "#33247a" }
129
+ style identityLimits { color "#33247a" }
130
+ style services, lgServices { fill "#eef6f9"; stroke "#2f7f9c"; color "#144a5e" }
131
+ style data, lgData { fill "#fdf5e6"; stroke "#b9800f"; color "#6b4500" }
132
+ style gateway { fill "#e2f3e5"; stroke "#3d8c50"; color "#1d5a2d" }
133
+ style tPkce, tJwt, tObo { fill "#6a4fd0"; color "#ffffff" }
134
+ style lgDashed { fill "#ffffff"; stroke "#526579"; color "#526579" }
135
+ style r1, r2, r3, r4 { fill "#0B1830"; color "#FFFFFF" }
136
+
137
+ // ---- Proposed or to validate ---------------------------------------------------------------
138
+ style obo, approvals, documents, partner, lgDashed { line dashed }
139
+ }
@@ -0,0 +1,52 @@
1
+ language "0.2"
2
+
3
+ // A payment with an approval branch, a call that returns, a retry loop and two scenarios.
4
+ diagram payment: sequence {
5
+ title "Card payment"
6
+ autonumber
7
+
8
+ actor customer "Customer"
9
+ boundary web "Checkout page"
10
+ group backend "Backend" {
11
+ participant api "Payments API"
12
+ database ledger "Ledger"
13
+ }
14
+ participant bank "Card network"
15
+
16
+ customer -> web: "Pay" as pay
17
+ web -> api: "Create payment" as create
18
+ activate api
19
+ api -> bank: "Authorize" as authorize
20
+
21
+ alt result "Approved" {
22
+ bank --> api: "Approved" as approved
23
+ // The ledger is active for the call, until it returns.
24
+ api -> ledger: "Record" as record {
25
+ return "Recorded" as recorded
26
+ }
27
+ api --> web: "Receipt" as receipt
28
+ } else "Declined" {
29
+ bank --> api: "Declined" as declined
30
+ loop retries "Until the card works" {
31
+ api --> web: "Ask for another card" as again
32
+ web -> api: "New card" as card
33
+ }
34
+ }
35
+
36
+ note over web, api "The page never sees the card number"
37
+ deactivate api
38
+ api -> web: "Payment settled" as settled { kind async }
39
+
40
+ placement {
41
+ space authorize 14
42
+ }
43
+
44
+ scenario approved "Payment approved" {
45
+ choose result "Approved"
46
+ }
47
+
48
+ scenario declined "Declined twice" {
49
+ choose result "Declined"
50
+ repeat retries 2
51
+ }
52
+ }
@@ -0,0 +1,60 @@
1
+ language "0.2"
2
+
3
+ // The source flow: the slide below links each of its boxes to these elements.
4
+ diagram checkout: flow {
5
+ layout manual
6
+
7
+ client["Client app"]
8
+ api["Order API"]
9
+ data orders "Orders DB"
10
+
11
+ client -> api: "HTTPS" as request
12
+ api -> orders as persist
13
+
14
+ placement {
15
+ place client at (120, 60)
16
+ place api at (380, 60)
17
+ place orders at (640, 60)
18
+ }
19
+ }
20
+
21
+ // A free composition: text, shapes, an icon, a group placed by its interior, and two layers.
22
+ diagram slide: free {
23
+ title "Checkout at a glance"
24
+ preset slide
25
+ routing orthogonal
26
+ layers main, front
27
+
28
+ text heading "Checkout at a glance"
29
+ text lead "Every order passes through one API" { class muted }
30
+
31
+ box client "Client app" { link checkout.client }
32
+ group backend "Backend" {
33
+ box api "Order API" { description "REST · validates input"; link checkout.api }
34
+ box orders "Orders DB" { link checkout.orders }
35
+ api -> orders as persist
36
+ }
37
+ icon secure "tabler:lock" { layer front }
38
+ text secureNote "TLS everywhere" { layer front }
39
+
40
+ client -> api: "HTTPS" as request
41
+
42
+ placement {
43
+ place heading at (960, 140)
44
+ place lead at (960, 210)
45
+ place client at (420, 560)
46
+ place backend at (1180, 560)
47
+ size backend (640, 240)
48
+ place api at (140, 92)
49
+ place orders at (460, 92)
50
+ place secure at (420, 420)
51
+ place secureNote at (420, 470)
52
+ }
53
+
54
+ class muted { color muted; fontSize 28; fontWeight 400 }
55
+ style heading { fontSize 56; fontWeight 700; textAlign center }
56
+ style lead { textAlign center }
57
+ style client { shape pill }
58
+ style orders { shape cylinder }
59
+ style secureNote { textAlign center }
60
+ }
@@ -0,0 +1,53 @@
1
+ language "0.2"
2
+
3
+ // A checkout flow and the story that walks through a purchase. Export any instant with
4
+ // pnpm mdg export story.meltemi --story purchase --at 2.4s
5
+ diagram checkout: flow {
6
+ title "Checkout"
7
+ layout manual
8
+
9
+ client["Client app"]
10
+ api["Order API"]
11
+ orders["Orders service"]
12
+ data db "Orders DB"
13
+
14
+ client -> api: "HTTPS" as request
15
+ api -> orders: "Create order" as create
16
+ orders -> db: "Persist" as save
17
+
18
+ placement {
19
+ place client at (120, 80)
20
+ place api at (380, 80)
21
+ place orders at (640, 80)
22
+ place db at (640, 220)
23
+ }
24
+
25
+ animate request { effect flow }
26
+ }
27
+
28
+ story purchase for checkout {
29
+ title "A purchase"
30
+ description "From the client's request to the stored order."
31
+
32
+ scene overview "The pieces" {
33
+ reveal client, api, orders, db over 800ms
34
+ hold 1s
35
+ }
36
+
37
+ scene request "The request" {
38
+ focus client, api
39
+ trace request over 1200ms
40
+ camera api, orders
41
+ trace create over 1200ms
42
+ }
43
+
44
+ scene stored "Stored" {
45
+ focus all
46
+ camera all
47
+ parallel {
48
+ trace save over 1200ms
49
+ highlight db over 1200ms
50
+ }
51
+ hold 2s
52
+ }
53
+ }
@@ -0,0 +1,92 @@
1
+ # Models and C4 views
2
+
3
+ Use a `model` block for the architecture (who uses what, which containers a system has) and C4
4
+ views to draw it at one level each. Declare entities once in the model; views only list them.
5
+
6
+ ## Model
7
+
8
+ ```text
9
+ model commerce {
10
+ person customer "Cliente" { description "Compra en línea" }
11
+ system shop "Commerce" {
12
+ container web "Web" { technology "React" }
13
+ container api "API" {
14
+ technology "Kotlin"
15
+ component orders "Pedidos"
16
+ }
17
+ datastore db "Pedidos" { technology "PostgreSQL" }
18
+ api -> db: "SQL" as persist // inside shop: api is shop.api
19
+ }
20
+ system bank "Banco" { external }
21
+
22
+ customer -> shop.web: "Compra" as visit
23
+ shop.web -> shop.api: "HTTPS" as request { technology "JSON/HTTPS" }
24
+ shop.api.orders -> bank: "Autoriza" as authorize
25
+ }
26
+ ```
27
+
28
+ - Persons and systems at the root; containers and datastores in systems; components in containers
29
+ (`model.invalid-nesting` otherwise).
30
+ - Entities are named by path: `shop.api.orders`. Relations use `->` only and name paths.
31
+ - `external` marks persons and systems outside the organisation (drawn grey and dashed).
32
+
33
+ ## Views
34
+
35
+ ```text
36
+ diagram containers: c4 using commerce {
37
+ level container // context | container | component
38
+ scope shop // a system; a container for component views
39
+ include customer, shop.web, shop.api, shop.db
40
+ label shop.api "API de pedidos" // local text, the model keeps "API"
41
+ direction LR
42
+ layout assisted
43
+ placement { place shop.api at (420, 120) }
44
+ style shop.db { fill accent }
45
+ }
46
+ ```
47
+
48
+ - Without `include`, a view draws its default set: everything at the context level, otherwise
49
+ the scope's children and the entities related to them. `exclude` removes entities.
50
+ - A container view draws the scope's containers and datastores (inside a dashed boundary),
51
+ persons and other systems; a component view the scope's components, the other containers of the
52
+ system, persons and other systems. Anything else is `c4.out-of-level`.
53
+ - Relations come from the model; ends inside hidden entities are lifted to the drawn ancestor
54
+ (at the context level `customer -> shop.web` becomes `customer -> shop`). Two relations to the
55
+ same pair stay two arrows; to draw one, write a combination in the view:
56
+ `customer -> shop: "Usa" as uses`. A combination with no model relation behind it is
57
+ `c4.unsupported-relation`.
58
+ - Placement, styles and routes take paths: `route request from shop.web.east to shop.api.west`.
59
+
60
+ ## Notes in views
61
+
62
+ A view accepts `note <id> "Text" [on <entity path>]` beside its lists: an annotation of the view,
63
+ never of the model and never an entity (`include`, `exclude`, `label` and relations cannot name it).
64
+ `note cache "Cached 5 min" on shop.api` draws a note with a dotted leader to `shop.api`, which the
65
+ view must draw (else `ref.unknown-element`). It takes `class` and `url`, the view's `style`, `class`,
66
+ `rule` and `animate`, and a `place` in the view's `placement`.
67
+
68
+ ## Files
69
+
70
+ Keep the model in `models/` and the views in `diagrams/` of a project, and import the model:
71
+
72
+ ```text
73
+ import commerce from "../models/commerce.meltemi"
74
+ diagram context: c4 using commerce { level context }
75
+ ```
76
+
77
+ Sequence and free objects link to entities with `link commerce.shop.api`; a participant without its
78
+ own label shows the entity's.
79
+
80
+ ## Diagnostics
81
+
82
+ | Code | Fix |
83
+ | ------------------------- | ------------------------------------------------------------------------ |
84
+ | `c4.invalid-level` | add `level context`, `level container` or `level component` |
85
+ | `c4.scope-required` | add `scope <system>` (container view) or `scope <container>` (component) |
86
+ | `c4.invalid-scope` | scope a system or a container; datastores have no components |
87
+ | `c4.out-of-level` | remove the entity from `include`, or change the level |
88
+ | `c4.unsupported-relation` | add the relation to the model, or remove the combination |
89
+ | `ref.unknown-entity` | use the full path from the model's root (`shop.api`, not `api`) |
90
+ | `ref.unknown-model` | declare or import the model named after `using` |
91
+ | `model.invalid-nesting` | move the entity into the right parent |
92
+ | `model.invalid-relation` | relate separate entities, not an entity and its parent |
@@ -0,0 +1,19 @@
1
+ # Sharing in the cloud (only when the person asks)
2
+
3
+ A project can mirror itself in the optional Meltemi cloud service, to open it in the browser, share
4
+ it or publish its catalog as a web page. These commands need a signed-in person and change things
5
+ outside the repository, so run them only when asked, and never add `--force` unasked.
6
+
7
+ - `pnpm mdg login` opens the person's browser to approve the request (`--no-browser` prints the
8
+ address); `logout` revokes the token and `whoami` says who it is for. In CI the token is
9
+ `MELTEMI_TOKEN`. Exit code 3 means "run `login`".
10
+ - `pnpm mdg push <folder> --create` makes the cloud project and records it in `project.json`
11
+ (`cloud`). Later `push <folder>` lists what differs by path and by id and asks. `push --check`
12
+ writes nothing and exits 1 when the cloud differs, so it is safe to run.
13
+ - `pnpm mdg pull [<id>] [folder]` brings the cloud's files into the folder (files that differ are
14
+ kept unless `--force`); `pnpm mdg review <folder> --base cloud` lists what differs by id.
15
+ - `pnpm mdg publish <folder> --slug name` makes the catalog a public web page, so only on request;
16
+ `--unpublish` takes it down. `pnpm mdg projects --json` lists the person's cloud projects.
17
+
18
+ Never print, read or copy a token (`mdg_…`): it lives in `MELTEMI_TOKEN` or in the credentials file
19
+ that `login` keeps, and belongs in no command line, file or commit. `docs/cli.md` has the details.
@@ -0,0 +1,101 @@
1
+ # Converting an existing diagram into a `.meltemi` sheet
2
+
3
+ The goal is a sheet whose export can be put beside the original with only intended differences.
4
+ Work from the source's own geometry whenever it has one.
5
+
6
+ ## Mermaid and PlantUML: import
7
+
8
+ Never retype a Mermaid or PlantUML diagram; import it:
9
+
10
+ ````bash
11
+ pnpm mdg import docs/checkout.mmd # writes docs/checkout.meltemi
12
+ pnpm mdg import design.puml --out sheets/design.meltemi
13
+ pnpm mdg import README.md # every ```mermaid and ```plantuml block
14
+ ````
15
+
16
+ - Mermaid `flowchart`/`graph`, `sequenceDiagram`, `C4Context`/`C4Container`/`C4Component`/
17
+ `C4Dynamic`, `architecture-beta` and `block-beta`; PlantUML component, deployment, use case,
18
+ sequence and C4-PlantUML diagrams, with `!define`, `!procedure`, `!function`, variables,
19
+ conditionals, loops and local `!include` files. Other types are refused.
20
+ - Read every finding: `import.approximated` (kept with another drawing), `import.unsupported-construct`
21
+ (dropped) and `import.syntax` (a line it could not read, kept as a `// Not imported:` comment).
22
+ Exit 1 means something essential is missing: add it by hand from the comment and the source.
23
+ - Flow imports use `layout auto`; adjust them on the canvas or with `layout assisted` and `place`.
24
+ When the source changes, run `pnpm mdg import <source> --merge`: placement, styles, classes,
25
+ animations, scenarios and local labels are kept for everything still in the source.
26
+ - C4 macros become a `model` and a view; check the level, the scope and the `include` list.
27
+ - Shapes are kept: Mermaid hexagons, parallelograms, trapezoids, circles, stadiums, subroutines
28
+ and flags, and PlantUML clouds, hexagons, actors, use cases, interfaces and files become nodes
29
+ (or boxes) with `style <id> { shape … }`; mirrored Mermaid forms are drawn as the nearest shape
30
+ and reported. Mermaid `block:` groups become untitled groups.
31
+ - `docs/import/mermaid.md` and `docs/import/plantuml.md` in the repository list what each construct
32
+ becomes.
33
+
34
+ The rest of this page is for sources that cannot be imported: HTML, SVG, draw.io, screenshots.
35
+
36
+ ## 1. Get the geometry
37
+
38
+ | Source | Where the numbers are |
39
+ | ----------------------- | ------------------------------------------------------------------------------------------- |
40
+ | HTML or SVG sheet | `rect x y width height` and `text x y`; arrows as `line`/`path`; classes tell the category |
41
+ | draw.io / Excalidraw | the XML or JSON holds `x`, `y`, `width`, `height` per shape |
42
+ | D2 and other text tools | no coordinates: list nodes and edges, then design a grid (columns 200 px apart, rows 80 px) |
43
+ | Screenshot or photo | estimate on a 20 px grid; keep relative alignment, not pixel fidelity |
44
+
45
+ Record each box as centre and size: `place id at (x + w/2, y + h/2)` and `size id (w, h)`.
46
+
47
+ In draw.io a shape inside a container has `parent` set to the container and `x`, `y` relative to
48
+ the container's top-left corner. In a free diagram write the container as a group and the child's
49
+ `place` relative to the group's interior: `(x + w/2 - 16, y + h/2 - 16)` for an untitled group,
50
+ `(x + w/2 - 16, y + h/2 - 40)` for a titled one (technical themes). In a flow diagram keep diagram
51
+ coordinates.
52
+
53
+ ## 2. Map the pieces
54
+
55
+ | In the original | In the sheet |
56
+ | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
57
+ | Coloured band or swimlane with a title | `group id "Title" { ... }` with `place` and `size` of the band; colours in `style` |
58
+ | Nested plain rectangles, untitled containers (draw.io) | untitled groups `group id "" { ... }`, `style id { fill "…"; stroke "…"; radius 0 }` |
59
+ | Backdrop behind a row of boxes | an untitled group with `place`, `size` and `layer back` (`layers back, main`) |
60
+ | Rectangles drawn one inside another | boxes declared outer first, outer labels `""`; the stack is not an overlap |
61
+ | Hexagon, ellipse, circle, cloud, document, actor, star, triangle | `style id { shape hexagon }` on a `node` (flow) or `box` (free); see the note below |
62
+ | Square or more rounded corners (`rounded=0`) | `style id { radius 0 }`, or `radius 16`; `rule group { radius 0 }` for all groups |
63
+ | Box with title and subtitle | `node id "Title" { description "subtitle" }` (or `id["Title"]` without subtitle) |
64
+ | Database, cache, bucket, queue of records | `data id "Name" { description "..." }` |
65
+ | Diamond / question | `decision id "Question?"` |
66
+ | Free text, footnotes, limits | `note id "line\nline"` |
67
+ | Small badges or pills on boxes | `tag id "TEXT"` placed on the corner |
68
+ | Dashed outline, "proposed", "to validate" | `style a, b, c { line dashed }` |
69
+ | Numbered step circles on arrows | relation labels `"1"`, `"2"` with `label r1 at 50% offset (16, 0)` and a dark style |
70
+ | Arrow | `a -> b` (named `as id` when it has a label, a route or a style) |
71
+ | Bent arrow | `route id from a.side to b.side via [(x, y)]`, one waypoint per bend |
72
+ | Legend | a row of `tag`s under the sheet with the category colours |
73
+ | Explanatory paragraphs, step list | comments next to the relations; the ones not drawn stay as comments |
74
+
75
+ Some shapes are the nearest picture, not the same one. `shape triangle` points up, while draw.io's
76
+ `triangle` points right unless rotated: draw a right-pointing marker as `shape arrow`, or accept
77
+ the turned triangle. `shape person` is a head over a body, not draw.io's stick-figure actor.
78
+
79
+ Keep the original ids where they exist; otherwise derive camelCase ids from the labels.
80
+
81
+ ## 3. Write the file
82
+
83
+ Order inside the diagram: properties, bands with their children, free-standing elements, tags,
84
+ relations with comments, legend, `placement`, then `style`. Group the placement block by area and
85
+ the style block by palette, with one shared statement for "dashed".
86
+
87
+ ## 4. Prove it
88
+
89
+ 1. `pnpm mdg validate file.meltemi` until no diagnostics remain.
90
+ 2. `pnpm mdg export file.meltemi`, open the SVG beside the original (`pnpm preview`).
91
+ 3. Compare arrow by arrow: in the original the arrows usually join boxes where they overlap, which
92
+ is what the exporter does without routes; only arrows that bend need waypoints.
93
+ 4. Write down the intended differences (cylinders for stores, left-aligned band titles, legend inside
94
+ the sheet, fonts) in a README next to the file.
95
+
96
+ ## Worked example
97
+
98
+ A real architecture sheet (30 boxes, 4 bands, 13 arrows, 8 steps, 7 tags) converts into one
99
+ file where only one arrow carries a waypoint; every other arrow is reproduced by the anchor rules.
100
+ See [examples/platform.meltemi](../examples/platform.meltemi) in this skill for a complete sheet
101
+ of the same shape.