ranger-compiler 3.5.1 → 3.5.2

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 (338) hide show
  1. package/CHANGELOG.md +1064 -20
  2. package/LICENSE +3 -1
  3. package/README.md +123 -28
  4. package/dist/Lang.rgr +1188 -290
  5. package/dist/api.d.ts +2343 -879
  6. package/dist/api.js +79923 -56921
  7. package/dist/lib/JSON.rgr +102 -91
  8. package/dist/lib/Shell.rgr +4 -4
  9. package/dist/lib/apple/AppleToolchain.rgr +4 -4
  10. package/dist/lib/apple/README.md +5 -4
  11. package/dist/lib/apple/apple_test.rgr +1 -1
  12. package/dist/lib/core/README.md +1 -1
  13. package/dist/lib/evg/EVG.rgr +12 -0
  14. package/dist/lib/evg/EVGA11yFromTree.rgr +302 -0
  15. package/dist/lib/evg/EVGA11yTree.rgr +894 -0
  16. package/dist/lib/evg/EVGBox.rgr +267 -0
  17. package/dist/lib/evg/EVGBoxShorthandTest.rgr +220 -0
  18. package/dist/lib/evg/EVGCodepoint.rgr +316 -0
  19. package/dist/lib/evg/EVGColor.rgr +700 -0
  20. package/dist/lib/evg/EVGCommands.rgr +177 -0
  21. package/dist/lib/evg/EVGComponent.rgr +331 -0
  22. package/dist/lib/evg/EVGComponentTest.rgr +387 -0
  23. package/dist/lib/evg/EVGConnector.rgr +541 -0
  24. package/dist/lib/evg/EVGConnectorTest.rgr +306 -0
  25. package/dist/lib/evg/EVGDisplayList.rgr +4186 -0
  26. package/dist/lib/evg/EVGEasing.rgr +370 -0
  27. package/dist/lib/evg/EVGEffectTest.rgr +253 -0
  28. package/dist/lib/evg/EVGElement.rgr +4914 -0
  29. package/dist/lib/evg/EVGFixedTest.rgr +289 -0
  30. package/dist/lib/evg/EVGFlexRulesTest.rgr +317 -0
  31. package/dist/lib/evg/EVGFlexWrapTest.rgr +246 -0
  32. package/dist/lib/evg/EVGFling.rgr +244 -0
  33. package/dist/lib/evg/EVGFocus.rgr +400 -0
  34. package/dist/lib/evg/EVGFocusTest.rgr +399 -0
  35. package/dist/lib/evg/EVGGradient.rgr +322 -0
  36. package/dist/lib/evg/EVGGrapheme.rgr +190 -0
  37. package/dist/lib/evg/EVGGrid.rgr +975 -0
  38. package/dist/lib/evg/EVGHitTest.rgr +208 -0
  39. package/dist/lib/evg/EVGHoles.rgr +294 -0
  40. package/dist/lib/evg/EVGHostMeasurerTest.rgr +281 -0
  41. package/dist/lib/evg/EVGHostTextMeasurer.rgr +331 -0
  42. package/dist/lib/evg/EVGHostTree.rgr +834 -0
  43. package/dist/lib/evg/EVGHostTreeTest.rgr +447 -0
  44. package/dist/lib/evg/EVGImageDecode.rgr +117 -0
  45. package/dist/lib/evg/EVGImageMeasurer.rgr +86 -0
  46. package/dist/lib/evg/EVGInspect.rgr +883 -0
  47. package/dist/lib/evg/EVGInvalidateTest.rgr +432 -0
  48. package/dist/lib/evg/EVGJsonTest.rgr +535 -0
  49. package/dist/lib/evg/EVGLayout.rgr +4220 -0
  50. package/dist/lib/evg/EVGMeasure.rgr +1267 -0
  51. package/dist/lib/evg/EVGOverlayTest.rgr +626 -0
  52. package/dist/lib/evg/EVGPatch.rgr +1721 -0
  53. package/dist/lib/evg/EVGPatchTest.rgr +692 -0
  54. package/dist/lib/evg/EVGPopoverTest.rgr +395 -0
  55. package/dist/lib/evg/EVGReconcile.rgr +226 -0
  56. package/dist/lib/evg/EVGReconcileTest.rgr +421 -0
  57. package/dist/lib/evg/EVGReject.rgr +126 -0
  58. package/dist/lib/evg/EVGRelayoutTest.rgr +375 -0
  59. package/dist/lib/evg/EVGRtlLayoutTest.rgr +319 -0
  60. package/dist/lib/evg/EVGRuler.rgr +232 -0
  61. package/dist/lib/evg/EVGRulerTest.rgr +172 -0
  62. package/dist/lib/evg/EVGSelectChrome.rgr +178 -0
  63. package/dist/lib/evg/EVGStyleCacheTest.rgr +419 -0
  64. package/dist/lib/evg/EVGStyleSheet.rgr +2148 -0
  65. package/dist/lib/evg/EVGStyleStateTest.rgr +407 -0
  66. package/dist/lib/evg/EVGStyleVarTest.rgr +471 -0
  67. package/dist/lib/evg/EVGText.rgr +105 -0
  68. package/dist/lib/evg/EVGTextEngine.rgr +536 -0
  69. package/dist/lib/evg/EVGTextMeasurer.rgr +720 -0
  70. package/dist/lib/evg/EVGTimingTest.rgr +1417 -0
  71. package/dist/lib/evg/EVGToolbar.rgr +1369 -0
  72. package/dist/lib/evg/EVGTransition.rgr +728 -0
  73. package/dist/lib/evg/EVGTreeJson.rgr +721 -0
  74. package/dist/lib/evg/EVGUnit.rgr +554 -0
  75. package/dist/lib/evg/EVGViewportUnitTest.rgr +236 -0
  76. package/dist/lib/evg/EvgApp.rgr +189 -0
  77. package/dist/lib/evg/EvgBitmapTracer.rgr +4277 -0
  78. package/dist/lib/evg/EvgBitmapTracerTest.rgr +2119 -0
  79. package/dist/lib/evg/EvgHost.rgr +451 -0
  80. package/dist/lib/evg/EvgTest.rgr +91 -0
  81. package/dist/lib/evg/EvgTraceColor.rgr +236 -0
  82. package/dist/lib/evg/EvgTraceCurve.rgr +648 -0
  83. package/dist/lib/evg/EvgTraceFit.rgr +767 -0
  84. package/dist/lib/evg/EvgTracePath.rgr +435 -0
  85. package/dist/lib/evg/EvgTraceTypes.rgr +559 -0
  86. package/dist/lib/evg/EvgViewport.rgr +313 -0
  87. package/dist/lib/evg/FxDemoDoc.rgr +185 -0
  88. package/dist/lib/evg/HOSTS.md +227 -0
  89. package/dist/lib/evg/ISSUES.md +835 -0
  90. package/dist/lib/evg/PLAN_ACCESSIBILITY.md +650 -0
  91. package/dist/lib/evg/PLAN_CSS_LAYOUT_AND_FONTS.md +1124 -0
  92. package/dist/lib/evg/PLAN_EFFECTS.md +431 -0
  93. package/dist/lib/evg/PLAN_EVG.md +518 -0
  94. package/dist/lib/evg/PLAN_EVG_RENDERER.md +1674 -0
  95. package/dist/lib/evg/PLAN_INSPECTOR.md +788 -0
  96. package/dist/lib/evg/PLAN_LINKS_AND_FORMS.md +157 -0
  97. package/dist/lib/evg/PLAN_NATIVE_HOSTS.md +671 -0
  98. package/dist/lib/evg/PLAN_VECTOR_IR.md +664 -0
  99. package/dist/lib/evg/PLAN_VIEW_TRANSFORM.md +322 -0
  100. package/dist/lib/evg/PathBuilder.rgr +333 -0
  101. package/dist/lib/evg/README.md +1236 -0
  102. package/dist/lib/evg/SPEC.md +1252 -0
  103. package/dist/lib/evg/SVGPathParser.rgr +1199 -0
  104. package/dist/lib/evg/SvgParser.rgr +1736 -0
  105. package/dist/lib/evg/TODO_EVG_RENDERER.md +595 -0
  106. package/dist/lib/evg/VectorShapes.rgr +331 -0
  107. package/dist/lib/evg/VectorStroke.rgr +107 -0
  108. package/dist/lib/evg/VectorViewBox.rgr +380 -0
  109. package/dist/lib/evg/agent/README.md +290 -0
  110. package/dist/lib/evg/agent/evg_agent.rgr +899 -0
  111. package/dist/lib/evg/agent/fixtures/broken.evg.json +7 -0
  112. package/dist/lib/evg/agent/fixtures/card.evg.json +9 -0
  113. package/dist/lib/evg/agent/fixtures/connector.css +63 -0
  114. package/dist/lib/evg/agent/fixtures/connector.evg.json +14 -0
  115. package/dist/lib/evg/agent/fixtures/drawn.evg.json +129 -0
  116. package/dist/lib/evg/agent/fixtures/gradient.evg.json +4 -0
  117. package/dist/lib/evg/agent/fixtures/popover.css +99 -0
  118. package/dist/lib/evg/agent/fixtures/popover.evg.json +30 -0
  119. package/dist/lib/evg/agent/roundtrip.sh +74 -0
  120. package/dist/lib/evg/agent/smoke.sh +230 -0
  121. package/dist/lib/evg/android/README.md +97 -0
  122. package/dist/lib/evg/android/androidstubs/AndroidStubs.kt +175 -0
  123. package/dist/lib/evg/android/androidstubs/Annotation.kt +10 -0
  124. package/dist/lib/evg/android/androidstubs/App.kt +30 -0
  125. package/dist/lib/evg/android/androidstubs/Content.kt +41 -0
  126. package/dist/lib/evg/android/androidstubs/ContentRes.kt +12 -0
  127. package/dist/lib/evg/android/androidstubs/InputMethod.kt +46 -0
  128. package/dist/lib/evg/android/androidstubs/Net.kt +6 -0
  129. package/dist/lib/evg/android/androidstubs/Os.kt +30 -0
  130. package/dist/lib/evg/android/androidstubs/Util.kt +15 -0
  131. package/dist/lib/evg/android/androidstubs/View.kt +113 -0
  132. package/dist/lib/evg/android/androidstubs/Widget.kt +16 -0
  133. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidEvgSurface.kt +323 -0
  134. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidTextMeasurer.kt +56 -0
  135. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/RippleEffect.kt +262 -0
  136. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtEvgSurface.kt +238 -0
  137. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtTextMeasurer.kt +85 -0
  138. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgEngineThread.kt +115 -0
  139. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgPainter.kt +231 -0
  140. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgSurface.kt +117 -0
  141. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/RecordingSurface.kt +94 -0
  142. package/dist/lib/evg/apple/README.md +128 -0
  143. package/dist/lib/evg/apple/Sources/CoreGraphicsEvgSurface.swift +329 -0
  144. package/dist/lib/evg/apple/Sources/CoreTextMeasurer.swift +70 -0
  145. package/dist/lib/evg/apple/Sources/EvgEngineQueue.swift +105 -0
  146. package/dist/lib/evg/apple/Sources/EvgPainter.swift +225 -0
  147. package/dist/lib/evg/apple/Sources/EvgSurface.swift +163 -0
  148. package/dist/lib/evg/apple/Sources/RecordingSurface.swift +110 -0
  149. package/dist/lib/evg/bench/EvgLayoutBench.rgr +34 -0
  150. package/dist/lib/evg/bench/README.md +64 -0
  151. package/dist/lib/evg/bench/layout-bench.mjs +316 -0
  152. package/dist/lib/evg/bench/layout-cases.mjs +510 -0
  153. package/dist/lib/evg/bench/layout-conformance.mjs +254 -0
  154. package/dist/lib/evg/bin/.gitignore +17 -0
  155. package/dist/lib/evg/evg_test.rgr +313 -0
  156. package/dist/lib/evg/gl/README.md +198 -0
  157. package/dist/lib/evg/gl/a11y-paint-check.mjs +73 -0
  158. package/dist/lib/evg/gl/blur-check.mjs +399 -0
  159. package/dist/lib/evg/gl/boxmodel.json +1 -0
  160. package/dist/lib/evg/gl/demo.html +46 -0
  161. package/dist/lib/evg/gl/effect-presets.css +285 -0
  162. package/dist/lib/evg/gl/effect-presets.js +63 -0
  163. package/dist/lib/evg/gl/effect-shots.mjs +135 -0
  164. package/dist/lib/evg/gl/evg-a11y.js +566 -0
  165. package/dist/lib/evg/gl/evg-binary.js +160 -0
  166. package/dist/lib/evg/gl/evg-engine.js +296 -0
  167. package/dist/lib/evg/gl/evg-fx.js +237 -0
  168. package/dist/lib/evg/gl/evg-gestures.js +209 -0
  169. package/dist/lib/evg/gl/evg-list.js +167 -0
  170. package/dist/lib/evg/gl/evg-measure.js +186 -0
  171. package/dist/lib/evg/gl/evg-textinput.js +303 -0
  172. package/dist/lib/evg/gl/evg-view.js +144 -0
  173. package/dist/lib/evg/gl/evg-webgl.js +3942 -0
  174. package/dist/lib/evg/gl/fx-check.mjs +998 -0
  175. package/dist/lib/evg/gl/fx-demo.html +166 -0
  176. package/dist/lib/evg/gl/fx-demo.js +2 -0
  177. package/dist/lib/evg/gl/fx-serve.mjs +47 -0
  178. package/dist/lib/evg/gl/gestures-check.mjs +189 -0
  179. package/dist/lib/evg/gl/list-binary-check.mjs +152 -0
  180. package/dist/lib/evg/gl/measure-check.mjs +135 -0
  181. package/dist/lib/evg/gl/rotation-check.mjs +207 -0
  182. package/dist/lib/evg/gl/shift-check.mjs +113 -0
  183. package/dist/lib/evg/gl/stroke-check.mjs +168 -0
  184. package/dist/lib/evg/gl/text-snap-check.mjs +139 -0
  185. package/dist/lib/evg/gl/view-check.mjs +343 -0
  186. package/dist/lib/evg/gl/view-policy-check.mjs +184 -0
  187. package/dist/lib/evg/html/evg-dom.js +318 -0
  188. package/dist/lib/evg/html/evg-html.js +600 -0
  189. package/dist/lib/evg/inspect/README.md +415 -0
  190. package/dist/lib/evg/inspect/browser-smoke.mjs +115 -0
  191. package/dist/lib/evg/inspect/evg-inspect.js +947 -0
  192. package/dist/lib/evg/inspect/shots/css.png +0 -0
  193. package/dist/lib/evg/inspect/shots/dashboard.png +0 -0
  194. package/dist/lib/evg/inspect/shots/pptx-slide.png +0 -0
  195. package/dist/lib/evg/inspect/shots/state.png +0 -0
  196. package/dist/lib/evg/inspect/shots.mjs +226 -0
  197. package/dist/lib/evg/oracle/css-blur.json +576 -0
  198. package/dist/lib/evg/oracle/css-box.json +157 -0
  199. package/dist/lib/evg/oracle/css-timing.json +709 -0
  200. package/dist/lib/evg/oracle/css_blur_oracle.mjs +529 -0
  201. package/dist/lib/evg/oracle/css_box_oracle.mjs +106 -0
  202. package/dist/lib/evg/oracle/css_timing_oracle.mjs +389 -0
  203. package/dist/lib/evg/original/EVGColor.clj +310 -0
  204. package/dist/lib/evg/original/EVGColorContext.rgr +178 -0
  205. package/dist/lib/evg/original/SVGPath.rgr +627 -0
  206. package/dist/lib/evg/original/Vec2.crgr +103 -0
  207. package/dist/lib/evg/ranger.json +9 -0
  208. package/dist/lib/evg/showcase/README.md +246 -0
  209. package/dist/lib/evg/showcase/assets/emblem.svg +30 -0
  210. package/dist/lib/evg/showcase/assets/rosette.svg +22 -0
  211. package/dist/lib/evg/showcase/build.mjs +651 -0
  212. package/dist/lib/evg/showcase/pages/album.tsx +30 -0
  213. package/dist/lib/evg/showcase/pages/boxmodel.tsx +37 -0
  214. package/dist/lib/evg/showcase/pages/cards.tsx +41 -0
  215. package/dist/lib/evg/showcase/pages/chart_api.tsx +170 -0
  216. package/dist/lib/evg/showcase/pages/charts.tsx +219 -0
  217. package/dist/lib/evg/showcase/pages/drawing.tsx +160 -0
  218. package/dist/lib/evg/showcase/pages/emoji.tsx +91 -0
  219. package/dist/lib/evg/showcase/pages/flex.tsx +46 -0
  220. package/dist/lib/evg/showcase/pages/more.tsx +332 -0
  221. package/dist/lib/evg/showcase/pages/plots.tsx +262 -0
  222. package/dist/lib/evg/showcase/pages/svg.tsx +63 -0
  223. package/dist/lib/evg/showcase/pages/tables.tsx +209 -0
  224. package/dist/lib/evg/showcase/pages/typography.tsx +43 -0
  225. package/dist/lib/evg/showcase/pages/units.tsx +35 -0
  226. package/dist/lib/evg/showcase/pages/variants.tsx +233 -0
  227. package/dist/lib/evg/showcase/pages/vector.tsx +75 -0
  228. package/dist/lib/evg/showcase/pages/views.tsx +223 -0
  229. package/dist/lib/evg/showcase/tests/chart_api_smoke.mjs +339 -0
  230. package/dist/lib/evg/showcase/tests/gl_smoke.mjs +125 -0
  231. package/dist/lib/evg/showcase/themes/chart_api-default.css +15 -0
  232. package/dist/lib/evg/showcase/themes/charts-default.css +29 -0
  233. package/dist/lib/evg/showcase/themes/drawing-default.css +35 -0
  234. package/dist/lib/evg/showcase/themes/more-default.css +128 -0
  235. package/dist/lib/evg/showcase/themes/plots-default.css +18 -0
  236. package/dist/lib/evg/showcase/themes/showcase.css +508 -0
  237. package/dist/lib/evg/showcase/themes/tables-default.css +123 -0
  238. package/dist/lib/evg/showcase/themes/variants-default.css +15 -0
  239. package/dist/lib/evg/showcase/themes/views-default.css +15 -0
  240. package/dist/lib/evg/tools/bench_vs_potrace.mjs +290 -0
  241. package/dist/lib/evg/tools/evg_image_tool.rgr +488 -0
  242. package/dist/lib/evg/tools/evg_trace_bench.rgr +114 -0
  243. package/dist/lib/evg/tools/evg_trace_cli.rgr +662 -0
  244. package/dist/lib/evg/tools/evg_trace_cpp_bench.rgr +83 -0
  245. package/dist/lib/evg/tools/run_trace_bench.sh +74 -0
  246. package/dist/lib/evg/tools/run_trace_cli_smoke.sh +128 -0
  247. package/dist/lib/evg/web/responsive/EvgResponsiveCheck.rgr +271 -0
  248. package/dist/lib/evg/web/responsive/EvgResponsiveDemo.rgr +531 -0
  249. package/dist/lib/evg/web/responsive/README.md +97 -0
  250. package/dist/lib/evg/web/responsive/build.mjs +90 -0
  251. package/dist/lib/evg/web/responsive/dom-check.mjs +169 -0
  252. package/dist/lib/evg/web/responsive/index.html +177 -0
  253. package/dist/lib/evg/web/responsive/smoke.mjs +221 -0
  254. package/dist/lib/evg/web/tools/assets-client.mjs +95 -0
  255. package/dist/lib/evg/web/tools/boot-bench.mjs +189 -0
  256. package/dist/lib/evg/web/tools/inline-assets.mjs +119 -0
  257. package/dist/lib/evg/web/tools/minify.mjs +60 -0
  258. package/dist/lib/evg/web/tracer/build.mjs +87 -0
  259. package/dist/lib/evg/web/tracer/index.html +2805 -0
  260. package/dist/lib/evg/web/tracer/sample.png +0 -0
  261. package/dist/lib/evg/web/tracer/smoke.mjs +1162 -0
  262. package/dist/lib/evgr/Cargo.lock +21 -0
  263. package/dist/lib/evgr/Cargo.toml +19 -0
  264. package/dist/lib/evgr/README.md +140 -0
  265. package/dist/lib/evgr/bench/NativeBench.rgr +246 -0
  266. package/dist/lib/evgr/bench/compare.mjs +252 -0
  267. package/dist/lib/evgr/bench/speed.mjs +277 -0
  268. package/dist/lib/evgr/bin/.gitignore +3 -0
  269. package/dist/lib/evgr/src/bin/bench.rs +106 -0
  270. package/dist/lib/evgr/src/bin/smoke.rs +13 -0
  271. package/dist/lib/evgr/src/grid.rs +730 -0
  272. package/dist/lib/evgr/src/lib.rs +1003 -0
  273. package/dist/lib/evgr/src/style.rs +468 -0
  274. package/dist/lib/evgr/src/text.rs +83 -0
  275. package/dist/lib/image/BitReader.rgr +171 -0
  276. package/dist/lib/image/Buffer.rgr +173 -0
  277. package/dist/lib/image/DCT.rgr +283 -0
  278. package/dist/lib/image/Deflate.rgr +339 -0
  279. package/dist/lib/image/HuffmanDecoder.rgr +181 -0
  280. package/dist/lib/image/ImageBuffer.rgr +706 -0
  281. package/dist/lib/image/JPEGDecoder.rgr +808 -0
  282. package/dist/lib/image/PNGDecoder.rgr +544 -0
  283. package/dist/lib/image/PNGEncoder.rgr +388 -0
  284. package/dist/lib/image/PPMImage.rgr +224 -0
  285. package/dist/lib/image/ProgressiveJPEGDecoder.rgr +1154 -0
  286. package/dist/lib/image/README.md +33 -0
  287. package/dist/lib/image/RasterBuffer.rgr +294 -0
  288. package/dist/lib/image/VP8BoolDecoder.rgr +163 -0
  289. package/dist/lib/image/WebPDecoder.rgr +433 -0
  290. package/dist/lib/image/WebPLossless.rgr +1035 -0
  291. package/dist/lib/image/WebPLossy.rgr +1929 -0
  292. package/dist/lib/image/ranger.json +9 -0
  293. package/dist/lib/image/testdata/webp/anim_2f_24x16.webp +0 -0
  294. package/dist/lib/image/testdata/webp/fixtures.txt +33 -0
  295. package/dist/lib/image/testdata/webp/gen_fixtures.py +261 -0
  296. package/dist/lib/image/testdata/webp/ll_1x1.webp +0 -0
  297. package/dist/lib/image/testdata/webp/ll_alpha_29x21.webp +0 -0
  298. package/dist/lib/image/testdata/webp/ll_gradient_64x64.webp +0 -0
  299. package/dist/lib/image/testdata/webp/ll_meta_32x32.webp +0 -0
  300. package/dist/lib/image/testdata/webp/ll_noise_17x9.webp +0 -0
  301. package/dist/lib/image/testdata/webp/ll_pal11_23x11.webp +0 -0
  302. package/dist/lib/image/testdata/webp/ll_pal2_19x7.webp +0 -0
  303. package/dist/lib/image/testdata/webp/ll_pal40_16x16.webp +0 -0
  304. package/dist/lib/image/testdata/webp/ll_pal4_13x5.webp +0 -0
  305. package/dist/lib/image/testdata/webp/ll_photo_40x30.webp +0 -0
  306. package/dist/lib/image/testdata/webp/ll_predictors_64x32.webp +0 -0
  307. package/dist/lib/image/testdata/webp/ly_1x1.webp +0 -0
  308. package/dist/lib/image/testdata/webp/ly_alph_raw_f0_21x13.webp +0 -0
  309. package/dist/lib/image/testdata/webp/ly_alph_raw_f1_21x13.webp +0 -0
  310. package/dist/lib/image/testdata/webp/ly_alph_raw_f2_21x13.webp +0 -0
  311. package/dist/lib/image/testdata/webp/ly_alph_raw_f3_21x13.webp +0 -0
  312. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f0_21x13.webp +0 -0
  313. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f1_21x13.webp +0 -0
  314. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f2_21x13.webp +0 -0
  315. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f3_21x13.webp +0 -0
  316. package/dist/lib/image/testdata/webp/ly_alpha_33x17.webp +0 -0
  317. package/dist/lib/image/testdata/webp/ly_exif_15x11.webp +0 -0
  318. package/dist/lib/image/testdata/webp/ly_i16_96x80.webp +0 -0
  319. package/dist/lib/image/testdata/webp/ly_nofilter_24x20.webp +0 -0
  320. package/dist/lib/image/testdata/webp/ly_odd_17x9.webp +0 -0
  321. package/dist/lib/image/testdata/webp/ly_photo_48x40.webp +0 -0
  322. package/dist/lib/image/testdata/webp/ly_q100_20x18.webp +0 -0
  323. package/dist/lib/image/testdata/webp/ly_sharp_40x36.webp +0 -0
  324. package/dist/lib/image/testdata/webp/ly_simple_filter_33x31.webp +0 -0
  325. package/dist/lib/image/testdata/webp/ly_vpx_parts8_37x45.webp +0 -0
  326. package/dist/lib/image/testdata/webp/ly_vpx_skip_96x80.webp +0 -0
  327. package/dist/lib/image/tests/WebPDecodeTool.rgr +81 -0
  328. package/dist/lib/image/tests/WebPDecoderTest.rgr +1162 -0
  329. package/dist/lib/image/tests/run_webp_tests.sh +39 -0
  330. package/dist/lib/rust/RsJson.rgr +468 -0
  331. package/dist/lib/rust/RsPrelude.rgr +1663 -0
  332. package/dist/lib/shell_test.rgr +7 -7
  333. package/dist/lib/stdlib.rgr +21 -5
  334. package/dist/lib/zip/ranger.json +6 -0
  335. package/dist/rgrc.js +87318 -67610
  336. package/package.json +1010 -1040
  337. package/dist/README.md +0 -117
  338. package/dist/package.json +0 -47
