@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
@@ -6,6 +6,7 @@
6
6
  export declare const messages: (locale?: import("@meltemi/diagrams-i18n").Locale) => {
7
7
  help: {
8
8
  main: (name: string, alias: string) => string;
9
+ skill: string;
9
10
  init: (templates: string) => string;
10
11
  import: string;
11
12
  review: string;
@@ -109,7 +110,6 @@ export declare const messages: (locale?: import("@meltemi/diagrams-i18n").Locale
109
110
  size: (max: number, size: string) => string;
110
111
  backgroundHtml: string;
111
112
  background: (background: string) => string;
112
- mp4Transparent: string;
113
113
  linkFormats: string;
114
114
  link: (link: string) => string;
115
115
  oneFile: (option: string) => string;
@@ -148,14 +148,47 @@ export declare const messages: (locale?: import("@meltemi/diagrams-i18n").Locale
148
148
  };
149
149
  folderSummary: (check: boolean, files: number, folder: string, parts: readonly string[]) => string;
150
150
  };
151
+ skill: {
152
+ wrote: (path: string) => string;
153
+ subcommand: (given: string) => string;
154
+ tooMany: string;
155
+ userWithFolder: string;
156
+ unknownAgent: (agent: string, agents: readonly string[]) => string;
157
+ promptArguments: string;
158
+ exists: (path: string) => string;
159
+ };
151
160
  init: {
152
161
  templates: {
153
- flow: string;
154
- c4: string;
155
- sequence: string;
156
- free: string;
157
- purchase: string;
162
+ flow: {
163
+ title: string;
164
+ description: string;
165
+ };
166
+ c4: {
167
+ title: string;
168
+ description: string;
169
+ };
170
+ sequence: {
171
+ title: string;
172
+ description: string;
173
+ };
174
+ free: {
175
+ title: string;
176
+ description: string;
177
+ };
178
+ kanban: {
179
+ title: string;
180
+ description: string;
181
+ };
182
+ whiteboard: {
183
+ title: string;
184
+ description: string;
185
+ };
186
+ purchase: {
187
+ title: string;
188
+ description: string;
189
+ };
158
190
  };
191
+ contents: (counts: readonly (readonly ["models" | "views" | "diagrams" | "stories", number])[]) => string;
159
192
  exists: (path: string) => string;
160
193
  gitlab: string;
161
194
  oneFolder: string;
@@ -179,6 +212,8 @@ export declare const messages: (locale?: import("@meltemi/diagrams-i18n").Locale
179
212
  packs: string;
180
213
  aliases: string;
181
214
  fonts: string;
215
+ bundledFonts: string;
216
+ fontGroups: Readonly<Record<string, string>>;
182
217
  noWords: string;
183
218
  limit: string;
184
219
  noMatch: (query: string) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/messages/index.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAkB,CAAC;AAExC;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAoBrD;AAED,4FAA4F;AAC5F,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/messages/index.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAkB,CAAC;AAExC;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAoBrD;AAED,4FAA4F;AAC5F,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7C"}
@@ -0,0 +1,48 @@
1
+ /** What the skill command needs from the CLI. */
2
+ export interface SkillContext {
3
+ readonly name: string;
4
+ readonly stdout: (text: string) => void;
5
+ readonly stderr: (text: string) => void;
6
+ readonly cwd: string;
7
+ /** A path as printed: relative to the working folder. */
8
+ readonly display: (path: string) => string;
9
+ /** The person's home folder, where `--user` installs; the system's by default. */
10
+ readonly home?: string;
11
+ }
12
+ /**
13
+ * The agents the skill installs for, with the folder under the project (or the home folder) each
14
+ * reads skills from, as the vendors' pages name them (decision 0063): Claude Code reads
15
+ * `.claude/skills`; Codex, Cursor, GitHub Copilot, Gemini CLI and Devin Desktop (once Windsurf)
16
+ * read the cross-agent `.agents/skills`, which `agents` names for any other agent that reads it.
17
+ */
18
+ export declare const SKILL_AGENTS: {
19
+ readonly claude: ".claude/skills";
20
+ readonly codex: ".agents/skills";
21
+ readonly cursor: ".agents/skills";
22
+ readonly copilot: ".agents/skills";
23
+ readonly gemini: ".agents/skills";
24
+ readonly windsurf: ".agents/skills";
25
+ readonly devin: ".agents/skills";
26
+ readonly agents: ".agents/skills";
27
+ };
28
+ export type SkillAgent = keyof typeof SKILL_AGENTS;
29
+ /** The skill the package ships. */
30
+ export declare const SKILL_NAME = "meltemi-diagrams";
31
+ /**
32
+ * The skill's text as an installed project reads it: the repository's `pnpm mdg <command>` becomes
33
+ * the installed command's `mdg <command>`, the repository's preview server the command's own, and
34
+ * the repository root the project's folder.
35
+ */
36
+ export declare function installedText(text: string): string;
37
+ /**
38
+ * The skill folders the named agents read, each once, in the table's order; `all` names every
39
+ * folder. The first name that is empty or unknown otherwise.
40
+ */
41
+ export declare function skillFolders(names: readonly string[]): {
42
+ folders: string[];
43
+ } | {
44
+ unknown: string;
45
+ };
46
+ /** `meltemi-diagrams skill install` and `meltemi-diagrams skill prompt`. */
47
+ export declare function skillCommand(args: readonly string[], context: SkillContext): number;
48
+ //# sourceMappingURL=skill-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-command.d.ts","sourceRoot":"","sources":["../src/skill-command.ts"],"names":[],"mappings":"AAeA,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,kFAAkF;IAClF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY;;;;;;;;;CASf,CAAC;AACX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,YAAY,CAAC;AAKnD,mCAAmC;AACnC,eAAO,MAAM,UAAU,qBAAqB,CAAC;AAW7C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASlD;AAsBD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB;IAAE,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAQ7C;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CA2DnF"}
@@ -0,0 +1,148 @@
1
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync, } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join, resolve } from "node:path";
4
+ import { parseArgs } from "node:util";
5
+ import { fileURLToPath } from "node:url";
6
+ import { argumentsError, messages } from "./messages/index.js";
7
+ /**
8
+ * The agents the skill installs for, with the folder under the project (or the home folder) each
9
+ * reads skills from, as the vendors' pages name them (decision 0063): Claude Code reads
10
+ * `.claude/skills`; Codex, Cursor, GitHub Copilot, Gemini CLI and Devin Desktop (once Windsurf)
11
+ * read the cross-agent `.agents/skills`, which `agents` names for any other agent that reads it.
12
+ */
13
+ export const SKILL_AGENTS = {
14
+ claude: ".claude/skills",
15
+ codex: ".agents/skills",
16
+ cursor: ".agents/skills",
17
+ copilot: ".agents/skills",
18
+ gemini: ".agents/skills",
19
+ windsurf: ".agents/skills",
20
+ devin: ".agents/skills",
21
+ agents: ".agents/skills",
22
+ };
23
+ /** The agents' names and `all`, as the help and the refusal list them. */
24
+ const AGENT_NAMES = [...Object.keys(SKILL_AGENTS), "all"];
25
+ /** The skill the package ships. */
26
+ export const SKILL_NAME = "meltemi-diagrams";
27
+ /** The folder of the shipped skills: `skills/` beside `src/` and `dist/`. */
28
+ const SKILL_ROOT = fileURLToPath(new URL("../skills/", import.meta.url));
29
+ /** The agent setup prompt the package ships, which `skill prompt` prints and the site serves. */
30
+ const PROMPT = fileURLToPath(new URL("../agent-setup/prompt.md", import.meta.url));
31
+ const EXIT_OK = 0;
32
+ const EXIT_USAGE = 2;
33
+ /**
34
+ * The skill's text as an installed project reads it: the repository's `pnpm mdg <command>` becomes
35
+ * the installed command's `mdg <command>`, the repository's preview server the command's own, and
36
+ * the repository root the project's folder.
37
+ */
38
+ export function installedText(text) {
39
+ return text
40
+ .replaceAll("`pnpm preview` serves the repository at `http://localhost:4173`", "`mdg preview` serves the folder at `http://localhost:4173`")
41
+ .replaceAll("`pnpm preview`", "`mdg preview`")
42
+ .replaceAll("(from the repository root)", "(from the project's folder)")
43
+ .replaceAll("pnpm mdg ", "mdg ");
44
+ }
45
+ /**
46
+ * Copies the shipped skill to `destination`, rewriting its text for an installed project: the
47
+ * Markdown and the commands the examples' comments name.
48
+ */
49
+ function writeSkill(destination) {
50
+ const source = join(SKILL_ROOT, SKILL_NAME);
51
+ mkdirSync(destination, { recursive: true });
52
+ cpSync(source, destination, { recursive: true });
53
+ const rewrite = (dir) => {
54
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
55
+ const path = join(dir, entry.name);
56
+ if (entry.isDirectory())
57
+ rewrite(path);
58
+ else if (entry.name.endsWith(".md") || entry.name.endsWith(".meltemi")) {
59
+ writeFileSync(path, installedText(readFileSync(path, "utf8")));
60
+ }
61
+ }
62
+ };
63
+ rewrite(destination);
64
+ }
65
+ /**
66
+ * The skill folders the named agents read, each once, in the table's order; `all` names every
67
+ * folder. The first name that is empty or unknown otherwise.
68
+ */
69
+ export function skillFolders(names) {
70
+ const wanted = new Set();
71
+ for (const name of names) {
72
+ if (name === "all")
73
+ Object.values(SKILL_AGENTS).forEach((folder) => wanted.add(folder));
74
+ else if (Object.hasOwn(SKILL_AGENTS, name))
75
+ wanted.add(SKILL_AGENTS[name]);
76
+ else
77
+ return { unknown: name };
78
+ }
79
+ return { folders: [...new Set(Object.values(SKILL_AGENTS))].filter((f) => wanted.has(f)) };
80
+ }
81
+ /** `meltemi-diagrams skill install` and `meltemi-diagrams skill prompt`. */
82
+ export function skillCommand(args, context) {
83
+ const fail = (message) => {
84
+ context.stderr(`${context.name} skill: ${message}\n`);
85
+ return EXIT_USAGE;
86
+ };
87
+ let options;
88
+ let positionals;
89
+ try {
90
+ const parsed = parseArgs({
91
+ args: [...args],
92
+ options: {
93
+ agent: { type: "string", multiple: true },
94
+ user: { type: "boolean", default: false },
95
+ force: { type: "boolean", default: false },
96
+ help: { type: "boolean", short: "h", default: false },
97
+ },
98
+ allowPositionals: true,
99
+ strict: true,
100
+ });
101
+ options = parsed.values;
102
+ positionals = parsed.positionals;
103
+ }
104
+ catch (error) {
105
+ return fail(argumentsError(error));
106
+ }
107
+ const t = messages().skill;
108
+ if (options.help) {
109
+ context.stdout(messages().help.skill);
110
+ return EXIT_OK;
111
+ }
112
+ const [subcommand, folder, ...extra] = positionals;
113
+ if (subcommand === "prompt") {
114
+ const given = options.agent !== undefined || options.user || options.force;
115
+ if (folder !== undefined || given)
116
+ return fail(t.promptArguments);
117
+ // Byte for byte: the text is written for the installed command and is never rewritten.
118
+ context.stdout(readFileSync(PROMPT, "utf8"));
119
+ return EXIT_OK;
120
+ }
121
+ if (subcommand !== "install")
122
+ return fail(t.subcommand(subcommand ?? ""));
123
+ if (extra.length > 0)
124
+ return fail(t.tooMany);
125
+ if (options.user && folder !== undefined)
126
+ return fail(t.userWithFolder);
127
+ const names = (options.agent ?? ["all"]).flatMap((value) => value.split(",").map((name) => name.trim()));
128
+ const chosen = skillFolders(names);
129
+ if ("unknown" in chosen)
130
+ return fail(t.unknownAgent(chosen.unknown, AGENT_NAMES));
131
+ const base = options.user ? (context.home ?? homedir()) : resolve(context.cwd, folder ?? ".");
132
+ const destinations = chosen.folders.map((agentFolder) => join(base, agentFolder, SKILL_NAME));
133
+ // Nothing is written when any destination holds a copy, unless asked to replace it.
134
+ if (!options.force) {
135
+ const existing = destinations.find((path) => existsSync(path));
136
+ if (existing)
137
+ return fail(t.exists(context.display(existing)));
138
+ }
139
+ for (const destination of destinations) {
140
+ // Only the skill's own folder is replaced; the folders beside it stay.
141
+ if (options.force)
142
+ rmSync(destination, { recursive: true, force: true });
143
+ writeSkill(destination);
144
+ context.stdout(`${t.wrote(context.display(destination))}\n`);
145
+ }
146
+ return EXIT_OK;
147
+ }
148
+ //# sourceMappingURL=skill-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-command.js","sourceRoot":"","sources":["../src/skill-command.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meltemi/diagrams-cli",
3
- "version": "1.9.0",
3
+ "version": "1.11.1",
4
4
  "description": "Command line interface (meltemi-diagrams, alias mdg) for .meltemi projects.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -27,31 +27,38 @@
27
27
  }
