xbintsc 0.5.45 → 0.5.52

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 (286) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +5 -4
  3. package/README.zh-CN.md +4 -3
  4. package/dist/src/cli/extensions.d.ts +24 -0
  5. package/dist/src/cli/extensions.js +62 -0
  6. package/dist/src/cli/extensions.js.map +1 -0
  7. package/dist/src/cli/help.d.ts +1 -1
  8. package/dist/src/cli/help.js +3 -1
  9. package/dist/src/cli/help.js.map +1 -1
  10. package/dist/src/cli/hints.js +8 -3
  11. package/dist/src/cli/hints.js.map +1 -1
  12. package/dist/src/cli/main.js +21 -28
  13. package/dist/src/cli/main.js.map +1 -1
  14. package/dist/src/diagnostics/diagnostic.d.ts +3 -1
  15. package/dist/src/diagnostics/diagnostic.js +2 -0
  16. package/dist/src/diagnostics/diagnostic.js.map +1 -1
  17. package/dist/src/driver/build-key.d.ts +2 -0
  18. package/dist/src/driver/build-key.js +1 -0
  19. package/dist/src/driver/build-key.js.map +1 -1
  20. package/dist/src/driver/compiler.js +61 -8
  21. package/dist/src/driver/compiler.js.map +1 -1
  22. package/dist/src/driver/config.d.ts +4 -0
  23. package/dist/src/driver/config.js +2 -0
  24. package/dist/src/driver/config.js.map +1 -1
  25. package/dist/src/driver/link-features.d.ts +37 -0
  26. package/dist/src/driver/link-features.js +123 -0
  27. package/dist/src/driver/link-features.js.map +1 -0
  28. package/dist/src/driver/options.d.ts +10 -0
  29. package/dist/src/driver/runtime-objects.d.ts +5 -0
  30. package/dist/src/driver/runtime-objects.js +20 -1
  31. package/dist/src/driver/runtime-objects.js.map +1 -1
  32. package/dist/src/driver/usage.d.ts +23 -0
  33. package/dist/src/driver/usage.js +353 -0
  34. package/dist/src/driver/usage.js.map +1 -0
  35. package/dist/src/driver/version.d.ts +1 -1
  36. package/dist/src/driver/version.js +1 -1
  37. package/dist/src/extensions/catalog.js +1 -2
  38. package/dist/src/extensions/catalog.js.map +1 -1
  39. package/dist/src/extensions/gui/features.d.ts +34 -0
  40. package/dist/src/extensions/gui/features.js +165 -0
  41. package/dist/src/extensions/gui/features.js.map +1 -0
  42. package/dist/src/extensions/gui/index.js +10 -4
  43. package/dist/src/extensions/gui/index.js.map +1 -1
  44. package/dist/src/extensions/link-feature.d.ts +70 -0
  45. package/dist/src/extensions/link-feature.js +18 -0
  46. package/dist/src/extensions/link-feature.js.map +1 -0
  47. package/dist/src/extensions/registry.d.ts +24 -4
  48. package/dist/src/extensions/registry.js +26 -3
  49. package/dist/src/extensions/registry.js.map +1 -1
  50. package/dist/src/index.d.ts +3 -2
  51. package/dist/src/index.js +0 -1
  52. package/dist/src/index.js.map +1 -1
  53. package/dist/tests/cli/hints.test.js +5 -7
  54. package/dist/tests/cli/hints.test.js.map +1 -1
  55. package/dist/tests/driver/link-features.test.js +105 -0
  56. package/dist/tests/driver/link-features.test.js.map +1 -0
  57. package/dist/tests/driver/usage.test.d.ts +1 -0
  58. package/dist/tests/driver/usage.test.js +88 -0
  59. package/dist/tests/driver/usage.test.js.map +1 -0
  60. package/dist/tests/e2e/gui-audio.test.js +4 -4
  61. package/dist/tests/e2e/gui-audio.test.js.map +1 -1
  62. package/dist/tests/e2e/gui-css-coverage.test.d.ts +9 -0
  63. package/dist/tests/e2e/gui-css-coverage.test.js +333 -0
  64. package/dist/tests/e2e/gui-css-coverage.test.js.map +1 -0
  65. package/dist/tests/e2e/gui-css-features.test.d.ts +6 -0
  66. package/dist/tests/e2e/gui-css-features.test.js +270 -0
  67. package/dist/tests/e2e/gui-css-features.test.js.map +1 -0
  68. package/dist/tests/e2e/gui-effects.test.js +92 -11
  69. package/dist/tests/e2e/gui-effects.test.js.map +1 -1
  70. package/dist/tests/e2e/gui-feature-linking.test.d.ts +9 -0
  71. package/dist/tests/e2e/gui-feature-linking.test.js +68 -0
  72. package/dist/tests/e2e/gui-feature-linking.test.js.map +1 -0
  73. package/dist/tests/e2e/gui-font-face.test.d.ts +10 -0
  74. package/dist/tests/e2e/gui-font-face.test.js +142 -0
  75. package/dist/tests/e2e/gui-font-face.test.js.map +1 -0
  76. package/dist/tests/e2e/gui-fonts.test.d.ts +10 -0
  77. package/dist/tests/e2e/gui-fonts.test.js +150 -0
  78. package/dist/tests/e2e/gui-fonts.test.js.map +1 -0
  79. package/dist/tests/e2e/gui-helpers.d.ts +10 -1
  80. package/dist/tests/e2e/gui-helpers.js +6 -0
  81. package/dist/tests/e2e/gui-helpers.js.map +1 -1
  82. package/dist/tests/e2e/gui-layout.test.js +7 -3
  83. package/dist/tests/e2e/gui-layout.test.js.map +1 -1
  84. package/dist/tests/e2e/gui-media-disabled.test.d.ts +5 -4
  85. package/dist/tests/e2e/gui-media-disabled.test.js +7 -6
  86. package/dist/tests/e2e/gui-media-disabled.test.js.map +1 -1
  87. package/dist/tests/e2e/gui-media.test.d.ts +5 -4
  88. package/dist/tests/e2e/gui-media.test.js +9 -9
  89. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  90. package/dist/tests/e2e/gui-paint.test.js +5 -2
  91. package/dist/tests/e2e/gui-paint.test.js.map +1 -1
  92. package/dist/tests/e2e/gui-shaping.test.d.ts +5 -0
  93. package/dist/tests/e2e/gui-shaping.test.js +47 -0
  94. package/dist/tests/e2e/gui-shaping.test.js.map +1 -0
  95. package/dist/tests/e2e/gui-track-sizing.test.d.ts +6 -0
  96. package/dist/tests/e2e/gui-track-sizing.test.js +173 -0
  97. package/dist/tests/e2e/gui-track-sizing.test.js.map +1 -0
  98. package/dist/tests/e2e/gui-transform.test.js +3 -2
  99. package/dist/tests/e2e/gui-transform.test.js.map +1 -1
  100. package/dist/tests/e2e/gui-webgl-pipeline-cache.test.d.ts +18 -0
  101. package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js +120 -0
  102. package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js.map +1 -0
  103. package/dist/tests/extensions/gui-features.test.d.ts +1 -0
  104. package/dist/tests/extensions/gui-features.test.js +175 -0
  105. package/dist/tests/extensions/gui-features.test.js.map +1 -0
  106. package/doc/ai/cli.md +5 -1
  107. package/doc/ai/extensions.md +56 -26
  108. package/doc/ai/troubleshooting.md +10 -7
  109. package/doc/ai/zh-CN/cli.md +5 -1
  110. package/doc/ai/zh-CN/extensions.md +48 -22
  111. package/doc/ai/zh-CN/troubleshooting.md +6 -5
  112. package/doc/gui/animation.md +39 -9
  113. package/doc/gui/api.md +2 -1
  114. package/doc/gui/build.md +137 -19
  115. package/doc/gui/canvas.md +1 -1
  116. package/doc/gui/dom.md +20 -4
  117. package/doc/gui/known-issues.md +63 -26
  118. package/doc/gui/layout.md +31 -8
  119. package/doc/gui/media.md +13 -7
  120. package/doc/gui/rendering.md +114 -39
  121. package/doc/gui/runtime.md +5 -0
  122. package/doc/gui/webgl.md +24 -6
  123. package/doc/gui.md +110 -47
  124. package/doc/implemented/cli.md +2 -0
  125. package/doc/implemented/extensions.md +9 -3
  126. package/doc/npm-package.md +4 -4
  127. package/doc/xbintsc.config.schema.json +10 -0
  128. package/doc/zh-CN/gui/animation.md +33 -10
  129. package/doc/zh-CN/gui/api.md +2 -1
  130. package/doc/zh-CN/gui/build.md +110 -16
  131. package/doc/zh-CN/gui/canvas.md +1 -1
  132. package/doc/zh-CN/gui/dom.md +16 -3
  133. package/doc/zh-CN/gui/known-issues.md +45 -15
  134. package/doc/zh-CN/gui/layout.md +23 -6
  135. package/doc/zh-CN/gui/media.md +11 -6
  136. package/doc/zh-CN/gui/rendering.md +84 -26
  137. package/doc/zh-CN/gui/runtime.md +3 -0
  138. package/doc/zh-CN/gui/webgl.md +3 -3
  139. package/doc/zh-CN/gui.md +92 -41
  140. package/doc/zh-CN/implemented/cli.md +2 -0
  141. package/doc/zh-CN/implemented/extensions.md +9 -3
  142. package/doc/zh-CN/npm-package.md +4 -3
  143. package/package.json +7 -7
  144. package/runtime/ext_gui/animation_values.cpp +425 -0
  145. package/runtime/ext_gui/animation_values.h +64 -0
  146. package/runtime/ext_gui/browser.cpp +22 -15
  147. package/runtime/ext_gui/browser_loop.cpp +13 -1
  148. package/runtime/ext_gui/canvas.h +1 -1
  149. package/runtime/ext_gui/canvas_raster.cpp +1 -1
  150. package/runtime/ext_gui/canvas_text.cpp +1 -1
  151. package/runtime/ext_gui/css.cpp +172 -21
  152. package/runtime/ext_gui/css.h +75 -4
  153. package/runtime/ext_gui/css_match.cpp +4 -0
  154. package/runtime/ext_gui/css_sheet.cpp +218 -2
  155. package/runtime/ext_gui/document.cpp +42 -192
  156. package/runtime/ext_gui/document.h +25 -12
  157. package/runtime/ext_gui/document_animation.cpp +428 -0
  158. package/runtime/ext_gui/dom_api_canvas.cpp +15 -8
  159. package/runtime/ext_gui/dom_api_canvas_extra.cpp +44 -20
  160. package/runtime/ext_gui/dom_api_canvas_image.cpp +3 -1
  161. package/runtime/ext_gui/dom_api_node_read.cpp +10 -0
  162. package/runtime/ext_gui/dom_api_offscreen.cpp +3 -1
  163. package/runtime/ext_gui/dom_api_style.cpp +7 -0
  164. package/runtime/ext_gui/dom_api_webgl_internal.h +4 -0
  165. package/runtime/ext_gui/dom_api_webgl_source.cpp +5 -2
  166. package/runtime/ext_gui/effect_values.cpp +245 -21
  167. package/runtime/ext_gui/gpu_bridge.c +28 -0
  168. package/runtime/ext_gui/gpu_feature.cpp +30 -0
  169. package/runtime/ext_gui/gpu_shader.cpp +22 -0
  170. package/runtime/ext_gui/gpu_shader_api.h +50 -0
  171. package/runtime/ext_gui/gradient_values.cpp +24 -0
  172. package/runtime/ext_gui/grid_values.cpp +23 -0
  173. package/runtime/ext_gui/gui.cpp +6 -37
  174. package/runtime/ext_gui/gui_canvas.cpp +14 -6
  175. package/runtime/ext_gui/gui_cursor.cpp +50 -0
  176. package/runtime/ext_gui/gui_engine.h +1 -18
  177. package/runtime/ext_gui/gui_events.cpp +19 -6
  178. package/runtime/ext_gui/gui_internal.h +3 -0
  179. package/runtime/ext_gui/gui_webgl.cpp +25 -10
  180. package/runtime/ext_gui/image_api.cpp +18 -0
  181. package/runtime/ext_gui/image_api.h +43 -0
  182. package/runtime/ext_gui/image_bitmap_browser.cpp +20 -11
  183. package/runtime/ext_gui/image_bridge.c +22 -0
  184. package/runtime/ext_gui/image_feature.cpp +107 -0
  185. package/runtime/ext_gui/inline_svg.cpp +95 -8
  186. package/runtime/ext_gui/inline_svg.h +5 -1
  187. package/runtime/ext_gui/layout.cpp +15 -9
  188. package/runtime/ext_gui/layout.h +8 -2
  189. package/runtime/ext_gui/layout_flex.cpp +134 -29
  190. package/runtime/ext_gui/layout_flow.cpp +58 -7
  191. package/runtime/ext_gui/layout_flow_internal.h +39 -4
  192. package/runtime/ext_gui/layout_grid.cpp +31 -0
  193. package/runtime/ext_gui/layout_inline.cpp +26 -2
  194. package/runtime/ext_gui/layout_vertical.cpp +196 -0
  195. package/runtime/ext_gui/media.cpp +4 -2
  196. package/runtime/ext_gui/media.h +3 -3
  197. package/runtime/ext_gui/media_api.h +7 -6
  198. package/runtime/ext_gui/paint.cpp +67 -9
  199. package/runtime/ext_gui/paint.h +61 -8
  200. package/runtime/ext_gui/paint_backdrop.cpp +211 -0
  201. package/runtime/ext_gui/paint_background.cpp +175 -97
  202. package/runtime/ext_gui/paint_effects.cpp +12 -6
  203. package/runtime/ext_gui/paint_internal.h +27 -0
  204. package/runtime/ext_gui/paint_outline.cpp +44 -0
  205. package/runtime/ext_gui/paint_shadow.cpp +368 -0
  206. package/runtime/ext_gui/renderer.cpp +15 -7
  207. package/runtime/ext_gui/renderer.h +11 -2
  208. package/runtime/ext_gui/renderer_backdrop.cpp +374 -0
  209. package/runtime/ext_gui/renderer_bitmap.cpp +82 -0
  210. package/runtime/ext_gui/renderer_gradient.cpp +51 -17
  211. package/runtime/ext_gui/renderer_image.cpp +19 -7
  212. package/runtime/ext_gui/renderer_internal.h +21 -0
  213. package/runtime/ext_gui/renderer_layer.cpp +37 -6
  214. package/runtime/ext_gui/renderer_text.cpp +2 -1
  215. package/runtime/ext_gui/stb_truetype.h +5077 -0
  216. package/runtime/ext_gui/style.cpp +62 -8
  217. package/runtime/ext_gui/style.h +111 -4
  218. package/runtime/ext_gui/style_cascade.cpp +83 -0
  219. package/runtime/ext_gui/style_internal.h +13 -1
  220. package/runtime/ext_gui/style_length.cpp +92 -0
  221. package/runtime/ext_gui/style_print.cpp +83 -2
  222. package/runtime/ext_gui/style_svg.cpp +40 -0
  223. package/runtime/ext_gui/style_text.cpp +302 -0
  224. package/runtime/ext_gui/style_ui.cpp +150 -0
  225. package/runtime/ext_gui/style_values.cpp +76 -62
  226. package/runtime/ext_gui/style_values_internal.h +23 -0
  227. package/runtime/ext_gui/text.cpp +27 -499
  228. package/runtime/ext_gui/text.h +18 -9
  229. package/runtime/ext_gui/text_api.h +45 -0
  230. package/runtime/ext_gui/text_bridge.c +23 -0
  231. package/runtime/ext_gui/text_cache.cpp +12 -3
  232. package/runtime/ext_gui/text_font_db.cpp +427 -0
  233. package/runtime/ext_gui/text_font_paths.cpp +250 -0
  234. package/runtime/ext_gui/text_font_paths.h +39 -0
  235. package/runtime/ext_gui/text_font_sfnt.cpp +396 -0
  236. package/runtime/ext_gui/text_font_sfnt.h +44 -0
  237. package/runtime/ext_gui/text_fonts.cpp +348 -0
  238. package/runtime/ext_gui/text_fonts.h +78 -0
  239. package/runtime/ext_gui/text_fonts_internal.h +77 -0
  240. package/runtime/ext_gui/text_glyph_cache.cpp +2 -2
  241. package/runtime/ext_gui/text_hb.cpp +438 -0
  242. package/runtime/ext_gui/text_stb.cpp +369 -0
  243. package/runtime/ext_gui/transform.cpp +107 -9
  244. package/runtime/ext_gui/transform.h +5 -0
  245. package/runtime/ext_gui/webgl_api.cpp +19 -0
  246. package/runtime/ext_gui/webgl_api.h +53 -0
  247. package/runtime/ext_gui/webgl_bridge.c +25 -0
  248. package/runtime/ext_gui/webgl_draw_setup.cpp +42 -1
  249. package/runtime/ext_gui/webgl_feature.cpp +82 -0
  250. package/runtime/ext_gui/webgl_feature.h +28 -0
  251. package/runtime/ext_gui/webgl_msl.cpp +41 -0
  252. package/runtime/ext_gui/webgl_msl.h +6 -0
  253. package/runtime/ext_gui/webgl_shader.cpp +40 -32
  254. package/runtime/ext_gui/window.cpp +7 -7
  255. package/runtime/ext_media/decode_audio.cpp +1 -1
  256. package/runtime/ext_media/media.cpp +1 -1
  257. package/runtime/ext_media/media_bridge.c +7 -7
  258. package/scripts/build-gui.ts +97 -98
  259. package/scripts/check-file-length.ts +1 -0
  260. package/scripts/gui-build-options.ts +122 -0
  261. package/src/cli/extensions.ts +72 -0
  262. package/src/cli/help.ts +3 -1
  263. package/src/cli/hints.ts +9 -3
  264. package/src/cli/main.ts +21 -27
  265. package/src/diagnostics/diagnostic.ts +2 -0
  266. package/src/driver/build-key.ts +3 -0
  267. package/src/driver/compiler.ts +63 -8
  268. package/src/driver/config.ts +6 -0
  269. package/src/driver/link-features.ts +163 -0
  270. package/src/driver/options.ts +10 -0
  271. package/src/driver/runtime-objects.ts +26 -1
  272. package/src/driver/usage.ts +376 -0
  273. package/src/driver/version.ts +1 -1
  274. package/src/extensions/catalog.ts +1 -2
  275. package/src/extensions/gui/features.ts +166 -0
  276. package/src/extensions/gui/index.ts +10 -4
  277. package/src/extensions/link-feature.ts +72 -0
  278. package/src/extensions/registry.ts +45 -4
  279. package/src/index.ts +3 -2
  280. package/dist/src/extensions/media/index.d.ts +0 -28
  281. package/dist/src/extensions/media/index.js +0 -59
  282. package/dist/src/extensions/media/index.js.map +0 -1
  283. package/dist/tests/extensions/media.test.js +0 -63
  284. package/dist/tests/extensions/media.test.js.map +0 -1
  285. package/src/extensions/media/index.ts +0 -65
  286. /package/dist/tests/{extensions/media.test.d.ts → driver/link-features.test.d.ts} +0 -0