@@ -0,0 +1,380 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; ==============================================================================
4
+ ; VectorViewBox.rgr — the one place that decides what vector coordinates mean
5
+ ; ==============================================================================
6
+ ; PLAN_VECTOR_IR.md §2.1 and §5 Stage 0.
7
+ ;
8
+ ; Before this file, each renderer answered "where on the page does user unit
9
+ ; (10, 20) land?" for itself, and they answered differently:
10
+ ;
11
+ ; PDF fitted the path's BOUNDING BOX to the element box with independent X
12
+ ; and Y scale factors, and ignored viewBox entirely — so a non-square
13
+ ; icon was stretched, and deliberate padding inside the viewBox was
14
+ ; cropped away.
15
+ ; HTML handed viewBox to the browser, which applied real SVG semantics:
16
+ ; uniform scale, centred, letterboxed.
17
+ ;
18
+ ; Same document, two geometries. The fix is not to patch either renderer but to
19
+ ; have exactly one implementation of the SVG rule, which every renderer calls.
20
+ ;
21
+ ; The rule implemented here is SVG 1.1 viewBox / preserveAspectRatio: derive a
22
+ ; scale from viewport/viewBox on each axis, collapse the two to one (min for
23
+ ; `meet`, max for `slice`) unless alignment is `none`, then translate so the
24
+ ; requested alignment point of the scaled viewBox meets the same point of the
25
+ ; viewport.
26
+ ;
27
+ ; Nothing here renders. It returns a Matrix2D, so PDF can emit it as a `cm`
28
+ ; operand, raster can transform points before flattening, and a test can assert
29
+ ; the numbers directly against the spec — no image comparison needed.
30
+ ; ==============================================================================
31
+
32
+ ; ------------------------------------------------------------------------------
33
+ ; Matrix2D — a 2D affine transform in SVG/PDF operand order.
34
+ ;
35
+ ; | a c e | x' = a*x + c*y + e
36
+ ; | b d f | y' = b*x + d*y + f
37
+ ; | 0 0 1 |
38
+ ;
39
+ ; Deliberately the same six-number layout as an SVG `matrix(...)` and a PDF `cm`
40
+ ; operator, so handing it to either renderer needs no reordering.
41
+ ; ------------------------------------------------------------------------------
42
+ class Matrix2D {
43
+ def a:double 1.0
44
+ def b:double 0.0
45
+ def c:double 0.0
46
+ def d:double 1.0
47
+ def e:double 0.0
48
+ def f:double 0.0
49
+
50
+ sfn identity:Matrix2D () {
51
+ def m (new Matrix2D())
52
+ return m
53
+ }
54
+
55
+ sfn create:Matrix2D (ma:double mb:double mc:double md:double me:double mf:double) {
56
+ def m (new Matrix2D())
57
+ m.a = ma
58
+ m.b = mb
59
+ m.c = mc
60
+ m.d = md
61
+ m.e = me
62
+ m.f = mf
63
+ return m
64
+ }
65
+
66
+ sfn translate:Matrix2D (tx:double ty:double) {
67
+ return (Matrix2D.create(1.0 0.0 0.0 1.0 tx ty))
68
+ }
69
+
70
+ sfn scale:Matrix2D (sx:double sy:double) {
71
+ return (Matrix2D.create(sx 0.0 0.0 sy 0.0 0.0))
72
+ }
73
+
74
+ fn applyX:double (x:double y:double) {
75
+ def v:double (((a * x) + (c * y)) + e)
76
+ return v
77
+ }
78
+
79
+ fn applyY:double (x:double y:double) {
80
+ def v:double (((b * x) + (d * y)) + f)
81
+ return v
82
+ }
83
+
84
+ ; this ∘ other — apply `other` first, then this.
85
+ fn multiply:Matrix2D (o:Matrix2D) {
86
+ def na:double ((a * o.a) + (c * o.b))
87
+ def nb:double ((b * o.a) + (d * o.b))
88
+ def nc:double ((a * o.c) + (c * o.d))
89
+ def nd:double ((b * o.c) + (d * o.d))
90
+ def ne:double (((a * o.e) + (c * o.f)) + e)
91
+ def nf:double (((b * o.e) + (d * o.f)) + f)
92
+ return (Matrix2D.create(na nb nc nd ne nf))
93
+ }
94
+
95
+ fn isIdentity:boolean () {
96
+ def flat:boolean true
97
+ if ((a == 1.0) == false) { flat = false }
98
+ if ((b == 0.0) == false) { flat = false }
99
+ if ((c == 0.0) == false) { flat = false }
100
+ if ((d == 1.0) == false) { flat = false }
101
+ if ((e == 0.0) == false) { flat = false }
102
+ if ((f == 0.0) == false) { flat = false }
103
+ return flat
104
+ }
105
+ }
106
+
107
+ ; ------------------------------------------------------------------------------
108
+ ; ViewBoxRect — a parsed `viewBox="minX minY width height"`.
109
+ ;
110
+ ; `isSet` is false for a missing or malformed viewBox. Callers must check it:
111
+ ; per spec a negative or zero width/height disables rendering rather than
112
+ ; silently meaning something else, so guessing here would hide a document bug.
113
+ ; ------------------------------------------------------------------------------
114
+ class ViewBoxRect {
115
+ def minX:double 0.0
116
+ def minY:double 0.0
117
+ def width:double 0.0
118
+ def height:double 0.0
119
+ def isSet:boolean false
120
+
121
+ sfn create:ViewBoxRect (x:double y:double w:double h:double) {
122
+ def r (new ViewBoxRect())
123
+ r.minX = x
124
+ r.minY = y
125
+ r.width = w
126
+ r.height = h
127
+ r.isSet = true
128
+ return r
129
+ }
130
+
131
+ ; Back to the attribute form, for renderers that emit SVG rather than
132
+ ; consume it. Round-trips through parseViewBox.
133
+ fn asAttribute:string () {
134
+ def s:string ((to_string minX) + " " + (to_string minY))
135
+ s = (s + " " + (to_string width) + " " + (to_string height))
136
+ return s
137
+ }
138
+ }
139
+
140
+ ; ------------------------------------------------------------------------------
141
+ ; VectorViewBox — viewBox + preserveAspectRatio → Matrix2D.
142
+ ; ------------------------------------------------------------------------------
143
+ class VectorViewBox {
144
+
145
+ ; Alignment codes. X and Y are independent in SVG, so they are kept apart
146
+ ; rather than enumerating the nine combined keywords.
147
+ ; 0 = Min (left / top), 1 = Mid (centre), 2 = Max (right / bottom)
148
+ ; `none` is signalled separately, because it is the one case where the two
149
+ ; axes keep independent scales.
150
+
151
+ sfn splitTokens:[string] (s:string) {
152
+ def parts:[string]
153
+ def current:string ""
154
+ def i:int 0
155
+ def n:int (strlen s)
156
+ while (i < n) {
157
+ def ch:int (charAt s i)
158
+ def isSep:boolean false
159
+ if (ch == 32) { isSep = true }
160
+ if (ch == 9) { isSep = true }
161
+ if (ch == 10) { isSep = true }
162
+ if (ch == 13) { isSep = true }
163
+ if (ch == 44) { isSep = true }
164
+ if isSep {
165
+ if ((strlen current) > 0) {
166
+ push parts current
167
+ current = ""
168
+ }
169
+ } {
170
+ current = (current + (strfromcode ch))
171
+ }
172
+ i = (i + 1)
173
+ }
174
+ if ((strlen current) > 0) {
175
+ push parts current
176
+ }
177
+ return parts
178
+ }
179
+
180
+ ; "minX minY width height", separated by whitespace and/or commas.
181
+ ;
182
+ ; Returns an unset rect when the list is not four numbers, or when width or
183
+ ; height is not positive. SVG 1.1: a negative value is an error and zero
184
+ ; disables rendering of the element — either way there is no transform to
185
+ ; compute, and the caller decides what to do about it.
186
+ sfn parseViewBox:ViewBoxRect (s:string) {
187
+ def out (new ViewBoxRect())
188
+ def parts:[string] (VectorViewBox.splitTokens(s))
189
+ if ((array_length parts) != 4) {
190
+ return out
191
+ }
192
+ def vals:[double]
193
+ def i:int 0
194
+ while (i < 4) {
195
+ def tok:string (itemAt parts i)
196
+ def num@(optional):double (to_double tok)
197
+ if num {
198
+ push vals (unwrap num)
199
+ } {
200
+ return out
201
+ }
202
+ i = (i + 1)
203
+ }
204
+ def w:double (itemAt vals 2)
205
+ def h:double (itemAt vals 3)
206
+ if (w <= 0.0) {
207
+ return out
208
+ }
209
+ if (h <= 0.0) {
210
+ return out
211
+ }
212
+ out.minX = (itemAt vals 0)
213
+ out.minY = (itemAt vals 1)
214
+ out.width = w
215
+ out.height = h
216
+ out.isSet = true
217
+ return out
218
+ }
219
+
220
+ ; preserveAspectRatio → the three things the transform needs.
221
+ ;
222
+ ; Grammar: [defer] <align> [meet | slice], where align is "none" or one of
223
+ ; the nine xM..YM.. keywords. `defer` only applies to <image> referencing
224
+ ; another SVG, so it is accepted and ignored. An unrecognised value falls
225
+ ; back to the spec default rather than failing: an odd string should not
226
+ ; make an icon vanish.
227
+ sfn alignX:int (par:string) {
228
+ def parts:[string] (VectorViewBox.splitTokens(par))
229
+ def i:int 0
230
+ while (i < (array_length parts)) {
231
+ def tok:string (itemAt parts i)
232
+ if ((indexOf tok "xMin") == 0) { return 0 }
233
+ if ((indexOf tok "xMid") == 0) { return 1 }
234
+ if ((indexOf tok "xMax") == 0) { return 2 }
235
+ i = (i + 1)
236
+ }
237
+ return 1
238
+ }
239
+
240
+ sfn alignY:int (par:string) {
241
+ def parts:[string] (VectorViewBox.splitTokens(par))
242
+ def i:int 0
243
+ while (i < (array_length parts)) {
244
+ def tok:string (itemAt parts i)
245
+ if ((indexOf tok "YMin") > 0) { return 0 }
246
+ if ((indexOf tok "YMid") > 0) { return 1 }
247
+ if ((indexOf tok "YMax") > 0) { return 2 }
248
+ i = (i + 1)
249
+ }
250
+ return 1
251
+ }
252
+
253
+ sfn isNone:boolean (par:string) {
254
+ def parts:[string] (VectorViewBox.splitTokens(par))
255
+ def i:int 0
256
+ while (i < (array_length parts)) {
257
+ def tok:string (itemAt parts i)
258
+ if (tok == "none") { return true }
259
+ i = (i + 1)
260
+ }
261
+ return false
262
+ }
263
+
264
+ sfn isSlice:boolean (par:string) {
265
+ def parts:[string] (VectorViewBox.splitTokens(par))
266
+ def i:int 0
267
+ while (i < (array_length parts)) {
268
+ def tok:string (itemAt parts i)
269
+ if (tok == "slice") { return true }
270
+ i = (i + 1)
271
+ }
272
+ return false
273
+ }
274
+
275
+ ; The transform mapping viewBox user units onto a viewport of viewW x viewH
276
+ ; whose origin is (0, 0). Callers translate that origin into place
277
+ ; themselves — for PDF that means composing with the page flip, which is why
278
+ ; this stays viewport-local.
279
+ ;
280
+ ; SVG 1.1, in order:
281
+ ; 1. scale-x = viewW / vb.width, scale-y = viewH / vb.height
282
+ ; 2. unless align is `none`, collapse to one scale: min for meet (the
283
+ ; whole viewBox fits, with letterboxing), max for slice (the viewport
284
+ ; is covered, with overflow)
285
+ ; 3. translate by -minX/-minY scaled, then by the alignment offset
286
+ sfn resolve:Matrix2D (vb:ViewBoxRect viewW:double viewH:double par:string) {
287
+ if (vb.isSet == false) {
288
+ return (Matrix2D.identity())
289
+ }
290
+ if (viewW <= 0.0) {
291
+ return (Matrix2D.identity())
292
+ }
293
+ if (viewH <= 0.0) {
294
+ return (Matrix2D.identity())
295
+ }
296
+
297
+ def scaleX:double (viewW / vb.width)
298
+ def scaleY:double (viewH / vb.height)
299
+
300
+ if ((VectorViewBox.isNone(par)) == false) {
301
+ def uniform:double scaleX
302
+ if (VectorViewBox.isSlice(par)) {
303
+ if (scaleY > uniform) {
304
+ uniform = scaleY
305
+ }
306
+ } {
307
+ if (scaleY < uniform) {
308
+ uniform = scaleY
309
+ }
310
+ }
311
+ scaleX = uniform
312
+ scaleY = uniform
313
+ }
314
+
315
+ def tx:double (0.0 - (vb.minX * scaleX))
316
+ def ty:double (0.0 - (vb.minY * scaleY))
317
+
318
+ def slackX:double (viewW - (vb.width * scaleX))
319
+ def slackY:double (viewH - (vb.height * scaleY))
320
+
321
+ def ax:int (VectorViewBox.alignX(par))
322
+ def ay:int (VectorViewBox.alignY(par))
323
+
324
+ if (ax == 1) {
325
+ tx = (tx + (slackX / 2.0))
326
+ }
327
+ if (ax == 2) {
328
+ tx = (tx + slackX)
329
+ }
330
+ if (ay == 1) {
331
+ ty = (ty + (slackY / 2.0))
332
+ }
333
+ if (ay == 2) {
334
+ ty = (ty + slackY)
335
+ }
336
+
337
+ return (Matrix2D.create(scaleX 0.0 0.0 scaleY tx ty))
338
+ }
339
+
340
+ ; Which viewBox actually governs an element, given what the document
341
+ ; declared and where the path's ink turned out to be.
342
+ ;
343
+ ; An explicit viewBox always wins — that is the author saying what the
344
+ ; coordinate system is. When there is none, SVG proper would draw at 1:1 and
345
+ ; clip, but EVG's <Path> has always been sized by its `width`/`height` and
346
+ ; every existing document relies on the art being fitted to that box. So the
347
+ ; fallback synthesises a viewBox from the path bounds, which keeps those
348
+ ; documents working AND — the point of doing it here rather than in one
349
+ ; renderer — gives every renderer the same fallback. Previously PDF fitted
350
+ ; the bounds while HTML drew at 1:1, so the two disagreed on exactly the
351
+ ; documents that never set a viewBox, which is all of them.
352
+ ;
353
+ ; Degenerate ink (a horizontal line has zero height) yields an unset rect,
354
+ ; and the caller falls back to identity rather than dividing by zero.
355
+ sfn effectiveViewBox:ViewBoxRect (declared:string boundsX:double boundsY:double boundsW:double boundsH:double) {
356
+ def explicit:ViewBoxRect (VectorViewBox.parseViewBox(declared))
357
+ if explicit.isSet {
358
+ return explicit
359
+ }
360
+ def synth (new ViewBoxRect())
361
+ if (boundsW <= 0.0) {
362
+ return synth
363
+ }
364
+ if (boundsH <= 0.0) {
365
+ return synth
366
+ }
367
+ return (ViewBoxRect.create(boundsX boundsY boundsW boundsH))
368
+ }
369
+
370
+ ; Convenience: parse and resolve in one step, with the SVG default
371
+ ; preserveAspectRatio when none was given on the element.
372
+ sfn resolveString:Matrix2D (viewBox:string viewW:double viewH:double par:string) {
373
+ def effective:string par
374
+ if ((strlen effective) == 0) {
375
+ effective = "xMidYMid meet"
376
+ }
377
+ def vb:ViewBoxRect (VectorViewBox.parseViewBox(viewBox))
378
+ return (VectorViewBox.resolve(vb viewW viewH effective))
379
+ }
380
+ }
@@ -0,0 +1,290 @@
1
+ # `evg_agent` — the tool surface
2
+
3
+ Four verbs over an EVG document. An agent with a shell already has everything
4
+ it needs to edit one; MCP, a widget and an editor panel are transports over
5
+ exactly these, added when something needs them. The plan they belong to is
6
+ [`PLAN_AI_BRIDGE.md`](../../../docs/plans/PLAN_AI_BRIDGE.md).
7
+
8
+ ```bash
9
+ npm run agent -- outline <doc.evg.json> [--depth=N] [--at=PATH]
10
+ npm run agent -- query <doc.evg.json> <.class | #id | tag | path>
11
+ npm run agent -- patch <doc.evg.json> <ops.json> [--out=FILE]
12
+ npm run agent -- measure <doc.evg.json> [--width=N] [--height=N]
13
+ ```
14
+
15
+ ## outline — the addresses
16
+
17
+ ```
18
+ $ npm run agent -- outline lib/evg/agent/fixtures/card.evg.json --depth=1
19
+ 0 div .page width=600px height=400px background-color=rgb(246,247,249) …
20
+ 0/0 div .card width=320px height=120px background-color=rgb(255,255,255) …
21
+ 0/1 div .card width=320px height=120px background-color=rgb(255,255,255) …
22
+
23
+ … 3 deeper nodes not shown — raise --depth or pass --at to go into one
24
+ ```
25
+
26
+ The only verb that does not print JSON, because it is the only one meant to be
27
+ **read** rather than parsed. One line per node — its address, what it is, and
28
+ just the properties it actually sets — costs a fraction of the same tree as
29
+ JSON while carrying the addresses every other verb takes.
30
+
31
+ A truncated outline says so. A model that cannot see there is more will
32
+ confidently describe a document it has only the top of.
33
+
34
+ Addresses are `EVGInspect` paths: `0` is the root, `0/3` its fourth child,
35
+ `0/3/k:share` a child with a `key`. Keyed children survive a sibling being
36
+ inserted above them; unkeyed ones do not, which is the reason to key anything
37
+ an edit will come back to.
38
+
39
+ ## query — finding one
40
+
41
+ ```
42
+ $ npm run agent -- query lib/evg/agent/fixtures/card.evg.json .card
43
+ {"matches":[
44
+ {"at":"0/0","tag":"div","props":{"class-name":"card","width":"320px", …},"children":2},
45
+ {"at":"0/1","tag":"div","props":{"class-name":"card","width":"320px", …},"children":1}
46
+ ],"count":2}
47
+ ```
48
+
49
+ `.class`, `#id`, a bare tag, or a path. Not a selector engine — a compound
50
+ selector belongs to `EVGStyleSheet`, and a second weaker implementation of one
51
+ here would be worth less than the honest limit.
52
+
53
+ ## patch — the edit
54
+
55
+ Ops are the only way to change a document. Each is addressed by a path,
56
+ validated against the engine's real property set, and carries its own inverse.
57
+
58
+ ```json
59
+ {"ops":[
60
+ {"op":"set-text","at":"0/0/k:title","value":"Invoices"},
61
+ {"op":"set-prop","at":"0/0","prop":"background-color","value":"rgb(255,251,235)"},
62
+ {"op":"insert","at":"0/0","index":2,"tag":"span"},
63
+ {"op":"remove","at":"0/1"},
64
+ {"op":"move","at":"0/0/k:sub","to":"0/1","index":0}
65
+ ]}
66
+ ```
67
+
68
+ ```
69
+ $ npm run agent -- patch doc.evg.json ops.json
70
+ {"ok":true,"applied":4,"wrote":"doc.evg.json","inverse":[
71
+ {"op":"set-text","at":"0/0/k:title","value":"Orders"},
72
+ {"op":"set-prop","at":"0/0","prop":"background-color","value":"rgb(255,255,255)"},
73
+ {"op":"remove","at":"0/0/2"}
74
+ ]}
75
+ ```
76
+
77
+ `patch` answers with `layout` too — the same summary, without being asked:
78
+
79
+ ```
80
+ {"ok":true,"applied":1,"wrote":"doc.evg.json",
81
+ "layout":{"nodes":30,"count":1,"bottomFree":-13,
82
+ "findings":["0/8: bottom edge 856 is past the page height 844"]},
83
+ "inverse":[…]}
84
+ ```
85
+
86
+ An agent that patches and stops has changed a picture it cannot see. One
87
+ layout pass here costs less than the round trip it would skip.
88
+
89
+ The `inverse` list is a **runnable ops file**: save it, run `patch` with the
90
+ ops in reverse order, and the document is what it was. That is the difference
91
+ between "here is how to undo it" and "here is a description of the undo".
92
+
93
+ Four rules worth knowing before writing ops:
94
+
95
+ - **A rejected op fails the whole batch.** Nothing is applied and the document
96
+ is untouched. "3 of 5 applied" hands you a document nobody designed.
97
+ - **An op can apply and leave no trace.** A file carries only what differs from
98
+ a fresh element of that tag, and EVG's defaults are not CSS's — a div is
99
+ `flex-direction: column`. Setting a property to its default therefore removes
100
+ a line rather than adding one, and the node changed anyway. `patch` names
101
+ those ops in `atDefault` so that re-reading the file is not read as the edit
102
+ having been dropped:
103
+
104
+ ```
105
+ {"ok":true,"applied":1,"wrote":"doc.evg.json","atDefault":[
106
+ {"at":"0/0","prop":"flex-direction","value":"column","tag":"div"}
107
+ ],"note":"applied — but those values are the tag default …","inverse":[…]}
108
+ ```
109
+
110
+ - **A property that cannot be read back cannot be patched.** The patchable set
111
+ is `EVGPatch.patchableNames()` — which is also exactly what a document file
112
+ can carry, so nothing can be written down that an edit would silently drop.
113
+ - **`remove`'s inverse is in-process only.** It names a subtree the patch that
114
+ removed it is holding. A file cannot replay it; keep the pre-patch document
115
+ if you want that undo across two runs.
116
+
117
+ ## measure — the part a model cannot do for itself
118
+
119
+ ```
120
+ $ npm run agent -- measure lib/evg/agent/fixtures/broken.evg.json --width=600 --height=300
121
+ {"width":600,"height":300,"nodes":5,"findings":[
122
+ "0/0 and 0/1 overlap by 100×40",
123
+ "0/0/0 overflows its parent to the right by 200",
124
+ "0/2: right edge 820 is past the page width 600",
125
+ "0/2: bottom edge 320 is past the page height 300"
126
+ ],"count":4,"bottomFree":200}
127
+ ```
128
+
129
+ It lays the document out and answers, in numbers, whether the result is wrong.
130
+ A screenshot asks a model to *see* that — badly, and for a thousand times the
131
+ tokens. This reads it off the boxes layout already computed.
132
+
133
+ What it checks today: a node past the page, a child spilling out of a parent
134
+ that clips, and two in-flow siblings on top of each other — with the overlap
135
+ in pixels, because "they overlap" and "they overlap by 1" are different bugs.
136
+ `overflow: visible` is not a finding — the author meant it to spill. Absolutely
137
+ positioned nodes are not checked for overlap; overlapping is what they are for.
138
+
139
+ Two numbers come back on a sound document as well, because "nothing is wrong"
140
+ is not the same as "this is what it looks like":
141
+
142
+ - **`bottomFree`** — the room left under the content, absolutes excluded. A
143
+ screen that grew by a card and reports the same free space did not put the
144
+ card where you think.
145
+ - **`tight`** — neighbours less than 4px apart. Not a defect; the measurement
146
+ of one, for a caller who can decide whether 2px between two cards was meant.
147
+ - **`align`** — what does not line up. Children that share a left edge are
148
+ aligned, children whose centres agree are centred, children that agree on
149
+ neither were aligned to nothing, and the spread says by how much. This is
150
+ the defect every other check misses: a screen where each row starts at a
151
+ different x has no overlap, no overflow, and is plainly wrong to look at.
152
+ An absolutely positioned child is compared against the flow it floats over,
153
+ because it is exempt from every other check and still has to line up; when
154
+ it is off by exactly the parent's padding, the report says so, since `left`
155
+ on an absolute child is resolved from inside that padding and asking for it
156
+ again adds it twice.
157
+
158
+ ### Distances, when spacing is the question
159
+
160
+ ```
161
+ $ npm run agent -- measure doc.evg.json --boxes --at=0/2
162
+ {…,"boxes":[
163
+ {"at":"0/2","tag":"div","x":16,"y":113,"w":358,"h":64,"gapNext":8},
164
+ {"at":"0/2/0","tag":"span","x":32,"y":122,"w":65,"h":29,"gapNext":4,"text":"1,284"}
165
+ ]}
166
+ ```
167
+
168
+ Where each node really is, and how far the next sibling starts from it.
169
+ `gapNext` is the layout's answer, not the markup's: it is what `gap`, the
170
+ margins and `flex` actually produced, which is the thing a model cannot work
171
+ out from the document it just wrote. The listing is the only part of `measure`
172
+ that grows with the document, so it costs nothing until `--boxes` asks for it,
173
+ and `--at` narrows it to one subtree.
174
+
175
+ The same checks run inside the live-build server (`EVGMeasure`), so the numbers
176
+ the agent reads and the numbers the page shows cannot drift apart.
177
+
178
+ A `path` has no box — its geometry is the `d` string — so its page bounds are
179
+ read from the coordinates in `d`, control points included. That bound is looser
180
+ than the shape, which is the right way round: a shape reported as on the page
181
+ is on it. A path using `A` is left unchecked, because arc flags among the
182
+ coordinates would invent a bound rather than widen one.
183
+
184
+ **What it does NOT check, on a diagram.** A document exported from RangerFlow
185
+ is entirely absolute positions and paths, so the overlap and parent-overflow
186
+ checks have nothing to work with: a label that no longer fits the shape drawn
187
+ behind it is not a finding, because nothing in the document says the two belong
188
+ together. Off-page is caught; fit is not. Look at a diagram before believing a
189
+ count of zero.
190
+
191
+ ## A bitmap in — `evg_image_tool`
192
+
193
+ ```
194
+ $ npm run agent:image # once, to build it
195
+ $ node lib/evg/bin/evg_image_tool.js photo.png --out=photo --width=180
196
+ {"width":320,"height":221,"layers":8,"rings":126,"colors":[
197
+ {"hex":"#E3C8A6","share":0.223},
198
+ {"hex":"#F0E9D4","share":0.214},
199
+ {"hex":"#0E184D","share":0.108}
200
+ ],"wrote":{"svg":"photo.svg","ops":"photo.ops.json"},
201
+ "insertsAt":"0/0","placed":"180x124"}
202
+ ```
203
+
204
+ A model handed a photograph can describe it and cannot put it on a screen. The
205
+ bridge — `EvgBitmapTracer`, the same one the live tracer page uses —
206
+ has been here all along with nothing pointing an agent at it. This turns an
207
+ image into the two things an agent can act on:
208
+
209
+ - **the picture**, traced to flat colour layers and written out as an ops file,
210
+ so `npm run agent -- patch doc.evg.json photo.ops.json` puts it in the
211
+ document. It goes in as an `svg` node: vector, painted by the browser, the
212
+ rasteriser and the PDF backend alike, with no image loading anywhere.
213
+ - **the colours**, each with its share of the pixels — counted over the image,
214
+ not inferred from how many paths a layer produced, because one huge
215
+ background region and four hundred specks of the same colour say opposite
216
+ things about which colour the picture *is*.
217
+
218
+ The ops file is the point. A traced photograph is tens of kilobytes of
219
+ coordinates, and printing them would put every one through a model's context on
220
+ the way back into a patch. `--at` and `--index` say where the picture is
221
+ inserted, `--width` what it is placed at, and `--preset` picks how it is traced
222
+ (lineart, poster, photo, broken, print — see `EvgTraceTypes.rgr`).
223
+
224
+ ## Getting a real document in, and a picture out
225
+
226
+ The four verbs read `.evg.json`. Two neighbours in `gallery/pdf_writer/src/tools`
227
+ connect that to everything else — and both of them read either format, so
228
+ nothing below is a special path for agents:
229
+
230
+ ```bash
231
+ # a .tsx document (with its stylesheet resolved in) -> the editable format
232
+ npm run agent:import -- page.tsx page.evg.json -css themes/showcase.css -theme editorial
233
+
234
+ # the editable format -> a picture to look at
235
+ npm run agent:render -- page.evg.json page.png
236
+ npm run agent:html -- page.evg.json page.html
237
+ ```
238
+
239
+ These build the tool if it is not there and then run it — the compiled
240
+ JavaScript under `gallery/pdf_writer/bin/` is not in the repository, because a
241
+ regenerated bundle is 40 000 lines of diff nobody can review. Running the tool
242
+ directly with `node` works too, once something has built it.
243
+
244
+ There is no `render` verb here, and that is deliberate: the painters already
245
+ exist and adding a second entry point to them would be two things to keep
246
+ working instead of one.
247
+
248
+ **The conversion is checked, not asserted.** `evg_json_tool` lays the original
249
+ out, reads its own output back, lays that out too, and compares — the boxes,
250
+ and then the draw commands the two produce. It also names anything it had to
251
+ drop. `-strict` turns that report into a refusal, which is what a build step
252
+ wants.
253
+
254
+ **Stylesheets are resolved in.** Whatever `-css` decides becomes inline props
255
+ in the output, so the agent edits one document rather than a tree plus a
256
+ cascade it cannot see. The cost is that theming is baked: re-theming means
257
+ converting again from the source.
258
+
259
+ **Asset paths move with the document.** A `src` is resolved against the file it
260
+ is written in, so the converter re-anchors every one for wherever the output is
261
+ going. When the two places have no expressible relation — one absolute, one not
262
+ — it says so instead of writing a path that resolves somewhere else.
263
+
264
+ ## The document format
265
+
266
+ [`EVGTreeJson`](../EVGTreeJson.rgr). A node says its tag, identity, text, and
267
+ `props` — and `props` is exactly the patchable set. Only what differs from a
268
+ fresh element **of the same tag** is written, so a file stays short and a span
269
+ and a div can disagree about their defaults.
270
+
271
+ It is not a lossless container for an arbitrary EVG tree: a `path` element's
272
+ `d`, an image's `alt`, a `viewBox` — the engine has them and this format does
273
+ not. A converter into this format from JSX or a `.fig` has to say what it drops
274
+ rather than round-trip through here and call it identity.
275
+
276
+ ## Running the tests
277
+
278
+ ```bash
279
+ npm run evg:patch:test # EVGPatch and EVGTreeJson — 81 assertions
280
+ npm run agent:smoke # the four verbs, against the fixtures
281
+ npm run agent:roundtrip # every showcase page, converted and re-rendered
282
+ ```
283
+
284
+ `agent:roundtrip` is the one that matters most and the one that found every
285
+ loss so far. It converts all seventeen showcase pages and requires the PNG
286
+ rendered from the conversion to be **byte-identical** to the PNG rendered from
287
+ the original. It asks nothing and compares everything, which is why it caught
288
+ three properties the format was missing — `grid-row`, an imported SVG's source,
289
+ and the `emoji-color` tint — each of which the converter's own audit had called
290
+ clean.