28
28
  },
29
29
  "files": [
30
+ "agent-setup",
30
31
  "dist",
32
+ "skills",
31
33
  "templates"
32
34
  ],
33
35
  "dependencies": {
34
- "@meltemi/diagrams-assets": "1.9.0",
35
- "@meltemi/diagrams-assist": "1.9.0",
36
- "@meltemi/diagrams-capture": "1.9.0",
37
- "@meltemi/diagrams-catalog": "1.9.0",
38
- "@meltemi/diagrams-edit": "1.9.0",
39
- "@meltemi/diagrams-fonts": "1.9.0",
40
- "@meltemi/diagrams-i18n": "1.9.0",
41
- "@meltemi/diagrams-editor": "1.9.0",
42
- "@meltemi/diagrams-import": "1.9.0",
43
- "@meltemi/diagrams-layout": "1.9.0",
44
- "@meltemi/diagrams-layout-elk": "1.9.0",
45
- "@meltemi/diagrams-model": "1.9.0",
46
- "@meltemi/diagrams-language": "1.9.0",
47
- "@meltemi/diagrams-motion": "1.9.0",
48
- "@meltemi/diagrams-project": "1.9.0",
49
- "@meltemi/diagrams-render": "1.9.0",
50
- "@meltemi/diagrams-player": "1.9.0"
36
+ "@meltemi/diagrams-assets": "1.11.1",
37
+ "@meltemi/diagrams-assist": "1.11.1",
38
+ "@meltemi/diagrams-capture": "1.11.1",
39
+ "@meltemi/diagrams-edit": "1.11.1",
40
+ "@meltemi/diagrams-editor": "1.11.1",
41
+ "@meltemi/diagrams-catalog": "1.11.1",
42
+ "@meltemi/diagrams-fonts": "1.11.1",
43
+ "@meltemi/diagrams-i18n": "1.11.1",
44
+ "@meltemi/diagrams-language": "1.11.1",
45
+ "@meltemi/diagrams-layout": "1.11.1",
46
+ "@meltemi/diagrams-import": "1.11.1",
47
+ "@meltemi/diagrams-model": "1.11.1",
48
+ "@meltemi/diagrams-layout-elk": "1.11.1",
49
+ "@meltemi/diagrams-motion": "1.11.1",
50
+ "@meltemi/diagrams-player": "1.11.1",
51
+ "@meltemi/diagrams-render": "1.11.1",
52
+ "@meltemi/diagrams-project": "1.11.1"
51
53
  },
