nodality 1.3.19 → 1.3.21

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 (293) hide show
  1. package/bin/mcp-server.mjs +8 -3
  2. package/bin/nodality.mjs +41 -0
  3. package/dist/animator.cjs.js +1 -1
  4. package/dist/animator.cjs.js.LICENSE.txt +1 -1
  5. package/dist/animator.esm.js +1 -1
  6. package/dist/animator.esm.js.LICENSE.txt +1 -1
  7. package/dist/audionew.cjs.js +1 -1
  8. package/dist/audionew.cjs.js.LICENSE.txt +1 -1
  9. package/dist/audionew.esm.js +1 -1
  10. package/dist/audionew.esm.js.LICENSE.txt +1 -1
  11. package/dist/base.cjs.js +1 -1
  12. package/dist/base.cjs.js.LICENSE.txt +1 -1
  13. package/dist/base.esm.js +1 -1
  14. package/dist/base.esm.js.LICENSE.txt +1 -1
  15. package/dist/beta-desktop-bar.cjs.js +1 -1
  16. package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
  17. package/dist/beta-desktop-bar.esm.js +1 -1
  18. package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
  19. package/dist/beta-mobile-bar.cjs.js +1 -1
  20. package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
  21. package/dist/beta-mobile-bar.esm.js +1 -1
  22. package/dist/beta-mobile-bar.esm.js.LICENSE.txt +1 -1
  23. package/dist/bundle.umd.js +1 -1
  24. package/dist/bundle.umd.js.LICENSE.txt +1 -1
  25. package/dist/button.cjs.js +1 -1
  26. package/dist/button.cjs.js.LICENSE.txt +1 -1
  27. package/dist/button.esm.js +1 -1
  28. package/dist/button.esm.js.LICENSE.txt +1 -1
  29. package/dist/card-getter.cjs.js.LICENSE.txt +1 -1
  30. package/dist/card-getter.esm.js.LICENSE.txt +1 -1
  31. package/dist/center.cjs.js +1 -1
  32. package/dist/center.cjs.js.LICENSE.txt +1 -1
  33. package/dist/center.esm.js +1 -1
  34. package/dist/center.esm.js.LICENSE.txt +1 -1
  35. package/dist/checkbox.cjs.js +1 -1
  36. package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
  37. package/dist/checkbox.esm.js +1 -1
  38. package/dist/checkbox.esm.js.LICENSE.txt +1 -1
  39. package/dist/code.cjs.js +1 -1
  40. package/dist/code.cjs.js.LICENSE.txt +1 -1
  41. package/dist/code.esm.js +1 -1
  42. package/dist/code.esm.js.LICENSE.txt +1 -1
  43. package/dist/container.cjs.js +1 -1
  44. package/dist/container.cjs.js.LICENSE.txt +1 -1
  45. package/dist/container.esm.js +1 -1
  46. package/dist/container.esm.js.LICENSE.txt +1 -1
  47. package/dist/data-list.cjs.js +1 -1
  48. package/dist/data-list.cjs.js.LICENSE.txt +1 -1
  49. package/dist/data-list.esm.js +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 +3 -2
  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 +1 -1
  131. package/dist/radio.cjs.js.LICENSE.txt +1 -1
  132. package/dist/radio.esm.js +1 -1
  133. package/dist/radio.esm.js.LICENSE.txt +1 -1
  134. package/dist/range.cjs.js +1 -1
  135. package/dist/range.cjs.js.LICENSE.txt +1 -1
  136. package/dist/range.esm.js +1 -1
  137. package/dist/range.esm.js.LICENSE.txt +1 -1
  138. package/dist/scroll-video.cjs.js.LICENSE.txt +1 -1
  139. package/dist/scroll-video.esm.js.LICENSE.txt +1 -1
  140. package/dist/side-bar.cjs.js +1 -1
  141. package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
  142. package/dist/side-bar.esm.js +1 -1
  143. package/dist/side-bar.esm.js.LICENSE.txt +1 -1
  144. package/dist/side-nav-bar.cjs.js +1 -1
  145. package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
  146. package/dist/side-nav-bar.esm.js +1 -1
  147. package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
  148. package/dist/simple-bar.cjs.js +1 -1
  149. package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
  150. package/dist/simple-bar.esm.js +1 -1
  151. package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
  152. package/dist/slider-2025.cjs.js +1 -1
  153. package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
  154. package/dist/slider-2025.esm.js +1 -1
  155. package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
  156. package/dist/spacer.cjs.js +1 -1
  157. package/dist/spacer.cjs.js.LICENSE.txt +1 -1
  158. package/dist/spacer.esm.js +1 -1
  159. package/dist/spacer.esm.js.LICENSE.txt +1 -1
  160. package/dist/stack.cjs.js +1 -1
  161. package/dist/stack.cjs.js.LICENSE.txt +1 -1
  162. package/dist/stack.esm.js +1 -1
  163. package/dist/stack.esm.js.LICENSE.txt +1 -1
  164. package/dist/stacker.cjs.js.LICENSE.txt +1 -1
  165. package/dist/stacker.esm.js.LICENSE.txt +1 -1
  166. package/dist/table.cjs.js +1 -1
  167. package/dist/table.cjs.js.LICENSE.txt +1 -1
  168. package/dist/table.esm.js +1 -1
  169. package/dist/table.esm.js.LICENSE.txt +1 -1
  170. package/dist/text-field.cjs.js +1 -1
  171. package/dist/text-field.cjs.js.LICENSE.txt +1 -1
  172. package/dist/text-field.esm.js +1 -1
  173. package/dist/text-field.esm.js.LICENSE.txt +1 -1
  174. package/dist/text.cjs.js +1 -1
  175. package/dist/text.cjs.js.LICENSE.txt +1 -1
  176. package/dist/text.esm.js +1 -1
  177. package/dist/text.esm.js.LICENSE.txt +1 -1
  178. package/dist/theme.cjs.js.LICENSE.txt +1 -1
  179. package/dist/theme.esm.js.LICENSE.txt +1 -1
  180. package/dist/transform-anim.cjs.js.LICENSE.txt +1 -1
  181. package/dist/transform-anim.esm.js.LICENSE.txt +1 -1
  182. package/dist/ulist.cjs.js +1 -1
  183. package/dist/ulist.cjs.js.LICENSE.txt +1 -1
  184. package/dist/ulist.esm.js +1 -1
  185. package/dist/ulist.esm.js.LICENSE.txt +1 -1
  186. package/dist/video.cjs.js +1 -1
  187. package/dist/video.cjs.js.LICENSE.txt +1 -1
  188. package/dist/video.esm.js +1 -1
  189. package/dist/video.esm.js.LICENSE.txt +1 -1
  190. package/dist/wrap.cjs.js +1 -1
  191. package/dist/wrap.cjs.js.LICENSE.txt +1 -1
  192. package/dist/wrap.esm.js +1 -1
  193. package/dist/wrap.esm.js.LICENSE.txt +1 -1
  194. package/dist/zoom-card.cjs.js +1 -1
  195. package/dist/zoom-card.cjs.js.LICENSE.txt +1 -1
  196. package/dist/zoom-card.esm.js +1 -1
  197. package/dist/zoom-card.esm.js.LICENSE.txt +1 -1
  198. package/layout/animator.js +191 -135
  199. package/layout/audio.js +1 -1
  200. package/layout/audionew.js +1 -1
  201. package/layout/base.js +1 -1
  202. package/layout/beta-desktop-bar.js +7 -1
  203. package/layout/beta-mobile-bar.js +13 -3
  204. package/layout/button.js +1 -1
  205. package/layout/center.js +1 -1
  206. package/layout/checkbox.js +1 -1
  207. package/layout/circle.js +1 -1
  208. package/layout/code.js +1 -1
  209. package/layout/container.js +1 -1
  210. package/layout/dropdown-2025.js +1 -1
  211. package/layout/flex-card.js +1 -1
  212. package/layout/flex-grid.js +1 -1
  213. package/layout/flex-row.js +1 -1
  214. package/layout/form-components/custom.js +1 -1
  215. package/layout/form-components/data-list.js +1 -1
  216. package/layout/form-components/floating-input.js +1 -1
  217. package/layout/form-components/form-all.js +1 -1
  218. package/layout/form-components/form.js +1 -1
  219. package/layout/form-components/image-picker.js +1 -1
  220. package/layout/form-components/picker.js +1 -1
  221. package/layout/form-components/radio.js +1 -1
  222. package/layout/form-components/radiogroup.js +1 -1
  223. package/layout/form-components/range.js +1 -1
  224. package/layout/free.js +1 -1
  225. package/layout/grid-overlay.js +1 -1
  226. package/layout/grid-switcher.js +1 -1
  227. package/layout/grid.js +1 -1
  228. package/layout/horizontal-scroller.js +1 -1
  229. package/layout/image.js +1 -1
  230. package/layout/index.js +1 -1
  231. package/layout/link.js +1 -1
  232. package/layout/list.js +1 -1
  233. package/layout/meta-adder.js +1 -1
  234. package/layout/modal-2025.js +1 -1
  235. package/layout/morph.js +1 -1
  236. package/layout/multiswitcher.js +1 -1
  237. package/layout/nav-bar.js +1 -1
  238. package/layout/nav-factor/custom-div.js +1 -1
  239. package/layout/new-nav-bar.js +1 -1
  240. package/layout/polygon.js +1 -1
  241. package/layout/prerender-site.js +1 -1
  242. package/layout/prerender.js +1 -1
  243. package/layout/progress.js +1 -1
  244. package/layout/row.js +1 -1
  245. package/layout/scroll-video.js +1 -1
  246. package/layout/shop.js +9 -1
  247. package/layout/side-bar.js +1 -1
  248. package/layout/side-nav-bar.js +1 -1
  249. package/layout/simple-bar.js +1 -1
  250. package/layout/slider-2025.js +1 -1
  251. package/layout/spacer.js +1 -1
  252. package/layout/stack.js +1 -1
  253. package/layout/svg.js +1 -1
  254. package/layout/switcher.js +1 -1
  255. package/layout/table.js +1 -1
  256. package/layout/text-field.js +1 -1
  257. package/layout/text.js +7 -1
  258. package/layout/ulist.js +1 -1
  259. package/layout/video.js +1 -1
  260. package/layout/wrap.js +1 -1
  261. package/layout/zoom-card.js +1 -1
  262. package/lib/agent-surface.js +1 -1
  263. package/lib/card-getter.js +1 -1
  264. package/lib/check-page.js +14 -2
  265. package/lib/codegen.js +1 -1
  266. package/lib/data.js +1 -1
  267. package/lib/designer.js +1 -1
  268. package/lib/element-mapper.js +23 -8
  269. package/lib/element-params.generated.js +4 -4
  270. package/lib/grid-geometry.js +1 -1
  271. package/lib/keyframe-animation.js +1 -1
  272. package/lib/known-inert.js +8 -9
  273. package/lib/link-getter.js +1 -1
  274. package/lib/morph-node.js +1 -1
  275. package/lib/normalize-spec.js +1 -1
  276. package/lib/parse-html.js +1 -1
  277. package/lib/raster-inspect.js +1 -1
  278. package/lib/raster-ops.js +1 -1
  279. package/lib/raster-presets.js +1 -1
  280. package/lib/resolve-refs.js +1 -1
  281. package/lib/scroll-video.js +1 -1
  282. package/lib/seo.js +1 -1
  283. package/lib/stacker.js +1 -1
  284. package/lib/suggest.js +1 -1
  285. package/lib/theme.js +1 -1
  286. package/lib/transform-anim.js +1 -1
  287. package/lib/transition.js +1 -1
  288. package/lib/validate-nodes.js +9 -2
  289. package/lib/webmcp-adapter.js +1 -1
  290. package/package.json +2 -1
  291. package/schema.json +10100 -2535
  292. package/scripts/generate-schema.mjs +83 -2
  293. package/skills/nodality/SKILL.md +16 -3
