nodality 1.2.5 → 1.2.7

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 (278) hide show
  1. package/API.md +8 -4
  2. package/README.md +15 -1
  3. package/bin/install-skill.mjs +160 -0
  4. package/bin/nodality.js +12 -0
  5. package/dist/animator.cjs.js +1 -1
  6. package/dist/animator.cjs.js.LICENSE.txt +1 -1
  7. package/dist/animator.esm.js +1 -1
  8. package/dist/animator.esm.js.LICENSE.txt +1 -1
  9. package/dist/audionew.cjs.js +1 -1
  10. package/dist/audionew.cjs.js.LICENSE.txt +1 -1
  11. package/dist/audionew.esm.js +1 -1
  12. package/dist/audionew.esm.js.LICENSE.txt +1 -1
  13. package/dist/base.cjs.js +1 -1
  14. package/dist/base.cjs.js.LICENSE.txt +1 -1
  15. package/dist/base.esm.js +1 -1
  16. package/dist/base.esm.js.LICENSE.txt +1 -1
  17. package/dist/beta-desktop-bar.cjs.js +1 -1
  18. package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
  19. package/dist/beta-desktop-bar.esm.js +1 -1
  20. package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
  21. package/dist/beta-mobile-bar.cjs.js +1 -1
  22. package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
  23. package/dist/beta-mobile-bar.esm.js +1 -1
  24. package/dist/beta-mobile-bar.esm.js.LICENSE.txt +1 -1
  25. package/dist/bundle.umd.js +1 -1
  26. package/dist/bundle.umd.js.LICENSE.txt +1 -1
  27. package/dist/button.cjs.js +1 -1
  28. package/dist/button.cjs.js.LICENSE.txt +1 -1
  29. package/dist/button.esm.js +1 -1
  30. package/dist/button.esm.js.LICENSE.txt +1 -1
  31. package/dist/card-getter.cjs.js.LICENSE.txt +1 -1
  32. package/dist/card-getter.esm.js.LICENSE.txt +1 -1
  33. package/dist/center.cjs.js +1 -1
  34. package/dist/center.cjs.js.LICENSE.txt +1 -1
  35. package/dist/center.esm.js +1 -1
  36. package/dist/center.esm.js.LICENSE.txt +1 -1
  37. package/dist/checkbox.cjs.js +1 -1
  38. package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
  39. package/dist/checkbox.esm.js +1 -1
  40. package/dist/checkbox.esm.js.LICENSE.txt +1 -1
  41. package/dist/code.cjs.js +1 -1
  42. package/dist/code.cjs.js.LICENSE.txt +1 -1
  43. package/dist/code.esm.js +1 -1
  44. package/dist/code.esm.js.LICENSE.txt +1 -1
  45. package/dist/container.cjs.js +1 -1
  46. package/dist/container.cjs.js.LICENSE.txt +1 -1
  47. package/dist/container.esm.js +1 -1
  48. package/dist/container.esm.js.LICENSE.txt +1 -1
  49. package/dist/data-list.cjs.js.LICENSE.txt +1 -1
  50. package/dist/data-list.esm.js.LICENSE.txt +1 -1
  51. package/dist/designer.cjs.js +1 -1
  52. package/dist/designer.cjs.js.LICENSE.txt +1 -1
  53. package/dist/designer.esm.js +1 -1
  54. package/dist/designer.esm.js.LICENSE.txt +1 -1
  55. package/dist/element-mapper.cjs.js +1 -1
  56. package/dist/element-mapper.cjs.js.LICENSE.txt +1 -1
  57. package/dist/element-mapper.esm.js +1 -1
  58. package/dist/element-mapper.esm.js.LICENSE.txt +1 -1
  59. package/dist/finalresult.esm.js +1 -1
  60. package/dist/finalresult.esm.js.LICENSE.txt +1 -1
  61. package/dist/flex-card.cjs.js +1 -1
  62. package/dist/flex-card.cjs.js.LICENSE.txt +1 -1
  63. package/dist/flex-card.esm.js +1 -1
  64. package/dist/flex-card.esm.js.LICENSE.txt +1 -1
  65. package/dist/flex-grid.cjs.js +1 -1
  66. package/dist/flex-grid.cjs.js.LICENSE.txt +1 -1
  67. package/dist/flex-grid.esm.js +1 -1
  68. package/dist/flex-grid.esm.js.LICENSE.txt +1 -1
  69. package/dist/flex-row.cjs.js +1 -1
  70. package/dist/flex-row.cjs.js.LICENSE.txt +1 -1
  71. package/dist/flex-row.esm.js +1 -1
  72. package/dist/flex-row.esm.js.LICENSE.txt +1 -1
  73. package/dist/floating-input.cjs.js +1 -1
  74. package/dist/floating-input.cjs.js.LICENSE.txt +1 -1
  75. package/dist/floating-input.esm.js +1 -1
  76. package/dist/floating-input.esm.js.LICENSE.txt +1 -1
  77. package/dist/free.cjs.js +1 -1
  78. package/dist/free.cjs.js.LICENSE.txt +1 -1
  79. package/dist/free.esm.js +1 -1
  80. package/dist/free.esm.js.LICENSE.txt +1 -1
  81. package/dist/horizontal-scroller.cjs.js.LICENSE.txt +1 -1
  82. package/dist/horizontal-scroller.esm.js.LICENSE.txt +1 -1
  83. package/dist/image-picker.cjs.js +1 -1
  84. package/dist/image-picker.cjs.js.LICENSE.txt +1 -1
  85. package/dist/image-picker.esm.js +1 -1
  86. package/dist/image-picker.esm.js.LICENSE.txt +1 -1
  87. package/dist/image.cjs.js +1 -1
  88. package/dist/image.cjs.js.LICENSE.txt +1 -1
  89. package/dist/image.esm.js +1 -1
  90. package/dist/image.esm.js.LICENSE.txt +1 -1
  91. package/dist/index.cjs.js +1 -1
  92. package/dist/index.cjs.js.LICENSE.txt +1 -1
  93. package/dist/index.d.ts +1 -1
  94. package/dist/index.esm.js +1 -1
  95. package/dist/index.esm.js.LICENSE.txt +1 -1
  96. package/dist/keyframe-animation.cjs.js.LICENSE.txt +1 -1
  97. package/dist/keyframe-animation.esm.js.LICENSE.txt +1 -1
  98. package/dist/link-getter.cjs.js +1 -1
  99. package/dist/link-getter.cjs.js.LICENSE.txt +1 -1
  100. package/dist/link-getter.esm.js +1 -1
  101. package/dist/link-getter.esm.js.LICENSE.txt +1 -1
  102. package/dist/link.cjs.js +1 -1
  103. package/dist/link.cjs.js.LICENSE.txt +1 -1
  104. package/dist/link.esm.js +1 -1
  105. package/dist/link.esm.js.LICENSE.txt +1 -1
  106. package/dist/meta-adder.cjs.js +1 -1
  107. package/dist/meta-adder.cjs.js.LICENSE.txt +1 -1
  108. package/dist/meta-adder.esm.js +1 -1
  109. package/dist/meta-adder.esm.js.LICENSE.txt +1 -1
  110. package/dist/modal-2025.cjs.js +1 -1
  111. package/dist/modal-2025.cjs.js.LICENSE.txt +1 -1
  112. package/dist/modal-2025.esm.js +1 -1
  113. package/dist/modal-2025.esm.js.LICENSE.txt +1 -1
  114. package/dist/multiswitcher.cjs.js +1 -1
  115. package/dist/multiswitcher.cjs.js.LICENSE.txt +1 -1
  116. package/dist/multiswitcher.esm.js +1 -1
  117. package/dist/multiswitcher.esm.js.LICENSE.txt +1 -1
  118. package/dist/new-nav-bar.cjs.js +1 -1
  119. package/dist/new-nav-bar.cjs.js.LICENSE.txt +1 -1
  120. package/dist/new-nav-bar.esm.js +1 -1
  121. package/dist/new-nav-bar.esm.js.LICENSE.txt +1 -1
  122. package/dist/picker.cjs.js +1 -1
  123. package/dist/picker.cjs.js.LICENSE.txt +1 -1
  124. package/dist/picker.esm.js +1 -1
  125. package/dist/picker.esm.js.LICENSE.txt +1 -1
  126. package/dist/progress.cjs.js +1 -1
  127. package/dist/progress.cjs.js.LICENSE.txt +1 -1
  128. package/dist/progress.esm.js +1 -1
  129. package/dist/progress.esm.js.LICENSE.txt +1 -1
  130. package/dist/radio.cjs.js.LICENSE.txt +1 -1
  131. package/dist/radio.esm.js.LICENSE.txt +1 -1
  132. package/dist/range.cjs.js.LICENSE.txt +1 -1
  133. package/dist/range.esm.js.LICENSE.txt +1 -1
  134. package/dist/scroll-video.cjs.js.LICENSE.txt +1 -1
  135. package/dist/scroll-video.esm.js.LICENSE.txt +1 -1
  136. package/dist/side-bar.cjs.js +1 -1
  137. package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
  138. package/dist/side-bar.esm.js +1 -1
  139. package/dist/side-bar.esm.js.LICENSE.txt +1 -1
  140. package/dist/side-nav-bar.cjs.js +1 -1
  141. package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
  142. package/dist/side-nav-bar.esm.js +1 -1
  143. package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
  144. package/dist/simple-bar.cjs.js +1 -1
  145. package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
  146. package/dist/simple-bar.esm.js +1 -1
  147. package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
  148. package/dist/slider-2025.cjs.js +1 -1
  149. package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
  150. package/dist/slider-2025.esm.js +1 -1
  151. package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
  152. package/dist/spacer.cjs.js +1 -1
  153. package/dist/spacer.cjs.js.LICENSE.txt +1 -1
  154. package/dist/spacer.esm.js +1 -1
  155. package/dist/spacer.esm.js.LICENSE.txt +1 -1
  156. package/dist/stack.cjs.js +1 -1
  157. package/dist/stack.cjs.js.LICENSE.txt +1 -1
  158. package/dist/stack.esm.js +1 -1
  159. package/dist/stack.esm.js.LICENSE.txt +1 -1
  160. package/dist/stacker.cjs.js.LICENSE.txt +1 -1
  161. package/dist/stacker.esm.js.LICENSE.txt +1 -1
  162. package/dist/table.cjs.js +1 -1
  163. package/dist/table.cjs.js.LICENSE.txt +1 -1
  164. package/dist/table.esm.js +1 -1
  165. package/dist/table.esm.js.LICENSE.txt +1 -1
  166. package/dist/text-field.cjs.js +1 -1
  167. package/dist/text-field.cjs.js.LICENSE.txt +1 -1
  168. package/dist/text-field.esm.js +1 -1
  169. package/dist/text-field.esm.js.LICENSE.txt +1 -1
  170. package/dist/text.cjs.js +1 -1
  171. package/dist/text.cjs.js.LICENSE.txt +1 -1
  172. package/dist/text.esm.js +1 -1
  173. package/dist/text.esm.js.LICENSE.txt +1 -1
  174. package/dist/theme.cjs.js.LICENSE.txt +1 -1
  175. package/dist/theme.esm.js.LICENSE.txt +1 -1
  176. package/dist/transform-anim.cjs.js.LICENSE.txt +1 -1
  177. package/dist/transform-anim.esm.js.LICENSE.txt +1 -1
  178. package/dist/ulist.cjs.js +1 -1
  179. package/dist/ulist.cjs.js.LICENSE.txt +1 -1
  180. package/dist/ulist.esm.js +1 -1
  181. package/dist/ulist.esm.js.LICENSE.txt +1 -1
  182. package/dist/video.cjs.js +1 -1
  183. package/dist/video.cjs.js.LICENSE.txt +1 -1
  184. package/dist/video.esm.js +1 -1
  185. package/dist/video.esm.js.LICENSE.txt +1 -1
  186. package/dist/wrap.cjs.js +1 -1
  187. package/dist/wrap.cjs.js.LICENSE.txt +1 -1
  188. package/dist/wrap.esm.js +1 -1
  189. package/dist/wrap.esm.js.LICENSE.txt +1 -1
  190. package/dist/zoom-card.cjs.js +1 -1
  191. package/dist/zoom-card.cjs.js.LICENSE.txt +1 -1
  192. package/dist/zoom-card.esm.js +1 -1
  193. package/dist/zoom-card.esm.js.LICENSE.txt +1 -1
  194. package/layout/animator.js +13 -2
  195. package/layout/audio.js +1 -1
  196. package/layout/audionew.js +1 -1
  197. package/layout/base.js +1 -1
  198. package/layout/beta-desktop-bar.js +1 -1
  199. package/layout/beta-mobile-bar.js +1 -1
  200. package/layout/button.js +1 -1
  201. package/layout/center.js +1 -1
  202. package/layout/checkbox.js +1 -1
  203. package/layout/circle.js +1 -1
  204. package/layout/code.js +1 -1
  205. package/layout/container.js +1 -1
  206. package/layout/dropdown-2025.js +1 -1
  207. package/layout/flex-card.js +1 -1
  208. package/layout/flex-grid.js +1 -1
  209. package/layout/flex-row.js +1 -1
  210. package/layout/form-components/custom.js +1 -1
  211. package/layout/form-components/data-list.js +1 -1
  212. package/layout/form-components/floating-input.js +1 -1
  213. package/layout/form-components/form-all.js +1 -1
  214. package/layout/form-components/form.js +1 -1
  215. package/layout/form-components/image-picker.js +1 -1
  216. package/layout/form-components/picker.js +1 -1
  217. package/layout/form-components/radio.js +1 -1
  218. package/layout/form-components/radiogroup.js +1 -1
  219. package/layout/form-components/range.js +1 -1
  220. package/layout/free.js +1 -1
  221. package/layout/grid-switcher.js +1 -1
  222. package/layout/grid.js +1 -1
  223. package/layout/horizontal-scroller.js +1 -1
  224. package/layout/image.js +1 -1
  225. package/layout/index.js +1 -1
  226. package/layout/link.js +1 -1
  227. package/layout/list.js +1 -1
  228. package/layout/meta-adder.js +1 -1
  229. package/layout/modal-2025.js +1 -1
  230. package/layout/morph.js +1 -1
  231. package/layout/multiswitcher.js +1 -1
  232. package/layout/nav-bar.js +1 -1
  233. package/layout/nav-factor/custom-div.js +1 -1
  234. package/layout/new-nav-bar.js +1 -1
  235. package/layout/polygon.js +1 -1
  236. package/layout/prerender-site.js +1 -1
  237. package/layout/prerender.js +1 -1
  238. package/layout/progress.js +1 -1
  239. package/layout/row.js +1 -1
  240. package/layout/scroll-video.js +1 -1
  241. package/layout/side-bar.js +1 -1
  242. package/layout/side-nav-bar.js +1 -1
  243. package/layout/simple-bar.js +1 -1
  244. package/layout/slider-2025.js +1 -1
  245. package/layout/spacer.js +1 -1
  246. package/layout/stack.js +1 -1
  247. package/layout/svg.js +1 -1
  248. package/layout/switcher.js +1 -1
  249. package/layout/table.js +1 -1
  250. package/layout/text-field.js +1 -1
  251. package/layout/text.js +1 -1
  252. package/layout/ulist.js +1 -1
  253. package/layout/video.js +1 -1
  254. package/layout/wrap.js +1 -1
  255. package/layout/zoom-card.js +1 -1
  256. package/lib/agent-surface.js +1 -1
  257. package/lib/card-getter.js +1 -1
  258. package/lib/codegen.js +1 -1
  259. package/lib/data.js +1 -1
  260. package/lib/designer.js +6 -2
  261. package/lib/element-mapper.js +5 -5
  262. package/lib/keyframe-animation.js +1 -1
  263. package/lib/link-getter.js +1 -1
  264. package/lib/morph-node.js +1 -1
  265. package/lib/raster-inspect.js +1 -1
  266. package/lib/raster-ops.js +1 -1
  267. package/lib/raster-presets.js +1 -1
  268. package/lib/scroll-video.js +1 -1
  269. package/lib/seo.js +1 -1
  270. package/lib/stacker.js +1 -1
  271. package/lib/suggest.js +1 -1
  272. package/lib/theme.js +1 -1
  273. package/lib/transform-anim.js +1 -1
  274. package/lib/transition.js +1 -1
  275. package/lib/validate-nodes.js +107 -2
  276. package/lib/webmcp-adapter.js +1 -1
  277. package/package.json +3 -2
  278. package/skills/nodality/SKILL.md +203 -0