package/doc/gui.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # xbintsc GUI extension (self-hosted HTML/CSS renderer)
2
2
 
3
- Status: **M20** — features (M1–M15) are complete: HTML parsing, CSS selector
3
+ Status: **M22** — features (M1–M15) are complete: HTML parsing, CSS selector
4
4
  matching, the cascade, computed styles and layout (block, inline, Flexbox and
5
5
  CSS positioning) are
6
6
  in place, and the engine *paints*: it builds a display list of rectangles, images
@@ -21,13 +21,15 @@ what `examples/gui/pelican-bike` — a playable 2D game — is built on. **M12**
21
21
  DOM node lifetime explicit (what a mutation releases, what it keeps) and gives the
22
22
  engine bounded memory: see [Node lifetime](./gui/dom.md#node-lifetime) and
23
23
  [Memory & GC](./gui/runtime.md#memory--gc). **M13** plays real
24
- `<video>`/`<audio>` — the optional `media` extension decodes them on the main
25
- thread with a vendored minimal FFmpeg, video frames go through the image texture
26
- path and audio to an SDL stream, with the DOM media API exposing
27
- `play`/`pause`/`currentTime`/… and media events. Enabling `gui` alone does not
24
+ `<video>`/`<audio>` — the optional **`media` link feature** decodes them on the
25
+ main thread with a vendored minimal FFmpeg, video frames go through the image
26
+ texture path and audio to an SDL stream, with the DOM media API exposing
27
+ `play`/`pause`/`currentTime`/… and media events. The compiler selects the
28
+ feature from the program (a `<video>`/`<audio>` element, `new Audio()`,
29
+ `decodeAudioData`, or markup built at run time), so a DOM/CSS program does not
28
30
  link FFmpeg. The browser globals also get a real `AudioContext`: a 48 kHz mixer
29
31
  in `runtime/ext_gui/audio_mixer.cpp` plus `decodeAudioData` (WAV in-engine,
30
- compressed formats through `media`) — see
32
+ compressed formats through the `media` feature) — see
31
33
  [GUI API](./gui/api.md#web-audio).
32
34
  **M14** adds `<canvas>` with a self-written 2D software rasteriser (anti-aliased
33
35
  fills, paths, text and `drawImage`) uploaded through the image texture path —
@@ -38,17 +40,21 @@ them) can be translated, scaled and rotated without reflowing anything — and
38
40
  `transition: transform`, so those poses animate. See
39
41
  [Layout](./gui/layout.md#transforms-m15) and
40
42
  [Animation](./gui/animation.md#css-transforms-m15).
41
- **M17** adds real **WebGL 1.0**, and **M18** adds **WebGL 2.0**: `<canvas>.getContext("webgl2")` accepts `#version 300 es` shaders, vertex-array objects, instanced draws and sampler objects, all compiled to SPIR-V by the bundled glslang (and to MSL by the bundled SPIRV-Cross on Metal) and rendered through SDL_GPU. Geometry, lighting, texture sampling and blending run on the GPU and the page composites the colour texture without a readback — see [WebGL](./gui/webgl.md).
43
+ **M17** adds real **WebGL 1.0**, and **M18** adds **WebGL 2.0**: `<canvas>.getContext("webgl2")` accepts `#version 300 es` shaders, vertex-array objects, instanced draws and sampler objects, all compiled to SPIR-V by the bundled glslang (and to MSL by the bundled SPIRV-Cross on Metal) and rendered through SDL_GPU. Geometry, lighting, texture sampling and blending run on the GPU and the page composites the colour texture without a readback — see [WebGL](./gui/webgl.md). glslang is an optional **`gpu` link feature** shared with `mix-blend-mode`; the WebGL context/DOM bindings are the separate **`webgl` feature**, which requires `gpu`. A DOM/2D-canvas page links neither.
42
44
  **M19** fills in the decorative CSS layer: `@media` queries, generated content
43
45
  (`::before`/`::after`), multi-layer linear/radial/repeating backgrounds,
44
46
  `text-shadow`, `clip-path`, `mix-blend-mode` (through an offscreen compositor)
45
- and the `filter` colour/shadow effects. `backdrop-filter` still needs a backdrop
46
- snapshot, and true group blur remains an approximation — see
47
+ and the `filter` colour effects. See
47
48
  [Rendering](./gui/rendering.md#backgrounds-generated-content-and-effects-m19).
48
49
  **M20** makes large documents interactive: `@media` is evaluated once per rule,
49
50
  layout and paint share a bounded shaping cache, and a frame only does (and
50
51
  presents) the work a change requires — see
51
52
  [Performance](./gui/rendering.md#performance-m20).
53
+ **M21** completes the value/animation gaps: `calc()` arithmetic everywhere a
54
+ length is accepted, true Gaussian `text-shadow`/`box-shadow`, backdrop
55
+ compositing, `@keyframes` and the full transition timing-function set. See
56
+ [Rendering](./gui/rendering.md#backgrounds-generated-content-and-effects-m19)
57
+ and [Animation](./gui/animation.md#css-animations-keyframes).
52
58
  This overview records the locked decisions, the architecture, the milestone plan
53
59
  and the current progress; the engine itself is documented by function in the
54
60
  pages above.
@@ -100,7 +106,8 @@ pages above.
100
106
  | 4 | The engine is **not self-hosted** (it is C/C++, not TS), but must not affect the compiler's platform-agnostic design. Delivered as a per-platform prebuilt archive linked via `nativeObjects`. |
101
107
  | 5 | The **event loop is generic**: the runtime exposes a generic main-loop hook and a poll primitive; nothing GUI-specific enters `runtime/`. |
102
108
  | 6 | **Multiple windows** are supported by the core object model. |
103
- | 7 | Third-party low-level libs are **statically linked into the extension archives** so releases stay self-contained; only OS frameworks are added at link time. `gui.a` carries SDL3/FreeType/HarfBuzz, and the optional `media.a` carries FFmpeg and is linked only with `--ext media`. |
109
+ | 7 | Third-party low-level libs are **statically linked into the extension archives** so releases stay self-contained; only OS frameworks are added at link time. `gui.a` carries SDL3, FreeType/HarfBuzz for the optional `shaping` feature, glslang and (on macOS only) SPIRV-Cross; the default text path uses the bundled stb_truetype. glslang and SPIRV-Cross are only *extracted* when the compiler selects the **`gpu` link feature**; Metal is the only SDL_GPU backend that consumes MSL, so merging SPIRV-Cross elsewhere would add ~2.5 MiB no driver can ask for. The WebGL context/DOM code is the **`webgl` feature** (requires `gpu`), and stb_image/NanoSVG are the **`images` feature**. The optional `media.a` carries FFmpeg and is linked only when the **`media` link feature** is selected. All features are chosen from the program's static usage; `--feature`/`--no-feature` override the scan. |
110
+ | 8 | **Heavy optional halves are link features, not extensions.** FFmpeg and glslang are selected by what the bundled HTML/CSS/TS may use, and a small C bridge (linked only when active) installs the feature's dispatch table and forces the linker to extract the implementation. This keeps one user-facing `gui` extension while a DOM-only program pays for neither stack. |
104
111
 
105
112
  ## Architecture
106
113
 
@@ -120,7 +127,7 @@ pages above.
120
127
  │
121
128
  ▼
122
129
  windowing + input (SDL3) ── multiple windows
123
- text (HarfBuzz + FreeType) ── glyph atlas / SDF
130
+ text (stb_truetype) ── glyph atlas
124
131
  images (stb_image; SVG via NanoSVG)
125
132
  media DOM + audio sink ── optional media.a (FFmpeg) installs the decoder
126
133
  ```
@@ -134,14 +141,19 @@ with `nativeObjects()`, `linkerFlags()` and `modules()`.
134
141
  | --- | --- | --- |
135
142
  | Window + input + multi-window | **SDL3** | cross-platform windows, HiDPI, IME, clipboard, DnD, close/hide events |
136
143
  | GPU | **SDL_GPU** (SDL3) | one render path over Metal / Vulkan / D3D12; avoids three backends |
137
- | Text shaping | **HarfBuzz** | correct complex-script shaping |
138
- | Glyph raster | **FreeType** | glyph outlines → GPU atlas / SDF |
144
+ | Text shaping | **stb_truetype** simple shaper; optional **`shaping`** feature links HarfBuzz + FreeType | default keeps the DOM-only binary near 3 MiB; `shaping` restores ligatures and complex-script shaping |
145
+ | Glyph raster | **stb_truetype**; FreeType only under `shaping` | TrueType outlines → grayscale atlas by default |
139
146
  | Images | **stb_image** (vendored header) for bitmaps, **NanoSVG** (vendored headers) for SVG | single headers to start; SVG files rasterise on demand |
140
- | Video + audio | **FFmpeg** (statically vendored, minimal build, optional `media` extension) | decodes the common container/codec set; no WebView or platform media framework |
147
+ | Video + audio | **FFmpeg** (statically vendored, minimal build, optional `media` link feature) | decodes the common container/codec set; no WebView or platform media framework |
141
148
 
142
- Pinned versions: SDL3 `release-3.2.10`, FreeType `2.13.3`, HarfBuzz `10.1.0`,
143
- FFmpeg `7.1` for the optional `media` archive (overridable with `SDL3_TAG` /
144
- `FREETYPE_VERSION` / `HARFBUZZ_VERSION` / `FFMPEG_VERSION`).
149
+ Pinned versions: SDL3 `release-3.2.10`, FreeType `2.13.3`, HarfBuzz `10.1.0`
150
+ (for the optional `shaping` feature), glslang `16.6.0`, SPIRV-Cross
151
+ `vulkan-sdk-1.4.313.0`, FFmpeg `7.1` for the optional `media` archive
152
+ (overridable with `SDL3_TAG` / `FREETYPE_VERSION` / `HARFBUZZ_VERSION` /
153
+ `GLSLANG_VERSION` / `SPIRV_CROSS_VERSION` / `FFMPEG_VERSION`). The default text
154
+ backend is the bundled `stb_truetype.h`; it accepts TrueType outlines (not
155
+ CFF/OTF or variable fonts). The `shaping` feature swaps in HarfBuzz + FreeType
156
+ for full OpenType shaping.
145
157
 
146
158
  Alternative if SDL3 is rejected: **GLFW + OpenGL 3.3** (simpler, but OpenGL is
147
159
  deprecated on macOS and gives no modern GPU abstraction). **wgpu-native** if the
@@ -169,10 +181,13 @@ engine were Rust.
169
181
  4. **M4 — paint + text + display list**
170
182
  - **M4a — display list + GPU shapes** ✅ background/border display list,
171
183
  rounded-rect SDL_GPU pipeline (`paint.*`, `renderer.*`).
172
- - **M4b-1 — text stack + metrics** ✅ HarfBuzz + FreeType linked into
173
- `gui.a`, font resolution/caching, shaping-based text metrics used by
174
- layout (`text.*`, `measureText`/`fontMetrics`).
175
- - **M4b-2 — glyph rendering** ✅ FreeType rasterisation, a shared shelf-packed
184
+ - **M4b-1 — text stack + metrics** ✅ the text module (`text.*`) with font
185
+ resolution/caching and shaping-based metrics used by layout
186
+ (`measureText`/`fontMetrics`); the CSS family list, weight and italic style
187
+ select real installed faces, and author `@font-face` rules load local font
188
+ files (relative URLs resolve as `file:` paths against the process working
189
+ directory). Originally HarfBuzz + FreeType, now the bundled stb_truetype.
190
+ - **M4b-2 — glyph rendering** ✅ stb_truetype rasterisation, a shared shelf-packed
176
191
  glyph atlas, textured text quads in the display list and HiDPI-aware raster
177
192
  scaling. Gradients remain.
178
193
  5. **M5 — input + events** ✅
@@ -186,8 +201,8 @@ engine were Rust.
186
201
  per-file GPU textures and textured quads (`image.*`, `svg.*`, `paint.*`,
187
202
  `renderer.*`).
188
203
  - **M6b — transitions/animations** ✅ `transition` shorthand + longhands,
189
- animated `background-color`/`color`/`border-color`/`border-radius`, retargeting
190
- and `win.advance(ms)`. `@keyframes` remain.
204
+ retargeting, `cubic-bezier()`/`steps()`, `win.advance(ms)` and (M21)
205
+ `@keyframes` with every animation longhand.
191
206
  7. **M7 — CI & releases** ✅ (Linux/macOS/Windows x64 build) / 🚧 (run + Windows arm64)
192
207
  - `compile-examples` builds `gui.a` and `media.a` on Linux and macOS
193
208
  (required), then runs the examples and `tests/e2e/gui-*.test.ts` under
@@ -199,16 +214,17 @@ engine were Rust.
199
214
  (`package-release` copies all of `runtime/`) and inside the optional
200
215
  `@xbintsc/<os>-<arch>` npm package. Windows x64 is included; Windows arm64
201
216
  still skips them.
202
- - `vendor/` (SDL3/FreeType/HarfBuzz for the GUI archive, FFmpeg for `media`)
217
+ - `vendor/` (SDL3/FreeType/HarfBuzz/glslang for the GUI archive, FFmpeg for `media`)
203
218
  is cached per OS/arch, keyed by `scripts/build-gui.ts` /
204
219
  `scripts/build-media.ts`. Windows x64 gets its own source cache plus the
205
220
  installed `vendor/ffmpeg-build-msvc/dist` prefix.
206
- - Windows x64 builds both archives in CI and links a `gui,media` program,
207
- using the same Visual Studio `vcvarsall` + bundled LLVM toolchain as a
208
- local build (`.github/actions/vs-toolchain`); the host has no GPU/Vulkan
209
- driver, so *running* the GUI/media examples there remains provisional (a
210
- failure is logged without annotating the run). The Windows arm64 job still
211
- skips both archives (see
221
+ - Windows x64 builds both archives in CI and links a `gui` program that
222
+ exercises the `media` link feature (plus an explicit `--feature media`
223
+ build), using the same Visual Studio `vcvarsall` + bundled LLVM toolchain
224
+ as a local build (`.github/actions/vs-toolchain`); the host has no
225
+ GPU/Vulkan driver, so *running* the GUI/media examples there remains
226
+ provisional (a failure is logged without annotating the run). The Windows
227
+ arm64 job still skips both archives (see
212
228
  [Open questions](./gui/known-issues.md#open-questions)).
213
229
  8. **M8 — interactive DOM** ✅
214
230
  - Element/document handles with stable identity, read/write properties via
@@ -260,15 +276,17 @@ engine were Rust.
260
276
  `tests/e2e/gui-retention.test.ts` (see [Memory & GC](./gui/runtime.md#memory--gc)).
261
277
  13. **M13 — video & audio** ✅
262
278
  - `<video>` / `<audio>` decode through a statically vendored minimal FFmpeg
263
- in the optional `media` extension (`runtime/ext_media/media.cpp`), frames
279
+ in the optional `media` link feature (`runtime/ext_media/media.cpp`); the
280
+ compiler selects it from the program and only then compiles the bridge and
281
+ links `media.a`. Frames
264
282
  upload to GPU textures through the existing image pipeline, audio is
265
283
  pushed to an SDL stream on the main thread by the GUI's audio sink, and
266
284
  the DOM media API plus `loadedmetadata`/`play`/`pause`/`ended`/
267
285
  `timeupdate`/`error` events are exposed on element handles
268
286
  (`dom_api_media.cpp`, `dom_api_proto.cpp`). Controlled from TS + CSS;
269
287
  there are no built-in controls. Example in `examples/gui/media.*`, e2e in
270
- `tests/e2e/gui-media.test.ts` (with the `media` extension) and
271
- `tests/e2e/gui-media-disabled.test.ts` (without it).
288
+ `tests/e2e/gui-media.test.ts` (auto-selected) and
289
+ `tests/e2e/gui-media-disabled.test.ts` (`--no-feature media`).
272
290
  14. **M14 — `<canvas>` 2D** ✅
273
291
  - `<canvas>` is a replaced element (`xtgui::Canvas2D`, `layout.*`), the
274
292
  `getContext("2d")` handle and drawing API live in `dom_api_canvas.cpp`,
@@ -336,16 +354,18 @@ engine were Rust.
336
354
  - Generated content: `::before`/`::after` selectors, inherited pseudo styles,
337
355
  `content` strings/escapes/`attr()`, and synthetic layout boxes that never
338
356
  leak into DOM traversal.
339
- - Multi-layer `background-image` with linear gradients painted bottom-up as
340
- solid bands (18 strips) and radial gradients rasterised per pixel into one
341
- image texture (`renderer_gradient.cpp`).
342
- - `text-shadow` as shadow text runs, including a nine-tap blur approximate.
357
+ - Multi-layer `background-image` with linear and radial gradients rasterised
358
+ per pixel into one image texture (`renderer_gradient.cpp`), so hard stops
359
+ and sub-pixel details (a 1px divider) are exact.
360
+ - `text-shadow` and `box-shadow` (outer/inset, spread, multiple layers),
361
+ blurred with a true separable Gaussian over the shape mask (M21).
343
362
  - `clip-path` polygons (`inset`/`circle`/`ellipse`/`polygon`) resolved to
344
363
  device space, ear-clipped and intersected with shape geometry in
345
364
  `renderer_clip.cpp` — no stencil/shader change.
346
365
  - `filter` colour functions, nine-tap `blur()` and silhouette
347
- `drop-shadow()`; `backdrop-filter` parses and cascades but needs an
348
- offscreen backdrop pass (see [Known issues](./gui/known-issues.md)).
366
+ `drop-shadow()`; `backdrop-filter` snapshots the scene, applies a Gaussian
367
+ and one combined colour matrix, and composites through the border-box mask
368
+ (M21).
349
369
  - E2E coverage in `tests/e2e/gui-effects.test.ts`; see
350
370
  [Rendering](./gui/rendering.md#backgrounds-generated-content-and-effects-m19).
351
371
  20. **M20 — rendering performance** ✅
@@ -360,6 +380,28 @@ engine were Rust.
360
380
  dirty frame, and redundant render-state binds removed.
361
381
  - `win.stats()`/`XT_GUI_PERF` counters and `tests/e2e/gui-perf.test.ts`; see
362
382
  [Performance](./gui/rendering.md#performance-m20).
383
+ 21. **M21 — CSS value/animation completeness** ✅
384
+ - `calc()` is parsed as an unresolved expression tree and resolved by both
385
+ layout (`toPx`) and paint; nested arithmetic, `calc()` inside
386
+ `min`/`max`/`clamp`, and calc in shadows/transforms/filters are covered.
387
+ - `box-shadow` (outer/inset, spread, multiple layers) and blurred
388
+ `text-shadow` are rasterised into a Gaussian mask, cached and composited
389
+ as one tinted image quad.
390
+ - `backdrop-filter` snapshots the painted scene and composites a Gaussian +
391
+ colour matrix through the border-box mask in a runtime-compiled shader.
392
+ - `@keyframes` plus every `animation-*` longhand (delay, iterations,
393
+ direction, fill mode, paused/running) share the property interpolator with
394
+ transitions; transitions now cover opacity, layout lengths, box shadows
395
+ and `cubic-bezier()`/`steps()`/`step-start`/`step-end`.
396
+ - E2E: `tests/e2e/gui-css-features.test.ts`.
397
+ 22. **M22 — CSS coverage for the boxing UI** ✅
398
+ - `letter-spacing`, `text-transform`, the `font` shorthand, length-form
399
+ `vertical-align`, `writing-mode` (text-only vertical layout), percentage
400
+ `border-radius`, `inline-flex`/`inline-grid`, `grid-area`, `aspect-ratio`,
401
+ auto margins, `outline` + `:focus-visible`/`:active`, `currentColor`,
402
+ `skewX()`/`skewY()`, `background-size` tiling for `url()` layers and
403
+ document CSS on SVG children (`fill`/`stroke`/…) are now honoured.
404
+ - E2E: `tests/e2e/gui-css-coverage.test.ts`.
363
405
 
364
406
  ## Progress log
365
407
 
@@ -373,9 +415,10 @@ engine were Rust.
373
415
  coverage.
374
416
  - **M4a** ✅ display list (`paint.*`) and the SDL_GPU 2D renderer with an MSL
375
417
  rounded-rect pipeline (`renderer.*`), `paintList`/`paintCount`, e2e coverage.
376
- - **M4b-1** ✅ FreeType + HarfBuzz fetched/built/merged into `gui.a`, the text
377
- module (`text.*`) with font resolution, HarfBuzz shaping and FreeType metrics,
378
- real text metrics in layout, `measureText`/`fontMetrics`, e2e coverage.
418
+ - **M4b-1** ✅ the text module (`text.*`) with font resolution, shaping and
419
+ metrics, real text metrics in layout, `measureText`/`fontMetrics`, e2e
420
+ coverage. Originally HarfBuzz + FreeType; now stb_truetype (see the stack
421
+ table and the size trade-off in [build](./gui/build.md#binary-size)).
379
422
  - **M4b-2** ✅ glyph atlas + textured text pipeline in `renderer.*`, shaped text
380
423
  runs in `paint.*`, `xt_text_shape_run`/`xt_text_rasterize` in `text.*`, HiDPI
381
424
  raster scaling, e2e coverage.
@@ -430,17 +473,19 @@ engine were Rust.
430
473
  ratcheting upwards. `win.stats()` exposes the engine counters and
431
474
  `tests/e2e/gui-retention.test.ts` pins them; a game loop rewriting its sprite
432
475
  every frame now runs in constant memory (see [Memory & GC](./gui/runtime.md#memory--gc)).
433
- - **M13** ✅ `<video>` / `<audio>` support. The optional `media` extension
476
+ - **M13** ✅ `<video>` / `<audio>` support. The optional `media` **link feature**
434
477
  vendors and builds a minimal static FFmpeg (`scripts/build-media.ts`) and
435
478
  merges it into `media.a` (or `media.lib` from clang-cl/MSVC objects on
436
- Windows); `runtime/ext_media/media.cpp` decodes video to RGBA
479
+ Windows). The compiler selects the feature from the program and only then
480
+ compiles `media_bridge.c` and links `media.a`; a DOM/CSS program never links
481
+ FFmpeg. `runtime/ext_media/media.cpp` decodes video to RGBA
437
482
  frames and audio to 48 kHz stereo PCM on the main thread,
438
483
  `runtime/ext_gui/gui_media.cpp` owns the players, implements the SDL audio
439
484
  sink and pumps the media clock and events each frame,
440
485
  `renderer_image.cpp` uploads each new video frame through the image texture
441
486
  path, and `dom_api_media.cpp` exposes `play`/`pause`/`load` plus the media
442
- properties on element handles. `gui.a` stays FFmpeg-free; enabling `media`
443
- without `gui` is rejected by the registry. `examples/gui/media.*` demonstrates
487
+ properties on element handles. `gui.a` stays FFmpeg-free.
488
+ `examples/gui/media.*` demonstrates
444
489
  the TS-plus-CSS-controls pattern and `tests/e2e/gui-media.test.ts` pins it.
445
490
  - **M14** ✅ `<canvas>` support. A new replaced element (`layout.*`) carries an
446
491
  intrinsic size from its `width`/`height` attributes (default `300x150`),
@@ -507,9 +552,27 @@ engine were Rust.
507
552
  `paint_background.cpp` resolves and paints it (radial layers become one
508
553
  `PaintGradient`, which `renderer_gradient.cpp` rasterises into a texture),
509
554
  `paint_effects.cpp` applies filter colour functions plus nine-tap
510
- blur/drop-shadow and emits `text-shadow` runs, and
555
+ blur/drop-shadow, `paint_shadow.cpp` rasterises Gaussian text/box shadows,
556
+ `paint_backdrop.cpp` + `renderer_layer.cpp` composite `backdrop-filter`, and
511
557
  `paint_clip.cpp`/`renderer_clip.cpp` clip geometry against triangulated
512
558
  `clip-path` polygons. E2E: `tests/e2e/gui-effects.test.ts`.
559
+ - **M22** ✅ CSS coverage for the boxing UI. The cascade/declaration parser
560
+ gained `letter-spacing`, `text-transform`, the `font` shorthand,
561
+ `vertical-align`, `writing-mode`, percentage `border-radius`, `outline`,
562
+ `background-size`, `currentColor` and the SVG presentation properties;
563
+ layout gained inline-level flex/grid, `grid-area`, `aspect-ratio`, auto
564
+ margins and text-only vertical writing mode; paint gained outline edges,
565
+ sized/tiled image backgrounds and rotated vertical text; `:focus-visible` is
566
+ an alias of `:focus` and `:active` is tracked from pointer down/up. E2E:
567
+ `tests/e2e/gui-css-coverage.test.ts`.
568
+ - **M21** ✅ CSS value/animation completeness. `calc()` is parsed as an
569
+ unresolved expression tree and resolved by layout/paint; `box-shadow` and
570
+ blurred `text-shadow` use a separable Gaussian mask cached as a texture;
571
+ `backdrop-filter` gets an offscreen snapshot pass; `@keyframes` (plus every
572
+ `animation-*` longhand, delay, iteration, direction and fill mode) shares the
573
+ property interpolator with transitions, which now also cover opacity, layout
574
+ lengths, box shadows and `cubic-bezier()`/`steps()`. E2E:
575
+ `tests/e2e/gui-css-features.test.ts`.
513
576
  - **M20** ✅ rendering performance. `@media` is evaluated once per rule per
514
577
  restyle, generated content is skipped for sheets without `::before`/`::after`,
515
578
  and `:hover`/`:focus` only restyle when the sheet tracks them
@@ -29,6 +29,8 @@ default; `--no-check` skips it (and is part of the cache key). See
29
29
  --emit <kind> exe | obj | ir (default: exe)
30
30
  -O0..-O3 Optimization level (default: -O2)
31
31
  --ext <names> Comma separated extensions (e.g. node)
32
+ --feature <names> Force optional link features on (media,gpu,images,shaping,webgl,all)
33
+ --no-feature <n> Keep optional link features out even when detected
32
34
  --ext-native <m> Register a C++/Rust extension from a JSON manifest
33
35
  --config <path> Use a project config (default: xbintsc.config.json)
34
36
  --no-config Do not read any project config
@@ -2,10 +2,16 @@
2
2
 
3
3
  > Part of [Implemented syntax and features](../implemented.md) · [简体中文](../zh-CN/implemented/extensions.md)
4
4
 
5
- Location: `src/extensions/registry.ts`, `src/extensions/node/`
5
+ Location: `src/extensions/registry.ts`, `src/extensions/node/`, `src/extensions/link-feature.ts`, `src/driver/usage.ts`, `src/driver/link-features.ts`
6
6
 
7
- - An extension is a plain object: `runtimeSources()` (extra C sources), `linkerFlags()` (extra link flags), `builtins()` (global identifier → runtime symbol, uniform `(argc, argv)` ABI) and `modules()` (import specifier → named exports / namespace).
8
- - `ExtensionRegistry`: register / unregister / lookup / aggregate builtins, modules, runtime sources and link flags.
7
+ - An extension is a plain object: `runtimeSources()` (extra C sources), `linkerFlags()` (extra link flags), `builtins()` (global identifier → runtime symbol, uniform `(argc, argv)` ABI), `modules()` (import specifier → named exports / namespace) and `linkFeatures()` (optional heavy capabilities).
8
+ - `ExtensionRegistry`: register / unregister / lookup / aggregate builtins, modules, runtime sources, link flags and link features.
9
+ - **Optional link features** (`media`, `gpu`, `images`, `shaping`, `webgl`):
10
+ - A feature declares `runtimeSources()` (a C bridge compiled only when active), `nativeObjects()` (archives linked only when active), `linkerFlags()`, optional `requires` (another feature it depends on) and `used(usage)`.
11
+ - The driver builds `ProgramUsage` from the bundled AST (`collectUsage` in `src/driver/usage.ts`): string literals (including imported HTML and inlined CSS), identifiers/property names, `getContext(...)` kinds, and whether markup can be built at run time. Simple `const` aliases are resolved; unresolved markup makes the program conservative.
12
+ - `resolveLinkFeatures` applies `--feature` / `--no-feature` (and `all`), expands `requires`, reports an unavailable auto-detected feature as a warning and a forced one as an error, and returns the bridges/archives/flags to link.
13
+ - The bridge is the strong reference: its constructor installs the feature's dispatch table and its references force the linker to extract the implementation. With no bridge, the table stays null and the implementation members are never linked.
14
+ - Current clients: `media` (FFmpeg, `runtime/ext_media/media_bridge.c` + `media.a`), `gpu` (glslang/SPIRV-Cross, `runtime/ext_gui/gpu_bridge.c` + `gpu_feature.cpp` inside `gui.a`), `images` (stb_image/NanoSVG, `runtime/ext_gui/image_bridge.c` + `image_feature.cpp`), `shaping` (HarfBuzz/FreeType, `runtime/ext_gui/text_bridge.c` + `text_hb.cpp`), and `webgl` (context/DOM bindings, `runtime/ext_gui/webgl_bridge.c` + `webgl_feature.cpp`, requiring `gpu`).
9
15
  - The built-in core extension `core`: exposes `print` (mapped to `xt_println`), always registered.
10
16
  - The Node extension `node`:
11
17
  - Modular organisation: `src/extensions/node/fs/` + `runtime/ext_node/fs/read_file.c`
@@ -69,8 +69,8 @@ The package does **not** contain:
69
69
  If npm skips the optional package (`--omit=optional`, a package manager that
70
70
  does not install optional dependencies, or a host the release does not build
71
71
  for), the driver falls back to compiling the C runtime from the shipped sources
72
- and caches the objects; that build works but is slower, and `--ext gui` /
73
- `--ext media` need the archive to be present.
72
+ and caches the objects; that build works but is slower, and `--ext gui` (plus
73
+ the auto-selected `media`/`gpu`/`images`/`shaping`/`webgl` link features) needs the archive to be present.
74
74
 
75
75
  ## Requirements
76
76
 
@@ -398,7 +398,7 @@ jobs:
398
398
  | --- | --- | --- |
399
399
  | Needs Node.js | Yes, 22+ | No |
400
400
  | First build | Links the prebuilt runtime from the optional platform package | Links the prebuilt runtime |
401
- | GUI / media extensions | Included on Linux/macOS and Windows x64 (the hosts the release builds them for) | Included in Linux/macOS and Windows x64 archives |
401
+ | GUI engine + media archive | Included on Linux/macOS and Windows x64 (the hosts the release builds them for) | Included in Linux/macOS and Windows x64 archives |
402
402
  | Installation | `npm install` + lockfile / provenance | Download, verify `.sha256`, unpack |
403
403
  | Programmatic API | Yes | No (CLI only) |
404
404
  | Cross-compiles | No — host only | No — host only |
@@ -439,7 +439,7 @@ the same file under `node_modules/xbintsc/doc/ai/`.
439
439
  | The first build takes a long time | The optional `@xbintsc/<os>-<arch>` package was skipped (or this host has no prebuilt package), so the runtime C sources are compiled and cached. Check `npm ls @xbintsc/<os>-<arch>` and reinstall without `--omit=optional`; `--time` confirms. |
440
440
  | Permission errors writing `.xbintsc/` | Set `xbintsc_CACHE_DIR` to a writable directory, or run from a writable working directory. |
441
441
  | `module 'fs' is provided by the 'node' extension` | Add `--ext node`, or `"extensions": ["node"]` in the config. |
442
- | `GUI native library not found` / `media native library not found` | The optional platform package that ships `gui.a`/`gui.lib` or `media.a`/`media.lib` was skipped, or this host has no prebuilt GUI/media archive (Windows arm64). Reinstall without `--omit=optional`, use a Linux/macOS/Windows x64 release archive, or build the archive from a source checkout. |
442
+ | `GUI native library not found` / `media native library not found` | The optional platform package that ships `gui.a`/`gui.lib` or `media.a`/`media.lib` was skipped, or this host has no prebuilt GUI/media archive (Windows arm64). Reinstall without `--omit=optional`, use a Linux/macOS/Windows x64 release archive, or build the archive from a source checkout. An auto-detected `media` feature with a missing archive only warns; `--feature media` makes it an error. |
443
443
  | `require("xbintsc")` fails | The package is ESM-only; use `import` (or dynamic `import()`). |
444
444
  | Windows link errors about missing MSVC libraries | Run from a Native Tools prompt, install the VS C++ build tools, and check `npx xbintsc doctor`. |
445
445
  | `npm ci --omit=dev` then the build cannot find `xbintsc` | Install devDependencies for the build stage, or move `xbintsc` to `dependencies`. |
@@ -48,6 +48,16 @@
48
48
  "items": { "type": "string" },
49
49
  "description": "Paths to native C++/Rust extension manifests."
50
50
  },
51
+ "features": {
52
+ "type": "array",
53
+ "items": { "type": "string" },
54
+ "description": "Optional link features to force on, e.g. [\"media\", \"gpu\", \"images\", \"shaping\", \"webgl\"] or [\"all\"]."
55
+ },
56
+ "noFeatures": {
57
+ "type": "array",
58
+ "items": { "type": "string" },
59
+ "description": "Optional link features to keep out even when auto-detection finds a use."
60
+ },
51
61
  "force": {
52
62
  "type": "boolean",
53
63
  "description": "Ignore the incremental cache."
@@ -30,27 +30,49 @@ transition 的属性时,会记录一个正在运行的 transition,并在每
30
30
  结束;引擎用真实帧间隔推进时钟(`XtDocument::advance`),`win.advance(ms)`
31
31
  让测试可以确定性地推进。
32
32
 
33
- - 支持的属性:`background-color`、`color`、`border-color`、
34
- `border-radius` 与 `transform`;`transition: all` 覆盖它们。影响布局的
35
- 属性(width、position 等)仍不做动画——那会每帧重新布局——但 `transform`
36
- 是绘制期效果,因此为它做动画的代价只是每个被动画的盒子每帧一个矩阵
37
- (见[布局](./layout.md#变换m15))。
33
+ - 支持的属性:`background-color`、`color`、`border-color`、`opacity`、
34
+ `border-radius`、`transform`、`text-shadow`、`box-shadow`、所有盒模型
35
+ 偏移/尺寸长度(`width`/`height`/`top`/`left`/`margin-*`/`padding-*`/…)、
36
+ gap/flex-basis 长度,以及 `filter`(形状一致的滤镜列表会插值模糊长度、数值与
37
+ drop-shadow 颜色);`transition: all` 覆盖整个列表。单位一致的长度会插值
38
+ (单位变化按 CSS 的离散回退处理),`opacity`、颜色与 `transform` 正常插值。
38
39
  - `transition` 简写与 `transition-property` / `-duration` / `-delay` /
39
- `-timing-function` 长写都会被解析;时间值接受 `s` 与 `ms`;缓动函数为
40
- `linear`、`ease`、`ease-in`、`ease-out` 与 `ease-in-out`(`ease` 是
41
- smoothstep 近似)。
40
+ `-timing-function` 长写都会被解析;时间值接受 `s` 与 `ms`;简写/长写内
41
+ 都接受 `calc()`。
42
+ - 缓动函数支持 `linear`、`ease`、`ease-in`、`ease-out`、`ease-in-out`、
43
+ `cubic-bezier(x1, y1, x2, y2)`、`steps(n, start|end)` 及其 `jump-*` 拼写;
44
+ 三次贝塞尔用数值求解,关键字曲线使用 CSS 控制点。
42
45
  - 在动画中途重定向会从当前插值启动一个新 transition,因此反转悬停会从它
43
46
  当前所在位置平滑动画。
44
47
  - `computedStyle()` 报告显示(已插值)的值,因此 transition 在测试中可直接
45
48
  观察。
46
49
 
47
- `transform` 列表按**逐项**插值(`document.cpp`、`xt_transform_interpolate`),
50
+ `transform` 列表按**逐项**插值(`animation_values.cpp`、`xt_transform_interpolate`),
48
51
  这正是让常见的一对 `translateY(-4px) rotate(-0.35deg)` 与 `none` 之间平滑
49
52
  滑行而不是跳变的原因:缺失的一侧会用同类型的单位(identity)操作补齐。两个
50
53
  列表形状或单位对不上时(`rotate(10deg)` 对 `rotate(10rad)`,或函数个数不同)
51
54
  完全不做插值——transition 直接吸附到目标值,即 CSS 的离散回退,而不是一段
52
55
  看起来错误的扫过。
53
56
 
57
+ ## CSS 动画(`@keyframes`)
58
+
59
+ `@keyframes` 会被解析进 `StyleSheet::keyframes`(`from`/`to`/百分比选择器产生的
60
+ 偏移会排序)。支持 `animation` 简写及全部 `animation-*` 长写:名称、时长、
61
+ 延迟、时间函数、迭代次数(含 `infinite`)、方向
62
+ (`normal`/`reverse`/`alternate`/`alternate-reverse`)、填充模式
63
+ (`none`/`forwards`/`backwards`/`both`)与 `paused`/`running`。
64
+
65
+ 当计算样式首次声明某个元素/名称时,`XtDocument` 启动一个活动动画;简写变化时
66
+ 重新启动,无关的 restyle 不会打断它。每帧把本地时间解析为迭代进度,**逐个
67
+ 关键帧区间**应用时间函数,并插值所有可动画属性。中间关键帧没有提到的属性会
68
+ 在最近两个声明了它的关键帧之间继续插值(因此 0% 与 100% 声明的 transform
69
+ 即使 50% 只改 `opacity` 也会贯穿全程)。缺失的 0%/100% 步骤使用元素的底层
70
+ 样式;`forwards`/`backwards` 在活动时间之外保持边缘值,`computedStyle()`
71
+ 报告动画后的值。
72
+
73
+ 动画与 transition 共享 `animation_values.cpp`,因此属性集合、阴影列表与
74
+ `transform` 的 identity 补齐行为一致。
75
+
54
76
  ## CSS transform(M15)
55
77
 
56
78
  `transform` 与 `transform-origin` 作为*绘制期*效果得到支持
@@ -89,5 +111,6 @@ const tick = (t: number): void => {
89
111
  两种方式都由 `examples/gui/pelican-svg` 演示(逐帧摇摆 + 悬停时说明文字的
90
112
  transition),并由 `tests/e2e/gui-transform.test.ts` 固定住。
91
113
 
92
- 动画仍需完成:`@keyframes` 动画与 `cubic-bezier(...)`。
114
+ 任意可动画长度都可以使用 `calc()`(例如
115
+ `transition: width 300ms ease-out; width: calc(100% - 20px)`)。
93
116
 
@@ -128,7 +128,8 @@ requestAnimationFrame(frame);
128
128
  `getChannelData(i)` 是真正的 `Float32Array`,可以用代码逐样本填充。
129
129
  `decodeAudioData(bytes)` 返回解码后的 AudioBuffer Promise:WAV(PCM 8/16/24/32 位、
130
130
  IEEE float 32/64、A-law 与 µ-law)由引擎自身解码;MP3、AAC/M4A、Vorbis、Opus 与 FLAC
131
- 需要可选的 `media` 扩展(`--ext gui,media`),以其中的 FFmpeg 解码器作为回退。
131
+ 需要可选的 `media` 链接特性(程序调用 `decodeAudioData` 时自动选中),以其中的
132
+ FFmpeg 解码器作为回退。
132
133
  `bytes` 可以是 ArrayBuffer、类型化数组、Node `Buffer`,或 `fs.readFileSync`
133
134
  返回的原始字节字符串(本运行时没有专门的二进制类型,而该字符串的存储正是文件字节)。
134
135
  解码结果会重采样到上下文的 48 kHz,因此 `buffer.sampleRate` 与