sketchmark 2.0.0 → 2.1.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 (56) hide show
  1. package/README.md +274 -188
  2. package/bin/editor-ui.cjs +2285 -0
  3. package/bin/preview-ui.cjs +74 -0
  4. package/bin/sketchmark.cjs +648 -2008
  5. package/dist/src/animatable.d.ts +21 -0
  6. package/dist/src/animatable.js +439 -0
  7. package/dist/src/builders/index.d.ts +1 -11
  8. package/dist/src/builders/index.js +1 -19
  9. package/dist/src/diagnostics.js +1 -64
  10. package/dist/src/edit.d.ts +27 -0
  11. package/dist/src/edit.js +162 -0
  12. package/dist/src/index.d.ts +4 -13
  13. package/dist/src/index.js +4 -13
  14. package/dist/src/keyframes.d.ts +48 -0
  15. package/dist/src/keyframes.js +182 -0
  16. package/dist/src/motion.d.ts +4 -0
  17. package/dist/src/motion.js +262 -0
  18. package/dist/src/normalize.js +120 -151
  19. package/dist/src/presets/characters.d.ts +15 -0
  20. package/dist/src/presets/characters.js +113 -0
  21. package/dist/src/presets/compose.d.ts +5 -0
  22. package/dist/src/presets/compose.js +80 -0
  23. package/dist/src/presets/effects.d.ts +40 -0
  24. package/dist/src/presets/effects.js +79 -0
  25. package/dist/src/presets/helpers.d.ts +33 -0
  26. package/dist/src/presets/helpers.js +165 -0
  27. package/dist/src/presets/index.d.ts +9 -0
  28. package/dist/src/presets/index.js +48 -0
  29. package/dist/src/presets/motions.d.ts +33 -0
  30. package/dist/src/presets/motions.js +75 -0
  31. package/dist/src/presets/scenes.d.ts +35 -0
  32. package/dist/src/presets/scenes.js +134 -0
  33. package/dist/src/presets/shapes.d.ts +71 -0
  34. package/dist/src/presets/shapes.js +96 -0
  35. package/dist/src/presets/transitions.d.ts +29 -0
  36. package/dist/src/presets/transitions.js +113 -0
  37. package/dist/src/presets/types.d.ts +34 -0
  38. package/dist/src/presets/types.js +2 -0
  39. package/dist/src/render/html.js +1 -4
  40. package/dist/src/render/svg.d.ts +2 -2
  41. package/dist/src/render/svg.js +86 -82
  42. package/dist/src/render/three-html.js +67 -113
  43. package/dist/src/scenes.js +1 -0
  44. package/dist/src/schema.js +218 -280
  45. package/dist/src/shapes/builtins.js +11 -47
  46. package/dist/src/shapes/common.js +12 -11
  47. package/dist/src/shapes/registry.d.ts +0 -1
  48. package/dist/src/shapes/registry.js +0 -4
  49. package/dist/src/shapes/types.d.ts +1 -3
  50. package/dist/src/types.d.ts +57 -288
  51. package/dist/src/utils.d.ts +2 -11
  52. package/dist/src/utils.js +13 -70
  53. package/dist/src/validate.js +321 -275
  54. package/dist/tests/run.js +576 -510
  55. package/package.json +46 -52
  56. package/schema/visual.schema.json +1086 -930