@@ -0,0 +1,203 @@
1
+ ---
2
+ name: nodality
3
+ description: Build or edit a page with the Nodality library – declarative static UI from two arrays (elements + nodes), GPU raster effects, morph navigation graphs, prerendering, and agent surfaces. Use when the user asks to create or change a Nodality page, mentions (E, N), Des(), morph/raster/agent-surface nodes, works with imperative Nodality code (new Text(), new Link(), .render()), or asks to draft a landing page with Nodality.
4
+ ---
5
+
6
+ # Working with Nodality
7
+
8
+ Nodality builds static, content-shaped sites from a pair of plain-data
9
+ arrays. You do not write components, CSS files, or DOM code. You write
10
+ data, and the library compiles it.
11
+
12
+ ```js
13
+ import { Des } from "nodality";
14
+
15
+ const elements = [ // E – what exists
16
+ { id: "hero", type: "h1", text: "Hello" },
17
+ ];
18
+
19
+ const nodes = [ // N – what is done to it
20
+ { op: { name: "gradient", gradient: "linear-gradient(90deg, #1d6fe0, #7fd1ff)" },
21
+ target: ["hero"] },
22
+ { op: "dither", target: ["hero"], levels: 6, size: 2 },
23
+ ];
24
+
25
+ new Des().nodes(nodes).add(elements).set({ mount: "#mount" });
26
+ ```
27
+
28
+ Nothing in `elements` names an effect; nothing in `nodes` names a
29
+ component. The two arrays meet only through `target`, `from`, and `to`,
30
+ each naming an element `id` (bare `"hero"` or selector form `"#hero"`).
31
+ Keep that separation absolute: if you find yourself putting styling in E
32
+ or content in N, you are writing it wrong.
33
+
34
+ ## The workflow – always in this order
35
+
36
+ The `nodality` MCP server is the source of truth for the vocabulary.
37
+ This skill deliberately contains **no op tables and no element-type
38
+ lists**: those come from the live registry via the MCP, so they cannot
39
+ drift. If the MCP is not configured, add it:
40
+
41
+ ```json
42
+ { "mcpServers": { "nodality": { "command": "npx", "args": ["nodality", "mcp"] } } }
43
+ ```
44
+
45
+ 1. **`list_ops` first.** Never guess an op name, a parameter, an easing
46
+ name, a transition preset, or an element type. One call returns all
47
+ of them as data.
48
+ 2. **Author the pair.** E top-down (page structure), then N (what
49
+ happens to it). Small pages fit in one file.
50
+ 3. **`validate_nodes` before showing the user anything.** Pass both
51
+ `nodes` AND `elements` – with elements included, targets are checked
52
+ against real ids and E itself is validated. The report never throws;
53
+ repair from its `did-you-mean` suggestions and re-validate until
54
+ clean.
55
+ 4. **`preview` to render.** It writes a self-contained HTML file through
56
+ the jsdom prerenderer. Know the boundary: the file is prerendered DOM
57
+ and morph scaffolding only and carries no runtime, so raster effects
58
+ and transitions will not run from it. To see them, put the pair in a
59
+ real page with the library loaded (the CDN snippet is enough).
60
+
61
+ Skipping step 3 is the classic failure: a misspelled op renders
62
+ *nothing* rather than erroring, so the page looks plausible and is
63
+ silently missing its effects.
64
+
65
+ ## The four node families
66
+
67
+ Told apart by the shape of `op`:
68
+
69
+ | Family | Shape | Example |
70
+ |---|---|---|
71
+ | Design | `op` is an object, or one of seven shorthand strings | `{ op: { name: "shadow" }, target: ["card"] }` |
72
+ | Raster | `op` is any other string | `{ op: "dither", target: ["hero"], levels: 6 }` |
73
+ | Morph | `op: "morph"` | one transition, or a whole graph via `chain` |
74
+ | Agent surface | `op: "agent-surface"` | exposes the page to AI agents as tools |
75
+
76
+ **The design family has two shapes.** The object form takes its options
77
+ inside `op`. The seven shorthand names – `blast`, `gradient`, `shadow`,
78
+ `filter`, `animation`, `transform`, `span` – expand against a table of
79
+ defaults, so `{ op: "gradient" }` is a whole valid node. Only the
80
+ shorthand accepts `gradient`, `filter`, `color` and `width` as top-level
81
+ keys, because its expansion lifts them into the op it substitutes. Any
82
+ other string is a raster op.
83
+
84
+ Rules that are not obvious from the schema:
85
+
86
+ - **Raster ops compose.** Several raster nodes aimed at the same element
87
+ become ONE shader pass, applied in array order. Order matters; do not
88
+ "fix" a wrong-looking result by duplicating nodes.
89
+ - **A morph `chain` is a list of EDGES, not keyframes.** Edge two is
90
+ reachable *from* the state edge one lands on – a landed view becomes a
91
+ source. Node-level settings (`effect`, `duration`) are defaults each
92
+ edge may override. `chain` wins outright: node-level `from`/`to` are
93
+ ignored beside it. `back: true` unwinds the path the user actually
94
+ took, not a lookup of a reverse edge.
95
+ - **`agent-surface` is opt-in and allow-listed.** No form is exposed
96
+ unless named in `forms`. Do not add it unless the user asks for an
97
+ agent-operable page.
98
+
99
+ A complete navigation graph is one node:
100
+
101
+ ```js
102
+ { op: "morph", effect: "t-vhs", duration: 620, back: true,
103
+ chain: [
104
+ { from: "home", to: { Work: "work", Contact: "contact" } },
105
+ { from: "work", to: { Aurora: "aurora" }, effect: "t-split" },
106
+ { from: "aurora", to: { Contact: "contact" }, effect: "t-bloom" },
107
+ ] }
108
+ ```
109
+
110
+ ## House rules – violations are bugs even when the page looks right
111
+
112
+ - **Never touch the DOM to style or fix a Nodality page.** No
113
+ `el.style.*`, no `createElement` in page code, no post-render DOM
114
+ patching. If the library cannot express something, the fix is a custom
115
+ element/op (extend the library), or the `keySet` option on an element
116
+ (`keySet: { key, value }`) for one custom CSS property. Note the
117
+ spelling: `keySet`, capital S.
118
+ - **Elements take `text`, never `value`.**
119
+ - **Every element that a node targets needs an `id`.** Short and stable
120
+ (`"hero"`, `"topnav"`); ids are the joint between the two arrays and
121
+ appear in generated code.
122
+ - **Know where options live.** Raster-op options sit on the node
123
+ (`levels: 6`); design-node options sit INSIDE the `op` object
124
+ (`op: { name: "gradient", gradient: "linear-gradient(...)" }`).
125
+ Putting a design option at the top level is the single most common
126
+ mistake with this library – the project's own README shipped
127
+ `colors: [...]` there and rendered its headline invisible. Since 1.2.7
128
+ `validate_nodes` reports it and tells you where it belongs, so run the
129
+ validator rather than trusting the shape by eye.
130
+ - **Do not invent options.** An option that no op declares is ignored in
131
+ silence rather than reported. If `list_ops` does not name it, it does
132
+ not exist.
133
+ - **Codegen:** the on-page panel showing the imperative equivalent of
134
+ the pair is on by default; pass `code: false` (and `elements: false`)
135
+ to `.set()` to hide it on a production page. From the CLI,
136
+ `npx nodality compile src/<file>.js` emits the same code as a
137
+ companion file without rendering anything.
138
+
139
+ ## The imperative layer – direct instantiation
140
+
141
+ The component classes behind E are public API, exported from the package
142
+ root. An agent can instantiate them directly instead of writing the
143
+ pair:
144
+
145
+ ```js
146
+ import { Text, Link, FlexRow } from "nodality";
147
+
148
+ new Text("Hello").set({ fluidc: "S3", color: "#f97316" }).render("#mount");
149
+ ```
150
+
151
+ This is exactly the code the codegen panel emits, so the two forms are
152
+ equivalent and interchangeable: `.set()` returns the instance, and
153
+ `.render(selector)` mounts it. Reach for it when adding a few elements
154
+ to an existing page or adapting generated code; prefer the (E, N) pair
155
+ for whole pages, because only the pair gets `validate_nodes`, morphs,
156
+ prerendering, and the agent surface – imperative code is not validated.
157
+
158
+ One naming caution: `Text` and `Image` collide with DOM constructor
159
+ names. Always use the module import; on a page using the CDN globals,
160
+ never assume `window.Text` / `window.Image` are still the DOM's own.
161
+
162
+ ## Verifying your work
163
+
164
+ - **Verify a morph by progress, not by DOM presence.** The destination
165
+ view is inserted before capture begins, so "the element exists" passes
166
+ even when the transition hangs. Assert that the animation *progressed*
167
+ (or landed state + painted output), and unwind with `back`/`go_back`
168
+ to check the reverse path.
169
+ - **Add a negative control.** When you write a check, break the thing
170
+ once and confirm the check fails; a check that cannot fail is not a
171
+ check.
172
+ - **Prerender caveat:** the jsdom build silently drops CSS `min()` /
173
+ `clamp()`. If the design depends on them, verify in a real browser,
174
+ not in the preview file.
175
+
176
+ ## Static site generation
177
+
178
+ `npx nodality prerender` interprets the same pair at build time: it
179
+ emits crawlable HTML, a sitemap, `hreflang` alternates, and JSON-LD. The
180
+ browser then re-reads the pair and rebuilds on top – the pair is
181
+ *shipped, not consumed*. `jsdom` must be present in the project
182
+ (deliberately not bundled). Builds are deterministic: the same pair
183
+ yields byte-identical output, so diffing two builds is a valid check.
184
+
185
+ ## When NOT to use Nodality
186
+
187
+ Static, content-shaped sites: marketing pages, storefronts,
188
+ documentation, brochures. It is not a component framework with
189
+ client-side state management. If the user needs an app (auth, live
190
+ data, complex client state), say so and recommend an app framework
191
+ instead of stretching Nodality.
192
+
193
+ ## References
194
+
195
+ - Docs: https://nodalityjs.github.io – machine index at
196
+ https://nodalityjs.github.io/llms.txt
197
+ - `node_modules/nodality/API.md` ships in the package: the full page
198
+ index with one-line summaries, readable offline.
199
+ - Copy-paste-ready full morph page:
200
+ https://nodalityjs.github.io/docs/raster/morph (section "A complete
201
+ page you can paste").
202
+ - Validator without MCP:
203
+ `import { validateNodes, describeOps } from "nodality/validate"`.