@cortex-js/compute-engine 0.55.6 → 0.57.0

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 (258) hide show
  1. package/dist/compile.esm.js +1224 -179
  2. package/dist/compile.min.esm.js +290 -91
  3. package/dist/compile.min.umd.cjs +291 -92
  4. package/dist/compile.umd.cjs +1224 -179
  5. package/dist/compute-engine.esm.js +1973 -306
  6. package/dist/compute-engine.min.esm.js +301 -102
  7. package/dist/compute-engine.min.umd.cjs +301 -102
  8. package/dist/compute-engine.umd.cjs +1973 -306
  9. package/dist/core.esm.js +1972 -305
  10. package/dist/core.min.esm.js +300 -101
  11. package/dist/core.min.umd.cjs +300 -101
  12. package/dist/core.umd.cjs +1972 -305
  13. package/dist/interval.esm.js +360 -19
  14. package/dist/interval.min.esm.js +6 -6
  15. package/dist/interval.min.umd.cjs +6 -6
  16. package/dist/interval.umd.cjs +360 -19
  17. package/dist/latex-syntax.esm.js +427 -25
  18. package/dist/latex-syntax.min.esm.js +7 -7
  19. package/dist/latex-syntax.min.umd.cjs +7 -7
  20. package/dist/latex-syntax.umd.cjs +427 -25
  21. package/dist/math-json.esm.js +2 -2
  22. package/dist/math-json.min.esm.js +2 -2
  23. package/dist/math-json.min.umd.cjs +2 -2
  24. package/dist/math-json.umd.cjs +2 -2
  25. package/dist/numerics.esm.js +4 -2
  26. package/dist/numerics.min.esm.js +3 -3
  27. package/dist/numerics.min.umd.cjs +3 -3
  28. package/dist/numerics.umd.cjs +4 -2
  29. package/dist/types/big-decimal/big-decimal.d.ts +1 -1
  30. package/dist/types/big-decimal/index.d.ts +1 -1
  31. package/dist/types/big-decimal/transcendentals.d.ts +1 -1
  32. package/dist/types/big-decimal/utils.d.ts +1 -1
  33. package/dist/types/common/ansi-codes.d.ts +1 -1
  34. package/dist/types/common/configuration-change.d.ts +1 -1
  35. package/dist/types/common/fuzzy-string-match.d.ts +1 -1
  36. package/dist/types/common/grapheme-splitter.d.ts +1 -1
  37. package/dist/types/common/interruptible.d.ts +1 -1
  38. package/dist/types/common/one-of.d.ts +1 -1
  39. package/dist/types/common/signals.d.ts +1 -1
  40. package/dist/types/common/type/ast-nodes.d.ts +1 -1
  41. package/dist/types/common/type/boxed-type.d.ts +1 -1
  42. package/dist/types/common/type/lexer.d.ts +1 -1
  43. package/dist/types/common/type/parse.d.ts +1 -1
  44. package/dist/types/common/type/parser.d.ts +1 -1
  45. package/dist/types/common/type/primitive.d.ts +1 -1
  46. package/dist/types/common/type/reduce.d.ts +1 -1
  47. package/dist/types/common/type/serialize.d.ts +1 -1
  48. package/dist/types/common/type/subtype.d.ts +1 -1
  49. package/dist/types/common/type/type-builder.d.ts +1 -1
  50. package/dist/types/common/type/types.d.ts +2 -2
  51. package/dist/types/common/type/utils.d.ts +1 -1
  52. package/dist/types/common/utils.d.ts +1 -1
  53. package/dist/types/compile.d.ts +1 -1
  54. package/dist/types/compute-engine/assume.d.ts +1 -1
  55. package/dist/types/compute-engine/boxed-expression/abstract-boxed-expression.d.ts +6 -1
  56. package/dist/types/compute-engine/boxed-expression/apply.d.ts +1 -1
  57. package/dist/types/compute-engine/boxed-expression/arithmetic-add.d.ts +1 -1
  58. package/dist/types/compute-engine/boxed-expression/arithmetic-mul-div.d.ts +1 -1
  59. package/dist/types/compute-engine/boxed-expression/arithmetic-power.d.ts +1 -1
  60. package/dist/types/compute-engine/boxed-expression/ascii-math.d.ts +1 -1
  61. package/dist/types/compute-engine/boxed-expression/box.d.ts +1 -1
  62. package/dist/types/compute-engine/boxed-expression/boxed-dictionary.d.ts +1 -1
  63. package/dist/types/compute-engine/boxed-expression/boxed-function.d.ts +1 -1
  64. package/dist/types/compute-engine/boxed-expression/boxed-number.d.ts +1 -1
  65. package/dist/types/compute-engine/boxed-expression/boxed-operator-definition.d.ts +1 -1
  66. package/dist/types/compute-engine/boxed-expression/boxed-patterns.d.ts +1 -1
  67. package/dist/types/compute-engine/boxed-expression/boxed-string.d.ts +1 -1
  68. package/dist/types/compute-engine/boxed-expression/boxed-symbol.d.ts +1 -1
  69. package/dist/types/compute-engine/boxed-expression/boxed-tensor.d.ts +1 -1
  70. package/dist/types/compute-engine/boxed-expression/boxed-value-definition.d.ts +1 -1
  71. package/dist/types/compute-engine/boxed-expression/cache.d.ts +1 -1
  72. package/dist/types/compute-engine/boxed-expression/canonical-utils.d.ts +1 -1
  73. package/dist/types/compute-engine/boxed-expression/canonical.d.ts +1 -1
  74. package/dist/types/compute-engine/boxed-expression/compare.d.ts +1 -1
  75. package/dist/types/compute-engine/boxed-expression/constants.d.ts +1 -1
  76. package/dist/types/compute-engine/boxed-expression/expand.d.ts +1 -1
  77. package/dist/types/compute-engine/boxed-expression/expression-map.d.ts +1 -1
  78. package/dist/types/compute-engine/boxed-expression/factor.d.ts +1 -1
  79. package/dist/types/compute-engine/boxed-expression/flatten.d.ts +1 -1
  80. package/dist/types/compute-engine/boxed-expression/hold.d.ts +1 -1
  81. package/dist/types/compute-engine/boxed-expression/inequality-bounds.d.ts +1 -1
  82. package/dist/types/compute-engine/boxed-expression/init-lazy-refs.d.ts +1 -1
  83. package/dist/types/compute-engine/boxed-expression/invisible-operator.d.ts +1 -1
  84. package/dist/types/compute-engine/boxed-expression/match.d.ts +1 -1
  85. package/dist/types/compute-engine/boxed-expression/negate.d.ts +1 -1
  86. package/dist/types/compute-engine/boxed-expression/numerics.d.ts +1 -1
  87. package/dist/types/compute-engine/boxed-expression/order.d.ts +1 -1
  88. package/dist/types/compute-engine/boxed-expression/pattern-utils.d.ts +1 -1
  89. package/dist/types/compute-engine/boxed-expression/polynomial-degree.d.ts +1 -1
  90. package/dist/types/compute-engine/boxed-expression/polynomials.d.ts +1 -1
  91. package/dist/types/compute-engine/boxed-expression/predicates.d.ts +1 -1
  92. package/dist/types/compute-engine/boxed-expression/rules.d.ts +1 -1
  93. package/dist/types/compute-engine/boxed-expression/serialize.d.ts +1 -1
  94. package/dist/types/compute-engine/boxed-expression/sgn.d.ts +1 -1
  95. package/dist/types/compute-engine/boxed-expression/simplify.d.ts +1 -1
  96. package/dist/types/compute-engine/boxed-expression/solve-linear-system.d.ts +1 -1
  97. package/dist/types/compute-engine/boxed-expression/solve.d.ts +1 -1
  98. package/dist/types/compute-engine/boxed-expression/stochastic-equal.d.ts +1 -1
  99. package/dist/types/compute-engine/boxed-expression/trigonometry.d.ts +1 -1
  100. package/dist/types/compute-engine/boxed-expression/type-guards.d.ts +1 -1
  101. package/dist/types/compute-engine/boxed-expression/utils.d.ts +1 -1
  102. package/dist/types/compute-engine/boxed-expression/validate.d.ts +1 -1
  103. package/dist/types/compute-engine/collection-utils.d.ts +1 -1
  104. package/dist/types/compute-engine/compilation/base-compiler.d.ts +55 -6
  105. package/dist/types/compute-engine/compilation/compile-expression.d.ts +1 -1
  106. package/dist/types/compute-engine/compilation/constant-folding.d.ts +1 -1
  107. package/dist/types/compute-engine/compilation/glsl-target.d.ts +1 -1
  108. package/dist/types/compute-engine/compilation/gpu-target.d.ts +15 -5
  109. package/dist/types/compute-engine/compilation/interval-javascript-target.d.ts +1 -1
  110. package/dist/types/compute-engine/compilation/javascript-target.d.ts +25 -3
  111. package/dist/types/compute-engine/compilation/python-target.d.ts +1 -1
  112. package/dist/types/compute-engine/compilation/types.d.ts +1 -1
  113. package/dist/types/compute-engine/compilation/wgsl-target.d.ts +1 -1
  114. package/dist/types/compute-engine/cost-function.d.ts +1 -1
  115. package/dist/types/compute-engine/engine-assumptions.d.ts +1 -1
  116. package/dist/types/compute-engine/engine-cache.d.ts +1 -1
  117. package/dist/types/compute-engine/engine-common-symbols.d.ts +1 -1
  118. package/dist/types/compute-engine/engine-compilation-targets.d.ts +1 -1
  119. package/dist/types/compute-engine/engine-configuration-lifecycle.d.ts +1 -1
  120. package/dist/types/compute-engine/engine-declarations.d.ts +1 -1
  121. package/dist/types/compute-engine/engine-expression-entrypoints.d.ts +1 -1
  122. package/dist/types/compute-engine/engine-extension-contracts.d.ts +1 -1
  123. package/dist/types/compute-engine/engine-library-bootstrap.d.ts +1 -1
  124. package/dist/types/compute-engine/engine-numeric-configuration.d.ts +1 -1
  125. package/dist/types/compute-engine/engine-runtime-state.d.ts +1 -1
  126. package/dist/types/compute-engine/engine-scope.d.ts +1 -1
  127. package/dist/types/compute-engine/engine-sequences.d.ts +1 -1
  128. package/dist/types/compute-engine/engine-simplification-rules.d.ts +1 -1
  129. package/dist/types/compute-engine/engine-startup-coordinator.d.ts +1 -1
  130. package/dist/types/compute-engine/engine-type-resolver.d.ts +1 -1
  131. package/dist/types/compute-engine/engine-validation-entrypoints.d.ts +1 -1
  132. package/dist/types/compute-engine/free-functions.d.ts +1 -1
  133. package/dist/types/compute-engine/function-utils.d.ts +1 -1
  134. package/dist/types/compute-engine/global-types.d.ts +1 -1
  135. package/dist/types/compute-engine/index.d.ts +24 -3
  136. package/dist/types/compute-engine/interval/arithmetic.d.ts +1 -1
  137. package/dist/types/compute-engine/interval/comparison.d.ts +1 -1
  138. package/dist/types/compute-engine/interval/elementary.d.ts +1 -1
  139. package/dist/types/compute-engine/interval/index.d.ts +1 -1
  140. package/dist/types/compute-engine/interval/trigonometric.d.ts +1 -1
  141. package/dist/types/compute-engine/interval/types.d.ts +1 -1
  142. package/dist/types/compute-engine/interval/util.d.ts +1 -1
  143. package/dist/types/compute-engine/latex-syntax/dictionary/default-dictionary.d.ts +4 -3
  144. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-algebra.d.ts +1 -1
  145. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-arithmetic.d.ts +1 -1
  146. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-calculus.d.ts +1 -1
  147. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-colors.d.ts +10 -0
  148. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-complex.d.ts +1 -1
  149. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-core.d.ts +1 -1
  150. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-linear-algebra.d.ts +1 -1
  151. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-logic.d.ts +1 -1
  152. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-other.d.ts +1 -1
  153. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-relational-operators.d.ts +1 -1
  154. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-sets.d.ts +1 -1
  155. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-statistics.d.ts +1 -1
  156. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-symbols.d.ts +1 -1
  157. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-trigonometry.d.ts +1 -1
  158. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-units.d.ts +1 -1
  159. package/dist/types/compute-engine/latex-syntax/dictionary/definitions.d.ts +1 -1
  160. package/dist/types/compute-engine/latex-syntax/dictionary/indexed-types.d.ts +9 -1
  161. package/dist/types/compute-engine/latex-syntax/latex-syntax.d.ts +1 -1
  162. package/dist/types/compute-engine/latex-syntax/parse-number.d.ts +1 -1
  163. package/dist/types/compute-engine/latex-syntax/parse-symbol.d.ts +1 -1
  164. package/dist/types/compute-engine/latex-syntax/parse.d.ts +1 -1
  165. package/dist/types/compute-engine/latex-syntax/serialize-dms.d.ts +1 -1
  166. package/dist/types/compute-engine/latex-syntax/serialize-number.d.ts +1 -1
  167. package/dist/types/compute-engine/latex-syntax/serializer-style.d.ts +1 -1
  168. package/dist/types/compute-engine/latex-syntax/serializer.d.ts +1 -1
  169. package/dist/types/compute-engine/latex-syntax/tokenizer.d.ts +1 -1
  170. package/dist/types/compute-engine/latex-syntax/types.d.ts +40 -1
  171. package/dist/types/compute-engine/latex-syntax/utils.d.ts +1 -1
  172. package/dist/types/compute-engine/library/arithmetic.d.ts +1 -1
  173. package/dist/types/compute-engine/library/calculus.d.ts +1 -1
  174. package/dist/types/compute-engine/library/collections.d.ts +5 -3
  175. package/dist/types/compute-engine/library/colors.d.ts +1 -1
  176. package/dist/types/compute-engine/library/combinatorics.d.ts +1 -1
  177. package/dist/types/compute-engine/library/complex.d.ts +1 -1
  178. package/dist/types/compute-engine/library/control-structures.d.ts +1 -1
  179. package/dist/types/compute-engine/library/core.d.ts +1 -1
  180. package/dist/types/compute-engine/library/fractals.d.ts +1 -1
  181. package/dist/types/compute-engine/library/library.d.ts +1 -1
  182. package/dist/types/compute-engine/library/linear-algebra.d.ts +1 -1
  183. package/dist/types/compute-engine/library/logic-analysis.d.ts +1 -1
  184. package/dist/types/compute-engine/library/logic.d.ts +1 -1
  185. package/dist/types/compute-engine/library/number-theory.d.ts +1 -1
  186. package/dist/types/compute-engine/library/polynomials.d.ts +1 -1
  187. package/dist/types/compute-engine/library/quantity-arithmetic.d.ts +1 -1
  188. package/dist/types/compute-engine/library/random-expression.d.ts +1 -1
  189. package/dist/types/compute-engine/library/relational-operator.d.ts +1 -1
  190. package/dist/types/compute-engine/library/sets.d.ts +1 -1
  191. package/dist/types/compute-engine/library/statistics.d.ts +1 -1
  192. package/dist/types/compute-engine/library/trigonometry.d.ts +1 -1
  193. package/dist/types/compute-engine/library/type-handlers.d.ts +1 -1
  194. package/dist/types/compute-engine/library/unit-data.d.ts +1 -1
  195. package/dist/types/compute-engine/library/units.d.ts +1 -1
  196. package/dist/types/compute-engine/library/utils.d.ts +1 -1
  197. package/dist/types/compute-engine/numeric-value/big-numeric-value.d.ts +1 -1
  198. package/dist/types/compute-engine/numeric-value/exact-numeric-value.d.ts +1 -1
  199. package/dist/types/compute-engine/numeric-value/machine-numeric-value.d.ts +1 -1
  200. package/dist/types/compute-engine/numeric-value/types.d.ts +1 -1
  201. package/dist/types/compute-engine/numerics/bigint.d.ts +1 -1
  202. package/dist/types/compute-engine/numerics/expression.d.ts +1 -1
  203. package/dist/types/compute-engine/numerics/interval.d.ts +1 -1
  204. package/dist/types/compute-engine/numerics/linear-algebra.d.ts +1 -1
  205. package/dist/types/compute-engine/numerics/monte-carlo.d.ts +1 -1
  206. package/dist/types/compute-engine/numerics/numeric-bigint.d.ts +1 -1
  207. package/dist/types/compute-engine/numerics/numeric-bignum.d.ts +1 -1
  208. package/dist/types/compute-engine/numerics/numeric-complex.d.ts +1 -1
  209. package/dist/types/compute-engine/numerics/numeric.d.ts +1 -1
  210. package/dist/types/compute-engine/numerics/primes.d.ts +1 -1
  211. package/dist/types/compute-engine/numerics/rationals.d.ts +1 -1
  212. package/dist/types/compute-engine/numerics/richardson.d.ts +1 -1
  213. package/dist/types/compute-engine/numerics/special-functions.d.ts +1 -1
  214. package/dist/types/compute-engine/numerics/statistics.d.ts +1 -1
  215. package/dist/types/compute-engine/numerics/strings.d.ts +1 -1
  216. package/dist/types/compute-engine/numerics/types.d.ts +1 -1
  217. package/dist/types/compute-engine/numerics/unit-data.d.ts +1 -1
  218. package/dist/types/compute-engine/oeis.d.ts +1 -1
  219. package/dist/types/compute-engine/sequence.d.ts +1 -1
  220. package/dist/types/compute-engine/symbolic/antiderivative.d.ts +1 -1
  221. package/dist/types/compute-engine/symbolic/derivative.d.ts +1 -1
  222. package/dist/types/compute-engine/symbolic/distribute.d.ts +1 -1
  223. package/dist/types/compute-engine/symbolic/fu-cost.d.ts +1 -1
  224. package/dist/types/compute-engine/symbolic/fu-transforms.d.ts +1 -1
  225. package/dist/types/compute-engine/symbolic/fu.d.ts +1 -1
  226. package/dist/types/compute-engine/symbolic/logic-utils.d.ts +1 -1
  227. package/dist/types/compute-engine/symbolic/simplify-abs.d.ts +1 -1
  228. package/dist/types/compute-engine/symbolic/simplify-divide.d.ts +1 -1
  229. package/dist/types/compute-engine/symbolic/simplify-factorial.d.ts +1 -1
  230. package/dist/types/compute-engine/symbolic/simplify-hyperbolic.d.ts +1 -1
  231. package/dist/types/compute-engine/symbolic/simplify-infinity.d.ts +1 -1
  232. package/dist/types/compute-engine/symbolic/simplify-log.d.ts +1 -1
  233. package/dist/types/compute-engine/symbolic/simplify-logic.d.ts +1 -1
  234. package/dist/types/compute-engine/symbolic/simplify-power.d.ts +1 -1
  235. package/dist/types/compute-engine/symbolic/simplify-product.d.ts +1 -1
  236. package/dist/types/compute-engine/symbolic/simplify-rules.d.ts +1 -1
  237. package/dist/types/compute-engine/symbolic/simplify-sum.d.ts +1 -1
  238. package/dist/types/compute-engine/symbolic/simplify-trig.d.ts +1 -1
  239. package/dist/types/compute-engine/tensor/tensor-fields.d.ts +1 -1
  240. package/dist/types/compute-engine/tensor/tensors.d.ts +1 -1
  241. package/dist/types/compute-engine/types-definitions.d.ts +1 -1
  242. package/dist/types/compute-engine/types-engine.d.ts +23 -2
  243. package/dist/types/compute-engine/types-evaluation.d.ts +1 -1
  244. package/dist/types/compute-engine/types-expression.d.ts +1 -1
  245. package/dist/types/compute-engine/types-kernel-evaluation.d.ts +1 -1
  246. package/dist/types/compute-engine/types-kernel-serialization.d.ts +1 -1
  247. package/dist/types/compute-engine/types-serialization.d.ts +1 -1
  248. package/dist/types/compute-engine/types.d.ts +1 -1
  249. package/dist/types/compute-engine.d.ts +1 -2
  250. package/dist/types/core.d.ts +1 -1
  251. package/dist/types/interval.d.ts +1 -1
  252. package/dist/types/latex-syntax.d.ts +2 -2
  253. package/dist/types/math-json/symbols.d.ts +1 -1
  254. package/dist/types/math-json/types.d.ts +1 -1
  255. package/dist/types/math-json/utils.d.ts +1 -1
  256. package/dist/types/math-json.d.ts +2 -2
  257. package/dist/types/numerics.d.ts +1 -1
  258. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- /** Compute Engine 0.55.6 */