52
54
  "publishConfig": {
53
55
  "access": "public"
54
56
  },
57
+ "meltemiRelease": {
58
+ "repository": "askenaz-dev/meltemi-diagrams",
59
+ "sha": "bdcca7b5a0690c564978e045e6d6d43f84d379ab",
60
+ "tag": "v1.11.1"
61
+ },
55
62
  "scripts": {
56
63
  "build": "tsc -p tsconfig.build.json",
57
64
  "typecheck": "tsc -p tsconfig.json"
@@ -0,0 +1,5 @@
1
+ {
2
+ "skills": [
3
+ "meltemi-diagrams"
4
+ ]
5
+ }
@@ -0,0 +1,232 @@
1
+ ---
2
+ name: meltemi-diagrams
3
+ description: Use when asked to draw, document or convert a system or software architecture, sketch a whiteboard or kanban board, turn a diagram or a screenshot into code, or change a `.meltemi` file. Creates, edits, converts and exports Meltemi diagrams as code (`.meltemi` files) - flow sheets with groups, plain containers, data stores, decisions, notes, tags and boxes in 24 shapes with icons, laid out by ELK, assisted or by hand, with ports, constraints, styles and themes; free compositions (slides with boxes, text, icons, images, layers and links to flow views, and whiteboards with pen strokes, stickies and kanban lists); sequence diagrams (participants, calls, replies, activations, notes, alt/opt/loop/par fragments, scenarios); C4 models with context, container and component views; motion effects and stories that walk through a diagram scene by scene; SVG, PNG, PDF and HTML-player exports with export profiles. Imports Mermaid and PlantUML instead of retyping them, and turns draw.io, HTML or SVG pictures into sheets.
4
+ license: MIT
5
+ metadata:
6
+ version: 1.11.1
7
+ ---
8
+
9
+ # Meltemi Diagrams
10
+
11
+ Diagrams as code for the Meltemi family. A sheet is a `.meltemi` text file; the `meltemi-diagrams` command
12
+ compiles it, validates it and exports SVG. The text is the source of truth: when a `.meltemi` file
13
+ can produce the image, never draw the image by hand and never edit the exported SVG.
14
+
15
+ ## Workflow
16
+
17
+ Before you start: `pnpm mdg --version` says which version of the command line is there; where
18
+ `mdg` is not on the path, `npx @meltemi/diagrams-cli@latest <command>` runs the same command. New
19
+ sheets go under `diagrams/`, or where the project keeps them (the `sources` of its
20
+ `project.json`). Cloud commands run only when the person asks
21
+ ([reference/cloud.md](reference/cloud.md)), and a token (`mdg_…`) is never printed, read, copied
22
+ or committed.
23
+
24
+ 1. Collect the pieces from the request or the source material: elements (boxes, data stores,
25
+ decisions), bands (groups), arrows with their labels, annotations (notes, tags), what is
26
+ proposed versus in use, and the numbered steps of the main path. Choose the profile: `flow` for
27
+ an architecture or process that ELK can arrange, `free` for a slide or a hand-composed picture
28
+ with headings, icons and images, or a whiteboard with pen strokes, stickies and kanban columns
29
+ under `preset board` ([reference/free.md](reference/free.md)), `sequence` for an
30
+ interaction over time between participants ([reference/sequence.md](reference/sequence.md)),
31
+ a `model` with `c4` views for a C4 architecture (context, containers, components) shared by
32
+ several pictures ([reference/c4.md](reference/c4.md)).
33
+ To walk an audience through a diagram, add a `story` after it
34
+ ([reference/stories.md](reference/stories.md)).
35
+ A Mermaid or PlantUML source is imported, never retyped: `pnpm mdg import source.mmd` writes
36
+ `source.meltemi` and reports what it approximated or dropped
37
+ ([reference/converting.md](reference/converting.md)).
38
+ A flow sheet becomes a slide with `pnpm mdg convert sheet.meltemi --to free`. Sequence
39
+ diagrams have no layout modes or positions: skip step 2's layout choice and write the events in
40
+ order.
41
+ 2. Write the file from the template below. Pick the layout mode:
42
+ - `layout auto` (the default) for a new sheet: write no positions; ELK arranges the boxes in the
43
+ `direction` (`LR`, `TB`, ...). Add constraints such as `row a, b` when you need alignment.
44
+ - `layout assisted` to pin some boxes with `place` and let ELK arrange the rest around them.
45
+ - `layout manual` when converting a picture or matching an original exactly: give every element
46
+ a `place`, and a `size` to any box whose width matters.
47
+
48
+ `pnpm mdg layout path/to/sheet.meltemi` writes ELK's positions into the file as `place`
49
+ statements (and turns `auto` into `assisted`) when you want to fine-tune them by hand. Keep the
50
+ labels in the language of the source.
51
+ For icons, find names with `pnpm mdg assets icons <words>` (for example `database`) and set
52
+ them with `style <id> { icon "tabler:database" }`; never invent an icon name. The icon goes
53
+ beside the text by default; `iconPosition right|top|bottom|center` moves it (`center` makes it
54
+ the picture of the box) and `iconSize 32` (8 to 128, or `auto`) sizes it. Architecture icons
55
+ with their label below, as provider diagrams draw them, are `shape icon`:
56
+ `style fn { icon "aws:lambda"; shape icon }` ([reference/free.md](reference/free.md)).
57
+
58
+ 3. Validate: `pnpm mdg validate path/to/sheet.meltemi` (from the repository root). Fix every
59
+ diagnostic, each code explained in [reference/language.md](reference/language.md), until the
60
+ last line reads `Checked 1 file: 0 errors, 0 warnings.`, which is what success prints.
61
+ 4. Export: `pnpm mdg export path/to/sheet.meltemi` writes `sheet.svg` beside the source.
62
+ `--stdout` prints it, `--theme editorial.light` gives a neutral sheet without the brand frame
63
+ and `--theme stage.light` a presentation sheet. `--format png` (with `--scale`, `--size 1920x1080`,
64
+ `--background transparent`) and `--format pdf` use the installed Edge or Chrome; an `export`
65
+ block in the file makes a delivery repeatable with `--profile <id>` or `--profiles`
66
+ ([reference/language.md](reference/language.md)).
67
+ 5. Review the SVG. When the person wants to look at it in a browser, start a server:
68
+ `pnpm preview` serves the repository at `http://localhost:4173` until stopped with Ctrl+C, and
69
+ tell them how to stop it. Check: no overlapping boxes, text fits its box, arrows leave and
70
+ enter the intended sides, labels are readable, a legend exists when colours carry meaning. The
71
+ export prints composition warnings (`layout.overlap`, `layout.label-under-connector`,
72
+ `layout.container-margin`, `layout.connector-overlap`); fix every one.
73
+ 6. Iterate with small edits. Keep ids stable and keep the author's comments. Finish with
74
+ `pnpm mdg format path/to/sheet.meltemi` so the file has the canonical layout.
75
+
76
+ People who prefer a visual tool open the same file in VS Code with the Meltemi Diagrams extension
77
+ (`docs/editor.md`). It shows a canvas beside the code, and each drag, resize or inspector change is
78
+ a small edit of the text. A sheet you write stays editable there, and their changes come back as
79
+ ordinary text edits that you can review.
80
+
81
+ ## Template
82
+
83
+ ```text
84
+ language "0.2"
85
+
86
+ diagram checkout: flow {
87
+ title "Checkout"
88
+ description "One sentence that becomes the <desc> of the SVG."
89
+ layout manual
90
+
91
+ group backend "Backend" {
92
+ api["Order API"] { description "REST · validates input" }
93
+ data orders "Orders DB" { description "PostgreSQL" }
94
+ }
95
+ client["Client app"] { description "web & mobile" }
96
+ tag jwt "JWT"
97
+ note limits "Limits to confirm\n500 rps per tenant"
98
+
99
+ client -> api: "1" as request
100
+ api -> orders: "2" as persist
101
+
102
+ placement {
103
+ place client at (120, 60); size client (160, 56)
104
+ place api at (420, 60); size api (200, 56)
105
+ place orders at (420, 200)
106
+ place jwt at (500, 32)
107
+ place limits at (700, 60)
108
+ label request at 50% offset (0, -16)
109
+ label persist at 50% offset (16, 0)
110
+ }
111
+
112
+ style request, persist { fill "#0B1830"; color "#FFFFFF" }
113
+ }
114
+ ```
115
+
116
+ ## Rules that save iterations
117
+
118
+ - Ids match `[A-Za-z_][A-Za-z0-9_]*` and are unique per diagram across elements and relations.
119
+ Labels carry the human text (`\n` breaks a label into lines); `description` is the smaller text
120
+ under the label, inside the box.
121
+ - Name every relation you need to route, position a label on, or style: `a -> b: "text" as id`.
122
+ - `place` is the centre of the box in pixels; y grows downwards. Groups fit their children unless
123
+ you give them both `place` and `size`.
124
+ - Default sizes: `node` 160 x 56, `decision` 160 x 80, `data` 160 x 64, widened automatically to
125
+ fit their text; a `shape` has its own default size ([reference/free.md](reference/free.md));
126
+ tags and notes size themselves from their text. Use `size` only to make boxes larger or equal;
127
+ if `layout.text-overflow` appears, use the width its hint gives.
128
+ - Shapes go on flow nodes and free boxes: `style api { shape hexagon }`, one of `rounded`,
129
+ `rectangle`, `square`, `ellipse`, `circle`, `diamond`, `cylinder`, `pill`, `triangle`,
130
+ `parallelogram`, `trapezoid`, `pentagon`, `hexagon`, `octagon`, `star`, `cloud`, `document`,
131
+ `callout`, `arrow`, `framed`, `flag`, `person`, `agent` (an AI agent: a robot head over a body
132
+ that holds the text), `icon` (the element drawn as its `icon` alone, 64 x 64, with the label
133
+ outside at `labelPosition`, `bottom` by default). Decisions, data stores, notes, tags and groups
134
+ draw their own shape and refuse it, and so do free texts, icons and images. Text stays inside
135
+ the shape and arrows end on its outline (on the icon's square for `shape icon`). `radius <n>`
136
+ (0 to 64) sets the corner radius of a node, box, decision, note or group, and rounds every
137
+ shape with corners: `rectangle` and `square` (square by default), the polygons' vertices (sharp
138
+ by default: `style h { shape hexagon; radius 10 }`); `radius 0` squares a rounded box,
139
+ `rule group { radius 0 }` squares every group. Circles, ellipses, pills, cylinders, clouds and
140
+ documents ignore it.
141
+ - `rotation <degrees>` (0 to 360, clockwise) turns an element of a flow or free diagram about the
142
+ centre of its box, text and icon included (`style label { rotation 270 }` for text up a side);
143
+ `place` and `size` stay those of the unturned box, and arrows meet the turned outline. Groups,
144
+ sequence diagrams and C4 views refuse it.
145
+ - Nested plain rectangles (a visual editor's containers) are untitled groups: `group g "" { ... }`
146
+ with `style g { fill "#dae8fc"; stroke "#6c8ebf"; radius 0 }`. They draw no title and reserve no
147
+ title band: their interior starts 16 px below the top edge instead of 40 px. A box meant to hold
148
+ others is such a group, never a `node` or `box` with boxes stacked on it: a stack is only drawn
149
+ on top, so the engine separates it and moving the outer box leaves the inner ones behind. A
150
+ group's `size` is the least the engine gives it in `layout auto`, its children centred.
151
+ - Boxes stacked on purpose, each strictly inside the one before, are declared outer first; give
152
+ the outer boxes empty labels (`box outer ""`) or labels away from the inner ones
153
+ (`textAlign left`, a separate `text`). A stack declared inner first, or two boxes of the same
154
+ size at the same place, is `layout.overlap`.
155
+ - A band behind boxes is an untitled group with `place`, `size` and `layer back` (with
156
+ `layers back, main`); boxes and groups on different layers are not checked against each other,
157
+ and the engine arranges boxes over the band, in `layout assisted` and, at the top level, in
158
+ `layout auto`.
159
+ - Arrows need no `route`: facing sides meet at the centre of their overlap, so boxes aligned in a
160
+ column get straight vertical arrows. Add `route id from a.east to b.north via [(x, y)]` only for
161
+ a bend.
162
+ - `place` is ignored in `layout auto` (`layout.placement-ignored`): write `layout manual` or
163
+ `layout assisted` whenever a sheet has positions.
164
+ - A box with named ports (`bus["Bus"] { port in west 30% }`) is entered at that exact point with
165
+ `route r from a.east to bus.in`. `routing orthogonal|polyline|bezier` changes the connector
166
+ shape for the diagram or, in a `style`, for one relation.
167
+ - Text takes a font, size and weight in every profile: `style api { font "Roboto"; fontSize 16;
168
+ fontWeight 600 }`, also in classes and rules (`rule note { font "Caveat" }`); icons, images and
169
+ pens refuse them. Name a bundled family, never a system one: Inter, IBM Plex Sans, Roboto, Open
170
+ Sans, Lato, Montserrat, Poppins, Nunito, Merriweather, Lora, Playfair Display, Cascadia Mono,
171
+ Roboto Mono, Source Code Pro, Patrick Hand, Caveat, Comic Neue (`pnpm mdg assets list` prints
172
+ them). A family nobody has is `layout.unmeasured-font` and measured with estimates.
173
+ - Dashed means proposed: one statement, `style a, b, c { line dashed }`.
174
+ - Numbered steps are relation labels `"1"`, `"2"` with `label r1 at 50% offset (16, 0)` and a
175
+ dark style; the narrative goes in comments next to the relations.
176
+ - A legend is a row of `tag` elements under the sheet with the category colours, plus a dashed
177
+ white tag for "proposed".
178
+ - One diagram per file unless they share a model; the SVG is named after the file.
179
+ - In `free` diagrams, a child's `place` is relative to its group's interior, every group has a
180
+ `place`, and the paint order is the source order within each layer: declare on-top objects last
181
+ or give them `layer front` (with `layers main, front`). A group with `layout column` or
182
+ `layout row` places its children itself, in source order: give them no `place`
183
+ (`layout.place-ignored`). Strokes are `pen` statements with their points, never lines with many
184
+ bends.
185
+
186
+ ## When the result looks wrong
187
+
188
+ | Symptom | Fix |
189
+ | ------------------------------------------------ | -------------------------------------------------------------------------------- |
190
+ | `layout.missing-placement` | add `place <id> at (x, y)`; groups need `place` and `size` together or neither |
191
+ | `layout.placement-ignored` | the sheet has positions but no `layout`: add `layout manual` or `assisted` |
192
+ | `layout.constraint-conflict` | two placed boxes cannot satisfy the constraint; move one or drop the constraint |
193
+ | `layout.overlap` after `auto` or `assisted` | add `distance a, b 40` or pin one box with `place` |
194
+ | `layout.overlap` on boxes stacked on purpose | declaration order: declare the outer box before the boxes inside it |
195
+ | `layout.label-overlap` on a stack | the stacked labels coincide; leave the outer labels empty or move them |
196
+ | `prop.invalid-value` on `shape` | only `node` and `box` take `shape`; a decision is already a diamond |
197
+ | `layout.icon-missing`, a dashed square | `shape icon` needs an `icon` style on the element (or a rule or class) |
198
+ | `layout.label-position-ignored` | `labelPosition` needs `iconPosition center` or `shape icon`; remove it otherwise |
199
+ | a band pushes boxes or warns | make it an untitled group with `place`, `size` and `layer back` |
200
+ | `ref.unknown-relation` on `route`/`label` | the relation is anonymous: add `as <id>` to it |
201
+ | `prop.duplicate` in a style | the property is already set for that target in an earlier `style` |
202
+ | arrow crosses a box | add a waypoint with `route ... via [(x, y)]` or move the box |
203
+ | text wider than its box | add `size <id> (w, h)` or shorten the description |
204
+ | diagonal arrow where a straight one was expected | the two boxes do not overlap on that axis; align them or use a waypoint |
205
+
206
+ ## Reference
207
+
208
+ - [reference/language.md](reference/language.md): grammar, vocabulary, diagnostics and fixes.
209
+ - [reference/layout.md](reference/layout.md): layout modes, constraints, ports, coordinates, sizes,
210
+ anchors, routes, groups, frame.
211
+ - [reference/themes.md](reference/themes.md): built-in themes, theme blocks, the brand frame.
212
+ - [reference/converting.md](reference/converting.md): importing Mermaid and PlantUML, turning any
213
+ other diagram or a screenshot into a sheet, with the checks that prove the conversion.
214
+ - [reference/free.md](reference/free.md): free compositions, the twenty-four shapes, icons in
215
+ boxes and as shapes, interior coordinates, plain containers, stacks and bands, layers, links,
216
+ images, the conversion from flow, and whiteboards: pen strokes, stickies and lists (kanban
217
+ boards).
218
+ - [reference/sequence.md](reference/sequence.md): sequence diagrams, fragments, scenarios,
219
+ spacing, their diagnostics and the mapping from Mermaid and PlantUML.
220
+ - [reference/c4.md](reference/c4.md): models, C4 views, levels and scopes, lifted and combined
221
+ relations, local labels, imported models and their diagnostics.
222
+ - [reference/stories.md](reference/stories.md): stories, scenes, actions, transitions, timing,
223
+ their diagnostics and frame exports.
224
+ - [reference/cloud.md](reference/cloud.md): sharing a project in the optional cloud service, only
225
+ when the person asks, and where its token lives.
226
+ - [examples/platform.meltemi](examples/platform.meltemi): a complete sheet using every construct.
227
+ - [examples/slide.meltemi](examples/slide.meltemi): a flow view and a free slide linked to it.
228
+ - [examples/sequence.meltemi](examples/sequence.meltemi): a payment sequence with a group, an
229
+ alternative, a loop, a note, an async message and two scenarios.
230
+ - [examples/architecture.meltemi](examples/architecture.meltemi): a model with a context, a
231
+ container and a component view.
232
+ - [examples/story.meltemi](examples/story.meltemi): a checkout flow and the story of a purchase.