package/README.md CHANGED
@@ -1,188 +1,274 @@
1
- # Sketchmark
2
-
3
- Primitive-first JSON visual language for AI-generated explanations.
4
-
5
- The canonical document format is a predictable scene graph of primitives. Higher-level helpers such as `node()`, `flow()`, `packet()`, and `callout()` are builder-time conveniences only: they expand into primitives before validation and rendering.
6
-
7
- ## Core Principles
8
-
9
- - JSON is the source of truth.
10
- - The canonical document contains primitives only.
11
- - Box primitives use top-left `x`, `y`, `width`, and `height`.
12
- - Circles use `cx`, `cy`, and `radius`.
13
- - Lines and arrows use `from` and `to`.
14
- - Missing geometry is an error, not an auto-layout hint.
15
- - No collision avoidance, auto-routing, auto-resize, or hidden object synthesis.
16
- - All computed values come from explicit builders, references, or `follow`.
17
-
18
- ## Example
19
-
20
- ```json
21
- {
22
- "version": 1,
23
- "canvas": {
24
- "width": 1280,
25
- "height": 720,
26
- "background": "#f8fafc",
27
- "duration": 8,
28
- "fps": 30
29
- },
30
- "elements": [
31
- {
32
- "id": "browser_box",
33
- "type": "rect",
34
- "x": 120,
35
- "y": 160,
36
- "width": 180,
37
- "height": 80,
38
- "radius": 12,
39
- "fill": "#ffffff",
40
- "stroke": "#2563eb"
41
- },
42
- {
43
- "id": "browser_label",
44
- "type": "text",
45
- "text": "Browser",
46
- "x": 210,
47
- "y": 200,
48
- "align": "center",
49
- "valign": "middle",
50
- "fontSize": 18
51
- }
52
- ]
53
- }
54
- ```
55
-
56
- ## Builders
57
-
58
- ```ts
59
- import { scene } from "sketchmark";
60
- import { node, arrow } from "sketchmark/builders";
61
-
62
- const browser = node({
63
- id: "browser",
64
- label: "Browser",
65
- x: 120,
66
- y: 160,
67
- width: 180,
68
- height: 80
69
- });
70
-
71
- const resolver = node({
72
- id: "resolver",
73
- label: "DNS Resolver",
74
- x: 380,
75
- y: 160,
76
- width: 180,
77
- height: 80
78
- });
79
-
80
- export default scene({
81
- canvas: { width: 1280, height: 720, background: "#f8fafc", duration: 8 },
82
- elements: [
83
- ...browser,
84
- ...resolver,
85
- arrow({
86
- id: "query_arrow",
87
- from: "browser_box.right",
88
- to: "resolver_box.left",
89
- stroke: "#2563eb",
90
- strokeWidth: 3
91
- })
92
- ]
93
- });
94
- ```
95
-
96
- ## Exports
97
-
98
- Build first:
99
-
100
- ```bash
101
- npm run build
102
- ```
103
-
104
- Open a browser preview:
105
-
106
- ```bash
107
- node bin/sketchmark.cjs preview examples/dns.visual.json
108
- ```
109
-
110
- The preview opens an inline editor with live render, play/scrub controls, scene/sequence selectors, and a save button for the source JSON.
111
-
112
- Render files:
113
-
114
- ```bash
115
- node bin/sketchmark.cjs render examples/dns.visual.json out.svg
116
- node bin/sketchmark.cjs render examples/dns.visual.json out.html
117
- node bin/sketchmark.cjs render examples/dns.visual.json out.png --time 1.5
118
- node bin/sketchmark.cjs render examples/dns.visual.json transparent.png --transparent
119
- node bin/sketchmark.cjs render examples/dns.visual.json out.pdf
120
- node bin/sketchmark.cjs render examples/dns.visual.json out.mp4 --fps 30 --duration 4
121
- node bin/sketchmark.cjs render examples/dns.visual.json transparent.webm --transparent --fps 30 --duration 4
122
- node bin/sketchmark.cjs lint examples/dns.visual.json
123
- node bin/sketchmark.cjs screenshot-lint examples/dns.visual.json
124
- ```
125
-
126
- SVG and HTML are built in. PNG/JPG/PDF/MP4/WebM use `sharp`; video also requires `ffmpeg`. Use WebM for transparent video; MP4 is intentionally opaque. Structured Three image/video export uses a deterministic isometric SVG preview adapter, while HTML uses the live Three renderer.
127
-
128
- ## Browser Player
129
-
130
- ```ts
131
- import { SketchmarkPlayer, createSketchmarkPlayer } from "sketchmark/player";
132
-
133
- const player = new SketchmarkPlayer(document.getElementById("preview")!, {
134
- document: visualDocument,
135
- autoplay: true,
136
- loop: true
137
- });
138
-
139
- player.seek(2);
140
- player.pause();
141
- player.setDocument(nextVisualDocument);
142
- await player.download("svg", { title: "visual" });
143
- await player.download("png", { title: "visual" });
144
- await player.download("mp4", { title: "visual" });
145
- player.destroy();
146
- ```
147
-
148
- The player is UI-free. It renders the primitive JSON document into the supplied element, and its browser export provider can download SVG, PNG, JPG, HTML, JSON, and MP4. MP4 uses WebCodecs/H.264 when available and falls back to WebM if the browser cannot encode MP4.
149
-
150
- Project and sequence examples:
151
-
152
- ```bash
153
- node bin/sketchmark.cjs preview examples/project.visual.json --sequence main
154
- node bin/sketchmark.cjs render examples/project.visual.json out.mp4 --sequence main
155
- node bin/sketchmark.cjs timeline examples/project.visual.json --sequence main --fps 12
156
- node bin/sketchmark.cjs render examples/deck.visual.json deck.html --deck --scene slide
157
- node bin/sketchmark.cjs render examples/deck.visual.json deck.pptx --deck --scene slide
158
- ```
159
-
160
- Feature catalog:
161
-
162
- The `examples/features/` folder contains 21 primitive-first examples covering the main language surface: primitives, references, groups, animation, keyframes, packet follow, path follow, patch-friendly ids, diagrams, charts, scenes, sequences, deck steps, images, structured 3D, and mixed 2D/3D sequences.
163
-
164
- Structured Three HTML example:
165
-
166
- ```bash
167
- node bin/sketchmark.cjs render examples/three-cube.visual.json cube.html
168
- node bin/sketchmark.cjs render examples/three-cube.visual.json cube.png
169
- node bin/sketchmark.cjs render examples/three-cube.visual.json cube.mp4 --duration 2 --fps 24
170
- ```
171
-
172
- Raw Three escape hatch:
173
-
174
- ```ts
175
- import { renderRawThreeModuleHtml } from "sketchmark";
176
-
177
- const html = renderRawThreeModuleHtml({
178
- width: 1280,
179
- height: 720,
180
- moduleUrl: "./scene.js"
181
- });
182
- ```
183
-
184
- The module must export `createSketchmarkThreeScene({ canvas, width, height, background })`.
185
-
186
- ## AI Reference
187
-
188
- Use [AI.md](./AI.md) as the compact model-facing reference. It teaches only the primitive JSON surface and points to advanced features without making them default.
1
+ # Sketchmark
2
+
3
+ Sketchmark is currently a **pure 2D render kernel**.
4
+
5
+ The canonical JSON contains only renderable atoms:
6
+
7
+ - `path`
8
+ - `text`
9
+ - `image`
10
+ - `point`
11
+ - `group`
12
+
13
+ Everything else, including rectangles, circles, arrows, diagrams, charts, scenes, decks, 3D, and walking cycles, belongs above the kernel and compiles down to this format. Sketchmark ships an official `presets` layer for common reusable authoring helpers.
14
+
15
+ Reference docs:
16
+
17
+ - [Kernel Spec](./KERNEL_SPEC.md)
18
+ - [Animatable Property Matrix](./ANIMATABLE_MATRIX.md)
19
+ - [Presets](./PRESETS.md)
20
+ - [Packs](./PACKS.md)
21
+ - [What Needs Improvement](./WHAT_NEEDS_IMPROVEMENT.md)
22
+
23
+ ## Kernel Document
24
+
25
+ ```json
26
+ {
27
+ "version": 1,
28
+ "canvas": {
29
+ "width": 640,
30
+ "height": 360,
31
+ "background": "#f8fafc",
32
+ "duration": 2,
33
+ "fps": 30
34
+ },
35
+ "elements": [
36
+ {
37
+ "id": "line",
38
+ "type": "path",
39
+ "d": "M 80 240 C 180 80 320 280 520 120",
40
+ "fill": "none",
41
+ "stroke": "#111827",
42
+ "strokeWidth": 5,
43
+ "strokeCap": "round"
44
+ },
45
+ {
46
+ "id": "title",
47
+ "type": "text",
48
+ "text": "Render kernel",
49
+ "x": 320,
50
+ "y": 70,
51
+ "align": "center",
52
+ "valign": "middle",
53
+ "fontSize": 28,
54
+ "weight": 800,
55
+ "fill": "#0f172a"
56
+ }
57
+ ]
58
+ }
59
+ ```
60
+
61
+ Only `version`, `canvas`, and `elements` are canonical top-level fields.
62
+
63
+ ## Timeline
64
+
65
+ Animation is element-local. Tuple keyframes are still valid, but editor-facing tools should prefer object keyframes because curves live on the outgoing segment:
66
+
67
+ ```json
68
+ {
69
+ "id": "label",
70
+ "type": "text",
71
+ "text": "Move",
72
+ "x": 40,
73
+ "y": 80,
74
+ "timeline": {
75
+ "start": 0.5,
76
+ "end": 2,
77
+ "tracks": {
78
+ "position": {
79
+ "keyframes": [
80
+ {
81
+ "time": 0,
82
+ "value": [40, 80],
83
+ "out": {
84
+ "type": "cubicBezier",
85
+ "x1": 0.42,
86
+ "y1": 0,
87
+ "x2": 0.58,
88
+ "y2": 1
89
+ }
90
+ },
91
+ { "time": 1.5, "value": [260, 80] }
92
+ ]
93
+ },
94
+ "opacity": {
95
+ "keyframes": [[0, 0], [0.4, 1]]
96
+ }
97
+ }
98
+ }
99
+ }
100
+ ```
101
+
102
+ Track values may be numbers, strings, `[x,y]` points, same-length number arrays, string arrays, or JSON objects. Known kernel properties are type-checked more strictly than the broad schema shape. `position` maps to `x/y` for `path`, `point`, `text`, `image`, and `group`. Tracks can also define a fallback interpolation graph:
103
+
104
+ ```json
105
+ {
106
+ "keyframes": [[0, [0, 0]], [1, [100, 0]]],
107
+ "curve": {
108
+ "type": "graph",
109
+ "points": [[0, 0], [0.35, 0.08], [0.65, 0.92], [1, 1]]
110
+ }
111
+ }
112
+ ```
113
+
114
+ The graph maps normalized time progress `x` to normalized value progress `y`. Kernel curves can be `graph`, `cubicBezier`, or `hold`. Segment resolution is: previous keyframe `out`, previous keyframe `interpolation`, next keyframe `in`, track `curve`, legacy `ease`, then linear. Named easing strings are still accepted as compatibility shorthands, but helpers/presets should prefer emitting explicit curves. There are no expressions, path followers, pose drivers, scenes, or 3D in this kernel pass.
115
+
116
+ Current known animatable properties include transform/layout (`position`, `x`, `y`, `rotation`, `scale`, `scaleX`, `scaleY`, `origin`, `width`, `height`, `opacity`), path data/drawing/style (`d`, `fill`, `stroke`, `strokeWidth`, caps/joins, `dashArray`, `dashOffset`, `drawStart`, `drawEnd`), text content/layout (`text`, `lines`, `align`, `valign`, `fontStyle`, typography sizing), image `src`/`fit`/`source.*`, clip/mask paths and opacity, filter effects (`effects.*`), whole paint switching, structured gradient internals such as `fill.to` or `fill.stops.0.color`, and pattern internals such as `fill.x`, `fill.width`, or `fill.opacity`.
117
+
118
+ Unknown timeline tracks are invalid in the frozen kernel. Rounded images should be authored above the kernel and compiled to `clip.d`; `cornerRadius` and editor metadata are intentionally not kernel fields.
119
+
120
+ ## Keyframe Authoring
121
+
122
+ For AI or editor-style authoring, use visual snapshots and compile them down to kernel timelines:
123
+
124
+ ```ts
125
+ import { compileKeyframeStates, timelineCurvePreset } from "sketchmark";
126
+
127
+ const animated = compileKeyframeStates(document, [
128
+ {
129
+ time: 0,
130
+ set: {
131
+ card: { position: [80, 160], scale: 0.85, opacity: 0 }
132
+ }
133
+ },
134
+ {
135
+ time: 1,
136
+ set: {
137
+ card: {
138
+ position: {
139
+ value: [220, 120],
140
+ curve: timelineCurvePreset("ease-out")
141
+ },
142
+ scale: 1,
143
+ opacity: 1
144
+ }
145
+ }
146
+ }
147
+ ]);
148
+ ```
149
+
150
+ This is an authoring adapter, not a new JSON schema feature. The compiled output is still only kernel elements with local timelines.
151
+
152
+ ## Preset Layer
153
+
154
+ Presets are reusable authoring helpers that compile to pure kernel output. They are exported separately so the root package can stay kernel-focused:
155
+
156
+ ```js
157
+ const { applyPresetFragments, shapes, motions, effects } = require("sketchmark/presets");
158
+
159
+ const visual = applyPresetFragments(
160
+ {
161
+ version: 1,
162
+ canvas: { width: 960, height: 540, duration: 2, fps: 30 },
163
+ elements: []
164
+ },
165
+ [
166
+ shapes.roundedRect({
167
+ id: "card",
168
+ x: 80,
169
+ y: 80,
170
+ width: 260,
171
+ height: 120,
172
+ radius: 16,
173
+ fill: "#ffffff",
174
+ stroke: "#cbd5e1"
175
+ }),
176
+ motions.riseIn({ id: "card", from: [80, 120], to: [80, 80] }),
177
+ effects.dropShadow({ id: "card", dy: 10, blur: 24, opacity: 0.2 })
178
+ ]
179
+ );
180
+ ```
181
+
182
+ The output `.visual.json` still contains only kernel elements and timelines. Official namespaces include `shapes`, `characters`, `motions`, `effects`, `transitions`, and `scenes`.
183
+
184
+ ## CLI
185
+
186
+ Build first:
187
+
188
+ ```bash
189
+ npm run build
190
+ ```
191
+
192
+ Render:
193
+
194
+ ```bash
195
+ node bin/sketchmark.cjs render examples/basic.visual.json out.svg
196
+ node bin/sketchmark.cjs render examples/timeline.visual.json out.html --time 1
197
+ node bin/sketchmark.cjs render examples/timeline.visual.json out.mp4
198
+ node bin/sketchmark.cjs render examples/timeline.visual.json out.webm --fps 30
199
+ ```
200
+
201
+ Generate the key-pose walking example:
202
+
203
+ ```bash
204
+ node examples/make-keypose-walk.cjs
205
+ node bin/sketchmark.cjs preview examples/keypose-walk.visual.json
206
+ ```
207
+
208
+ Generate the key-pose cyclist example:
209
+
210
+ ```bash
211
+ node examples/make-keypose-cycle.cjs
212
+ node bin/sketchmark.cjs preview examples/keypose-cycle.visual.json
213
+ ```
214
+
215
+ Generate preset-layer examples:
216
+
217
+ ```bash
218
+ node examples/make-presets-demo.cjs
219
+ node examples/make-preset-character-motion.cjs
220
+ node bin/sketchmark.cjs preview examples/presets-demo.visual.json
221
+ node bin/sketchmark.cjs preview examples/preset-character-motion.visual.json
222
+ ```
223
+
224
+ Generate heavier real-world stress scenes:
225
+
226
+ ```bash
227
+ node examples/make-stress-city-traffic.cjs
228
+ node examples/make-stress-ops-dashboard.cjs
229
+ node examples/make-stress-airport-radar.cjs
230
+
231
+ node bin/sketchmark.cjs preview examples/stress-city-traffic.visual.json
232
+ node bin/sketchmark.cjs preview examples/stress-ops-dashboard.visual.json
233
+ node bin/sketchmark.cjs preview examples/stress-airport-radar.visual.json
234
+ ```
235
+
236
+ These are intentionally dense (many elements/keyframes) to pressure test preview responsiveness.
237
+
238
+ Preview animated timelines in the browser:
239
+
240
+ ```bash
241
+ node bin/sketchmark.cjs preview examples/timeline.visual.json
242
+ ```
243
+
244
+ Open the tiny editor:
245
+
246
+ ```bash
247
+ node bin/sketchmark.cjs edit examples/keypose-walk.visual.json
248
+ ```
249
+
250
+ Lint:
251
+
252
+ ```bash
253
+ node bin/sketchmark.cjs lint examples/basic.visual.json
254
+ ```
255
+
256
+ Video export is an adapter, not a kernel feature. It samples the document timeline into SVG frames, rasterizes those frames, and hands them to `ffmpeg`. It requires `sharp` and `ffmpeg` to be available in the local environment.
257
+
258
+ ## Public API
259
+
260
+ ```ts
261
+ import {
262
+ validateVisualDocument,
263
+ compileKeyframeStates,
264
+ timelineCurvePreset,
265
+ resolveVisualFrame,
266
+ renderToSvg,
267
+ renderToHtml,
268
+ lintVisualDocument
269
+ } from "sketchmark";
270
+ ```
271
+
272
+ The root package intentionally exports no builders, player, project loader, deck/sequence helpers, 3D renderer, or preset compiler.
273
+
274
+ The official preset authoring layer is available from `sketchmark/presets`, not the root kernel entrypoint.