1
+ /** Compute Engine 0.57.0 */
2
2
 
3
3
  // src/compute-engine/numerics/richardson.ts
4
4
  function extrapolate(f, x0, options = {}) {
@@ -1511,6 +1511,7 @@ var SCALAR_TYPES = [
1511
1511
  ];
1512
1512
  var VALUE_TYPES = [
1513
1513
  "value",
1514
+ "color",
1514
1515
  ...COLLECTION_TYPES,
1515
1516
  ...SCALAR_TYPES
1516
1517
  ];
@@ -3206,6 +3207,7 @@ var PRIMITIVE_SUBTYPES = {
3206
3207
  symbol: [],
3207
3208
  boolean: [],
3208
3209
  string: [],
3210
+ color: [],
3209
3211
  expression: EXPRESSION_TYPES
3210
3212
  };
3211
3213
  function isPrimitiveSubtype(lhs, rhs) {
@@ -5176,6 +5178,64 @@ function parseQuantifier(kind) {
5176
5178
  }
5177
5179
 
5178
5180
  // src/compute-engine/latex-syntax/dictionary/definitions-core.ts
5181
+ var COMPONENT_ACCESS_HEADS = {
5182
+ x: "First",
5183
+ y: "Second",
5184
+ z: "Third",
5185
+ real: "Real",
5186
+ re: "Real",
5187
+ imag: "Imaginary",
5188
+ im: "Imaginary",
5189
+ count: "Length",
5190
+ total: "Sum",
5191
+ max: "Max",
5192
+ min: "Min"
5193
+ };
5194
+ function memberHead(name) {
5195
+ return COMPONENT_ACCESS_HEADS[name] ?? null;
5196
+ }
5197
+ function parseComponentAccess(parser, lhs) {
5198
+ parser.skipVisualSpace();
5199
+ if (parser.match("\\operatorname")) {
5200
+ const name = parser.parseStringGroup();
5201
+ if (name === null) return null;
5202
+ const head = memberHead(name.trim());
5203
+ if (head === null) return null;
5204
+ return [head, lhs];
5205
+ }
5206
+ const tok = parser.peek;
5207
+ if (typeof tok === "string" && tok.startsWith("\\")) {
5208
+ const bare = tok.slice(1);
5209
+ const head = memberHead(bare);
5210
+ if (head !== null) {
5211
+ parser.nextToken();
5212
+ return [head, lhs];
5213
+ }
5214
+ return null;
5215
+ }
5216
+ if (typeof tok === "string" && /^[a-zA-Z]$/.test(tok)) {
5217
+ const head = memberHead(tok);
5218
+ if (head === null) return null;
5219
+ parser.nextToken();
5220
+ return [head, lhs];
5221
+ }
5222
+ return null;
5223
+ }
5224
+ function parseWhenRestriction(parser, lhs, close) {
5225
+ parser.addBoundary(close);
5226
+ parser.skipVisualSpace();
5227
+ const cond = parser.parseExpression({ minPrec: 0 });
5228
+ if (cond === null) {
5229
+ parser.removeBoundary();
5230
+ return null;
5231
+ }
5232
+ parser.skipVisualSpace();
5233
+ if (!parser.matchBoundary()) {
5234
+ parser.removeBoundary();
5235
+ return null;
5236
+ }
5237
+ return ["When", lhs, cond];
5238
+ }
5179
5239
  function parseSequence(parser, terminator, lhs, prec, sep) {
5180
5240
  if (terminator && terminator.minPrec >= prec) return null;
5181
5241
  const result = lhs ? [lhs] : ["Nothing"];
@@ -5647,6 +5707,15 @@ var DEFINITIONS_CORE = [
5647
5707
  }
5648
5708
  },
5649
5709
  { name: "LatexTokens", serialize: serializeLatexTokens },
5710
+ // Component-access postfix: expr.member (C3)
5711
+ // The '.' trigger is consumed before the parse function is called.
5712
+ // Precedence 850 > 810 (At/indexing) so .x chains tightly.
5713
+ {
5714
+ kind: "postfix",
5715
+ precedence: 850,
5716
+ latexTrigger: ["."],
5717
+ parse: parseComponentAccess
5718
+ },
5650
5719
  {
5651
5720
  name: "At",
5652
5721
  kind: "postfix",
@@ -5667,6 +5736,29 @@ var DEFINITIONS_CORE = [
5667
5736
  latexTrigger: ["\\left", "\\lbrack"],
5668
5737
  parse: parseAt("\\right", "\\rbrack")
5669
5738
  },
5739
+ // When-restriction: `expr\left\{cond\right\}` → `When(expr, cond)` (D3)
5740
+ {
5741
+ name: "When",
5742
+ kind: "postfix",
5743
+ precedence: 800,
5744
+ latexTrigger: ["\\left", "\\{"],
5745
+ parse: (parser, lhs) => parseWhenRestriction(parser, lhs, ["\\right", "\\}"]),
5746
+ serialize: (serializer, expr) => {
5747
+ const e = operand(expr, 1);
5748
+ const cond = operand(expr, 2);
5749
+ if (!e || !cond) return "";
5750
+ const clauses = operator(cond) === "And" ? operands(cond) ?? [] : [cond];
5751
+ const inner = clauses.map((c) => `\\left\\{${serializer.serialize(c)}\\right\\}`).join("");
5752
+ return `${serializer.serialize(e)}${inner}`;
5753
+ }
5754
+ },
5755
+ // When-restriction: bare `expr\{cond\}` → `When(expr, cond)`
5756
+ {
5757
+ kind: "postfix",
5758
+ precedence: 800,
5759
+ latexTrigger: ["\\{"],
5760
+ parse: (parser, lhs) => parseWhenRestriction(parser, lhs, ["\\}"])
5761
+ },
5670
5762
  {
5671
5763
  kind: "postfix",
5672
5764
  latexTrigger: ["_"],
@@ -5749,6 +5841,29 @@ var DEFINITIONS_CORE = [
5749
5841
  return "";
5750
5842
  }
5751
5843
  },
5844
+ // Additional triggers for Range: `...`, `\ldots`, and `\dots` are
5845
+ // equivalent to `..` when used as infix operators (e.g. `[1...9]`).
5846
+ // No `name` field here — names must be unique per the dictionary rules;
5847
+ // the first Range entry owns the name. When there is no LHS the symbol
5848
+ // entries near the top of the file still fire (ContinuationPlaceholder).
5849
+ {
5850
+ latexTrigger: [".", ".", "."],
5851
+ kind: "infix",
5852
+ precedence: 800,
5853
+ parse: parseRange
5854
+ },
5855
+ {
5856
+ latexTrigger: ["\\ldots"],
5857
+ kind: "infix",
5858
+ precedence: 800,
5859
+ parse: parseRange
5860
+ },
5861
+ {
5862
+ latexTrigger: ["\\dots"],
5863
+ kind: "infix",
5864
+ precedence: 800,
5865
+ parse: parseRange
5866
+ },
5752
5867
  {
5753
5868
  latexTrigger: [";"],
5754
5869
  kind: "infix",
@@ -5933,13 +6048,24 @@ var DEFINITIONS_CORE = [
5933
6048
  const args = operands(expr);
5934
6049
  if (!args || args.length < 2) return "";
5935
6050
  const body = args[0];
5936
- const indexing = args[1];
5937
- if (operator(indexing) === "Element") {
5938
- const index = operand(indexing, 1);
5939
- const range2 = operand(indexing, 2);
5940
- if (operator(range2) === "Range") {
5941
- const lo = operand(range2, 1);
5942
- const hi = operand(range2, 2);
6051
+ const elements = args.slice(1);
6052
+ const allElements = elements.every((e) => operator(e) === "Element");
6053
+ if (!allElements) {
6054
+ return joinLatex([
6055
+ "\\operatorname{Loop}(",
6056
+ serializer.serialize(body),
6057
+ ", ",
6058
+ serializer.serialize(elements[0]),
6059
+ ")"
6060
+ ]);
6061
+ }
6062
+ if (elements.length === 1) {
6063
+ const elem = elements[0];
6064
+ const index = operand(elem, 1);
6065
+ const coll = operand(elem, 2);
6066
+ if (operator(coll) === "Range") {
6067
+ const lo = operand(coll, 1);
6068
+ const hi = operand(coll, 2);
5943
6069
  return joinLatex([
5944
6070
  "\\text{for }",
5945
6071
  serializer.serialize(index),
@@ -5951,13 +6077,27 @@ var DEFINITIONS_CORE = [
5951
6077
  serializer.serialize(body)
5952
6078
  ]);
5953
6079
  }
6080
+ return joinLatex([
6081
+ serializer.serialize(body),
6082
+ " \\operatorname{for} ",
6083
+ serializer.serialize(index),
6084
+ " = ",
6085
+ serializer.serialize(coll)
6086
+ ]);
5954
6087
  }
6088
+ const bindings = elements.map((elem) => {
6089
+ const name = operand(elem, 1);
6090
+ const coll = operand(elem, 2);
6091
+ return joinLatex([
6092
+ serializer.serialize(name),
6093
+ " = ",
6094
+ serializer.serialize(coll)
6095
+ ]);
6096
+ }).join(", ");
5955
6097
  return joinLatex([
5956
- "\\operatorname{Loop}(",
5957
6098
  serializer.serialize(body),
5958
- ", ",
5959
- serializer.serialize(indexing),
5960
- ")"
6099
+ " \\operatorname{for} ",
6100
+ bindings
5961
6101
  ]);
5962
6102
  }
5963
6103
  },
@@ -5990,6 +6130,18 @@ var DEFINITIONS_CORE = [
5990
6130
  precedence: 245,
5991
6131
  parse: (parser, until) => parseForExpression(parser, until)
5992
6132
  },
6133
+ // \operatorname{for} as postfix infix (list comprehension):
6134
+ // `body \operatorname{for} x = L_1, y = L_2`
6135
+ // Precedence 19 — just below comma (20) so the body is allowed to use
6136
+ // any operator (including comma sequencing) up to the keyword, and the
6137
+ // bindings can be comma-separated below us.
6138
+ {
6139
+ symbolTrigger: "for",
6140
+ kind: "infix",
6141
+ associativity: "none",
6142
+ precedence: 19,
6143
+ parse: (parser, lhs, until) => parseForComprehension(parser, lhs, until)
6144
+ },
5993
6145
  // \operatorname{break}
5994
6146
  {
5995
6147
  symbolTrigger: "break",
@@ -6194,7 +6346,10 @@ var DEFINITIONS_CORE = [
6194
6346
  if (!sym2 || !parser.getSymbolType(sym2).matches("function")) return null;
6195
6347
  parser.addBoundary([")"]);
6196
6348
  const expr = parser.parseExpression(until);
6197
- if (!parser.matchBoundary()) return null;
6349
+ if (!parser.matchBoundary()) {
6350
+ parser.removeBoundary();
6351
+ return null;
6352
+ }
6198
6353
  if (!parser.match("<}>")) return null;
6199
6354
  return ["Derivative", lhs, expr];
6200
6355
  }
@@ -6635,7 +6790,12 @@ function parseBrackets(parser, body) {
6635
6790
  if (isEmptySequence(body)) return ["List"];
6636
6791
  const h = operator(body);
6637
6792
  if (h === "Range" || h === "Linspace") return body;
6638
- if (h === "Sequence") return ["List", ...operands(body)];
6793
+ if (h === "Sequence") {
6794
+ const elems = operands(body);
6795
+ const inferred = tryInferRangeFromElements(elems, parser);
6796
+ if (inferred) return inferred;
6797
+ return ["List", ...elems];
6798
+ }
6639
6799
  if (h === "Delimiter") {
6640
6800
  const delim = stringValue(operand(body, 2)) ?? "...";
6641
6801
  if (delim === ";" || delim === ".;.") {
@@ -6648,12 +6808,37 @@ function parseBrackets(parser, body) {
6648
6808
  }
6649
6809
  if (delim === "," || delim === ".,.") {
6650
6810
  body = operand(body, 1);
6651
- if (operator(body) === "Sequence") return ["List", ...operands(body)];
6811
+ if (operator(body) === "Sequence") {
6812
+ const elems = operands(body);
6813
+ const inferred = tryInferRangeFromElements(elems, parser);
6814
+ if (inferred) return inferred;
6815
+ return ["List", ...elems];
6816
+ }
6652
6817
  return ["List", body ?? "Nothing"];
6653
6818
  }
6654
6819
  }
6655
6820
  return ["List", body];
6656
6821
  }
6822
+ function tryInferRangeFromElements(elems, parser) {
6823
+ if (elems.length < 4) return null;
6824
+ const penultimate = elems[elems.length - 2];
6825
+ if (symbol(penultimate) !== "ContinuationPlaceholder") return null;
6826
+ const samples = elems.slice(0, -2);
6827
+ const endExpr = elems[elems.length - 1];
6828
+ if (samples.length < 2) return null;
6829
+ const sampleNums = samples.map(machineValue);
6830
+ if (sampleNums.some((n) => n === null)) return null;
6831
+ const nums = sampleNums;
6832
+ const step = nums[nums.length - 1] - nums[nums.length - 2];
6833
+ const tol = parser.options.tolerance;
6834
+ if (Math.abs(step) < tol)
6835
+ return parser.error("degenerate-range-step", parser.index);
6836
+ for (let i = 1; i < nums.length; i++) {
6837
+ if (Math.abs(nums[i] - nums[i - 1] - step) > tol)
6838
+ return parser.error("inconsistent-range-samples", parser.index);
6839
+ }
6840
+ return ["Range", nums[0], endExpr, step];
6841
+ }
6657
6842
  function serializeList(serializer, expr) {
6658
6843
  if (nops(expr) > 1 && operands(expr).every((x) => {
6659
6844
  const op = operator(x);
@@ -6905,6 +7090,35 @@ function parseForExpression(parser, until) {
6905
7090
  ["Element", index, ["Range", lower, upper]]
6906
7091
  ];
6907
7092
  }
7093
+ function parseForComprehension(parser, lhs, until) {
7094
+ const bindingTerminator = {
7095
+ minPrec: 21,
7096
+ // Above comma (20) and ; (19), so `x = L_1` is captured whole
7097
+ condition: (p) => {
7098
+ if (until?.condition?.(p)) return true;
7099
+ const saved = p.index;
7100
+ p.skipVisualSpace();
7101
+ const isComma = p.peek === ",";
7102
+ p.index = saved;
7103
+ return isComma;
7104
+ }
7105
+ };
7106
+ const elements = [];
7107
+ do {
7108
+ parser.skipVisualSpace();
7109
+ const binding = parser.parseExpression(bindingTerminator);
7110
+ if (binding === null) break;
7111
+ const op = operator(binding);
7112
+ if (op !== "Equal" && op !== "Assign") return null;
7113
+ const name = operand(binding, 1);
7114
+ const list = operand(binding, 2);
7115
+ if (!name || !list) return null;
7116
+ elements.push(["Element", name, list]);
7117
+ parser.skipVisualSpace();
7118
+ } while (parser.match(","));
7119
+ if (elements.length === 0) return null;
7120
+ return ["Loop", lhs, ...elements];
7121
+ }
6908
7122
  function parseWhereExpression(parser, lhs, until) {
6909
7123
  const bindingTerminator = {
6910
7124
  minPrec: 21,
@@ -8793,6 +9007,8 @@ var DEFINITIONS_ARITHMETIC = [
8793
9007
  precedence: DIVISION_PRECEDENCE,
8794
9008
  parse: "Mod"
8795
9009
  },
9010
+ // Function-style alias: `\operatorname{mod}(a, b)`
9011
+ { latexTrigger: "\\operatorname{mod}", parse: "Mod" },
8796
9012
  {
8797
9013
  latexTrigger: "\\pmod",
8798
9014
  kind: "prefix",
@@ -9033,6 +9249,13 @@ var DEFINITIONS_ARITHMETIC = [
9033
9249
  const rhs = serializer.wrap(operand(expr, 2), ADDITION_PRECEDENCE + 3);
9034
9250
  return joinLatex([lhs, "-", rhs]);
9035
9251
  }
9252
+ },
9253
+ // Euclidean distance between two points (tuples of numbers).
9254
+ {
9255
+ name: "Distance",
9256
+ latexTrigger: ["\\operatorname{distance}"],
9257
+ kind: "function",
9258
+ serialize: (serializer, expr) => "\\operatorname{distance}" + serializer.wrapArguments(expr)
9036
9259
  }
9037
9260
  ];
9038
9261
  function getIndexAssignment(expr, upper) {
@@ -10457,7 +10680,9 @@ var DEFINITIONS_STATISTICS = [
10457
10680
  if (!expr || !symbol(expr)) return null;
10458
10681
  return ["Mean", expr];
10459
10682
  }
10460
- }
10683
+ },
10684
+ // Function-style alias: `\operatorname{var}(...)`
10685
+ { latexTrigger: "\\operatorname{var}", parse: "Variance" }
10461
10686
  ];
10462
10687
 
10463
10688
  // src/compute-engine/numerics/unit-data.ts
@@ -11465,7 +11690,7 @@ var DEFINITIONS_OTHERS = [
11465
11690
  36: "\\qquad"
11466
11691
  }[v] ?? "";
11467
11692
  }
11468
- }
11693
+ },
11469
11694
  // if (
11470
11695
  // [
11471
11696
  // '\\!',
@@ -11489,6 +11714,121 @@ var DEFINITIONS_OTHERS = [
11489
11714
  // name: '',
11490
11715
  // trigger: '\\check',
11491
11716
  // },
11717
+ // ---------------------------------------------------------------------------
11718
+ // Function-style aliases for collection / random operators that some
11719
+ // notations write in lowercase (e.g. `\operatorname{shuffle}(L)`).
11720
+ // The capitalized library entries already exist; these are pure parse
11721
+ // aliases so the lowercase names don't land in `unsupported-operator`.
11722
+ // ---------------------------------------------------------------------------
11723
+ { latexTrigger: "\\operatorname{random}", parse: "Random" },
11724
+ { latexTrigger: "\\operatorname{shuffle}", parse: "Shuffle" },
11725
+ { latexTrigger: "\\operatorname{repeat}", parse: "Repeat" },
11726
+ { latexTrigger: "\\operatorname{join}", parse: "Join" },
11727
+ // ---------------------------------------------------------------------------
11728
+ // Geometric primitive heads. Registered as known typed heads so consumers
11729
+ // can branch on the operator name; CE itself doesn't render them. The
11730
+ // library entries (with no evaluator) live in `library/core.ts`.
11731
+ // ---------------------------------------------------------------------------
11732
+ {
11733
+ name: "Triangle",
11734
+ latexTrigger: ["\\operatorname{triangle}"],
11735
+ kind: "function",
11736
+ serialize: (serializer, expr) => "\\operatorname{triangle}" + serializer.wrapArguments(expr)
11737
+ },
11738
+ // Desmos's geometric `vector(p1, p2)` — a directed segment between two
11739
+ // points. Routed to a dedicated head (not the existing column-vector
11740
+ // `Vector`, which has a narrower `(number+) -> vector` signature).
11741
+ {
11742
+ name: "GeometricVector",
11743
+ latexTrigger: ["\\operatorname{vector}"],
11744
+ kind: "function",
11745
+ serialize: (serializer, expr) => "\\operatorname{vector}" + serializer.wrapArguments(expr)
11746
+ },
11747
+ {
11748
+ name: "Sphere",
11749
+ latexTrigger: ["\\operatorname{sphere}"],
11750
+ kind: "function",
11751
+ serialize: (serializer, expr) => "\\operatorname{sphere}" + serializer.wrapArguments(expr)
11752
+ },
11753
+ {
11754
+ name: "Segment",
11755
+ latexTrigger: ["\\operatorname{segment}"],
11756
+ kind: "function",
11757
+ serialize: (serializer, expr) => "\\operatorname{segment}" + serializer.wrapArguments(expr)
11758
+ }
11759
+ ];
11760
+
11761
+ // src/compute-engine/latex-syntax/dictionary/definitions-colors.ts
11762
+ var DEFINITIONS_COLORS = [
11763
+ // Color constructors (one per colorspace, preserves space on evaluation)
11764
+ {
11765
+ name: "Rgb",
11766
+ latexTrigger: ["\\operatorname{rgb}"],
11767
+ kind: "function",
11768
+ serialize: (serializer, expr) => "\\operatorname{rgb}" + serializer.wrapArguments(expr)
11769
+ },
11770
+ {
11771
+ name: "Hsv",
11772
+ latexTrigger: ["\\operatorname{hsv}"],
11773
+ kind: "function",
11774
+ serialize: (serializer, expr) => "\\operatorname{hsv}" + serializer.wrapArguments(expr)
11775
+ },
11776
+ {
11777
+ name: "Hsl",
11778
+ latexTrigger: ["\\operatorname{hsl}"],
11779
+ kind: "function",
11780
+ serialize: (serializer, expr) => "\\operatorname{hsl}" + serializer.wrapArguments(expr)
11781
+ },
11782
+ {
11783
+ name: "Oklab",
11784
+ latexTrigger: ["\\operatorname{oklab}"],
11785
+ kind: "function",
11786
+ serialize: (serializer, expr) => "\\operatorname{oklab}" + serializer.wrapArguments(expr)
11787
+ },
11788
+ {
11789
+ name: "Oklch",
11790
+ latexTrigger: ["\\operatorname{oklch}"],
11791
+ kind: "function",
11792
+ serialize: (serializer, expr) => "\\operatorname{oklch}" + serializer.wrapArguments(expr)
11793
+ },
11794
+ // Conversion functions (color → color in the named space)
11795
+ {
11796
+ name: "AsRgb",
11797
+ latexTrigger: ["\\operatorname{asRgb}"],
11798
+ kind: "function",
11799
+ serialize: (serializer, expr) => "\\operatorname{asRgb}" + serializer.wrapArguments(expr)
11800
+ },
11801
+ {
11802
+ name: "AsHsv",
11803
+ latexTrigger: ["\\operatorname{asHsv}"],
11804
+ kind: "function",
11805
+ serialize: (serializer, expr) => "\\operatorname{asHsv}" + serializer.wrapArguments(expr)
11806
+ },
11807
+ {
11808
+ name: "AsHsl",
11809
+ latexTrigger: ["\\operatorname{asHsl}"],
11810
+ kind: "function",
11811
+ serialize: (serializer, expr) => "\\operatorname{asHsl}" + serializer.wrapArguments(expr)
11812
+ },
11813
+ {
11814
+ name: "AsOklab",
11815
+ latexTrigger: ["\\operatorname{asOklab}"],
11816
+ kind: "function",
11817
+ serialize: (serializer, expr) => "\\operatorname{asOklab}" + serializer.wrapArguments(expr)
11818
+ },
11819
+ {
11820
+ name: "AsOklch",
11821
+ latexTrigger: ["\\operatorname{asOklch}"],
11822
+ kind: "function",
11823
+ serialize: (serializer, expr) => "\\operatorname{asOklch}" + serializer.wrapArguments(expr)
11824
+ },
11825
+ // Perceptual difference (returns a scalar in [0, ~1])
11826
+ {
11827
+ name: "ColorDelta",
11828
+ latexTrigger: ["\\operatorname{colorDelta}"],
11829
+ kind: "function",
11830
+ serialize: (serializer, expr) => "\\operatorname{colorDelta}" + serializer.wrapArguments(expr)
11831
+ }
11492
11832
  ];
11493
11833
 
11494
11834
  // src/compute-engine/latex-syntax/dictionary/default-dictionary.ts
@@ -11519,7 +11859,8 @@ var LATEX_DICTIONARY = [
11519
11859
  ...DEFINITIONS_STATISTICS,
11520
11860
  ...DEFINITIONS_UNITS,
11521
11861
  ...DEFINITIONS_OTHERS,
11522
- ...DEFINITIONS_PHYSICS
11862
+ ...DEFINITIONS_PHYSICS,
11863
+ ...DEFINITIONS_COLORS
11523
11864
  ];
11524
11865
 
11525
11866
  // src/math-json/symbols.ts
@@ -12674,7 +13015,11 @@ var COLLECTIONS_LIBRARY = {
12674
13015
  //
12675
13016
  Range: {
12676
13017
  complexity: 8200,
12677
- signature: "(number, number?, step: number?) -> indexed_collection<integer>",
13018
+ signature: "(number, number?, step: number?) -> indexed_collection<number>",
13019
+ type: (ops) => {
13020
+ const allInt = ops.every((op) => op.isInteger);
13021
+ return allInt ? parseType("indexed_collection<integer>") : parseType("indexed_collection<number>");
13022
+ },
12678
13023
  canonical: (ops, { engine: ce }) => {
12679
13024
  if (ops.length === 0) return null;
12680
13025
  if (ops.length === 1) return ce._fn("Range", [ce.One, ops[0].canonical]);
@@ -12698,19 +13043,26 @@ var COLLECTIONS_LIBRARY = {
12698
13043
  const [lower, upper, step] = range(expr);
12699
13044
  if (step === 0) return 0;
12700
13045
  if (!isFinite(lower) || !isFinite(upper)) return Infinity;
12701
- return 1 + Math.max(0, Math.floor((upper - lower) / step));
13046
+ return Math.max(0, Math.floor((upper - lower) / step) + 1);
12702
13047
  },
12703
13048
  contains: (expr, target) => {
12704
- if (!target.type.matches("integer")) return false;
12705
13049
  const t = target.re;
13050
+ if (!isFinite(t)) return false;
12706
13051
  const [lower, upper, step] = range(expr);
12707
13052
  if (step === 0) return false;
12708
- if (step > 0) return t >= lower && t <= upper;
12709
- return t <= lower && t >= upper;
13053
+ if (step > 0) {
13054
+ if (t < lower || t > upper) return false;
13055
+ } else {
13056
+ if (t > lower || t < upper) return false;
13057
+ }
13058
+ const k = (t - lower) / step;
13059
+ const tol = expr.engine.tolerance;
13060
+ const kRounded = Math.round(k);
13061
+ return kRounded >= 0 && Math.abs(k - kRounded) < tol;
12710
13062
  },
12711
13063
  iterator: (expr) => {
12712
13064
  const [lower, upper, step] = range(expr);
12713
- const maxCount = step === 0 ? 0 : Math.floor((upper - lower) / step) + 1;
13065
+ const maxCount = step === 0 ? 0 : Math.max(0, Math.floor((upper - lower) / step) + 1);
12714
13066
  let index = 1;
12715
13067
  return {
12716
13068
  next: () => {
@@ -12728,7 +13080,9 @@ var COLLECTIONS_LIBRARY = {
12728
13080
  at: (expr, index) => {
12729
13081
  if (typeof index !== "number") return void 0;
12730
13082
  const [lower, upper, step] = range(expr);
12731
- if (index < 1 || index > 1 + (upper - lower) / step) return void 0;
13083
+ if (step === 0) return void 0;
13084
+ const maxCount = Math.max(0, Math.floor((upper - lower) / step) + 1);
13085
+ if (index < 1 || index > maxCount) return void 0;
12732
13086
  return expr.engine.number(lower + step * (index - 1));
12733
13087
  },
12734
13088
  indexWhere: void 0,
@@ -12753,7 +13107,13 @@ var COLLECTIONS_LIBRARY = {
12753
13107
  if (step > 0) return lower <= upper ? "positive" : "negative";
12754
13108
  return lower >= upper ? "positive" : "negative";
12755
13109
  },
12756
- elttype: (_expr) => "finite_integer"
13110
+ elttype: (expr) => {
13111
+ if (!isFunction2(expr)) return "finite_integer";
13112
+ for (let i = 1; i <= expr.nops; i++) {
13113
+ if (!expr[`op${i}`].isInteger) return "finite_real";
13114
+ }
13115
+ return "finite_integer";
13116
+ }
12757
13117
  }
12758
13118
  },
12759
13119
  Interval: {
@@ -13351,15 +13711,45 @@ var COLLECTIONS_LIBRARY = {
13351
13711
  },
13352
13712
  First: {
13353
13713
  complexity: 8200,
13354
- signature: "(collection) -> any",
13714
+ signature: "(any) -> any",
13355
13715
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13356
- evaluate: ([xs], { engine: ce }) => xs.at(1) ?? ce.Nothing
13716
+ evaluate: ([xs], { engine: ce }) => {
13717
+ if (!xs.isCollection)
13718
+ return ce.error([
13719
+ "incompatible-type",
13720
+ `'collection'`,
13721
+ xs.type.toString()
13722
+ ]);
13723
+ return xs.at(1) ?? ce.Nothing;
13724
+ }
13357
13725
  },
13358
13726
  Second: {
13359
13727
  complexity: 8200,
13360
- signature: "(collection) -> any",
13728
+ signature: "(any) -> any",
13361
13729
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13362
- evaluate: ([xs], { engine: ce }) => xs.at(2) ?? ce.Nothing
13730
+ evaluate: ([xs], { engine: ce }) => {
13731
+ if (!xs.isCollection)
13732
+ return ce.error([
13733
+ "incompatible-type",
13734
+ `'collection'`,
13735
+ xs.type.toString()
13736
+ ]);
13737
+ return xs.at(2) ?? ce.Nothing;
13738
+ }
13739
+ },
13740
+ Third: {
13741
+ complexity: 8200,
13742
+ signature: "(any) -> any",
13743
+ type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13744
+ evaluate: ([xs], { engine: ce }) => {
13745
+ if (!xs.isCollection)
13746
+ return ce.error([
13747
+ "incompatible-type",
13748
+ `'collection'`,
13749
+ xs.type.toString()
13750
+ ]);
13751
+ return xs.at(3) ?? ce.Nothing;
13752
+ }
13363
13753
  },
13364
13754
  Last: {
13365
13755
  complexity: 8200,
@@ -14338,17 +14728,14 @@ function range(expr) {
14338
14728
  if (!isFunction2(expr)) return [1, 0, 0];
14339
14729
  if (expr.nops === 0) return [1, 0, 0];
14340
14730
  let op1 = expr.op1.re;
14341
- if (!isFinite(op1)) op1 = 1;
14342
- else op1 = Math.round(op1);
14731
+ if (!isFinite(op1) && !op1) op1 = 1;
14343
14732
  if (expr.nops === 1) return [1, op1, 1];
14344
14733
  let op2 = expr.op2.re;
14345
14734
  if (!isFinite(op2) && !op2) op2 = 1;
14346
- else if (isFinite(op2)) op2 = Math.round(op2);
14347
- if (expr.nops === 2) return [op1, op2, op2 > op1 ? 1 : -1];
14735
+ if (expr.nops === 2) return [op1, op2, op2 >= op1 ? 1 : -1];
14348
14736
  let op3 = expr.op3.re;
14349
- if (!isFinite(op3)) op3 = 1;
14350
- else op3 = Math.abs(Math.round(op3));
14351
- return [op1, op2, op1 < op2 ? op3 : -op3];
14737
+ if (!isFinite(op3) && !op3) op3 = 1;
14738
+ return [op1, op2, op3];
14352
14739
  }
14353
14740
  function canonicalList(ops, { engine: ce }) {
14354
14741
  const op1 = ops[0];
@@ -14697,6 +15084,23 @@ var BaseCompiler = class _BaseCompiler {
14697
15084
  };
14698
15085
  return compilePair(0);
14699
15086
  }
15087
+ if (h === "When") {
15088
+ if (args.length !== 2)
15089
+ throw new Error("When: expected exactly 2 arguments (expr, cond)");
15090
+ const fn2 = target.functions?.(h);
15091
+ if (fn2) {
15092
+ if (typeof fn2 === "function") {
15093
+ return fn2(args, (expr) => _BaseCompiler.compile(expr, target), target);
15094
+ }
15095
+ return `${fn2}(${args.map((x) => _BaseCompiler.compile(x, target)).join(", ")})`;
15096
+ }
15097
+ if (isSymbol2(args[1], "True"))
15098
+ return `(${_BaseCompiler.compile(args[0], target)})`;
15099
+ if (isSymbol2(args[1], "False")) return "NaN";
15100
+ const val = _BaseCompiler.compile(args[0], target);
15101
+ const cond = _BaseCompiler.compile(args[1], target);
15102
+ return `((${cond}) ? (${val}) : NaN)`;
15103
+ }
14700
15104
  if (h === "Block") {
14701
15105
  return _BaseCompiler.compileBlock(args, target);
14702
15106
  }
@@ -14771,17 +15175,91 @@ var BaseCompiler = class _BaseCompiler {
14771
15175
  )}${target.ws("\n")}})()`;
14772
15176
  }
14773
15177
  /**
14774
- * Compile a Loop expression with Element(index, Range(lo, hi)) indexing.
14775
- * Generates: (() => { for (let i = lo; i <= hi; i++) { body } })()
15178
+ * Compile a Loop expression.
15179
+ *
15180
+ * Two forms are supported:
15181
+ *
15182
+ * 1. **Imperative / single-Element form** (existing behaviour):
15183
+ * `Loop(body, Element(i, Range(lo, hi)))`
15184
+ * Generates a raw `for (let i = lo; i <= hi; i++) { body }` loop wrapped
15185
+ * in an IIFE. The loop counter is always a plain number. For targets
15186
+ * that wrap numeric values (e.g. interval-js uses `_IA.point()`),
15187
+ * references to the loop index inside the body are re-wrapped via
15188
+ * `target.number`. `break` / `continue` / `return` are preserved.
15189
+ *
15190
+ * 2. **Comprehension / variadic-Element form** (new):
15191
+ * `Loop(body, Element(x, coll1), Element(y, coll2), …)`
15192
+ * When two or more `Element` clauses are present — or when the single
15193
+ * Element's collection is not a `Range` — the loop is compiled as a
15194
+ * comprehension that collects results into an array. Each clause
15195
+ * produces a `for (const name of collection)` loop, nested
15196
+ * outermost-to-innermost, and the innermost body pushes into `result`.
15197
+ *
15198
+ * Example output (JS):
15199
+ * ```js
15200
+ * (() => { const result = [];
15201
+ * for (const x of [1,2]) { for (const y of [3,4]) { result.push(body); } }
15202
+ * return result; })()
15203
+ * ```
14776
15204
  *
14777
- * The loop counter is always a raw number. For targets that wrap numeric
14778
- * values (e.g. interval-js wraps with `_IA.point()`), references to the
14779
- * loop index inside the body are wrapped via `target.number`.
15205
+ * GLSL: multi-Element comprehension is not trivially representable in
15206
+ * GLSL (no dynamic arrays, no push). A compile-time error is thrown.
15207
+ * TODO(E3-GLSL): support GLSL multi-Element via a pre-declared fixed-size
15208
+ * array or by unrolling when bounds are known at compile time.
14780
15209
  */
14781
15210
  static compileForLoop(args, target) {
14782
15211
  if (!args[0]) throw new Error("Loop: no body");
14783
15212
  if (!args[1]) throw new Error("Loop: no indexing set");
14784
- const indexing = args[1];
15213
+ const body = args[0];
15214
+ const elements = args.slice(1);
15215
+ const useComprehension = elements.length > 1 || elements.length === 1 && isFunction2(elements[0], "Element") && !_BaseCompiler.isLegacyCompatibleRange(elements[0].ops[1]);
15216
+ if (useComprehension) {
15217
+ const lang = target.language ?? "";
15218
+ if (lang === "glsl" || lang === "wgsl") {
15219
+ throw new Error(
15220
+ `${lang.toUpperCase()}: multi-Element Loop comprehension is not yet supported. TODO(E3-GLSL): unroll or use a fixed-size array.`
15221
+ );
15222
+ }
15223
+ const narrowedElements = [];
15224
+ for (let i = 0; i < elements.length; i++) {
15225
+ const elem = elements[i];
15226
+ if (!isFunction2(elem, "Element"))
15227
+ throw new Error(
15228
+ `Loop: argument ${i + 1} must be an Element clause, got ${elem.operator ?? "?"}`
15229
+ );
15230
+ if (!isSymbol2(elem.ops[0]))
15231
+ throw new Error(
15232
+ `Loop: Element index (argument ${i + 1}) must be a symbol`
15233
+ );
15234
+ narrowedElements.push(elem);
15235
+ }
15236
+ const loopVarSet = new Set(
15237
+ narrowedElements.map(
15238
+ (e) => e.ops[0].symbol
15239
+ )
15240
+ );
15241
+ const needsWrap2 = target.number(0) !== "0";
15242
+ const bodyTarget2 = needsWrap2 ? {
15243
+ ...target,
15244
+ var: (id) => loopVarSet.has(id) ? target.number(0).replace("0", id) : target.var(id)
15245
+ } : target;
15246
+ const bodyCode = _BaseCompiler.compile(body, bodyTarget2);
15247
+ let inner = `result.push(${bodyCode});`;
15248
+ for (let i = narrowedElements.length - 1; i >= 0; i--) {
15249
+ const elem = narrowedElements[i];
15250
+ const name = elem.ops[0].symbol;
15251
+ const collExpr = elem.ops[1];
15252
+ let collection;
15253
+ if (isFunction2(collExpr, "Range")) {
15254
+ collection = _BaseCompiler.compileRangeIterable(collExpr, bodyTarget2);
15255
+ } else {
15256
+ collection = _BaseCompiler.compile(collExpr, bodyTarget2);
15257
+ }
15258
+ inner = `for (const ${name} of ${collection}) { ${inner} }`;
15259
+ }
15260
+ return `(() => { const result = []; ${inner} return result; })()`;
15261
+ }
15262
+ const indexing = elements[0];
14785
15263
  if (!isFunction2(indexing, "Element"))
14786
15264
  throw new Error("Loop: expected Element(index, Range(lo, hi))");
14787
15265
  const indexExpr = indexing.ops[0];
@@ -14799,13 +15277,72 @@ var BaseCompiler = class _BaseCompiler {
14799
15277
  ...target,
14800
15278
  var: (id) => id === index ? needsWrap ? target.number(0).replace("0", index) : index : target.var(id)
14801
15279
  };
14802
- const bodyStmts = _BaseCompiler.compileLoopBody(args[0], bodyTarget);
15280
+ const bodyStmts = _BaseCompiler.compileLoopBody(body, bodyTarget);
14803
15281
  return `(() => {${target.ws(
14804
15282
  "\n"
14805
15283
  )}for (let ${index} = ${lower}; ${index} <= ${upper}; ${index}++) {${target.ws(
14806
15284
  "\n"
14807
15285
  )}${bodyStmts}${target.ws("\n")}}${target.ws("\n")}})()`;
14808
15286
  }
15287
+ /**
15288
+ * Returns `true` when the given collection expression is a `Range` whose
15289
+ * runtime semantics match the legacy imperative for-loop shape
15290
+ * `for (let i = lo; i <= hi; i++)`.
15291
+ *
15292
+ * Concretely: integer-ascending bounds and step omitted-or-1. When bounds
15293
+ * are not statically numeric we accept the Range (the historical
15294
+ * behaviour) — runtime mismatch in the descending-unknown-bounds case is
15295
+ * left as a known limitation; callers can force the iterable path by
15296
+ * supplying an explicit step.
15297
+ */
15298
+ static isLegacyCompatibleRange(coll) {
15299
+ if (!isFunction2(coll, "Range")) return false;
15300
+ if (coll.ops.length >= 3) {
15301
+ const stepExpr = coll.ops[2];
15302
+ if (!isNumber(stepExpr) || stepExpr.re !== 1) return false;
15303
+ }
15304
+ const lo = coll.ops[0];
15305
+ const hi = coll.ops[1];
15306
+ if (isNumber(lo) && !Number.isInteger(lo.re)) return false;
15307
+ if (isNumber(hi) && !Number.isInteger(hi.re)) return false;
15308
+ if (isNumber(lo) && isNumber(hi) && lo.re > hi.re) return false;
15309
+ return true;
15310
+ }
15311
+ /**
15312
+ * Compile a `Range(lo, hi)` or `Range(lo, hi, step)` expression into a JS
15313
+ * iterable expression. Mirrors the runtime semantics in
15314
+ * `library/collections.ts` Range:
15315
+ * count = step === 0 ? 0 : max(0, floor((hi - lo) / step) + 1)
15316
+ * element = lo + step * k (0-indexed)
15317
+ * Default step is 1 when omitted. Bounds and step may be fractional.
15318
+ *
15319
+ * Only used from the comprehension path in `compileForLoop`.
15320
+ * Caller must have already verified `isFunction(rangeExpr, 'Range')`.
15321
+ */
15322
+ static compileRangeIterable(rangeExpr, target) {
15323
+ const loExpr = rangeExpr.ops[0];
15324
+ const hiExpr = rangeExpr.ops[1];
15325
+ const stepExpr = rangeExpr.ops[2];
15326
+ if (isNumber(loExpr) && isNumber(hiExpr) && (stepExpr === void 0 || isNumber(stepExpr))) {
15327
+ const lo2 = loExpr.re;
15328
+ const hi2 = hiExpr.re;
15329
+ const step2 = stepExpr === void 0 ? hi2 >= lo2 ? 1 : -1 : stepExpr.re;
15330
+ if (step2 === 0) return "[]";
15331
+ const len = Math.max(0, Math.floor((hi2 - lo2) / step2) + 1);
15332
+ if (step2 === 1) {
15333
+ if (lo2 === 0) return `Array.from({length:${len}},(_,k)=>k)`;
15334
+ return `Array.from({length:${len}},(_,k)=>${lo2}+k)`;
15335
+ }
15336
+ return `Array.from({length:${len}},(_,k)=>${lo2}+(${step2})*k)`;
15337
+ }
15338
+ const lo = _BaseCompiler.compile(loExpr, target);
15339
+ const hi = _BaseCompiler.compile(hiExpr, target);
15340
+ if (stepExpr === void 0) {
15341
+ return `((_lo,_hi)=>{const _st=_hi>=_lo?1:-1;return Array.from({length:Math.max(0,Math.floor((_hi-_lo)/_st)+1)},(_,k)=>_lo+_st*k);})(${lo},${hi})`;
15342
+ }
15343
+ const step = _BaseCompiler.compile(stepExpr, target);
15344
+ return `((_lo,_hi,_st)=>_st===0?[]:Array.from({length:Math.max(0,Math.floor((_hi-_lo)/_st)+1)},(_,k)=>_lo+_st*k))(${lo},${hi},${step})`;
15345
+ }
14809
15346
  /**
14810
15347
  * Compile a loop body expression as statements (not wrapped in IIFE).
14811
15348
  * Handles Break, Continue, Return as statements, and If as if-else when
@@ -15154,8 +15691,7 @@ function compile(expr, options) {
15154
15691
  ce.pushScope();
15155
15692
  try {
15156
15693
  if (vars && typeof vars === "object") {
15157
- for (const [k, v] of Object.entries(vars))
15158
- ce.assign(k, v);
15694
+ for (const [k, v] of Object.entries(vars)) ce.assign(k, v);
15159
15695
  }
15160
15696
  return expr.evaluate().re;
15161
15697
  } finally {
@@ -15242,8 +15778,7 @@ function tryGetComplexParts(expr, compile2) {
15242
15778
  return { re: null, im: formatFloat(iScale) };
15243
15779
  }
15244
15780
  const compiledFactors = remaining.map((r) => compile2(r));
15245
- if (iScale !== 1)
15246
- compiledFactors.unshift(formatFloat(iScale));
15781
+ if (iScale !== 1) compiledFactors.unshift(formatFloat(iScale));
15247
15782
  const imCode = foldTerms(compiledFactors, "1.0", "*");
15248
15783
  return { re: null, im: imCode };
15249
15784
  }
@@ -15308,6 +15843,40 @@ function rgbToHsl(r, g, b) {
15308
15843
  else h = ((r - g) / d + 4) / 6;
15309
15844
  return { h: h * 360, s, l };
15310
15845
  }
15846
+ function hsvToRgb(h, s, v) {
15847
+ h = (h % 360 + 360) % 360;
15848
+ s = Math.max(0, Math.min(1, s));
15849
+ v = Math.max(0, Math.min(1, v));
15850
+ const c = v * s;
15851
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
15852
+ const m = v - c;
15853
+ let r = 0, g = 0, b = 0;
15854
+ if (h < 60) [r, g, b] = [c, x, 0];
15855
+ else if (h < 120) [r, g, b] = [x, c, 0];
15856
+ else if (h < 180) [r, g, b] = [0, c, x];
15857
+ else if (h < 240) [r, g, b] = [0, x, c];
15858
+ else if (h < 300) [r, g, b] = [x, 0, c];
15859
+ else [r, g, b] = [c, 0, x];
15860
+ return { r: (r + m) * 255, g: (g + m) * 255, b: (b + m) * 255 };
15861
+ }
15862
+ function rgbToHsv(r, g, b) {
15863
+ r /= 255;
15864
+ g /= 255;
15865
+ b /= 255;
15866
+ const max2 = Math.max(r, g, b);
15867
+ const min2 = Math.min(r, g, b);
15868
+ const d = max2 - min2;
15869
+ let h = 0;
15870
+ if (d > 0) {
15871
+ if (max2 === r) h = (g - b) / d % 6;
15872
+ else if (max2 === g) h = (b - r) / d + 2;
15873
+ else h = (r - g) / d + 4;
15874
+ h *= 60;
15875
+ if (h < 0) h += 360;
15876
+ }
15877
+ const s = max2 === 0 ? 0 : d / max2;
15878
+ return { h, s, v: max2 };
15879
+ }
15311
15880
  function parseHexColor(s) {
15312
15881
  const hex = s.startsWith("#") ? s.substring(1) : s;
15313
15882
  let r, g, b;
@@ -15763,6 +16332,13 @@ var NAMED_COLORS = {
15763
16332
  };
15764
16333
  function parseColor(s, darkMode) {
15765
16334
  const str = s.trim().toLowerCase();
16335
+ const opacityMatch = str.match(/^(.+?)\s*\/\s*(\d+(?:\.\d+)?)%?\s*$/);
16336
+ if (opacityMatch) {
16337
+ const base = parseColor(opacityMatch[1].trim(), darkMode);
16338
+ const opacity = Math.max(0, Math.min(100, parseFloat(opacityMatch[2])));
16339
+ const alpha = Math.round(opacity / 100 * 255);
16340
+ return base & 4294967040 | alpha;
16341
+ }
15766
16342
  if (str.startsWith("#")) {
15767
16343
  const hex = str.substring(1);
15768
16344
  let r, g, b, a = 255;
@@ -15895,14 +16471,6 @@ function parseColor(s, darkMode) {
15895
16471
  console.warn(`parseColor: unrecognized color "${s}"`);
15896
16472
  return 0;
15897
16473
  }
15898
- function parseColorToRgb01(s, darkMode) {
15899
- const color = parseColor(s, darkMode);
15900
- return [
15901
- (color >>> 24 & 255) / 255,
15902
- (color >>> 16 & 255) / 255,
15903
- (color >>> 8 & 255) / 255
15904
- ];
15905
- }
15906
16474
  function apca(bgColor, fgColor) {
15907
16475
  const bgRgb = asRgb(bgColor);
15908
16476
  const fgRgb = asRgb(fgColor);
@@ -15961,6 +16529,12 @@ function contrastingColor(arg) {
15961
16529
  const contrast2 = Math.abs(apca(fg2, bg));
15962
16530
  return contrast1 >= contrast2 ? asColorNumber(fg1) : asColorNumber(fg2);
15963
16531
  }
16532
+ function oklabDeltaE(a, b) {
16533
+ const dL = a.L - b.L;
16534
+ const da = a.a - b.a;
16535
+ const db = a.b - b.b;
16536
+ return Math.sqrt(dL * dL + da * da + db * db);
16537
+ }
15964
16538
  var TYCHO_11 = [
15965
16539
  "#4e79a7",
15966
16540
  // Blue
@@ -20172,39 +20746,130 @@ var JAVASCRIPT_FUNCTIONS = {
20172
20746
  if (args.length >= 2)
20173
20747
  return `_SYS.colormap(${compile2(args[0])}, ${compile2(args[1])})`;
20174
20748
  return `_SYS.colormap(${compile2(args[0])})`;
20749
+ },
20750
+ // -----------------------------------------------------------------------
20751
+ // Color constructor heads. All compile to OKLCh arrays at runtime — the
20752
+ // canonical color representation in this target. The constructors take
20753
+ // their own colorspace's components and convert internally.
20754
+ // (Mirrors the GPU target's design: color values are vec3 OKLCh.)
20755
+ // -----------------------------------------------------------------------
20756
+ Rgb: (args, compile2) => {
20757
+ if (args.length < 3) throw new Error("Rgb: need 3 components");
20758
+ return `_SYS.rgb(${args.map(compile2).join(", ")})`;
20759
+ },
20760
+ Hsv: (args, compile2) => {
20761
+ if (args.length < 3) throw new Error("Hsv: need 3 components");
20762
+ return `_SYS.hsv(${args.map(compile2).join(", ")})`;
20763
+ },
20764
+ Hsl: (args, compile2) => {
20765
+ if (args.length < 3) throw new Error("Hsl: need 3 components");
20766
+ return `_SYS.hsl(${args.map(compile2).join(", ")})`;
20767
+ },
20768
+ Oklab: (args, compile2) => {
20769
+ if (args.length < 3) throw new Error("Oklab: need 3 components");
20770
+ return `_SYS.oklab(${args.map(compile2).join(", ")})`;
20771
+ },
20772
+ Oklch: (args, compile2) => {
20773
+ if (args.length < 3) throw new Error("Oklch: need 3 components");
20774
+ return `_SYS.oklch(${args.map(compile2).join(", ")})`;
20775
+ },
20776
+ // -----------------------------------------------------------------------
20777
+ // As* converters. Compile-time output convention matches the engine and
20778
+ // the GPU target: each returns components in the named space as a 3- or
20779
+ // 4-element array. `AsRgb` uses 0-1 sRGB channels (consistent across all
20780
+ // layers). `AsOklch` is the identity (canonical form).
20781
+ // -----------------------------------------------------------------------
20782
+ AsRgb: ([c], compile2) => {
20783
+ if (c === null) throw new Error("AsRgb: no argument");
20784
+ return `_SYS.asRgb(${compile2(c)})`;
20785
+ },
20786
+ AsHsv: ([c], compile2) => {
20787
+ if (c === null) throw new Error("AsHsv: no argument");
20788
+ return `_SYS.asHsv(${compile2(c)})`;
20789
+ },
20790
+ AsHsl: ([c], compile2) => {
20791
+ if (c === null) throw new Error("AsHsl: no argument");
20792
+ return `_SYS.asHsl(${compile2(c)})`;
20793
+ },
20794
+ AsOklab: ([c], compile2) => {
20795
+ if (c === null) throw new Error("AsOklab: no argument");
20796
+ return `_SYS.asOklab(${compile2(c)})`;
20797
+ },
20798
+ AsOklch: ([c], compile2) => {
20799
+ if (c === null) throw new Error("AsOklch: no argument");
20800
+ return compile2(c);
20801
+ },
20802
+ // Perceptual color difference (ΔE_OK).
20803
+ ColorDelta: ([a, b], compile2) => {
20804
+ if (a === null || b === null)
20805
+ throw new Error("ColorDelta: need two colors");
20806
+ return `_SYS.colorDelta(${compile2(a)}, ${compile2(b)})`;
20807
+ },
20808
+ // Euclidean distance between two tuples (any positive dimension).
20809
+ // The GPU target maps `Distance` to the GLSL/WGSL `distance()` builtin
20810
+ // (vec-only); this JS handler works on plain arrays of any length.
20811
+ Distance: ([a, b], compile2) => {
20812
+ if (a === null || b === null) throw new Error("Distance: need two points");
20813
+ return `_SYS.distance(${compile2(a)}, ${compile2(b)})`;
20175
20814
  }
20176
20815
  };
20177
20816
  function toRI(c) {
20178
20817
  return { re: c.re, im: c.im };
20179
20818
  }
20819
+ function normalizeAlpha(a) {
20820
+ if (a === void 0) return void 0;
20821
+ if (!Number.isFinite(a)) return void 0;
20822
+ if (Math.abs(a - 1) < 1e-9) return void 0;
20823
+ return a;
20824
+ }
20180
20825
  function toRgb255(input) {
20181
20826
  if (typeof input === "string") {
20182
20827
  const c = parseColor(input);
20183
- return {
20828
+ const rgb2 = {
20184
20829
  r: c >>> 24 & 255,
20185
20830
  g: c >>> 16 & 255,
20186
- b: c >>> 8 & 255,
20187
- alpha: (c & 255) / 255
20831
+ b: c >>> 8 & 255
20188
20832
  };
20833
+ const alpha = normalizeAlpha((c & 255) / 255);
20834
+ if (alpha !== void 0) rgb2.alpha = alpha;
20835
+ return rgb2;
20836
+ }
20837
+ const rgb = oklchToRgb({ L: input[0], C: input[1], H: input[2] });
20838
+ if (input.length >= 4) {
20839
+ const alpha = normalizeAlpha(input[3]);
20840
+ if (alpha !== void 0) rgb.alpha = alpha;
20189
20841
  }
20190
- const rgb = {
20191
- r: input[0] * 255,
20192
- g: input[1] * 255,
20193
- b: input[2] * 255
20194
- };
20195
- if (input.length >= 4) rgb.alpha = input[3];
20196
20842
  return rgb;
20197
20843
  }
20198
- function packedToArray(c) {
20199
- const r = (c >>> 24 & 255) / 255;
20200
- const g = (c >>> 16 & 255) / 255;
20201
- const b = (c >>> 8 & 255) / 255;
20202
- const a = (c & 255) / 255;
20203
- return Math.abs(a - 1) < 1e-4 ? [r, g, b] : [r, g, b, a];
20844
+ function toOklch(input) {
20845
+ if (typeof input === "string") {
20846
+ const c = parseColor(input);
20847
+ const r = c >>> 24 & 255;
20848
+ const g = c >>> 16 & 255;
20849
+ const b = c >>> 8 & 255;
20850
+ const oklch2 = rgbToOklch({ r, g, b });
20851
+ const alpha = normalizeAlpha((c & 255) / 255);
20852
+ if (alpha !== void 0) oklch2.alpha = alpha;
20853
+ return oklch2;
20854
+ }
20855
+ return {
20856
+ L: input[0],
20857
+ C: input[1],
20858
+ H: input[2],
20859
+ alpha: input.length >= 4 ? normalizeAlpha(input[3]) : void 0
20860
+ };
20861
+ }
20862
+ function packedToOklch(c) {
20863
+ const r = c >>> 24 & 255;
20864
+ const g = c >>> 16 & 255;
20865
+ const b = c >>> 8 & 255;
20866
+ const oklch2 = rgbToOklch({ r, g, b });
20867
+ const alpha = normalizeAlpha((c & 255) / 255);
20868
+ return alpha !== void 0 ? [oklch2.L, oklch2.C, oklch2.H, alpha] : [oklch2.L, oklch2.C, oklch2.H];
20204
20869
  }
20205
20870
  var colorHelpers = {
20206
20871
  color(input) {
20207
- return packedToArray(parseColor(input));
20872
+ return packedToOklch(parseColor(input));
20208
20873
  },
20209
20874
  colorToString(input, format) {
20210
20875
  const rgb = toRgb255(input);
@@ -20215,7 +20880,7 @@ var colorHelpers = {
20215
20880
  const g = Math.round(Math.max(0, Math.min(255, rgb.g)));
20216
20881
  const b = Math.round(Math.max(0, Math.min(255, rgb.b)));
20217
20882
  let hex = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
20218
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4) {
20883
+ if (rgb.alpha !== void 0) {
20219
20884
  const a = Math.round(Math.max(0, Math.min(255, rgb.alpha * 255)));
20220
20885
  hex += a.toString(16).padStart(2, "0");
20221
20886
  }
@@ -20225,7 +20890,7 @@ var colorHelpers = {
20225
20890
  const r = Math.round(rgb.r);
20226
20891
  const g = Math.round(rgb.g);
20227
20892
  const b = Math.round(rgb.b);
20228
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
20893
+ if (rgb.alpha !== void 0)
20229
20894
  return `rgb(${r} ${g} ${b} / ${rgb.alpha})`;
20230
20895
  return `rgb(${r} ${g} ${b})`;
20231
20896
  }
@@ -20234,7 +20899,7 @@ var colorHelpers = {
20234
20899
  const h = Math.round(hsl.h * 10) / 10;
20235
20900
  const s = Math.round(hsl.s * 1e3) / 10;
20236
20901
  const l = Math.round(hsl.l * 1e3) / 10;
20237
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
20902
+ if (rgb.alpha !== void 0)
20238
20903
  return `hsl(${h} ${s}% ${l}% / ${rgb.alpha})`;
20239
20904
  return `hsl(${h} ${s}% ${l}%)`;
20240
20905
  }
@@ -20243,7 +20908,7 @@ var colorHelpers = {
20243
20908
  const L = Math.round(c.L * 1e3) / 1e3;
20244
20909
  const C = Math.round(c.C * 1e3) / 1e3;
20245
20910
  const H = Math.round(c.H * 10) / 10;
20246
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
20911
+ if (rgb.alpha !== void 0)
20247
20912
  return `oklch(${L} ${C} ${H} / ${rgb.alpha})`;
20248
20913
  return `oklch(${L} ${C} ${H})`;
20249
20914
  }
@@ -20252,29 +20917,29 @@ var colorHelpers = {
20252
20917
  }
20253
20918
  },
20254
20919
  colorMix(input1, input2, ratio = 0.5) {
20255
- const rgb1 = toRgb255(input1);
20256
- const rgb2 = toRgb255(input2);
20920
+ const c1 = toOklch(input1);
20921
+ const c2 = toOklch(input2);
20257
20922
  ratio = Math.max(0, Math.min(1, ratio));
20258
- const c1 = rgbToOklch(rgb1);
20259
- const c2 = rgbToOklch(rgb2);
20260
- let dh = c2.H - c1.H;
20261
- if (dh > 180) dh -= 360;
20262
- if (dh < -180) dh += 360;
20263
- let H = c1.H + dh * ratio;
20264
- if (H < 0) H += 360;
20265
- if (H >= 360) H -= 360;
20266
- const mixed = oklchToRgb({
20267
- L: c1.L + (c2.L - c1.L) * ratio,
20268
- C: c1.C + (c2.C - c1.C) * ratio,
20269
- H
20270
- });
20271
- const r = mixed.r / 255;
20272
- const g = mixed.g / 255;
20273
- const b = mixed.b / 255;
20274
- const a1 = rgb1.alpha ?? 1;
20275
- const a2 = rgb2.alpha ?? 1;
20276
- const alpha = a1 + (a2 - a1) * ratio;
20277
- return Math.abs(alpha - 1) > 1e-4 ? [r, g, b, alpha] : [r, g, b];
20923
+ const c1Achromatic = c1.C < 1e-6;
20924
+ const c2Achromatic = c2.C < 1e-6;
20925
+ let H;
20926
+ if (c1Achromatic && c2Achromatic) H = c1.H;
20927
+ else if (c1Achromatic) H = c2.H;
20928
+ else if (c2Achromatic) H = c1.H;
20929
+ else {
20930
+ let dh = c2.H - c1.H;
20931
+ if (dh > 180) dh -= 360;
20932
+ if (dh < -180) dh += 360;
20933
+ H = c1.H + dh * ratio;
20934
+ if (H < 0) H += 360;
20935
+ if (H >= 360) H -= 360;
20936
+ }
20937
+ const L = c1.L + (c2.L - c1.L) * ratio;
20938
+ const C = c1.C + (c2.C - c1.C) * ratio;
20939
+ const a1 = c1.alpha ?? 1;
20940
+ const a2 = c2.alpha ?? 1;
20941
+ const alpha = normalizeAlpha(a1 + (a2 - a1) * ratio);
20942
+ return alpha !== void 0 ? [L, C, H, alpha] : [L, C, H];
20278
20943
  },
20279
20944
  colorContrast(bg, fg) {
20280
20945
  return apca(toRgb255(bg), toRgb255(fg));
@@ -20282,11 +20947,11 @@ var colorHelpers = {
20282
20947
  contrastingColor(bg, fg1, fg2) {
20283
20948
  const bgRgb = toRgb255(bg);
20284
20949
  if (fg1 !== void 0 && fg2 !== void 0) {
20285
- return packedToArray(
20950
+ return packedToOklch(
20286
20951
  contrastingColor({ bg: bgRgb, fg1: toRgb255(fg1), fg2: toRgb255(fg2) })
20287
20952
  );
20288
20953
  }
20289
- return packedToArray(contrastingColor(bgRgb));
20954
+ return packedToOklch(contrastingColor(bgRgb));
20290
20955
  },
20291
20956
  colorToColorspace(input, space) {
20292
20957
  const rgb = toRgb255(input);
@@ -20315,7 +20980,7 @@ var colorHelpers = {
20315
20980
  default:
20316
20981
  throw new Error(`Unknown color space: ${space}`);
20317
20982
  }
20318
- if (alpha !== void 0 && Math.abs(alpha - 1) > 1e-4) result.push(alpha);
20983
+ if (alpha !== void 0) result.push(alpha);
20319
20984
  return result;
20320
20985
  },
20321
20986
  colormap(name, arg) {
@@ -20327,7 +20992,7 @@ var colorHelpers = {
20327
20992
  const palette = allPalettes[name];
20328
20993
  if (!palette) throw new Error(`Unknown palette: ${name}`);
20329
20994
  const colors = palette.map(
20330
- (hex) => parseColorToRgb01(hex)
20995
+ (hex) => packedToOklch(parseColor(hex))
20331
20996
  );
20332
20997
  if (arg === void 0) return colors;
20333
20998
  if (Number.isInteger(arg) && arg >= 2) {
@@ -20351,62 +21016,128 @@ var colorHelpers = {
20351
21016
  const frac = pos - i;
20352
21017
  if (frac === 0 || i >= colors.length - 1)
20353
21018
  return [...colors[Math.min(i, colors.length - 1)]];
20354
- const rgb1 = {
20355
- r: colors[i][0] * 255,
20356
- g: colors[i][1] * 255,
20357
- b: colors[i][2] * 255
20358
- };
20359
- const rgb2 = {
20360
- r: colors[i + 1][0] * 255,
20361
- g: colors[i + 1][1] * 255,
20362
- b: colors[i + 1][2] * 255
20363
- };
20364
- const c1 = rgbToOklch(rgb1);
20365
- const c2 = rgbToOklch(rgb2);
20366
- let dh = c2.H - c1.H;
20367
- if (dh > 180) dh -= 360;
20368
- if (dh < -180) dh += 360;
20369
- let H = c1.H + dh * frac;
20370
- if (H < 0) H += 360;
20371
- if (H >= 360) H -= 360;
20372
- const mixed = oklchToRgb({
20373
- L: c1.L + (c2.L - c1.L) * frac,
20374
- C: c1.C + (c2.C - c1.C) * frac,
20375
- H
20376
- });
20377
- return [mixed.r / 255, mixed.g / 255, mixed.b / 255];
21019
+ const [L1, C1, H1] = colors[i];
21020
+ const [L2, C2, H2] = colors[i + 1];
21021
+ const c1Achromatic = C1 < 1e-6;
21022
+ const c2Achromatic = C2 < 1e-6;
21023
+ let H;
21024
+ if (c1Achromatic && c2Achromatic) H = H1;
21025
+ else if (c1Achromatic) H = H2;
21026
+ else if (c2Achromatic) H = H1;
21027
+ else {
21028
+ let dh = H2 - H1;
21029
+ if (dh > 180) dh -= 360;
21030
+ if (dh < -180) dh += 360;
21031
+ H = H1 + dh * frac;
21032
+ if (H < 0) H += 360;
21033
+ if (H >= 360) H -= 360;
21034
+ }
21035
+ return [L1 + (L2 - L1) * frac, C1 + (C2 - C1) * frac, H];
20378
21036
  },
20379
21037
  colorFromColorspace(components, space) {
20380
21038
  const c0 = components[0];
20381
21039
  const c1 = components[1];
20382
21040
  const c2 = components[2];
20383
21041
  const alpha = components.length >= 4 ? components[3] : void 0;
20384
- let result;
21042
+ let oklch2;
20385
21043
  switch (space.toLowerCase()) {
20386
21044
  case "rgb":
20387
- result = [c0, c1, c2];
21045
+ oklch2 = rgbToOklch({ r: c0 * 255, g: c1 * 255, b: c2 * 255 });
20388
21046
  break;
20389
21047
  case "hsl": {
20390
- const r = hslToRgb(c0, c1, c2);
20391
- result = [r.r / 255, r.g / 255, r.b / 255];
21048
+ const rgb = hslToRgb(c0, c1, c2);
21049
+ oklch2 = rgbToOklch(rgb);
20392
21050
  break;
20393
21051
  }
20394
- case "oklch": {
20395
- const r = oklchToRgb({ L: c0, C: c1, H: c2 });
20396
- result = [r.r / 255, r.g / 255, r.b / 255];
21052
+ case "oklch":
21053
+ oklch2 = { L: c0, C: c1, H: c2 };
20397
21054
  break;
20398
- }
20399
21055
  case "oklab":
20400
- case "lab": {
20401
- const r = oklabToRgb({ L: c0, a: c1, b: c2 });
20402
- result = [r.r / 255, r.g / 255, r.b / 255];
21056
+ case "lab":
21057
+ oklch2 = oklabToOklch({ L: c0, a: c1, b: c2 });
20403
21058
  break;
20404
- }
20405
21059
  default:
20406
21060
  throw new Error(`Unknown color space: ${space}`);
20407
21061
  }
20408
- if (alpha !== void 0 && Math.abs(alpha - 1) > 1e-4) result.push(alpha);
20409
- return result;
21062
+ return alpha !== void 0 ? [oklch2.L, oklch2.C, oklch2.H, alpha] : [oklch2.L, oklch2.C, oklch2.H];
21063
+ },
21064
+ // -----------------------------------------------------------------------
21065
+ // Color constructors. Each accepts components in its colorspace's natural
21066
+ // units and returns the canonical OKLCh array `[L, C, H]` (or with alpha).
21067
+ // -----------------------------------------------------------------------
21068
+ rgb(r, g, b, alpha) {
21069
+ const c = rgbToOklch({ r: r * 255, g: g * 255, b: b * 255 });
21070
+ const a = normalizeAlpha(alpha);
21071
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
21072
+ },
21073
+ hsv(h, s, v, alpha) {
21074
+ const rgb = hsvToRgb(h, s, v);
21075
+ const c = rgbToOklch(rgb);
21076
+ const a = normalizeAlpha(alpha);
21077
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
21078
+ },
21079
+ hsl(h, s, l, alpha) {
21080
+ const rgb = hslToRgb(h, s, l);
21081
+ const c = rgbToOklch({ r: rgb.r, g: rgb.g, b: rgb.b });
21082
+ const a = normalizeAlpha(alpha);
21083
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
21084
+ },
21085
+ oklab(L, a, b, alpha) {
21086
+ const c = oklabToOklch({ L, a, b });
21087
+ const al = normalizeAlpha(alpha);
21088
+ return al !== void 0 ? [c.L, c.C, c.H, al] : [c.L, c.C, c.H];
21089
+ },
21090
+ oklch(L, C, H, alpha) {
21091
+ const a = normalizeAlpha(alpha);
21092
+ return a !== void 0 ? [L, C, H, a] : [L, C, H];
21093
+ },
21094
+ // -----------------------------------------------------------------------
21095
+ // As* converters. Inputs are anything `toOklch` accepts (string, packed
21096
+ // int, or OKLCh array). Outputs are 3- or 4-element arrays in the named
21097
+ // space. sRGB-based outputs (asRgb/asHsv/asHsl) use 0-1 channels for
21098
+ // consistency with the GPU target's shader convention.
21099
+ // -----------------------------------------------------------------------
21100
+ asRgb(input) {
21101
+ const rgb = toRgb255(input);
21102
+ const r = rgb.r / 255;
21103
+ const g = rgb.g / 255;
21104
+ const b = rgb.b / 255;
21105
+ return rgb.alpha !== void 0 ? [r, g, b, rgb.alpha] : [r, g, b];
21106
+ },
21107
+ asHsv(input) {
21108
+ const rgb = toRgb255(input);
21109
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
21110
+ return rgb.alpha !== void 0 ? [hsv.h, hsv.s, hsv.v, rgb.alpha] : [hsv.h, hsv.s, hsv.v];
21111
+ },
21112
+ asHsl(input) {
21113
+ const rgb = toRgb255(input);
21114
+ const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
21115
+ return rgb.alpha !== void 0 ? [hsl.h, hsl.s, hsl.l, rgb.alpha] : [hsl.h, hsl.s, hsl.l];
21116
+ },
21117
+ asOklab(input) {
21118
+ const c = toOklch(input);
21119
+ const lab = oklchToOklab({ L: c.L, C: c.C, H: c.H });
21120
+ return c.alpha !== void 0 ? [lab.L, lab.a, lab.b, c.alpha] : [lab.L, lab.a, lab.b];
21121
+ },
21122
+ // asOklch is identity — handled at compile time as a pass-through
21123
+ // Perceptual color difference (ΔE_OK).
21124
+ colorDelta(a, b) {
21125
+ const labA = oklchToOklab(toOklch(a));
21126
+ const labB = oklchToOklab(toOklch(b));
21127
+ return oklabDeltaE(labA, labB);
21128
+ },
21129
+ // Euclidean distance between two tuples. Plain numeric — not a color
21130
+ // operation despite living in the same helpers block.
21131
+ distance(a, b) {
21132
+ if (!Array.isArray(a) || !Array.isArray(b))
21133
+ throw new Error("Distance: expected two arrays");
21134
+ if (a.length !== b.length) throw new Error("Distance: dimension mismatch");
21135
+ let sumSq = 0;
21136
+ for (let i = 0; i < a.length; i++) {
21137
+ const d = a[i] - b[i];
21138
+ sumSq += d * d;
21139
+ }
21140
+ return Math.sqrt(sumSq);
20410
21141
  }
20411
21142
  };
20412
21143
  var SYS_HELPERS = {
@@ -20845,6 +21576,13 @@ var GPU_OPERATORS = {
20845
21576
  function gpuVec2(target) {
20846
21577
  return target?.language === "wgsl" ? "vec2f" : "vec2";
20847
21578
  }
21579
+ function gpuVec3(target) {
21580
+ return target?.language === "wgsl" ? "vec3f" : "vec3";
21581
+ }
21582
+ function readStringLiteral(expr) {
21583
+ if (!isString(expr)) return null;
21584
+ return expr.string?.toLowerCase() ?? null;
21585
+ }
20848
21586
  function compileIntArg(expr, compile2, target) {
20849
21587
  const c = tryGetConstant(expr);
20850
21588
  if (c !== void 0 && Number.isInteger(c)) return c.toString();
@@ -20903,7 +21641,7 @@ function compileGPUSumProduct(kind, args, _compile, target) {
20903
21641
  `for (${indexDecl} = ${lowerStr}; ${index} <= ${upperStr}; ${index}++) {`,
20904
21642
  ` ${acc} ${op}= ${body};`,
20905
21643
  `}`,
20906
- `return ${acc}`
21644
+ `return ${acc};`
20907
21645
  ];
20908
21646
  return lines.join("\n");
20909
21647
  }
@@ -20957,8 +21695,7 @@ var GPU_FUNCTIONS = {
20957
21695
  const iScale = isSymbol2(iFactor, "ImaginaryUnit") ? 1 : iFactor.im;
20958
21696
  const realFactors = args.filter((_, i) => i !== iIndex);
20959
21697
  const v2 = gpuVec2(target);
20960
- if (realFactors.length === 0)
20961
- return `${v2}(0.0, ${formatFloat(iScale)})`;
21698
+ if (realFactors.length === 0) return `${v2}(0.0, ${formatFloat(iScale)})`;
20962
21699
  const factors = realFactors.map((f) => compile2(f));
20963
21700
  if (iScale !== 1) factors.unshift(formatFloat(iScale));
20964
21701
  const imCode = foldTerms(factors, "1.0", "*");
@@ -21011,8 +21748,7 @@ var GPU_FUNCTIONS = {
21011
21748
  if (isNumber(x) && x.im !== 0) {
21012
21749
  return `${gpuVec2(target)}(${formatFloat(-x.re)}, ${formatFloat(-x.im)})`;
21013
21750
  }
21014
- if (isSymbol2(x, "ImaginaryUnit"))
21015
- return `${gpuVec2(target)}(0.0, -1.0)`;
21751
+ if (isSymbol2(x, "ImaginaryUnit")) return `${gpuVec2(target)}(0.0, -1.0)`;
21016
21752
  return `(-${compile2(x)})`;
21017
21753
  },
21018
21754
  // Standard math functions with complex dispatch
@@ -21385,17 +22121,127 @@ var GPU_FUNCTIONS = {
21385
22121
  }
21386
22122
  const isWGSL = target?.language === "wgsl";
21387
22123
  const v3 = isWGSL ? "vec3f" : "vec3";
21388
- return `((_gpu_apca(${bg}, ${v3}(0.0)) > 50.0) ? ${v3}(0.0) : ${v3}(1.0))`;
22124
+ const black = `${v3}(0.0)`;
22125
+ const white = `${v3}(1.0, 0.0, 0.0)`;
22126
+ return `((_gpu_apca(${bg}, ${black}) > 50.0) ? ${black} : ${white})`;
21389
22127
  },
21390
22128
  ColorToColorspace: ([color, space], compile2) => {
21391
22129
  if (color === null || space === null)
21392
22130
  throw new Error("ColorToColorspace: need color and space");
21393
- return `_gpu_srgb_to_oklab(${compile2(color)})`;
22131
+ const spaceName = readStringLiteral(space);
22132
+ if (spaceName === null)
22133
+ throw new Error("ColorToColorspace: space must be a string literal");
22134
+ const c = compile2(color);
22135
+ switch (spaceName) {
22136
+ case "oklch":
22137
+ return c;
22138
+ case "oklab":
22139
+ case "lab":
22140
+ return `_gpu_oklch_to_oklab(${c})`;
22141
+ case "rgb":
22142
+ return `_gpu_oklch_to_srgb(${c})`;
22143
+ case "hsl":
22144
+ return `_gpu_rgb_to_hsl(_gpu_oklch_to_srgb(${c}))`;
22145
+ case "hsv":
22146
+ return `_gpu_rgb_to_hsv(_gpu_oklch_to_srgb(${c}))`;
22147
+ default:
22148
+ throw new Error(
22149
+ `ColorToColorspace: unsupported space "${spaceName}" on GPU target`
22150
+ );
22151
+ }
21394
22152
  },
21395
22153
  ColorFromColorspace: ([components, space], compile2) => {
21396
22154
  if (components === null || space === null)
21397
22155
  throw new Error("ColorFromColorspace: need components and space");
21398
- return `_gpu_oklab_to_srgb(${compile2(components)})`;
22156
+ const spaceName = readStringLiteral(space);
22157
+ if (spaceName === null)
22158
+ throw new Error("ColorFromColorspace: space must be a string literal");
22159
+ const c = compile2(components);
22160
+ switch (spaceName) {
22161
+ case "oklch":
22162
+ return c;
22163
+ case "oklab":
22164
+ case "lab":
22165
+ return `_gpu_oklab_to_oklch(${c})`;
22166
+ case "rgb":
22167
+ return `_gpu_srgb_to_oklch(${c})`;
22168
+ case "hsl":
22169
+ return `_gpu_srgb_to_oklch(_gpu_hsl_to_rgb(${c}))`;
22170
+ case "hsv":
22171
+ return `_gpu_srgb_to_oklch(_gpu_hsv_to_rgb(${c}))`;
22172
+ default:
22173
+ throw new Error(
22174
+ `ColorFromColorspace: unsupported space "${spaceName}" on GPU target`
22175
+ );
22176
+ }
22177
+ },
22178
+ // ---------------------------------------------------------------------------
22179
+ // Color literals. Each typed head compiles to a canonical OKLCh vec3.
22180
+ // Alpha (4th argument) is dropped — GPU color values are vec3 only. Pass
22181
+ // alpha as a separate uniform if it's needed at the framebuffer boundary.
22182
+ // ---------------------------------------------------------------------------
22183
+ Color: ([s], _compile, target) => {
22184
+ if (s === null) throw new Error("Color: no argument");
22185
+ const str = readStringLiteral(s);
22186
+ if (str === null)
22187
+ throw new Error("Color: argument must be a string literal on GPU target");
22188
+ const packed = parseColor(str);
22189
+ if (packed === 0 && str.trim().toLowerCase() !== "transparent")
22190
+ throw new Error(`Color: invalid color string "${str}"`);
22191
+ const r = packed >>> 24 & 255;
22192
+ const g = packed >>> 16 & 255;
22193
+ const b = packed >>> 8 & 255;
22194
+ const oklch2 = rgbToOklch({ r, g, b });
22195
+ return `${gpuVec3(target)}(${formatFloat(oklch2.L)}, ${formatFloat(oklch2.C)}, ${formatFloat(oklch2.H)})`;
22196
+ },
22197
+ Rgb: (args, compile2, target) => {
22198
+ if (args.length < 3) throw new Error("Rgb: need 3 components");
22199
+ const v3 = gpuVec3(target);
22200
+ return `_gpu_srgb_to_oklch(${v3}(${compile2(args[0])}, ${compile2(args[1])}, ${compile2(args[2])}))`;
22201
+ },
22202
+ Hsv: (args, compile2, target) => {
22203
+ if (args.length < 3) throw new Error("Hsv: need 3 components");
22204
+ const v3 = gpuVec3(target);
22205
+ return `_gpu_srgb_to_oklch(_gpu_hsv_to_rgb(${v3}(${compile2(args[0])}, ${compile2(args[1])}, ${compile2(args[2])})))`;
22206
+ },
22207
+ Hsl: (args, compile2, target) => {
22208
+ if (args.length < 3) throw new Error("Hsl: need 3 components");
22209
+ const v3 = gpuVec3(target);
22210
+ return `_gpu_srgb_to_oklch(_gpu_hsl_to_rgb(${v3}(${compile2(args[0])}, ${compile2(args[1])}, ${compile2(args[2])})))`;
22211
+ },
22212
+ Oklab: (args, compile2, target) => {
22213
+ if (args.length < 3) throw new Error("Oklab: need 3 components");
22214
+ const v3 = gpuVec3(target);
22215
+ return `_gpu_oklab_to_oklch(${v3}(${compile2(args[0])}, ${compile2(args[1])}, ${compile2(args[2])}))`;
22216
+ },
22217
+ Oklch: (args, compile2, target) => {
22218
+ if (args.length < 3) throw new Error("Oklch: need 3 components");
22219
+ const v3 = gpuVec3(target);
22220
+ return `${v3}(${compile2(args[0])}, ${compile2(args[1])}, ${compile2(args[2])})`;
22221
+ },
22222
+ // ---------------------------------------------------------------------------
22223
+ // As* operators. AsOklch is identity (canonical). The other As* return
22224
+ // components in the named space, equivalent to ColorToColorspace(c, 'x').
22225
+ // ---------------------------------------------------------------------------
22226
+ AsOklch: ([c], compile2) => {
22227
+ if (c === null) throw new Error("AsOklch: no argument");
22228
+ return compile2(c);
22229
+ },
22230
+ AsOklab: ([c], compile2) => {
22231
+ if (c === null) throw new Error("AsOklab: no argument");
22232
+ return `_gpu_oklch_to_oklab(${compile2(c)})`;
22233
+ },
22234
+ AsRgb: ([c], compile2) => {
22235
+ if (c === null) throw new Error("AsRgb: no argument");
22236
+ return `_gpu_oklch_to_srgb(${compile2(c)})`;
22237
+ },
22238
+ AsHsv: ([c], compile2) => {
22239
+ if (c === null) throw new Error("AsHsv: no argument");
22240
+ return `_gpu_rgb_to_hsv(_gpu_oklch_to_srgb(${compile2(c)}))`;
22241
+ },
22242
+ AsHsl: ([c], compile2) => {
22243
+ if (c === null) throw new Error("AsHsl: no argument");
22244
+ return `_gpu_rgb_to_hsl(_gpu_oklch_to_srgb(${compile2(c)}))`;
21399
22245
  },
21400
22246
  // Fractal functions
21401
22247
  Mandelbrot: ([c, maxIter], compile2, target) => {
@@ -22088,28 +22934,124 @@ vec3 _gpu_oklab_to_srgb(vec3 lab) {
22088
22934
 
22089
22935
  vec3 _gpu_oklab_to_oklch(vec3 lab) {
22090
22936
  float C = length(lab.yz);
22091
- float H = atan(lab.z, lab.y);
22937
+ float H = atan(lab.z, lab.y) * (180.0 / 3.14159265359);
22938
+ if (H < 0.0) H += 360.0;
22092
22939
  return vec3(lab.x, C, H);
22093
22940
  }
22094
22941
 
22095
22942
  vec3 _gpu_oklch_to_oklab(vec3 lch) {
22096
- return vec3(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));
22943
+ float h_rad = lch.z * (3.14159265359 / 180.0);
22944
+ return vec3(lch.x, lch.y * cos(h_rad), lch.y * sin(h_rad));
22945
+ }
22946
+
22947
+ vec3 _gpu_srgb_to_oklch(vec3 rgb) {
22948
+ return _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb));
22949
+ }
22950
+
22951
+ vec3 _gpu_oklch_to_srgb(vec3 lch) {
22952
+ return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(lch));
22953
+ }
22954
+
22955
+ // HSL conversion. Hue in degrees, saturation/lightness in 0-1.
22956
+ vec3 _gpu_hsl_to_rgb(vec3 hsl) {
22957
+ float h = hsl.x;
22958
+ float s = hsl.y;
22959
+ float l = hsl.z;
22960
+ float c = (1.0 - abs(2.0 * l - 1.0)) * s;
22961
+ float h6 = h / 60.0;
22962
+ float x = c * (1.0 - abs(mod(h6, 2.0) - 1.0));
22963
+ float r = 0.0;
22964
+ float g = 0.0;
22965
+ float b = 0.0;
22966
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
22967
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
22968
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
22969
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
22970
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
22971
+ else { r = c; g = 0.0; b = x; }
22972
+ float m = l - c / 2.0;
22973
+ return vec3(r + m, g + m, b + m);
22097
22974
  }
22098
22975
 
22099
- vec3 _gpu_color_mix(vec3 rgb1, vec3 rgb2, float t) {
22100
- vec3 lch1 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb1));
22101
- vec3 lch2 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb2));
22976
+ vec3 _gpu_rgb_to_hsl(vec3 rgb) {
22977
+ float maxc = max(max(rgb.x, rgb.y), rgb.z);
22978
+ float minc = min(min(rgb.x, rgb.y), rgb.z);
22979
+ float l = (maxc + minc) / 2.0;
22980
+ float d = maxc - minc;
22981
+ if (d < 1e-6) return vec3(0.0, 0.0, l);
22982
+ float s = d / (1.0 - abs(2.0 * l - 1.0));
22983
+ float h;
22984
+ if (maxc == rgb.x) h = mod((rgb.y - rgb.z) / d, 6.0);
22985
+ else if (maxc == rgb.y) h = (rgb.z - rgb.x) / d + 2.0;
22986
+ else h = (rgb.x - rgb.y) / d + 4.0;
22987
+ h *= 60.0;
22988
+ if (h < 0.0) h += 360.0;
22989
+ return vec3(h, s, l);
22990
+ }
22991
+
22992
+ // HSV conversion. Hue in degrees, saturation/value in 0-1.
22993
+ vec3 _gpu_hsv_to_rgb(vec3 hsv) {
22994
+ float h = hsv.x;
22995
+ float s = hsv.y;
22996
+ float v = hsv.z;
22997
+ float c = v * s;
22998
+ float h6 = h / 60.0;
22999
+ float x = c * (1.0 - abs(mod(h6, 2.0) - 1.0));
23000
+ float r = 0.0;
23001
+ float g = 0.0;
23002
+ float b = 0.0;
23003
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
23004
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
23005
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
23006
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
23007
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
23008
+ else { r = c; g = 0.0; b = x; }
23009
+ float m = v - c;
23010
+ return vec3(r + m, g + m, b + m);
23011
+ }
23012
+
23013
+ vec3 _gpu_rgb_to_hsv(vec3 rgb) {
23014
+ float maxc = max(max(rgb.x, rgb.y), rgb.z);
23015
+ float minc = min(min(rgb.x, rgb.y), rgb.z);
23016
+ float v = maxc;
23017
+ float d = maxc - minc;
23018
+ if (d < 1e-6) return vec3(0.0, 0.0, v);
23019
+ float s = (maxc < 1e-6) ? 0.0 : d / maxc;
23020
+ float h;
23021
+ if (maxc == rgb.x) h = mod((rgb.y - rgb.z) / d, 6.0);
23022
+ else if (maxc == rgb.y) h = (rgb.z - rgb.x) / d + 2.0;
23023
+ else h = (rgb.x - rgb.y) / d + 4.0;
23024
+ h *= 60.0;
23025
+ if (h < 0.0) h += 360.0;
23026
+ return vec3(h, s, v);
23027
+ }
23028
+
23029
+ vec3 _gpu_color_mix(vec3 lch1, vec3 lch2, float t) {
22102
23030
  float L = mix(lch1.x, lch2.x, t);
22103
23031
  float C = mix(lch1.y, lch2.y, t);
22104
- float dh = lch2.z - lch1.z;
22105
- const float PI = 3.14159265359;
22106
- if (dh > PI) dh -= 2.0 * PI;
22107
- if (dh < -PI) dh += 2.0 * PI;
22108
- float H = lch1.z + dh * t;
22109
- return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(vec3(L, C, H)));
23032
+ bool a1 = lch1.y < 1e-6;
23033
+ bool a2 = lch2.y < 1e-6;
23034
+ float H;
23035
+ if (a1 && a2) {
23036
+ H = lch1.z;
23037
+ } else if (a1) {
23038
+ H = lch2.z;
23039
+ } else if (a2) {
23040
+ H = lch1.z;
23041
+ } else {
23042
+ float dh = lch2.z - lch1.z;
23043
+ if (dh > 180.0) dh -= 360.0;
23044
+ if (dh < -180.0) dh += 360.0;
23045
+ H = lch1.z + dh * t;
23046
+ if (H < 0.0) H += 360.0;
23047
+ if (H >= 360.0) H -= 360.0;
23048
+ }
23049
+ return vec3(L, C, H);
22110
23050
  }
22111
23051
 
22112
- float _gpu_apca(vec3 bg, vec3 fg) {
23052
+ float _gpu_apca(vec3 lch_bg, vec3 lch_fg) {
23053
+ vec3 bg = _gpu_oklch_to_srgb(lch_bg);
23054
+ vec3 fg = _gpu_oklch_to_srgb(lch_fg);
22113
23055
  float bgR = _gpu_srgb_to_linear(bg.x);
22114
23056
  float bgG = _gpu_srgb_to_linear(bg.y);
22115
23057
  float bgB = _gpu_srgb_to_linear(bg.z);
@@ -22120,9 +23062,7 @@ float _gpu_apca(vec3 bg, vec3 fg) {
22120
23062
  float fgY = 0.2126729 * fgR + 0.7151522 * fgG + 0.0721750 * fgB;
22121
23063
  float bgC = pow(bgY, 0.56);
22122
23064
  float fgC = pow(fgY, 0.57);
22123
- float contrast = (bgC > fgC)
22124
- ? (bgC - fgC) * 1.14
22125
- : (bgC - fgC) * 1.14;
23065
+ float contrast = (bgC - fgC) * 1.14;
22126
23066
  return contrast * 100.0;
22127
23067
  }
22128
23068
  `;
@@ -22166,28 +23106,133 @@ fn _gpu_oklab_to_srgb(lab: vec3f) -> vec3f {
22166
23106
 
22167
23107
  fn _gpu_oklab_to_oklch(lab: vec3f) -> vec3f {
22168
23108
  let C = length(lab.yz);
22169
- let H = atan2(lab.z, lab.y);
23109
+ var H = atan2(lab.z, lab.y) * (180.0 / 3.14159265359);
23110
+ if (H < 0.0) { H = H + 360.0; }
22170
23111
  return vec3f(lab.x, C, H);
22171
23112
  }
22172
23113
 
22173
23114
  fn _gpu_oklch_to_oklab(lch: vec3f) -> vec3f {
22174
- return vec3f(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));
23115
+ let h_rad = lch.z * (3.14159265359 / 180.0);
23116
+ return vec3f(lch.x, lch.y * cos(h_rad), lch.y * sin(h_rad));
22175
23117
  }
22176
23118
 
22177
- fn _gpu_color_mix(rgb1: vec3f, rgb2: vec3f, t: f32) -> vec3f {
22178
- let lch1 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb1));
22179
- let lch2 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb2));
23119
+ fn _gpu_srgb_to_oklch(rgb: vec3f) -> vec3f {
23120
+ return _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb));
23121
+ }
23122
+
23123
+ fn _gpu_oklch_to_srgb(lch: vec3f) -> vec3f {
23124
+ return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(lch));
23125
+ }
23126
+
23127
+ fn _gpu_hsl_to_rgb(hsl: vec3f) -> vec3f {
23128
+ let h = hsl.x;
23129
+ let s = hsl.y;
23130
+ let l = hsl.z;
23131
+ let c = (1.0 - abs(2.0 * l - 1.0)) * s;
23132
+ let h6 = h / 60.0;
23133
+ let x = c * (1.0 - abs((h6 - 2.0 * floor(h6 / 2.0)) - 1.0));
23134
+ var r: f32 = 0.0;
23135
+ var g: f32 = 0.0;
23136
+ var b: f32 = 0.0;
23137
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
23138
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
23139
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
23140
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
23141
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
23142
+ else { r = c; g = 0.0; b = x; }
23143
+ let m = l - c / 2.0;
23144
+ return vec3f(r + m, g + m, b + m);
23145
+ }
23146
+
23147
+ fn _gpu_rgb_to_hsl(rgb: vec3f) -> vec3f {
23148
+ let maxc = max(max(rgb.x, rgb.y), rgb.z);
23149
+ let minc = min(min(rgb.x, rgb.y), rgb.z);
23150
+ let l = (maxc + minc) / 2.0;
23151
+ let d = maxc - minc;
23152
+ if (d < 1e-6) { return vec3f(0.0, 0.0, l); }
23153
+ let s = d / (1.0 - abs(2.0 * l - 1.0));
23154
+ var h: f32;
23155
+ if (maxc == rgb.x) {
23156
+ let v = (rgb.y - rgb.z) / d;
23157
+ h = v - 6.0 * floor(v / 6.0);
23158
+ } else if (maxc == rgb.y) {
23159
+ h = (rgb.z - rgb.x) / d + 2.0;
23160
+ } else {
23161
+ h = (rgb.x - rgb.y) / d + 4.0;
23162
+ }
23163
+ h = h * 60.0;
23164
+ if (h < 0.0) { h = h + 360.0; }
23165
+ return vec3f(h, s, l);
23166
+ }
23167
+
23168
+ fn _gpu_hsv_to_rgb(hsv: vec3f) -> vec3f {
23169
+ let h = hsv.x;
23170
+ let s = hsv.y;
23171
+ let v = hsv.z;
23172
+ let c = v * s;
23173
+ let h6 = h / 60.0;
23174
+ let x = c * (1.0 - abs((h6 - 2.0 * floor(h6 / 2.0)) - 1.0));
23175
+ var r: f32 = 0.0;
23176
+ var g: f32 = 0.0;
23177
+ var b: f32 = 0.0;
23178
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
23179
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
23180
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
23181
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
23182
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
23183
+ else { r = c; g = 0.0; b = x; }
23184
+ let m = v - c;
23185
+ return vec3f(r + m, g + m, b + m);
23186
+ }
23187
+
23188
+ fn _gpu_rgb_to_hsv(rgb: vec3f) -> vec3f {
23189
+ let maxc = max(max(rgb.x, rgb.y), rgb.z);
23190
+ let minc = min(min(rgb.x, rgb.y), rgb.z);
23191
+ let v = maxc;
23192
+ let d = maxc - minc;
23193
+ if (d < 1e-6) { return vec3f(0.0, 0.0, v); }
23194
+ var s: f32 = 0.0;
23195
+ if (maxc >= 1e-6) { s = d / maxc; }
23196
+ var h: f32;
23197
+ if (maxc == rgb.x) {
23198
+ let q = (rgb.y - rgb.z) / d;
23199
+ h = q - 6.0 * floor(q / 6.0);
23200
+ } else if (maxc == rgb.y) {
23201
+ h = (rgb.z - rgb.x) / d + 2.0;
23202
+ } else {
23203
+ h = (rgb.x - rgb.y) / d + 4.0;
23204
+ }
23205
+ h = h * 60.0;
23206
+ if (h < 0.0) { h = h + 360.0; }
23207
+ return vec3f(h, s, v);
23208
+ }
23209
+
23210
+ fn _gpu_color_mix(lch1: vec3f, lch2: vec3f, t: f32) -> vec3f {
22180
23211
  let L = mix(lch1.x, lch2.x, t);
22181
23212
  let C = mix(lch1.y, lch2.y, t);
22182
- let PI = 3.14159265359;
22183
- var dh = lch2.z - lch1.z;
22184
- if (dh > PI) { dh -= 2.0 * PI; }
22185
- if (dh < -PI) { dh += 2.0 * PI; }
22186
- let H = lch1.z + dh * t;
22187
- return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(vec3f(L, C, H)));
23213
+ let a1 = lch1.y < 1e-6;
23214
+ let a2 = lch2.y < 1e-6;
23215
+ var H: f32;
23216
+ if (a1 && a2) {
23217
+ H = lch1.z;
23218
+ } else if (a1) {
23219
+ H = lch2.z;
23220
+ } else if (a2) {
23221
+ H = lch1.z;
23222
+ } else {
23223
+ var dh = lch2.z - lch1.z;
23224
+ if (dh > 180.0) { dh = dh - 360.0; }
23225
+ if (dh < -180.0) { dh = dh + 360.0; }
23226
+ H = lch1.z + dh * t;
23227
+ if (H < 0.0) { H = H + 360.0; }
23228
+ if (H >= 360.0) { H = H - 360.0; }
23229
+ }
23230
+ return vec3f(L, C, H);
22188
23231
  }
22189
23232
 
22190
- fn _gpu_apca(bg: vec3f, fg: vec3f) -> f32 {
23233
+ fn _gpu_apca(lch_bg: vec3f, lch_fg: vec3f) -> f32 {
23234
+ let bg = _gpu_oklch_to_srgb(lch_bg);
23235
+ let fg = _gpu_oklch_to_srgb(lch_fg);
22191
23236
  let bgR = _gpu_srgb_to_linear(bg.x);
22192
23237
  let bgG = _gpu_srgb_to_linear(bg.y);
22193
23238
  let bgB = _gpu_srgb_to_linear(bg.z);
@@ -22475,7 +23520,7 @@ var GPUShaderTarget = class {
22475
23520
  if (stmts.length === 0) return "";
22476
23521
  const last = stmts.length - 1;
22477
23522
  stmts[last] = `return ${stmts[last]}`;
22478
- return stmts.join(";\n");
23523
+ return stmts.join(";\n") + ";";
22479
23524
  },
22480
23525
  ...options
22481
23526
  };
@@ -22574,7 +23619,7 @@ var GLSLTarget = class extends GPUShaderTarget {
22574
23619
  if (body.includes("\n")) {
22575
23620
  const indented = body.split("\n").map((l) => ` ${l}`).join("\n");
22576
23621
  return `${returnType} ${functionName}(${params}) {
22577
- ${indented};
23622
+ ${indented}
22578
23623
  }`;
22579
23624
  }
22580
23625
  return `${returnType} ${functionName}(${params}) {
@@ -22685,7 +23730,7 @@ var WGSLTarget = class extends GPUShaderTarget {
22685
23730
  return `fn ${functionName}(${params}) -> ${toWGSLType(
22686
23731
  returnType
22687
23732
  )} {
22688
- ${indented};
23733
+ ${indented}
22689
23734
  }`;
22690
23735
  }
22691
23736
  return `fn ${functionName}(${params}) -> ${toWGSLType(returnType)} {
@@ -24864,7 +25909,7 @@ function compileToIntervalTarget(expr, target) {
24864
25909
  }
24865
25910
 
24866
25911
  // src/compile.ts
24867
- var version = "0.55.6";
25912
+ var version = "0.57.0";
24868
25913
  export {
24869
25914
  BaseCompiler,
24870
25915
  GLSLTarget,