@@ -273,6 +273,34 @@ function annotationFor(table, name, from, type, qualified) {
273
273
  return (qualified ? DESC_GLOBAL : DEPR_GLOBAL)[name];
274
274
  }
275
275
 
276
+ // ── 6b. what commonMethods applies ───────────────────────────────────
277
+ // Read from animator.js itself, so the list cannot drift from the code.
278
+ const ANIMATOR = join(ROOT, "layout", "animator.js");
279
+ const ANIMATOR_SRC = readFileSync(ANIMATOR, "utf8");
280
+ const STYLE_MAP = (() => {
281
+ const m = ANIMATOR_SRC.match(/const STYLE_OPTIONS = \{([\s\S]*?)\n\};/);
282
+ const map = {};
283
+ if (m) for (const e of m[1].matchAll(/^\s*([A-Za-z][A-Za-z0-9]*)\s*:\s*"([A-Za-z]+)"/gm)) map[e[1]] = e[2];
284
+ return map;
285
+ })();
286
+ const STYLE_OPTIONS = Object.keys(STYLE_MAP);
287
+ const PIXELS_WHEN_BARE = new Set((ANIMATOR_SRC.match(/const PIXELS_WHEN_BARE = new Set\(\[([\s\S]*?)\]\)/) || [, ""])[1]
288
+ .match(/"([A-Za-z]+)"/g)?.map((s) => s.slice(1, -1)) || []);
289
+ // Of the options commonMethods reads by name, the ones it applies to the
290
+ // element itself on every component. The rest (theme, noTheme, hide, size,
291
+ // center, raster, …) depend on the component or on a theme being set, and are
292
+ // credited where a component reads them, if at all.
293
+ const COMMON_CREDITED = ["pad", "mar", "weight", "bold", "borderObj", "respad", "resmar"];
294
+ const COMMON_READS = (() => {
295
+ const start = ANIMATOR_SRC.search(/\bcommonMethods\s*\(\s*obj\s*\)\s*\{/);
296
+ if (start < 0) return [];
297
+ // The method ends at the first line that closes it at its own indentation.
298
+ const rest = ANIMATOR_SRC.slice(start);
299
+ const end = rest.search(/\n\t\t\}\s*\n/);
300
+ const body = end > 0 ? rest.slice(0, end) : rest.slice(0, 20000);
301
+ return [...new Set([...body.matchAll(/\bobj\.([a-zA-Z][a-zA-Z0-9]*)/g)].map((x) => x[1]))];
302
+ })();
303
+
276
304
  // ── 7. assemble ──────────────────────────────────────────────────────
