@svg-gen/tech-svg-generator 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +320 -0
- package/dist/cartoon.d.ts +53 -0
- package/dist/cartoon.d.ts.map +1 -0
- package/dist/cartoon.js +233 -0
- package/dist/characters.d.ts +47 -0
- package/dist/characters.d.ts.map +1 -0
- package/dist/characters.js +422 -0
- package/dist/generator.d.ts +36 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +103 -0
- package/dist/icons.d.ts +10 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +44 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/parser.d.ts +83 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +204 -0
- package/dist/primitives.d.ts +42 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +141 -0
- package/dist/scenes.d.ts +11 -0
- package/dist/scenes.d.ts.map +1 -0
- package/dist/scenes.js +257 -0
- package/dist/themes.d.ts +32 -0
- package/dist/themes.d.ts.map +1 -0
- package/dist/themes.js +106 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/package.json +65 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpG,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,KAAK,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG7E,OAAO,EAAE,oBAAoB,EAAE,KAAK,kBAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AACjH,OAAO,EACL,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,OAAO,EACb,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tech SVG Generator
|
|
3
|
+
* Generate clean, professional SVG illustrations for technical content
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
// Core generation
|
|
8
|
+
export { generateSVG, generateIllustration, detectScene, getAvailableScenes } from './generator.js';
|
|
9
|
+
export { SCENES } from './scenes.js';
|
|
10
|
+
export { THEMES, getTheme } from './themes.js';
|
|
11
|
+
export { ICONS } from './icons.js';
|
|
12
|
+
// Cartoon strip generation
|
|
13
|
+
export { generateCartoonStrip } from './cartoon.js';
|
|
14
|
+
export { renderCharacter, createCharacter, getCharacterPresets, getEmotions, CHARACTER_PRESETS } from './characters.js';
|
|
15
|
+
// YAML/JSON parsing
|
|
16
|
+
export { parseYAML, parseJSON, generateFromYAML, generateFromJSON, generateFromDescription, SCENE_YAML_EXAMPLE, CARTOON_YAML_EXAMPLE, CARTOON_JSON_EXAMPLE, } from './parser.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML/JSON scene description parser
|
|
3
|
+
* Allows defining scenes and cartoon strips in declarative format
|
|
4
|
+
*/
|
|
5
|
+
import type { SceneType } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Scene description format for technical illustrations
|
|
8
|
+
*/
|
|
9
|
+
export interface SceneDescription {
|
|
10
|
+
type: 'scene';
|
|
11
|
+
title: string;
|
|
12
|
+
content?: string;
|
|
13
|
+
scene?: SceneType;
|
|
14
|
+
theme?: string;
|
|
15
|
+
width?: number;
|
|
16
|
+
height?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Cartoon strip description format
|
|
20
|
+
*/
|
|
21
|
+
export interface CartoonDescription {
|
|
22
|
+
type: 'cartoon';
|
|
23
|
+
title?: string;
|
|
24
|
+
theme?: string;
|
|
25
|
+
width?: number;
|
|
26
|
+
height?: number;
|
|
27
|
+
layout?: string;
|
|
28
|
+
characters: Record<string, {
|
|
29
|
+
name: string;
|
|
30
|
+
preset?: string;
|
|
31
|
+
style?: {
|
|
32
|
+
primary?: string;
|
|
33
|
+
secondary?: string;
|
|
34
|
+
skin?: string;
|
|
35
|
+
hairStyle?: 'short' | 'long' | 'bald' | 'spiky' | 'curly';
|
|
36
|
+
accessory?: 'none' | 'glasses' | 'hat' | 'headphones';
|
|
37
|
+
};
|
|
38
|
+
}>;
|
|
39
|
+
panels: Array<{
|
|
40
|
+
characters: string[];
|
|
41
|
+
caption?: string;
|
|
42
|
+
dialogue: Array<{
|
|
43
|
+
character: string;
|
|
44
|
+
text: string;
|
|
45
|
+
emotion?: string;
|
|
46
|
+
type?: 'speech' | 'thought' | 'shout';
|
|
47
|
+
}>;
|
|
48
|
+
}>;
|
|
49
|
+
}
|
|
50
|
+
export type Description = SceneDescription | CartoonDescription;
|
|
51
|
+
/**
|
|
52
|
+
* Parse YAML string into description object
|
|
53
|
+
*/
|
|
54
|
+
export declare function parseYAML(yamlString: string): Description;
|
|
55
|
+
/**
|
|
56
|
+
* Parse JSON string into description object
|
|
57
|
+
*/
|
|
58
|
+
export declare function parseJSON(jsonString: string): Description;
|
|
59
|
+
/**
|
|
60
|
+
* Generate SVG from description object
|
|
61
|
+
*/
|
|
62
|
+
export declare function generateFromDescription(desc: Description): string;
|
|
63
|
+
/**
|
|
64
|
+
* Generate SVG from YAML string
|
|
65
|
+
*/
|
|
66
|
+
export declare function generateFromYAML(yamlString: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Generate SVG from JSON string
|
|
69
|
+
*/
|
|
70
|
+
export declare function generateFromJSON(jsonString: string): string;
|
|
71
|
+
/**
|
|
72
|
+
* Example YAML for a scene
|
|
73
|
+
*/
|
|
74
|
+
export declare const SCENE_YAML_EXAMPLE: string;
|
|
75
|
+
/**
|
|
76
|
+
* Example YAML for a cartoon strip
|
|
77
|
+
*/
|
|
78
|
+
export declare const CARTOON_YAML_EXAMPLE: string;
|
|
79
|
+
/**
|
|
80
|
+
* Example JSON for a cartoon strip
|
|
81
|
+
*/
|
|
82
|
+
export declare const CARTOON_JSON_EXAMPLE: string;
|
|
83
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QACzB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE;YACN,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;YAC1D,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,YAAY,CAAC;SACvD,CAAC;KACH,CAAC,CAAC;IACH,MAAM,EAAE,KAAK,CAAC;QACZ,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,KAAK,CAAC;YACd,SAAS,EAAE,MAAM,CAAC;YAClB,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;SACvC,CAAC,CAAC;KACJ,CAAC,CAAC;CACJ;AAED,MAAM,MAAM,WAAW,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;AAEhE;;GAEG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAIzD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAIzD;AAoDD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAgCjE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,QAQvB,CAAC;AAET;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAoCzB,CAAC;AAET;;GAEG;AACH,eAAO,MAAM,oBAAoB,QA2BtB,CAAC"}
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML/JSON scene description parser
|
|
3
|
+
* Allows defining scenes and cartoon strips in declarative format
|
|
4
|
+
*/
|
|
5
|
+
import yaml from 'js-yaml';
|
|
6
|
+
import { generateSVG } from './generator.js';
|
|
7
|
+
import { generateCartoonStrip } from './cartoon.js';
|
|
8
|
+
/**
|
|
9
|
+
* Parse YAML string into description object
|
|
10
|
+
*/
|
|
11
|
+
export function parseYAML(yamlString) {
|
|
12
|
+
const parsed = yaml.load(yamlString);
|
|
13
|
+
validateDescription(parsed);
|
|
14
|
+
return parsed;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse JSON string into description object
|
|
18
|
+
*/
|
|
19
|
+
export function parseJSON(jsonString) {
|
|
20
|
+
const parsed = JSON.parse(jsonString);
|
|
21
|
+
validateDescription(parsed);
|
|
22
|
+
return parsed;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validate description object
|
|
26
|
+
*/
|
|
27
|
+
function validateDescription(desc) {
|
|
28
|
+
if (!desc || typeof desc !== 'object') {
|
|
29
|
+
throw new Error('Invalid description: must be an object');
|
|
30
|
+
}
|
|
31
|
+
if (!desc.type) {
|
|
32
|
+
throw new Error('Invalid description: missing "type" field (must be "scene" or "cartoon")');
|
|
33
|
+
}
|
|
34
|
+
if (desc.type === 'scene') {
|
|
35
|
+
if (!desc.title || typeof desc.title !== 'string') {
|
|
36
|
+
throw new Error('Invalid scene description: missing or invalid "title" field');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (desc.type === 'cartoon') {
|
|
40
|
+
if (!desc.characters || typeof desc.characters !== 'object') {
|
|
41
|
+
throw new Error('Invalid cartoon description: missing "characters" field');
|
|
42
|
+
}
|
|
43
|
+
if (!Array.isArray(desc.panels) || desc.panels.length === 0) {
|
|
44
|
+
throw new Error('Invalid cartoon description: missing or empty "panels" array');
|
|
45
|
+
}
|
|
46
|
+
// Validate panels
|
|
47
|
+
for (let i = 0; i < desc.panels.length; i++) {
|
|
48
|
+
const panel = desc.panels[i];
|
|
49
|
+
if (!Array.isArray(panel.characters)) {
|
|
50
|
+
throw new Error(`Invalid panel ${i}: missing "characters" array`);
|
|
51
|
+
}
|
|
52
|
+
if (!Array.isArray(panel.dialogue)) {
|
|
53
|
+
throw new Error(`Invalid panel ${i}: missing "dialogue" array`);
|
|
54
|
+
}
|
|
55
|
+
// Validate dialogue
|
|
56
|
+
for (let j = 0; j < panel.dialogue.length; j++) {
|
|
57
|
+
const line = panel.dialogue[j];
|
|
58
|
+
if (!line.character || typeof line.character !== 'string') {
|
|
59
|
+
throw new Error(`Invalid dialogue in panel ${i}, line ${j}: missing "character" field`);
|
|
60
|
+
}
|
|
61
|
+
if (!line.text || typeof line.text !== 'string') {
|
|
62
|
+
throw new Error(`Invalid dialogue in panel ${i}, line ${j}: missing "text" field`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
throw new Error(`Invalid description type: "${desc.type}" (must be "scene" or "cartoon")`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Generate SVG from description object
|
|
73
|
+
*/
|
|
74
|
+
export function generateFromDescription(desc) {
|
|
75
|
+
if (desc.type === 'scene') {
|
|
76
|
+
const options = {
|
|
77
|
+
width: desc.width,
|
|
78
|
+
height: desc.height,
|
|
79
|
+
theme: desc.theme,
|
|
80
|
+
scene: desc.scene,
|
|
81
|
+
};
|
|
82
|
+
return generateSVG(desc.title, desc.content || '', options).svg;
|
|
83
|
+
}
|
|
84
|
+
else if (desc.type === 'cartoon') {
|
|
85
|
+
const config = {
|
|
86
|
+
title: desc.title,
|
|
87
|
+
theme: desc.theme,
|
|
88
|
+
width: desc.width,
|
|
89
|
+
height: desc.height,
|
|
90
|
+
layout: desc.layout,
|
|
91
|
+
characters: desc.characters,
|
|
92
|
+
panels: desc.panels.map(p => ({
|
|
93
|
+
characters: p.characters,
|
|
94
|
+
caption: p.caption,
|
|
95
|
+
dialogue: p.dialogue.map(d => ({
|
|
96
|
+
character: d.character,
|
|
97
|
+
text: d.text,
|
|
98
|
+
emotion: d.emotion,
|
|
99
|
+
type: d.type,
|
|
100
|
+
})),
|
|
101
|
+
})),
|
|
102
|
+
};
|
|
103
|
+
return generateCartoonStrip(config);
|
|
104
|
+
}
|
|
105
|
+
throw new Error('Unknown description type');
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Generate SVG from YAML string
|
|
109
|
+
*/
|
|
110
|
+
export function generateFromYAML(yamlString) {
|
|
111
|
+
const desc = parseYAML(yamlString);
|
|
112
|
+
return generateFromDescription(desc);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Generate SVG from JSON string
|
|
116
|
+
*/
|
|
117
|
+
export function generateFromJSON(jsonString) {
|
|
118
|
+
const desc = parseJSON(jsonString);
|
|
119
|
+
return generateFromDescription(desc);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Example YAML for a scene
|
|
123
|
+
*/
|
|
124
|
+
export const SCENE_YAML_EXAMPLE = `
|
|
125
|
+
type: scene
|
|
126
|
+
title: "Database Migration Strategy"
|
|
127
|
+
content: "PostgreSQL replication and failover"
|
|
128
|
+
scene: database
|
|
129
|
+
theme: github-dark
|
|
130
|
+
width: 700
|
|
131
|
+
height: 420
|
|
132
|
+
`.trim();
|
|
133
|
+
/**
|
|
134
|
+
* Example YAML for a cartoon strip
|
|
135
|
+
*/
|
|
136
|
+
export const CARTOON_YAML_EXAMPLE = `
|
|
137
|
+
type: cartoon
|
|
138
|
+
title: "The Code Review"
|
|
139
|
+
theme: github-dark
|
|
140
|
+
width: 800
|
|
141
|
+
height: 500
|
|
142
|
+
layout: "2x1"
|
|
143
|
+
|
|
144
|
+
characters:
|
|
145
|
+
alice:
|
|
146
|
+
name: Alice
|
|
147
|
+
preset: dev1
|
|
148
|
+
bob:
|
|
149
|
+
name: Bob
|
|
150
|
+
preset: dev2
|
|
151
|
+
|
|
152
|
+
panels:
|
|
153
|
+
- characters: [alice, bob]
|
|
154
|
+
caption: "Monday morning..."
|
|
155
|
+
dialogue:
|
|
156
|
+
- character: alice
|
|
157
|
+
text: "Did you see the PR I submitted?"
|
|
158
|
+
emotion: neutral
|
|
159
|
+
- character: bob
|
|
160
|
+
text: "The one with 2000 lines?"
|
|
161
|
+
emotion: surprised
|
|
162
|
+
|
|
163
|
+
- characters: [alice, bob]
|
|
164
|
+
caption: "Later..."
|
|
165
|
+
dialogue:
|
|
166
|
+
- character: bob
|
|
167
|
+
text: "Maybe we should split this up?"
|
|
168
|
+
emotion: thinking
|
|
169
|
+
- character: alice
|
|
170
|
+
text: "Good idea!"
|
|
171
|
+
emotion: happy
|
|
172
|
+
`.trim();
|
|
173
|
+
/**
|
|
174
|
+
* Example JSON for a cartoon strip
|
|
175
|
+
*/
|
|
176
|
+
export const CARTOON_JSON_EXAMPLE = JSON.stringify({
|
|
177
|
+
type: 'cartoon',
|
|
178
|
+
title: 'Debugging Session',
|
|
179
|
+
theme: 'dracula',
|
|
180
|
+
width: 800,
|
|
181
|
+
height: 400,
|
|
182
|
+
layout: '2x1',
|
|
183
|
+
characters: {
|
|
184
|
+
dev: { name: 'Dev', preset: 'dev1' },
|
|
185
|
+
rubber: { name: 'Rubber Duck', preset: 'robot' }
|
|
186
|
+
},
|
|
187
|
+
panels: [
|
|
188
|
+
{
|
|
189
|
+
characters: ['dev', 'rubber'],
|
|
190
|
+
dialogue: [
|
|
191
|
+
{ character: 'dev', text: "Why isn't this working?!", emotion: 'angry' },
|
|
192
|
+
{ character: 'rubber', text: '...', emotion: 'neutral' }
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
characters: ['dev', 'rubber'],
|
|
197
|
+
dialogue: [
|
|
198
|
+
{ character: 'dev', text: 'Oh wait, I see it now!', emotion: 'excited' },
|
|
199
|
+
{ character: 'rubber', text: '...', emotion: 'neutral' }
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
}, null, 2);
|
|
204
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SVG primitive components for building illustrations
|
|
3
|
+
*/
|
|
4
|
+
import type { ThemeColors } from './themes.js';
|
|
5
|
+
import type { CodeLine, TerminalLine } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Escape HTML entities
|
|
8
|
+
*/
|
|
9
|
+
export declare function escapeHtml(text: string | null | undefined): string;
|
|
10
|
+
/**
|
|
11
|
+
* Render an icon at position
|
|
12
|
+
*/
|
|
13
|
+
export declare function icon(name: string, x: number, y: number, size: number | undefined, color: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Card with icon and label
|
|
16
|
+
*/
|
|
17
|
+
export declare function card(x: number, y: number, w: number, h: number, iconName: string, label: string, colors: ThemeColors, accentColor?: string, sublabel?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Metric display box
|
|
20
|
+
*/
|
|
21
|
+
export declare function metric(x: number, y: number, label: string, value: string, colors: ThemeColors, unit?: string, accentColor?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Status indicator with text
|
|
24
|
+
*/
|
|
25
|
+
export declare function status(x: number, y: number, state: 'ok' | 'warn' | 'error' | 'info', text: string, colors: ThemeColors): string;
|
|
26
|
+
/**
|
|
27
|
+
* Arrow connector between points
|
|
28
|
+
*/
|
|
29
|
+
export declare function arrow(x1: number, y1: number, x2: number, y2: number, color: string, label?: string, dashed?: boolean, colors?: ThemeColors): string;
|
|
30
|
+
/**
|
|
31
|
+
* Code snippet block
|
|
32
|
+
*/
|
|
33
|
+
export declare function codeSnippet(x: number, y: number, w: number, h: number, lines: CodeLine[], colors: ThemeColors, title?: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Terminal block
|
|
36
|
+
*/
|
|
37
|
+
export declare function terminalBlock(x: number, y: number, w: number, h: number, lines: TerminalLine[], colors: ThemeColors): string;
|
|
38
|
+
/**
|
|
39
|
+
* Title bar at bottom with multi-line support
|
|
40
|
+
*/
|
|
41
|
+
export declare function titleBar(text: string, width: number, height: number, colors: ThemeColors): string;
|
|
42
|
+
//# sourceMappingURL=primitives.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../src/primitives.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAIzD;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAKlE;AAED;;GAEG;AACH,wBAAgB,IAAI,CAClB,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,MAAM,YAAK,EACjB,KAAK,EAAE,MAAM,GACZ,MAAM,CAOR;AAED;;GAEG;AACH,wBAAgB,IAAI,CAClB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,EACnB,WAAW,CAAC,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAQR;AAED;;GAEG;AACH,wBAAgB,MAAM,CACpB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,EACnB,IAAI,GAAE,MAAW,EACjB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAOR;AAED;;GAEG;AACH,wBAAgB,MAAM,CACpB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,EACvC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,GAClB,MAAM,CAWR;AAED;;GAEG;AACH,wBAAgB,KAAK,CACnB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAW,EAClB,MAAM,GAAE,OAAe,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,MAAM,CAeR;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,EAAE,WAAW,EACnB,KAAK,GAAE,MAAkB,GACxB,MAAM,CAUR;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,YAAY,EAAE,EACrB,MAAM,EAAE,WAAW,GAClB,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,MAAM,CA4BR"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SVG primitive components for building illustrations
|
|
3
|
+
*/
|
|
4
|
+
import { ICONS } from './icons.js';
|
|
5
|
+
const FONT = "'SF Mono', Menlo, Monaco, 'Courier New', monospace";
|
|
6
|
+
/**
|
|
7
|
+
* Escape HTML entities
|
|
8
|
+
*/
|
|
9
|
+
export function escapeHtml(text) {
|
|
10
|
+
return String(text || '')
|
|
11
|
+
.replace(/&/g, '&')
|
|
12
|
+
.replace(/</g, '<')
|
|
13
|
+
.replace(/>/g, '>');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Render an icon at position
|
|
17
|
+
*/
|
|
18
|
+
export function icon(name, x, y, size = 24, color) {
|
|
19
|
+
const path = ICONS[name];
|
|
20
|
+
if (!path)
|
|
21
|
+
return '';
|
|
22
|
+
const scale = size / 24;
|
|
23
|
+
return `<g transform="translate(${x - size / 2}, ${y - size / 2}) scale(${scale})">
|
|
24
|
+
<path d="${path}" fill="none" stroke="${color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
25
|
+
</g>`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Card with icon and label
|
|
29
|
+
*/
|
|
30
|
+
export function card(x, y, w, h, iconName, label, colors, accentColor, sublabel) {
|
|
31
|
+
const color = accentColor || colors.blue;
|
|
32
|
+
return `
|
|
33
|
+
<rect x="${x}" y="${y}" width="${w}" height="${h}" rx="12" fill="${colors.card}" stroke="${color}" stroke-width="2"/>
|
|
34
|
+
${icon(iconName, x + w / 2, y + h / 2 - (sublabel ? 8 : 0), Math.min(w, h) * 0.35, color)}
|
|
35
|
+
<text x="${x + w / 2}" y="${y + h - 16}" text-anchor="middle" fill="${colors.text}" font-size="12" font-family="${FONT}">${escapeHtml(label.substring(0, 12))}</text>
|
|
36
|
+
${sublabel ? `<text x="${x + w / 2}" y="${y + h - 4}" text-anchor="middle" fill="${colors.muted}" font-size="10" font-family="${FONT}">${escapeHtml(sublabel.substring(0, 15))}</text>` : ''}
|
|
37
|
+
`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Metric display box
|
|
41
|
+
*/
|
|
42
|
+
export function metric(x, y, label, value, colors, unit = '', accentColor) {
|
|
43
|
+
const color = accentColor || colors.blue;
|
|
44
|
+
return `
|
|
45
|
+
<rect x="${x}" y="${y}" width="110" height="60" rx="8" fill="${colors.card}" stroke="${colors.border}"/>
|
|
46
|
+
<text x="${x + 55}" y="${y + 22}" text-anchor="middle" fill="${colors.muted}" font-size="11" font-family="${FONT}">${escapeHtml(label.substring(0, 12))}</text>
|
|
47
|
+
<text x="${x + 55}" y="${y + 46}" text-anchor="middle" fill="${color}" font-size="18" font-family="${FONT}">${escapeHtml(value)}<tspan fill="${colors.muted}" font-size="11">${escapeHtml(unit)}</tspan></text>
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Status indicator with text
|
|
52
|
+
*/
|
|
53
|
+
export function status(x, y, state, text, colors) {
|
|
54
|
+
const stateColors = {
|
|
55
|
+
ok: colors.green,
|
|
56
|
+
warn: colors.orange,
|
|
57
|
+
error: colors.red,
|
|
58
|
+
info: colors.cyan,
|
|
59
|
+
};
|
|
60
|
+
const color = stateColors[state] || colors.muted;
|
|
61
|
+
return `
|
|
62
|
+
<circle cx="${x}" cy="${y}" r="6" fill="${color}"/>
|
|
63
|
+
<text x="${x + 14}" y="${y + 4}" fill="${colors.text}" font-size="11" font-family="${FONT}">${escapeHtml(text.substring(0, 30))}</text>`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Arrow connector between points
|
|
67
|
+
*/
|
|
68
|
+
export function arrow(x1, y1, x2, y2, color, label = '', dashed = false, colors) {
|
|
69
|
+
const mx = (x1 + x2) / 2;
|
|
70
|
+
const my = (y1 + y2) / 2;
|
|
71
|
+
const dash = dashed ? 'stroke-dasharray="6 4"' : '';
|
|
72
|
+
const markerId = `ah${x1}${y1}${x2}${y2}`;
|
|
73
|
+
const cardBg = colors?.card || '#161b22';
|
|
74
|
+
const mutedColor = colors?.muted || '#8b949e';
|
|
75
|
+
return `
|
|
76
|
+
<defs><marker id="${markerId}" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto">
|
|
77
|
+
<path d="M0,0 L8,4 L0,8 Z" fill="${color}"/>
|
|
78
|
+
</marker></defs>
|
|
79
|
+
<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${color}" stroke-width="2" ${dash} marker-end="url(#${markerId})"/>
|
|
80
|
+
${label ? `<rect x="${mx - 25}" y="${my - 10}" width="50" height="20" rx="4" fill="${cardBg}"/>
|
|
81
|
+
<text x="${mx}" y="${my + 4}" text-anchor="middle" fill="${mutedColor}" font-size="10" font-family="${FONT}">${escapeHtml(label.substring(0, 8))}</text>` : ''}`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Code snippet block
|
|
85
|
+
*/
|
|
86
|
+
export function codeSnippet(x, y, w, h, lines, colors, title = 'code.ts') {
|
|
87
|
+
return `
|
|
88
|
+
<rect x="${x}" y="${y}" width="${w}" height="${h}" rx="8" fill="${colors.elevated}" stroke="${colors.border}"/>
|
|
89
|
+
<rect x="${x}" y="${y}" width="${w}" height="28" rx="8" fill="${colors.card}"/>
|
|
90
|
+
<circle cx="${x + 16}" cy="${y + 14}" r="5" fill="${colors.red}" opacity="0.8"/>
|
|
91
|
+
<circle cx="${x + 32}" cy="${y + 14}" r="5" fill="${colors.orange}" opacity="0.8"/>
|
|
92
|
+
<circle cx="${x + 48}" cy="${y + 14}" r="5" fill="${colors.green}" opacity="0.8"/>
|
|
93
|
+
<text x="${x + w / 2}" y="${y + 18}" text-anchor="middle" fill="${colors.dim}" font-size="10" font-family="${FONT}">${escapeHtml(title.substring(0, 20))}</text>
|
|
94
|
+
${lines.slice(0, 5).map((l, i) => `<text x="${x + 12}" y="${y + 48 + i * 18}" fill="${l.hl ? colors.cyan : colors.text}" font-size="11" font-family="${FONT}">${escapeHtml(l.t.substring(0, 32))}</text>`).join('')}
|
|
95
|
+
`;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Terminal block
|
|
99
|
+
*/
|
|
100
|
+
export function terminalBlock(x, y, w, h, lines, colors) {
|
|
101
|
+
return `
|
|
102
|
+
<rect x="${x}" y="${y}" width="${w}" height="${h}" rx="8" fill="${colors.bg}" stroke="${colors.green}"/>
|
|
103
|
+
<text x="${x + 12}" y="${y + 20}" fill="${colors.green}" font-size="11" font-family="${FONT}">$ terminal</text>
|
|
104
|
+
${lines.slice(0, 4).map((l, i) => {
|
|
105
|
+
const col = l.err ? colors.red : l.ok ? colors.green : colors.text;
|
|
106
|
+
return `<text x="${x + 12}" y="${y + 44 + i * 18}" fill="${col}" font-size="11" font-family="${FONT}">${escapeHtml(l.t.substring(0, 35))}</text>`;
|
|
107
|
+
}).join('')}
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Title bar at bottom with multi-line support
|
|
112
|
+
*/
|
|
113
|
+
export function titleBar(text, width, height, colors) {
|
|
114
|
+
const maxCharsPerLine = 60;
|
|
115
|
+
const words = text.split(' ');
|
|
116
|
+
const lines = [];
|
|
117
|
+
let currentLine = '';
|
|
118
|
+
for (const word of words) {
|
|
119
|
+
if ((currentLine + ' ' + word).trim().length <= maxCharsPerLine) {
|
|
120
|
+
currentLine = (currentLine + ' ' + word).trim();
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
if (currentLine)
|
|
124
|
+
lines.push(currentLine);
|
|
125
|
+
currentLine = word;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (currentLine)
|
|
129
|
+
lines.push(currentLine);
|
|
130
|
+
// Limit to 2 lines max
|
|
131
|
+
if (lines.length > 2) {
|
|
132
|
+
lines[1] = lines[1].substring(0, maxCharsPerLine - 3) + '...';
|
|
133
|
+
lines.length = 2;
|
|
134
|
+
}
|
|
135
|
+
const boxHeight = lines.length === 1 ? 36 : 50;
|
|
136
|
+
const startY = height - boxHeight - 8;
|
|
137
|
+
return `
|
|
138
|
+
<rect x="30" y="${startY}" width="${width - 60}" height="${boxHeight}" rx="8" fill="${colors.card}" stroke="${colors.border}"/>
|
|
139
|
+
${lines.map((line, i) => `<text x="${width / 2}" y="${startY + 22 + i * 16}" text-anchor="middle" fill="${colors.text}" font-size="11" font-family="${FONT}">${escapeHtml(line)}</text>`).join('')}`;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=primitives.js.map
|
package/dist/scenes.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scene definitions for different technical contexts
|
|
3
|
+
*/
|
|
4
|
+
import type { ThemeColors } from './themes.js';
|
|
5
|
+
type SceneRenderer = (title: string, colors: ThemeColors, width: number, height: number) => string;
|
|
6
|
+
/**
|
|
7
|
+
* All available scenes
|
|
8
|
+
*/
|
|
9
|
+
export declare const SCENES: Record<string, SceneRenderer>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=scenes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenes.d.ts","sourceRoot":"","sources":["../src/scenes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;AAyPnG;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAehD,CAAC"}
|