277
305
  const schema = { generated: "scripts/generate-schema.mjs", types: {} };
278
306
  let resolved = 0;
@@ -365,11 +393,60 @@ for (const type of TYPES) {
365
393
  // component's own set() — currently `loop`. Component scans never see them,
366
394
  // because they are read in animator.js. Credited only where the type has no
367
395
  // parameter of that name already: `video` has its own boolean `loop`.
368
- const ANIMATOR = join(ROOT, "layout", "animator.js");
369
396
  const onAnimator = files.some((f) => { try { return /extends\s+Animator\b/.test(readFileSync(f, "utf8")); } catch { return false; } });
370
397
  // And only where the element's options reach the component at all.
371
398
  if (onAnimator && forwardsElement) for (const p of ["loop"]) if (!params.has(p)) contributed(p, ANIMATOR);
372
399
 
400
+ // Options commonMethods applies, for every component that runs it. Two
401
+ // kinds, both read in animator.js where no component scan looks: the
402
+ // CSS-named options of STYLE_OPTIONS (lineHeight, gap, exact, weight, …),
403
+ // read through a map rather than by name, and the ones commonMethods reads
404
+ // by name (pad, mar, hover, borderObj, …). Missing them made the schema
405
+ // omit working options and the validator report them as PARAM_NOT_ON_TYPE —
406
+ // "accepted and ignored" — so pages used keySet for options the library
407
+ // had. Until 1.3.21.
408
+ //
409
+ // Credited only through the component that RECEIVES the element's options:
410
+ // a type is often built from several classes, and the one that runs
411
+ // commonMethods may be a helper — checkbox renders its label with Text,
412
+ // which runs it, while the element's options go to Checkbox, which does not.
413
+ // Crediting by "some component runs it" claimed working options for a
414
+ // checkbox that ignores every one of them. Where the receiving class cannot
415
+ // be identified, nothing is credited.
416
+ // Each `new X(` owns the code up to the next one; X receives the element's
417
+ // options if that stretch hands them over (elOpts, a spread, or an alias).
418
+ // Looked for in the mapper's OWN body, not in the helpers it calls: sideNav
419
+ // hands the element's options to a Link inside a helper while its root,
420
+ // SideNav, takes none, and crediting through the helper claimed every
421
+ // style option for a component that applies not one. A mapper whose own
422
+ // body constructs nothing is a delegate, and its helpers are its body.
423
+ // Capped at the next static declaration: methodBody's brace matcher loses
424
+ // its place in sideNav's 300-line body and returned 52 kB — the rest of the
425
+ // file — so every later mapper's construction counted as sideNav's own.
426
+ const ownRaw = method ? methodBody(method) : "";
427
+ const nextStatic = ownRaw.search(/\n\s{4}static\s+[A-Za-z_]\w*\s*\(/);
428
+ const ownBody = nextStatic > 0 ? ownRaw.slice(0, nextStatic) : ownRaw;
429
+ const scope = /\bnew\s+[A-Z]/.test(ownBody) ? ownBody : body;
430
+ const news = [...scope.matchAll(/\bnew\s+([A-Z]\w*)\s*\(/g)];
431
+ const receivers = news.filter((h, i) => {
432
+ const seg = scope.slice(h.index, i + 1 < news.length ? news[i + 1].index : h.index + 3000);
433
+ return /\.set\s*\(/.test(seg) && (/\belOpts\s*\(/.test(seg) || /\.\.\.el\b/.test(seg)
434
+ || aliases.some((a) => new RegExp(`\\.set\\(\\s*${a}\\s*[,)]`).test(seg)));
435
+ }).map((h) => h[1]);
436
+ const runsCommon = receivers.some((c) => {
437
+ const f = fileFor(c);
438
+ try { return !!f && /\bcommonMethods\s*\(/.test(readFileSync(f, "utf8")); } catch { return false; }
439
+ });
440
+ if (runsCommon && forwardsElement) {
441
+ for (const p of [...STYLE_OPTIONS, ...COMMON_CREDITED]) if (!params.has(p)) contributed(p, ANIMATOR);
442
+ }
443
+ // A mapper that builds its own options but forwards the element's style
444
+ // options with styleOptionsOf(el) (nav, the commerce types) is credited
445
+ // with exactly those.
446
+ if (/\bstyleOptionsOf\s*\(/.test(body)) {
447
+ for (const p of STYLE_OPTIONS) if (!params.has(p)) contributed(p, ANIMATOR);
448
+ }
449
+
373
450
  // NOTE. A `settable` flag was attempted here and removed. The question it
374
451
  // was meant to answer -- which of these parameters an AUTHOR can set on the
375
452
  // element, as opposed to which the components READ -- is real and still
@@ -389,7 +466,11 @@ for (const type of TYPES) {
389
466
  components: classes,
390
467
  params: [...params].sort().map((name) => {
391
468
  const where = from.get(name) || [];
392
- const description = annotationFor(DESC_BY_FILE, name, where, type, true);
469
+ const description = annotationFor(DESC_BY_FILE, name, where, type, true)
470
+ || (where.includes(ANIMATOR) && STYLE_MAP[name]
471
+ ? `CSS ${STYLE_MAP[name].replace(/[A-Z]/g, (c) => "-" + c.toLowerCase())}, written verbatim.`
472
+ + (PIXELS_WHEN_BARE.has(name) ? " A bare number is read as px." : "")
473
+ : undefined);
393
474
  const deprecated = annotationFor(DEPR_BY_FILE, name, where, type, false);
394
475
  const unit = (UNIT_BY_TYPE[type] && UNIT_BY_TYPE[type][name])
395
476
  || where.map((f) => (UNIT_BY_FILE.get(f) || {})[name]).find(Boolean)
@@ -202,9 +202,16 @@ A complete navigation graph is one node:
202
202
  - **Never touch the DOM to style or fix a Nodality page.** No
203
203
  `el.style.*`, no `createElement` in page code, no post-render DOM
204
204
  patching. If the library cannot express something, the fix is a custom
205
- element/op (extend the library), or the `keySet` option on an element
206
- (`keySet: { key, value }`) for one custom CSS property. Note the
207
- spelling: `keySet`, capital S.
205
+ element/op (extend the library).
206
+ - **Style with options, not keySet.** Elements take styling as options:
207
+ the library's own names (`exact` for font size, `weight`, `pad`, `mar`,
208
+ `radius`, `gpos`, `borderObj`) and the CSS-named options every element
209
+ accepts (`lineHeight`, `letterSpacing`, `textTransform`, `gap`,
210
+ `alignContent`, `justifyContent`, `boxShadow`, `backdropFilter`,
211
+ `borderTop`, …). `get_schema <type>` lists them. Responsive values go in
212
+ `resprop`, which takes CSS names. `keySet: [{ key, value }]` is the escape
213
+ hatch for a property no option names — reach for it last, and if the same
214
+ property keeps needing it, extend the library instead.
208
215
  - **No CSS in the page either.** No `<style>` rules, no `@keyframes`, no
209
216
  stylesheet files. Anything that moves on its own takes `loop` on the element —
210
217
  `loop: { keyframes: [{…}, {…}], duration }` runs forever through the Web
@@ -326,6 +333,12 @@ document is untrusted input.
326
333
 
327
334
  ## Verifying your work
328
335
 
336
+ - **`check_page` works without the MCP too:** `npx nodality check
337
+ upload/*.html --base=http://localhost:4000/` (or `import { checkPage }
338
+ from "nodality/check"`). Pass `--base` for a prerendered site, or its fonts
339
+ and `/assets/` do not load and text is measured in a fallback face. It exits
340
+ 1 on findings, and on a shop page reports `LOADING_LAYOUT_SHIFT` when the
341
+ product's loading copy sits somewhere other than the loaded element.
329
342
  - **Read `FAINT_TEXT` from `check_page`.** It reports small text that passes
330
343
  WCAG and still reads faint (APCA), the usual case on mid-tone backgrounds.
331
344
  Fix with weight, a lighter or darker ground, or size; not by ignoring it.