@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
- /** Compile 0.55.6 */
1
+ /** Compile 0.57.0 */
2
2
  (function(global,factory){typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'],factory):(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Compile = {}));})(this, (function (exports) { 'use strict';
3
3
  var Compile = (() => {
4
4
  var __defProp = Object.defineProperty;
@@ -1544,6 +1544,7 @@ var Compile = (() => {
1544
1544
  ];
1545
1545
  var VALUE_TYPES = [
1546
1546
  "value",
1547
+ "color",
1547
1548
  ...COLLECTION_TYPES,
1548
1549
  ...SCALAR_TYPES
1549
1550
  ];
@@ -3239,6 +3240,7 @@ var Compile = (() => {
3239
3240
  symbol: [],
3240
3241
  boolean: [],
3241
3242
  string: [],
3243
+ color: [],
3242
3244
  expression: EXPRESSION_TYPES
3243
3245
  };
3244
3246
  function isPrimitiveSubtype(lhs, rhs) {
@@ -5209,6 +5211,64 @@ var Compile = (() => {
5209
5211
  }
5210
5212
 
5211
5213
  // src/compute-engine/latex-syntax/dictionary/definitions-core.ts
5214
+ var COMPONENT_ACCESS_HEADS = {
5215
+ x: "First",
5216
+ y: "Second",
5217
+ z: "Third",
5218
+ real: "Real",
5219
+ re: "Real",
5220
+ imag: "Imaginary",
5221
+ im: "Imaginary",
5222
+ count: "Length",
5223
+ total: "Sum",
5224
+ max: "Max",
5225
+ min: "Min"
5226
+ };
5227
+ function memberHead(name) {
5228
+ return COMPONENT_ACCESS_HEADS[name] ?? null;
5229
+ }
5230
+ function parseComponentAccess(parser, lhs) {
5231
+ parser.skipVisualSpace();
5232
+ if (parser.match("\\operatorname")) {
5233
+ const name = parser.parseStringGroup();
5234
+ if (name === null) return null;
5235
+ const head = memberHead(name.trim());
5236
+ if (head === null) return null;
5237
+ return [head, lhs];
5238
+ }
5239
+ const tok = parser.peek;
5240
+ if (typeof tok === "string" && tok.startsWith("\\")) {
5241
+ const bare = tok.slice(1);
5242
+ const head = memberHead(bare);
5243
+ if (head !== null) {
5244
+ parser.nextToken();
5245
+ return [head, lhs];
5246
+ }
5247
+ return null;
5248
+ }
5249
+ if (typeof tok === "string" && /^[a-zA-Z]$/.test(tok)) {
5250
+ const head = memberHead(tok);
5251
+ if (head === null) return null;
5252
+ parser.nextToken();
5253
+ return [head, lhs];
5254
+ }
5255
+ return null;
5256
+ }
5257
+ function parseWhenRestriction(parser, lhs, close) {
5258
+ parser.addBoundary(close);
5259
+ parser.skipVisualSpace();
5260
+ const cond = parser.parseExpression({ minPrec: 0 });
5261
+ if (cond === null) {
5262
+ parser.removeBoundary();
5263
+ return null;
5264
+ }
5265
+ parser.skipVisualSpace();
5266
+ if (!parser.matchBoundary()) {
5267
+ parser.removeBoundary();
5268
+ return null;
5269
+ }
5270
+ return ["When", lhs, cond];
5271
+ }
5212
5272
  function parseSequence(parser, terminator, lhs, prec, sep) {
5213
5273
  if (terminator && terminator.minPrec >= prec) return null;
5214
5274
  const result = lhs ? [lhs] : ["Nothing"];
@@ -5680,6 +5740,15 @@ var Compile = (() => {
5680
5740
  }
5681
5741
  },
5682
5742
  { name: "LatexTokens", serialize: serializeLatexTokens },
5743
+ // Component-access postfix: expr.member (C3)
5744
+ // The '.' trigger is consumed before the parse function is called.
5745
+ // Precedence 850 > 810 (At/indexing) so .x chains tightly.
5746
+ {
5747
+ kind: "postfix",
5748
+ precedence: 850,
5749
+ latexTrigger: ["."],
5750
+ parse: parseComponentAccess
5751
+ },
5683
5752
  {
5684
5753
  name: "At",
5685
5754
  kind: "postfix",
@@ -5700,6 +5769,29 @@ var Compile = (() => {
5700
5769
  latexTrigger: ["\\left", "\\lbrack"],
5701
5770
  parse: parseAt("\\right", "\\rbrack")
5702
5771
  },
5772
+ // When-restriction: `expr\left\{cond\right\}` → `When(expr, cond)` (D3)
5773
+ {
5774
+ name: "When",
5775
+ kind: "postfix",
5776
+ precedence: 800,
5777
+ latexTrigger: ["\\left", "\\{"],
5778
+ parse: (parser, lhs) => parseWhenRestriction(parser, lhs, ["\\right", "\\}"]),
5779
+ serialize: (serializer, expr) => {
5780
+ const e = operand(expr, 1);
5781
+ const cond = operand(expr, 2);
5782
+ if (!e || !cond) return "";
5783
+ const clauses = operator(cond) === "And" ? operands(cond) ?? [] : [cond];
5784
+ const inner = clauses.map((c) => `\\left\\{${serializer.serialize(c)}\\right\\}`).join("");
5785
+ return `${serializer.serialize(e)}${inner}`;
5786
+ }
5787
+ },
5788
+ // When-restriction: bare `expr\{cond\}` → `When(expr, cond)`
5789
+ {
5790
+ kind: "postfix",
5791
+ precedence: 800,
5792
+ latexTrigger: ["\\{"],
5793
+ parse: (parser, lhs) => parseWhenRestriction(parser, lhs, ["\\}"])
5794
+ },
5703
5795
  {
5704
5796
  kind: "postfix",
5705
5797
  latexTrigger: ["_"],
@@ -5782,6 +5874,29 @@ var Compile = (() => {
5782
5874
  return "";
5783
5875
  }
5784
5876
  },
5877
+ // Additional triggers for Range: `...`, `\ldots`, and `\dots` are
5878
+ // equivalent to `..` when used as infix operators (e.g. `[1...9]`).
5879
+ // No `name` field here — names must be unique per the dictionary rules;
5880
+ // the first Range entry owns the name. When there is no LHS the symbol
5881
+ // entries near the top of the file still fire (ContinuationPlaceholder).
5882
+ {
5883
+ latexTrigger: [".", ".", "."],
5884
+ kind: "infix",
5885
+ precedence: 800,
5886
+ parse: parseRange
5887
+ },
5888
+ {
5889
+ latexTrigger: ["\\ldots"],
5890
+ kind: "infix",
5891
+ precedence: 800,
5892
+ parse: parseRange
5893
+ },
5894
+ {
5895
+ latexTrigger: ["\\dots"],
5896
+ kind: "infix",
5897
+ precedence: 800,
5898
+ parse: parseRange
5899
+ },
5785
5900
  {
5786
5901
  latexTrigger: [";"],
5787
5902
  kind: "infix",
@@ -5966,13 +6081,24 @@ var Compile = (() => {
5966
6081
  const args = operands(expr);
5967
6082
  if (!args || args.length < 2) return "";
5968
6083
  const body = args[0];
5969
- const indexing = args[1];
5970
- if (operator(indexing) === "Element") {
5971
- const index = operand(indexing, 1);
5972
- const range2 = operand(indexing, 2);
5973
- if (operator(range2) === "Range") {
5974
- const lo = operand(range2, 1);
5975
- const hi = operand(range2, 2);
6084
+ const elements = args.slice(1);
6085
+ const allElements = elements.every((e) => operator(e) === "Element");
6086
+ if (!allElements) {
6087
+ return joinLatex([
6088
+ "\\operatorname{Loop}(",
6089
+ serializer.serialize(body),
6090
+ ", ",
6091
+ serializer.serialize(elements[0]),
6092
+ ")"
6093
+ ]);
6094
+ }
6095
+ if (elements.length === 1) {
6096
+ const elem = elements[0];
6097
+ const index = operand(elem, 1);
6098
+ const coll = operand(elem, 2);
6099
+ if (operator(coll) === "Range") {
6100
+ const lo = operand(coll, 1);
6101
+ const hi = operand(coll, 2);
5976
6102
  return joinLatex([
5977
6103
  "\\text{for }",
5978
6104
  serializer.serialize(index),
@@ -5984,13 +6110,27 @@ var Compile = (() => {
5984
6110
  serializer.serialize(body)
5985
6111
  ]);
5986
6112
  }
6113
+ return joinLatex([
6114
+ serializer.serialize(body),
6115
+ " \\operatorname{for} ",
6116
+ serializer.serialize(index),
6117
+ " = ",
6118
+ serializer.serialize(coll)
6119
+ ]);
5987
6120
  }
6121
+ const bindings = elements.map((elem) => {
6122
+ const name = operand(elem, 1);
6123
+ const coll = operand(elem, 2);
6124
+ return joinLatex([
6125
+ serializer.serialize(name),
6126
+ " = ",
6127
+ serializer.serialize(coll)
6128
+ ]);
6129
+ }).join(", ");
5988
6130
  return joinLatex([
5989
- "\\operatorname{Loop}(",
5990
6131
  serializer.serialize(body),
5991
- ", ",
5992
- serializer.serialize(indexing),
5993
- ")"
6132
+ " \\operatorname{for} ",
6133
+ bindings
5994
6134
  ]);
5995
6135
  }
5996
6136
  },
@@ -6023,6 +6163,18 @@ var Compile = (() => {
6023
6163
  precedence: 245,
6024
6164
  parse: (parser, until) => parseForExpression(parser, until)
6025
6165
  },
6166
+ // \operatorname{for} as postfix infix (list comprehension):
6167
+ // `body \operatorname{for} x = L_1, y = L_2`
6168
+ // Precedence 19 — just below comma (20) so the body is allowed to use
6169
+ // any operator (including comma sequencing) up to the keyword, and the
6170
+ // bindings can be comma-separated below us.
6171
+ {
6172
+ symbolTrigger: "for",
6173
+ kind: "infix",
6174
+ associativity: "none",
6175
+ precedence: 19,
6176
+ parse: (parser, lhs, until) => parseForComprehension(parser, lhs, until)
6177
+ },
6026
6178
  // \operatorname{break}
6027
6179
  {
6028
6180
  symbolTrigger: "break",
@@ -6227,7 +6379,10 @@ var Compile = (() => {
6227
6379
  if (!sym2 || !parser.getSymbolType(sym2).matches("function")) return null;
6228
6380
  parser.addBoundary([")"]);
6229
6381
  const expr = parser.parseExpression(until);
6230
- if (!parser.matchBoundary()) return null;
6382
+ if (!parser.matchBoundary()) {
6383
+ parser.removeBoundary();
6384
+ return null;
6385
+ }
6231
6386
  if (!parser.match("<}>")) return null;
6232
6387
  return ["Derivative", lhs, expr];
6233
6388
  }
@@ -6668,7 +6823,12 @@ var Compile = (() => {
6668
6823
  if (isEmptySequence(body)) return ["List"];
6669
6824
  const h = operator(body);
6670
6825
  if (h === "Range" || h === "Linspace") return body;
6671
- if (h === "Sequence") return ["List", ...operands(body)];
6826
+ if (h === "Sequence") {
6827
+ const elems = operands(body);
6828
+ const inferred = tryInferRangeFromElements(elems, parser);
6829
+ if (inferred) return inferred;
6830
+ return ["List", ...elems];
6831
+ }
6672
6832
  if (h === "Delimiter") {
6673
6833
  const delim = stringValue(operand(body, 2)) ?? "...";
6674
6834
  if (delim === ";" || delim === ".;.") {
@@ -6681,12 +6841,37 @@ var Compile = (() => {
6681
6841
  }
6682
6842
  if (delim === "," || delim === ".,.") {
6683
6843
  body = operand(body, 1);
6684
- if (operator(body) === "Sequence") return ["List", ...operands(body)];
6844
+ if (operator(body) === "Sequence") {
6845
+ const elems = operands(body);
6846
+ const inferred = tryInferRangeFromElements(elems, parser);
6847
+ if (inferred) return inferred;
6848
+ return ["List", ...elems];
6849
+ }
6685
6850
  return ["List", body ?? "Nothing"];
6686
6851
  }
6687
6852
  }
6688
6853
  return ["List", body];
6689
6854
  }
6855
+ function tryInferRangeFromElements(elems, parser) {
6856
+ if (elems.length < 4) return null;
6857
+ const penultimate = elems[elems.length - 2];
6858
+ if (symbol(penultimate) !== "ContinuationPlaceholder") return null;
6859
+ const samples = elems.slice(0, -2);
6860
+ const endExpr = elems[elems.length - 1];
6861
+ if (samples.length < 2) return null;
6862
+ const sampleNums = samples.map(machineValue);
6863
+ if (sampleNums.some((n) => n === null)) return null;
6864
+ const nums = sampleNums;
6865
+ const step = nums[nums.length - 1] - nums[nums.length - 2];
6866
+ const tol = parser.options.tolerance;
6867
+ if (Math.abs(step) < tol)
6868
+ return parser.error("degenerate-range-step", parser.index);
6869
+ for (let i = 1; i < nums.length; i++) {
6870
+ if (Math.abs(nums[i] - nums[i - 1] - step) > tol)
6871
+ return parser.error("inconsistent-range-samples", parser.index);
6872
+ }
6873
+ return ["Range", nums[0], endExpr, step];
6874
+ }
6690
6875
  function serializeList(serializer, expr) {
6691
6876
  if (nops(expr) > 1 && operands(expr).every((x) => {
6692
6877
  const op = operator(x);
@@ -6938,6 +7123,35 @@ var Compile = (() => {
6938
7123
  ["Element", index, ["Range", lower, upper]]
6939
7124
  ];
6940
7125
  }
7126
+ function parseForComprehension(parser, lhs, until) {
7127
+ const bindingTerminator = {
7128
+ minPrec: 21,
7129
+ // Above comma (20) and ; (19), so `x = L_1` is captured whole
7130
+ condition: (p) => {
7131
+ if (until?.condition?.(p)) return true;
7132
+ const saved = p.index;
7133
+ p.skipVisualSpace();
7134
+ const isComma = p.peek === ",";
7135
+ p.index = saved;
7136
+ return isComma;
7137
+ }
7138
+ };
7139
+ const elements = [];
7140
+ do {
7141
+ parser.skipVisualSpace();
7142
+ const binding = parser.parseExpression(bindingTerminator);
7143
+ if (binding === null) break;
7144
+ const op = operator(binding);
7145
+ if (op !== "Equal" && op !== "Assign") return null;
7146
+ const name = operand(binding, 1);
7147
+ const list = operand(binding, 2);
7148
+ if (!name || !list) return null;
7149
+ elements.push(["Element", name, list]);
7150
+ parser.skipVisualSpace();
7151
+ } while (parser.match(","));
7152
+ if (elements.length === 0) return null;
7153
+ return ["Loop", lhs, ...elements];
7154
+ }
6941
7155
  function parseWhereExpression(parser, lhs, until) {
6942
7156
  const bindingTerminator = {
6943
7157
  minPrec: 21,
@@ -8826,6 +9040,8 @@ var Compile = (() => {
8826
9040
  precedence: DIVISION_PRECEDENCE,
8827
9041
  parse: "Mod"
8828
9042
  },
9043
+ // Function-style alias: `\operatorname{mod}(a, b)`
9044
+ { latexTrigger: "\\operatorname{mod}", parse: "Mod" },
8829
9045
  {
8830
9046
  latexTrigger: "\\pmod",
8831
9047
  kind: "prefix",
@@ -9066,6 +9282,13 @@ var Compile = (() => {
9066
9282
  const rhs = serializer.wrap(operand(expr, 2), ADDITION_PRECEDENCE + 3);
9067
9283
  return joinLatex([lhs, "-", rhs]);
9068
9284
  }
9285
+ },
9286
+ // Euclidean distance between two points (tuples of numbers).
9287
+ {
9288
+ name: "Distance",
9289
+ latexTrigger: ["\\operatorname{distance}"],
9290
+ kind: "function",
9291
+ serialize: (serializer, expr) => "\\operatorname{distance}" + serializer.wrapArguments(expr)
9069
9292
  }
9070
9293
  ];
9071
9294
  function getIndexAssignment(expr, upper) {
@@ -10490,7 +10713,9 @@ var Compile = (() => {
10490
10713
  if (!expr || !symbol(expr)) return null;
10491
10714
  return ["Mean", expr];
10492
10715
  }
10493
- }
10716
+ },
10717
+ // Function-style alias: `\operatorname{var}(...)`
10718
+ { latexTrigger: "\\operatorname{var}", parse: "Variance" }
10494
10719
  ];
10495
10720
 
10496
10721
  // src/compute-engine/numerics/unit-data.ts
@@ -11498,7 +11723,7 @@ var Compile = (() => {
11498
11723
  36: "\\qquad"
11499
11724
  }[v] ?? "";
11500
11725
  }
11501
- }
11726
+ },
11502
11727
  // if (
11503
11728
  // [
11504
11729
  // '\\!',
@@ -11522,6 +11747,121 @@ var Compile = (() => {
11522
11747
  // name: '',
11523
11748
  // trigger: '\\check',
11524
11749
  // },
11750
+ // ---------------------------------------------------------------------------
11751
+ // Function-style aliases for collection / random operators that some
11752
+ // notations write in lowercase (e.g. `\operatorname{shuffle}(L)`).
11753
+ // The capitalized library entries already exist; these are pure parse
11754
+ // aliases so the lowercase names don't land in `unsupported-operator`.
11755
+ // ---------------------------------------------------------------------------
11756
+ { latexTrigger: "\\operatorname{random}", parse: "Random" },
11757
+ { latexTrigger: "\\operatorname{shuffle}", parse: "Shuffle" },
11758
+ { latexTrigger: "\\operatorname{repeat}", parse: "Repeat" },
11759
+ { latexTrigger: "\\operatorname{join}", parse: "Join" },
11760
+ // ---------------------------------------------------------------------------
11761
+ // Geometric primitive heads. Registered as known typed heads so consumers
11762
+ // can branch on the operator name; CE itself doesn't render them. The
11763
+ // library entries (with no evaluator) live in `library/core.ts`.
11764
+ // ---------------------------------------------------------------------------
11765
+ {
11766
+ name: "Triangle",
11767
+ latexTrigger: ["\\operatorname{triangle}"],
11768
+ kind: "function",
11769
+ serialize: (serializer, expr) => "\\operatorname{triangle}" + serializer.wrapArguments(expr)
11770
+ },
11771
+ // Desmos's geometric `vector(p1, p2)` — a directed segment between two
11772
+ // points. Routed to a dedicated head (not the existing column-vector
11773
+ // `Vector`, which has a narrower `(number+) -> vector` signature).
11774
+ {
11775
+ name: "GeometricVector",
11776
+ latexTrigger: ["\\operatorname{vector}"],
11777
+ kind: "function",
11778
+ serialize: (serializer, expr) => "\\operatorname{vector}" + serializer.wrapArguments(expr)
11779
+ },
11780
+ {
11781
+ name: "Sphere",
11782
+ latexTrigger: ["\\operatorname{sphere}"],
11783
+ kind: "function",
11784
+ serialize: (serializer, expr) => "\\operatorname{sphere}" + serializer.wrapArguments(expr)
11785
+ },
11786
+ {
11787
+ name: "Segment",
11788
+ latexTrigger: ["\\operatorname{segment}"],
11789
+ kind: "function",
11790
+ serialize: (serializer, expr) => "\\operatorname{segment}" + serializer.wrapArguments(expr)
11791
+ }
11792
+ ];
11793
+
11794
+ // src/compute-engine/latex-syntax/dictionary/definitions-colors.ts
11795
+ var DEFINITIONS_COLORS = [
11796
+ // Color constructors (one per colorspace, preserves space on evaluation)
11797
+ {
11798
+ name: "Rgb",
11799
+ latexTrigger: ["\\operatorname{rgb}"],
11800
+ kind: "function",
11801
+ serialize: (serializer, expr) => "\\operatorname{rgb}" + serializer.wrapArguments(expr)
11802
+ },
11803
+ {
11804
+ name: "Hsv",
11805
+ latexTrigger: ["\\operatorname{hsv}"],
11806
+ kind: "function",
11807
+ serialize: (serializer, expr) => "\\operatorname{hsv}" + serializer.wrapArguments(expr)
11808
+ },
11809
+ {
11810
+ name: "Hsl",
11811
+ latexTrigger: ["\\operatorname{hsl}"],
11812
+ kind: "function",
11813
+ serialize: (serializer, expr) => "\\operatorname{hsl}" + serializer.wrapArguments(expr)
11814
+ },
11815
+ {
11816
+ name: "Oklab",
11817
+ latexTrigger: ["\\operatorname{oklab}"],
11818
+ kind: "function",
11819
+ serialize: (serializer, expr) => "\\operatorname{oklab}" + serializer.wrapArguments(expr)
11820
+ },
11821
+ {
11822
+ name: "Oklch",
11823
+ latexTrigger: ["\\operatorname{oklch}"],
11824
+ kind: "function",
11825
+ serialize: (serializer, expr) => "\\operatorname{oklch}" + serializer.wrapArguments(expr)
11826
+ },
11827
+ // Conversion functions (color → color in the named space)
11828
+ {
11829
+ name: "AsRgb",
11830
+ latexTrigger: ["\\operatorname{asRgb}"],
11831
+ kind: "function",
11832
+ serialize: (serializer, expr) => "\\operatorname{asRgb}" + serializer.wrapArguments(expr)
11833
+ },
11834
+ {
11835
+ name: "AsHsv",
11836
+ latexTrigger: ["\\operatorname{asHsv}"],
11837
+ kind: "function",
11838
+ serialize: (serializer, expr) => "\\operatorname{asHsv}" + serializer.wrapArguments(expr)
11839
+ },
11840
+ {
11841
+ name: "AsHsl",
11842
+ latexTrigger: ["\\operatorname{asHsl}"],
11843
+ kind: "function",
11844
+ serialize: (serializer, expr) => "\\operatorname{asHsl}" + serializer.wrapArguments(expr)
11845
+ },
11846
+ {
11847
+ name: "AsOklab",
11848
+ latexTrigger: ["\\operatorname{asOklab}"],
11849
+ kind: "function",
11850
+ serialize: (serializer, expr) => "\\operatorname{asOklab}" + serializer.wrapArguments(expr)
11851
+ },
11852
+ {
11853
+ name: "AsOklch",
11854
+ latexTrigger: ["\\operatorname{asOklch}"],
11855
+ kind: "function",
11856
+ serialize: (serializer, expr) => "\\operatorname{asOklch}" + serializer.wrapArguments(expr)
11857
+ },
11858
+ // Perceptual difference (returns a scalar in [0, ~1])
11859
+ {
11860
+ name: "ColorDelta",
11861
+ latexTrigger: ["\\operatorname{colorDelta}"],
11862
+ kind: "function",
11863
+ serialize: (serializer, expr) => "\\operatorname{colorDelta}" + serializer.wrapArguments(expr)
11864
+ }
11525
11865
  ];
11526
11866
 
11527
11867
  // src/compute-engine/latex-syntax/dictionary/default-dictionary.ts
@@ -11552,7 +11892,8 @@ var Compile = (() => {
11552
11892
  ...DEFINITIONS_STATISTICS,
11553
11893
  ...DEFINITIONS_UNITS,
11554
11894
  ...DEFINITIONS_OTHERS,
11555
- ...DEFINITIONS_PHYSICS
11895
+ ...DEFINITIONS_PHYSICS,
11896
+ ...DEFINITIONS_COLORS
11556
11897
  ];
11557
11898
 
11558
11899
  // src/math-json/symbols.ts
@@ -12707,7 +13048,11 @@ ${lines.join("\n")}`;
12707
13048
  //
12708
13049
  Range: {
12709
13050
  complexity: 8200,
12710
- signature: "(number, number?, step: number?) -> indexed_collection<integer>",
13051
+ signature: "(number, number?, step: number?) -> indexed_collection<number>",
13052
+ type: (ops) => {
13053
+ const allInt = ops.every((op) => op.isInteger);
13054
+ return allInt ? parseType("indexed_collection<integer>") : parseType("indexed_collection<number>");
13055
+ },
12711
13056
  canonical: (ops, { engine: ce }) => {
12712
13057
  if (ops.length === 0) return null;
12713
13058
  if (ops.length === 1) return ce._fn("Range", [ce.One, ops[0].canonical]);
@@ -12731,19 +13076,26 @@ ${lines.join("\n")}`;
12731
13076
  const [lower, upper, step] = range(expr);
12732
13077
  if (step === 0) return 0;
12733
13078
  if (!isFinite(lower) || !isFinite(upper)) return Infinity;
12734
- return 1 + Math.max(0, Math.floor((upper - lower) / step));
13079
+ return Math.max(0, Math.floor((upper - lower) / step) + 1);
12735
13080
  },
12736
13081
  contains: (expr, target) => {
12737
- if (!target.type.matches("integer")) return false;
12738
13082
  const t = target.re;
13083
+ if (!isFinite(t)) return false;
12739
13084
  const [lower, upper, step] = range(expr);
12740
13085
  if (step === 0) return false;
12741
- if (step > 0) return t >= lower && t <= upper;
12742
- return t <= lower && t >= upper;
13086
+ if (step > 0) {
13087
+ if (t < lower || t > upper) return false;
13088
+ } else {
13089
+ if (t > lower || t < upper) return false;
13090
+ }
13091
+ const k = (t - lower) / step;
13092
+ const tol = expr.engine.tolerance;
13093
+ const kRounded = Math.round(k);
13094
+ return kRounded >= 0 && Math.abs(k - kRounded) < tol;
12743
13095
  },
12744
13096
  iterator: (expr) => {
12745
13097
  const [lower, upper, step] = range(expr);
12746
- const maxCount = step === 0 ? 0 : Math.floor((upper - lower) / step) + 1;
13098
+ const maxCount = step === 0 ? 0 : Math.max(0, Math.floor((upper - lower) / step) + 1);
12747
13099
  let index = 1;
12748
13100
  return {
12749
13101
  next: () => {
@@ -12761,7 +13113,9 @@ ${lines.join("\n")}`;
12761
13113
  at: (expr, index) => {
12762
13114
  if (typeof index !== "number") return void 0;
12763
13115
  const [lower, upper, step] = range(expr);
12764
- if (index < 1 || index > 1 + (upper - lower) / step) return void 0;
13116
+ if (step === 0) return void 0;
13117
+ const maxCount = Math.max(0, Math.floor((upper - lower) / step) + 1);
13118
+ if (index < 1 || index > maxCount) return void 0;
12765
13119
  return expr.engine.number(lower + step * (index - 1));
12766
13120
  },
12767
13121
  indexWhere: void 0,
@@ -12786,7 +13140,13 @@ ${lines.join("\n")}`;
12786
13140
  if (step > 0) return lower <= upper ? "positive" : "negative";
12787
13141
  return lower >= upper ? "positive" : "negative";
12788
13142
  },
12789
- elttype: (_expr) => "finite_integer"
13143
+ elttype: (expr) => {
13144
+ if (!isFunction2(expr)) return "finite_integer";
13145
+ for (let i = 1; i <= expr.nops; i++) {
13146
+ if (!expr[`op${i}`].isInteger) return "finite_real";
13147
+ }
13148
+ return "finite_integer";
13149
+ }
12790
13150
  }
12791
13151
  },
12792
13152
  Interval: {
@@ -13384,15 +13744,45 @@ ${lines.join("\n")}`;
13384
13744
  },
13385
13745
  First: {
13386
13746
  complexity: 8200,
13387
- signature: "(collection) -> any",
13747
+ signature: "(any) -> any",
13388
13748
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13389
- evaluate: ([xs], { engine: ce }) => xs.at(1) ?? ce.Nothing
13749
+ evaluate: ([xs], { engine: ce }) => {
13750
+ if (!xs.isCollection)
13751
+ return ce.error([
13752
+ "incompatible-type",
13753
+ `'collection'`,
13754
+ xs.type.toString()
13755
+ ]);
13756
+ return xs.at(1) ?? ce.Nothing;
13757
+ }
13390
13758
  },
13391
13759
  Second: {
13392
13760
  complexity: 8200,
13393
- signature: "(collection) -> any",
13761
+ signature: "(any) -> any",
13762
+ type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13763
+ evaluate: ([xs], { engine: ce }) => {
13764
+ if (!xs.isCollection)
13765
+ return ce.error([
13766
+ "incompatible-type",
13767
+ `'collection'`,
13768
+ xs.type.toString()
13769
+ ]);
13770
+ return xs.at(2) ?? ce.Nothing;
13771
+ }
13772
+ },
13773
+ Third: {
13774
+ complexity: 8200,
13775
+ signature: "(any) -> any",
13394
13776
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13395
- evaluate: ([xs], { engine: ce }) => xs.at(2) ?? ce.Nothing
13777
+ evaluate: ([xs], { engine: ce }) => {
13778
+ if (!xs.isCollection)
13779
+ return ce.error([
13780
+ "incompatible-type",
13781
+ `'collection'`,
13782
+ xs.type.toString()
13783
+ ]);
13784
+ return xs.at(3) ?? ce.Nothing;
13785
+ }
13396
13786
  },
13397
13787
  Last: {
13398
13788
  complexity: 8200,
@@ -14371,17 +14761,14 @@ ${lines.join("\n")}`;
14371
14761
  if (!isFunction2(expr)) return [1, 0, 0];
14372
14762
  if (expr.nops === 0) return [1, 0, 0];
14373
14763
  let op1 = expr.op1.re;
14374
- if (!isFinite(op1)) op1 = 1;
14375
- else op1 = Math.round(op1);
14764
+ if (!isFinite(op1) && !op1) op1 = 1;
14376
14765
  if (expr.nops === 1) return [1, op1, 1];
14377
14766
  let op2 = expr.op2.re;
14378
14767
  if (!isFinite(op2) && !op2) op2 = 1;
14379
- else if (isFinite(op2)) op2 = Math.round(op2);
14380
- if (expr.nops === 2) return [op1, op2, op2 > op1 ? 1 : -1];
14768
+ if (expr.nops === 2) return [op1, op2, op2 >= op1 ? 1 : -1];
14381
14769
  let op3 = expr.op3.re;
14382
- if (!isFinite(op3)) op3 = 1;
14383
- else op3 = Math.abs(Math.round(op3));
14384
- return [op1, op2, op1 < op2 ? op3 : -op3];
14770
+ if (!isFinite(op3) && !op3) op3 = 1;
14771
+ return [op1, op2, op3];
14385
14772
  }
14386
14773
  function canonicalList(ops, { engine: ce }) {
14387
14774
  const op1 = ops[0];
@@ -14730,6 +15117,23 @@ ${lines.join("\n")}`;
14730
15117
  };
14731
15118
  return compilePair(0);
14732
15119
  }
15120
+ if (h === "When") {
15121
+ if (args.length !== 2)
15122
+ throw new Error("When: expected exactly 2 arguments (expr, cond)");
15123
+ const fn2 = target.functions?.(h);
15124
+ if (fn2) {
15125
+ if (typeof fn2 === "function") {
15126
+ return fn2(args, (expr) => _BaseCompiler.compile(expr, target), target);
15127
+ }
15128
+ return `${fn2}(${args.map((x) => _BaseCompiler.compile(x, target)).join(", ")})`;
15129
+ }
15130
+ if (isSymbol2(args[1], "True"))
15131
+ return `(${_BaseCompiler.compile(args[0], target)})`;
15132
+ if (isSymbol2(args[1], "False")) return "NaN";
15133
+ const val = _BaseCompiler.compile(args[0], target);
15134
+ const cond = _BaseCompiler.compile(args[1], target);
15135
+ return `((${cond}) ? (${val}) : NaN)`;
15136
+ }
14733
15137
  if (h === "Block") {
14734
15138
  return _BaseCompiler.compileBlock(args, target);
14735
15139
  }
@@ -14804,17 +15208,91 @@ ${lines.join("\n")}`;
14804
15208
  )}${target.ws("\n")}})()`;
14805
15209
  }
14806
15210
  /**
14807
- * Compile a Loop expression with Element(index, Range(lo, hi)) indexing.
14808
- * Generates: (() => { for (let i = lo; i <= hi; i++) { body } })()
15211
+ * Compile a Loop expression.
15212
+ *
15213
+ * Two forms are supported:
15214
+ *
15215
+ * 1. **Imperative / single-Element form** (existing behaviour):
15216
+ * `Loop(body, Element(i, Range(lo, hi)))`
15217
+ * Generates a raw `for (let i = lo; i <= hi; i++) { body }` loop wrapped
15218
+ * in an IIFE. The loop counter is always a plain number. For targets
15219
+ * that wrap numeric values (e.g. interval-js uses `_IA.point()`),
15220
+ * references to the loop index inside the body are re-wrapped via
15221
+ * `target.number`. `break` / `continue` / `return` are preserved.
15222
+ *
15223
+ * 2. **Comprehension / variadic-Element form** (new):
15224
+ * `Loop(body, Element(x, coll1), Element(y, coll2), …)`
15225
+ * When two or more `Element` clauses are present — or when the single
15226
+ * Element's collection is not a `Range` — the loop is compiled as a
15227
+ * comprehension that collects results into an array. Each clause
15228
+ * produces a `for (const name of collection)` loop, nested
15229
+ * outermost-to-innermost, and the innermost body pushes into `result`.
15230
+ *
15231
+ * Example output (JS):
15232
+ * ```js
15233
+ * (() => { const result = [];
15234
+ * for (const x of [1,2]) { for (const y of [3,4]) { result.push(body); } }
15235
+ * return result; })()
15236
+ * ```
14809
15237
  *
14810
- * The loop counter is always a raw number. For targets that wrap numeric
14811
- * values (e.g. interval-js wraps with `_IA.point()`), references to the
14812
- * loop index inside the body are wrapped via `target.number`.
15238
+ * GLSL: multi-Element comprehension is not trivially representable in
15239
+ * GLSL (no dynamic arrays, no push). A compile-time error is thrown.
15240
+ * TODO(E3-GLSL): support GLSL multi-Element via a pre-declared fixed-size
15241
+ * array or by unrolling when bounds are known at compile time.
14813
15242
  */
14814
15243
  static compileForLoop(args, target) {
14815
15244
  if (!args[0]) throw new Error("Loop: no body");
14816
15245
  if (!args[1]) throw new Error("Loop: no indexing set");
14817
- const indexing = args[1];
15246
+ const body = args[0];
15247
+ const elements = args.slice(1);
15248
+ const useComprehension = elements.length > 1 || elements.length === 1 && isFunction2(elements[0], "Element") && !_BaseCompiler.isLegacyCompatibleRange(elements[0].ops[1]);
15249
+ if (useComprehension) {
15250
+ const lang = target.language ?? "";
15251
+ if (lang === "glsl" || lang === "wgsl") {
15252
+ throw new Error(
15253
+ `${lang.toUpperCase()}: multi-Element Loop comprehension is not yet supported. TODO(E3-GLSL): unroll or use a fixed-size array.`
15254
+ );
15255
+ }
15256
+ const narrowedElements = [];
15257
+ for (let i = 0; i < elements.length; i++) {
15258
+ const elem = elements[i];
15259
+ if (!isFunction2(elem, "Element"))
15260
+ throw new Error(
15261
+ `Loop: argument ${i + 1} must be an Element clause, got ${elem.operator ?? "?"}`
15262
+ );
15263
+ if (!isSymbol2(elem.ops[0]))
15264
+ throw new Error(
15265
+ `Loop: Element index (argument ${i + 1}) must be a symbol`
15266
+ );
15267
+ narrowedElements.push(elem);
15268
+ }
15269
+ const loopVarSet = new Set(
15270
+ narrowedElements.map(
15271
+ (e) => e.ops[0].symbol
15272
+ )
15273
+ );
15274
+ const needsWrap2 = target.number(0) !== "0";
15275
+ const bodyTarget2 = needsWrap2 ? {
15276
+ ...target,
15277
+ var: (id) => loopVarSet.has(id) ? target.number(0).replace("0", id) : target.var(id)
15278
+ } : target;
15279
+ const bodyCode = _BaseCompiler.compile(body, bodyTarget2);
15280
+ let inner = `result.push(${bodyCode});`;
15281
+ for (let i = narrowedElements.length - 1; i >= 0; i--) {
15282
+ const elem = narrowedElements[i];
15283
+ const name = elem.ops[0].symbol;
15284
+ const collExpr = elem.ops[1];
15285
+ let collection;
15286
+ if (isFunction2(collExpr, "Range")) {
15287
+ collection = _BaseCompiler.compileRangeIterable(collExpr, bodyTarget2);
15288
+ } else {
15289
+ collection = _BaseCompiler.compile(collExpr, bodyTarget2);
15290
+ }
15291
+ inner = `for (const ${name} of ${collection}) { ${inner} }`;
15292
+ }
15293
+ return `(() => { const result = []; ${inner} return result; })()`;
15294
+ }
15295
+ const indexing = elements[0];
14818
15296
  if (!isFunction2(indexing, "Element"))
14819
15297
  throw new Error("Loop: expected Element(index, Range(lo, hi))");
14820
15298
  const indexExpr = indexing.ops[0];
@@ -14832,13 +15310,72 @@ ${lines.join("\n")}`;
14832
15310
  ...target,
14833
15311
  var: (id) => id === index ? needsWrap ? target.number(0).replace("0", index) : index : target.var(id)
14834
15312
  };
14835
- const bodyStmts = _BaseCompiler.compileLoopBody(args[0], bodyTarget);
15313
+ const bodyStmts = _BaseCompiler.compileLoopBody(body, bodyTarget);
14836
15314
  return `(() => {${target.ws(
14837
15315
  "\n"
14838
15316
  )}for (let ${index} = ${lower}; ${index} <= ${upper}; ${index}++) {${target.ws(
14839
15317
  "\n"
14840
15318
  )}${bodyStmts}${target.ws("\n")}}${target.ws("\n")}})()`;
14841
15319
  }
15320
+ /**
15321
+ * Returns `true` when the given collection expression is a `Range` whose
15322
+ * runtime semantics match the legacy imperative for-loop shape
15323
+ * `for (let i = lo; i <= hi; i++)`.
15324
+ *
15325
+ * Concretely: integer-ascending bounds and step omitted-or-1. When bounds
15326
+ * are not statically numeric we accept the Range (the historical
15327
+ * behaviour) — runtime mismatch in the descending-unknown-bounds case is
15328
+ * left as a known limitation; callers can force the iterable path by
15329
+ * supplying an explicit step.
15330
+ */
15331
+ static isLegacyCompatibleRange(coll) {
15332
+ if (!isFunction2(coll, "Range")) return false;
15333
+ if (coll.ops.length >= 3) {
15334
+ const stepExpr = coll.ops[2];
15335
+ if (!isNumber(stepExpr) || stepExpr.re !== 1) return false;
15336
+ }
15337
+ const lo = coll.ops[0];
15338
+ const hi = coll.ops[1];
15339
+ if (isNumber(lo) && !Number.isInteger(lo.re)) return false;
15340
+ if (isNumber(hi) && !Number.isInteger(hi.re)) return false;
15341
+ if (isNumber(lo) && isNumber(hi) && lo.re > hi.re) return false;
15342
+ return true;
15343
+ }
15344
+ /**
15345
+ * Compile a `Range(lo, hi)` or `Range(lo, hi, step)` expression into a JS
15346
+ * iterable expression. Mirrors the runtime semantics in
15347
+ * `library/collections.ts` Range:
15348
+ * count = step === 0 ? 0 : max(0, floor((hi - lo) / step) + 1)
15349
+ * element = lo + step * k (0-indexed)
15350
+ * Default step is 1 when omitted. Bounds and step may be fractional.
15351
+ *
15352
+ * Only used from the comprehension path in `compileForLoop`.
15353
+ * Caller must have already verified `isFunction(rangeExpr, 'Range')`.
15354
+ */
15355
+ static compileRangeIterable(rangeExpr, target) {
15356
+ const loExpr = rangeExpr.ops[0];
15357
+ const hiExpr = rangeExpr.ops[1];
15358
+ const stepExpr = rangeExpr.ops[2];
15359
+ if (isNumber(loExpr) && isNumber(hiExpr) && (stepExpr === void 0 || isNumber(stepExpr))) {
15360
+ const lo2 = loExpr.re;
15361
+ const hi2 = hiExpr.re;
15362
+ const step2 = stepExpr === void 0 ? hi2 >= lo2 ? 1 : -1 : stepExpr.re;
15363
+ if (step2 === 0) return "[]";
15364
+ const len = Math.max(0, Math.floor((hi2 - lo2) / step2) + 1);
15365
+ if (step2 === 1) {
15366
+ if (lo2 === 0) return `Array.from({length:${len}},(_,k)=>k)`;
15367
+ return `Array.from({length:${len}},(_,k)=>${lo2}+k)`;
15368
+ }
15369
+ return `Array.from({length:${len}},(_,k)=>${lo2}+(${step2})*k)`;
15370
+ }
15371
+ const lo = _BaseCompiler.compile(loExpr, target);
15372
+ const hi = _BaseCompiler.compile(hiExpr, target);
15373
+ if (stepExpr === void 0) {
15374
+ 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})`;
15375
+ }
15376
+ const step = _BaseCompiler.compile(stepExpr, target);
15377
+ 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})`;
15378
+ }
14842
15379
  /**
14843
15380
  * Compile a loop body expression as statements (not wrapped in IIFE).
14844
15381
  * Handles Break, Continue, Return as statements, and If as if-else when
@@ -15187,8 +15724,7 @@ ${lines.join("\n")}`;
15187
15724
  ce.pushScope();
15188
15725
  try {
15189
15726
  if (vars && typeof vars === "object") {
15190
- for (const [k, v] of Object.entries(vars))
15191
- ce.assign(k, v);
15727
+ for (const [k, v] of Object.entries(vars)) ce.assign(k, v);
15192
15728
  }
15193
15729
  return expr.evaluate().re;
15194
15730
  } finally {
@@ -15275,8 +15811,7 @@ ${lines.join("\n")}`;
15275
15811
  return { re: null, im: formatFloat(iScale) };
15276
15812
  }
15277
15813
  const compiledFactors = remaining.map((r) => compile2(r));
15278
- if (iScale !== 1)
15279
- compiledFactors.unshift(formatFloat(iScale));
15814
+ if (iScale !== 1) compiledFactors.unshift(formatFloat(iScale));
15280
15815
  const imCode = foldTerms(compiledFactors, "1.0", "*");
15281
15816
  return { re: null, im: imCode };
15282
15817
  }
@@ -15341,6 +15876,40 @@ ${lines.join("\n")}`;
15341
15876
  else h = ((r - g) / d + 4) / 6;
15342
15877
  return { h: h * 360, s, l };
15343
15878
  }
15879
+ function hsvToRgb(h, s, v) {
15880
+ h = (h % 360 + 360) % 360;
15881
+ s = Math.max(0, Math.min(1, s));
15882
+ v = Math.max(0, Math.min(1, v));
15883
+ const c = v * s;
15884
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
15885
+ const m = v - c;
15886
+ let r = 0, g = 0, b = 0;
15887
+ if (h < 60) [r, g, b] = [c, x, 0];
15888
+ else if (h < 120) [r, g, b] = [x, c, 0];
15889
+ else if (h < 180) [r, g, b] = [0, c, x];
15890
+ else if (h < 240) [r, g, b] = [0, x, c];
15891
+ else if (h < 300) [r, g, b] = [x, 0, c];
15892
+ else [r, g, b] = [c, 0, x];
15893
+ return { r: (r + m) * 255, g: (g + m) * 255, b: (b + m) * 255 };
15894
+ }
15895
+ function rgbToHsv(r, g, b) {
15896
+ r /= 255;
15897
+ g /= 255;
15898
+ b /= 255;
15899
+ const max2 = Math.max(r, g, b);
15900
+ const min2 = Math.min(r, g, b);
15901
+ const d = max2 - min2;
15902
+ let h = 0;
15903
+ if (d > 0) {
15904
+ if (max2 === r) h = (g - b) / d % 6;
15905
+ else if (max2 === g) h = (b - r) / d + 2;
15906
+ else h = (r - g) / d + 4;
15907
+ h *= 60;
15908
+ if (h < 0) h += 360;
15909
+ }
15910
+ const s = max2 === 0 ? 0 : d / max2;
15911
+ return { h, s, v: max2 };
15912
+ }
15344
15913
  function parseHexColor(s) {
15345
15914
  const hex = s.startsWith("#") ? s.substring(1) : s;
15346
15915
  let r, g, b;
@@ -15796,6 +16365,13 @@ ${lines.join("\n")}`;
15796
16365
  };
15797
16366
  function parseColor(s, darkMode) {
15798
16367
  const str = s.trim().toLowerCase();
16368
+ const opacityMatch = str.match(/^(.+?)\s*\/\s*(\d+(?:\.\d+)?)%?\s*$/);
16369
+ if (opacityMatch) {
16370
+ const base = parseColor(opacityMatch[1].trim(), darkMode);
16371
+ const opacity = Math.max(0, Math.min(100, parseFloat(opacityMatch[2])));
16372
+ const alpha = Math.round(opacity / 100 * 255);
16373
+ return base & 4294967040 | alpha;
16374
+ }
15799
16375
  if (str.startsWith("#")) {
15800
16376
  const hex = str.substring(1);
15801
16377
  let r, g, b, a = 255;
@@ -15928,14 +16504,6 @@ ${lines.join("\n")}`;
15928
16504
  console.warn(`parseColor: unrecognized color "${s}"`);
15929
16505
  return 0;
15930
16506
  }
15931
- function parseColorToRgb01(s, darkMode) {
15932
- const color = parseColor(s, darkMode);
15933
- return [
15934
- (color >>> 24 & 255) / 255,
15935
- (color >>> 16 & 255) / 255,
15936
- (color >>> 8 & 255) / 255
15937
- ];
15938
- }
15939
16507
  function apca(bgColor, fgColor) {
15940
16508
  const bgRgb = asRgb(bgColor);
15941
16509
  const fgRgb = asRgb(fgColor);
@@ -15994,6 +16562,12 @@ ${lines.join("\n")}`;
15994
16562
  const contrast2 = Math.abs(apca(fg2, bg));
15995
16563
  return contrast1 >= contrast2 ? asColorNumber(fg1) : asColorNumber(fg2);
15996
16564
  }
16565
+ function oklabDeltaE(a, b) {
16566
+ const dL = a.L - b.L;
16567
+ const da = a.a - b.a;
16568
+ const db = a.b - b.b;
16569
+ return Math.sqrt(dL * dL + da * da + db * db);
16570
+ }
15997
16571
  var TYCHO_11 = [
15998
16572
  "#4e79a7",
15999
16573
  // Blue
@@ -20205,39 +20779,130 @@ ${lines.join("\n")}`;
20205
20779
  if (args.length >= 2)
20206
20780
  return `_SYS.colormap(${compile2(args[0])}, ${compile2(args[1])})`;
20207
20781
  return `_SYS.colormap(${compile2(args[0])})`;
20782
+ },
20783
+ // -----------------------------------------------------------------------
20784
+ // Color constructor heads. All compile to OKLCh arrays at runtime — the
20785
+ // canonical color representation in this target. The constructors take
20786
+ // their own colorspace's components and convert internally.
20787
+ // (Mirrors the GPU target's design: color values are vec3 OKLCh.)
20788
+ // -----------------------------------------------------------------------
20789
+ Rgb: (args, compile2) => {
20790
+ if (args.length < 3) throw new Error("Rgb: need 3 components");
20791
+ return `_SYS.rgb(${args.map(compile2).join(", ")})`;
20792
+ },
20793
+ Hsv: (args, compile2) => {
20794
+ if (args.length < 3) throw new Error("Hsv: need 3 components");
20795
+ return `_SYS.hsv(${args.map(compile2).join(", ")})`;
20796
+ },
20797
+ Hsl: (args, compile2) => {
20798
+ if (args.length < 3) throw new Error("Hsl: need 3 components");
20799
+ return `_SYS.hsl(${args.map(compile2).join(", ")})`;
20800
+ },
20801
+ Oklab: (args, compile2) => {
20802
+ if (args.length < 3) throw new Error("Oklab: need 3 components");
20803
+ return `_SYS.oklab(${args.map(compile2).join(", ")})`;
20804
+ },
20805
+ Oklch: (args, compile2) => {
20806
+ if (args.length < 3) throw new Error("Oklch: need 3 components");
20807
+ return `_SYS.oklch(${args.map(compile2).join(", ")})`;
20808
+ },
20809
+ // -----------------------------------------------------------------------
20810
+ // As* converters. Compile-time output convention matches the engine and
20811
+ // the GPU target: each returns components in the named space as a 3- or
20812
+ // 4-element array. `AsRgb` uses 0-1 sRGB channels (consistent across all
20813
+ // layers). `AsOklch` is the identity (canonical form).
20814
+ // -----------------------------------------------------------------------
20815
+ AsRgb: ([c], compile2) => {
20816
+ if (c === null) throw new Error("AsRgb: no argument");
20817
+ return `_SYS.asRgb(${compile2(c)})`;
20818
+ },
20819
+ AsHsv: ([c], compile2) => {
20820
+ if (c === null) throw new Error("AsHsv: no argument");
20821
+ return `_SYS.asHsv(${compile2(c)})`;
20822
+ },
20823
+ AsHsl: ([c], compile2) => {
20824
+ if (c === null) throw new Error("AsHsl: no argument");
20825
+ return `_SYS.asHsl(${compile2(c)})`;
20826
+ },
20827
+ AsOklab: ([c], compile2) => {
20828
+ if (c === null) throw new Error("AsOklab: no argument");
20829
+ return `_SYS.asOklab(${compile2(c)})`;
20830
+ },
20831
+ AsOklch: ([c], compile2) => {
20832
+ if (c === null) throw new Error("AsOklch: no argument");
20833
+ return compile2(c);
20834
+ },
20835
+ // Perceptual color difference (ΔE_OK).
20836
+ ColorDelta: ([a, b], compile2) => {
20837
+ if (a === null || b === null)
20838
+ throw new Error("ColorDelta: need two colors");
20839
+ return `_SYS.colorDelta(${compile2(a)}, ${compile2(b)})`;
20840
+ },
20841
+ // Euclidean distance between two tuples (any positive dimension).
20842
+ // The GPU target maps `Distance` to the GLSL/WGSL `distance()` builtin
20843
+ // (vec-only); this JS handler works on plain arrays of any length.
20844
+ Distance: ([a, b], compile2) => {
20845
+ if (a === null || b === null) throw new Error("Distance: need two points");
20846
+ return `_SYS.distance(${compile2(a)}, ${compile2(b)})`;
20208
20847
  }
20209
20848
  };
20210
20849
  function toRI(c) {
20211
20850
  return { re: c.re, im: c.im };
20212
20851
  }
20852
+ function normalizeAlpha(a) {
20853
+ if (a === void 0) return void 0;
20854
+ if (!Number.isFinite(a)) return void 0;
20855
+ if (Math.abs(a - 1) < 1e-9) return void 0;
20856
+ return a;
20857
+ }
20213
20858
  function toRgb255(input) {
20214
20859
  if (typeof input === "string") {
20215
20860
  const c = parseColor(input);
20216
- return {
20861
+ const rgb2 = {
20217
20862
  r: c >>> 24 & 255,
20218
20863
  g: c >>> 16 & 255,
20219
- b: c >>> 8 & 255,
20220
- alpha: (c & 255) / 255
20864
+ b: c >>> 8 & 255
20221
20865
  };
20866
+ const alpha = normalizeAlpha((c & 255) / 255);
20867
+ if (alpha !== void 0) rgb2.alpha = alpha;
20868
+ return rgb2;
20869
+ }
20870
+ const rgb = oklchToRgb({ L: input[0], C: input[1], H: input[2] });
20871
+ if (input.length >= 4) {
20872
+ const alpha = normalizeAlpha(input[3]);
20873
+ if (alpha !== void 0) rgb.alpha = alpha;
20222
20874
  }
20223
- const rgb = {
20224
- r: input[0] * 255,
20225
- g: input[1] * 255,
20226
- b: input[2] * 255
20227
- };
20228
- if (input.length >= 4) rgb.alpha = input[3];
20229
20875
  return rgb;
20230
20876
  }
20231
- function packedToArray(c) {
20232
- const r = (c >>> 24 & 255) / 255;
20233
- const g = (c >>> 16 & 255) / 255;
20234
- const b = (c >>> 8 & 255) / 255;
20235
- const a = (c & 255) / 255;
20236
- return Math.abs(a - 1) < 1e-4 ? [r, g, b] : [r, g, b, a];
20877
+ function toOklch(input) {
20878
+ if (typeof input === "string") {
20879
+ const c = parseColor(input);
20880
+ const r = c >>> 24 & 255;
20881
+ const g = c >>> 16 & 255;
20882
+ const b = c >>> 8 & 255;
20883
+ const oklch2 = rgbToOklch({ r, g, b });
20884
+ const alpha = normalizeAlpha((c & 255) / 255);
20885
+ if (alpha !== void 0) oklch2.alpha = alpha;
20886
+ return oklch2;
20887
+ }
20888
+ return {
20889
+ L: input[0],
20890
+ C: input[1],
20891
+ H: input[2],
20892
+ alpha: input.length >= 4 ? normalizeAlpha(input[3]) : void 0
20893
+ };
20894
+ }
20895
+ function packedToOklch(c) {
20896
+ const r = c >>> 24 & 255;
20897
+ const g = c >>> 16 & 255;
20898
+ const b = c >>> 8 & 255;
20899
+ const oklch2 = rgbToOklch({ r, g, b });
20900
+ const alpha = normalizeAlpha((c & 255) / 255);
20901
+ return alpha !== void 0 ? [oklch2.L, oklch2.C, oklch2.H, alpha] : [oklch2.L, oklch2.C, oklch2.H];
20237
20902
  }
20238
20903
  var colorHelpers = {
20239
20904
  color(input) {
20240
- return packedToArray(parseColor(input));
20905
+ return packedToOklch(parseColor(input));
20241
20906
  },
20242
20907
  colorToString(input, format) {
20243
20908
  const rgb = toRgb255(input);
@@ -20248,7 +20913,7 @@ ${lines.join("\n")}`;
20248
20913
  const g = Math.round(Math.max(0, Math.min(255, rgb.g)));
20249
20914
  const b = Math.round(Math.max(0, Math.min(255, rgb.b)));
20250
20915
  let hex = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
20251
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4) {
20916
+ if (rgb.alpha !== void 0) {
20252
20917
  const a = Math.round(Math.max(0, Math.min(255, rgb.alpha * 255)));
20253
20918
  hex += a.toString(16).padStart(2, "0");
20254
20919
  }
@@ -20258,7 +20923,7 @@ ${lines.join("\n")}`;
20258
20923
  const r = Math.round(rgb.r);
20259
20924
  const g = Math.round(rgb.g);
20260
20925
  const b = Math.round(rgb.b);
20261
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
20926
+ if (rgb.alpha !== void 0)
20262
20927
  return `rgb(${r} ${g} ${b} / ${rgb.alpha})`;
20263
20928
  return `rgb(${r} ${g} ${b})`;
20264
20929
  }
@@ -20267,7 +20932,7 @@ ${lines.join("\n")}`;
20267
20932
  const h = Math.round(hsl.h * 10) / 10;
20268
20933
  const s = Math.round(hsl.s * 1e3) / 10;
20269
20934
  const l = Math.round(hsl.l * 1e3) / 10;
20270
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
20935
+ if (rgb.alpha !== void 0)
20271
20936
  return `hsl(${h} ${s}% ${l}% / ${rgb.alpha})`;
20272
20937
  return `hsl(${h} ${s}% ${l}%)`;
20273
20938
  }
@@ -20276,7 +20941,7 @@ ${lines.join("\n")}`;
20276
20941
  const L = Math.round(c.L * 1e3) / 1e3;
20277
20942
  const C = Math.round(c.C * 1e3) / 1e3;
20278
20943
  const H = Math.round(c.H * 10) / 10;
20279
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
20944
+ if (rgb.alpha !== void 0)
20280
20945
  return `oklch(${L} ${C} ${H} / ${rgb.alpha})`;
20281
20946
  return `oklch(${L} ${C} ${H})`;
20282
20947
  }
@@ -20285,29 +20950,29 @@ ${lines.join("\n")}`;
20285
20950
  }
20286
20951
  },
20287
20952
  colorMix(input1, input2, ratio = 0.5) {
20288
- const rgb1 = toRgb255(input1);
20289
- const rgb2 = toRgb255(input2);
20953
+ const c1 = toOklch(input1);
20954
+ const c2 = toOklch(input2);
20290
20955
  ratio = Math.max(0, Math.min(1, ratio));
20291
- const c1 = rgbToOklch(rgb1);
20292
- const c2 = rgbToOklch(rgb2);
20293
- let dh = c2.H - c1.H;
20294
- if (dh > 180) dh -= 360;
20295
- if (dh < -180) dh += 360;
20296
- let H = c1.H + dh * ratio;
20297
- if (H < 0) H += 360;
20298
- if (H >= 360) H -= 360;
20299
- const mixed = oklchToRgb({
20300
- L: c1.L + (c2.L - c1.L) * ratio,
20301
- C: c1.C + (c2.C - c1.C) * ratio,
20302
- H
20303
- });
20304
- const r = mixed.r / 255;
20305
- const g = mixed.g / 255;
20306
- const b = mixed.b / 255;
20307
- const a1 = rgb1.alpha ?? 1;
20308
- const a2 = rgb2.alpha ?? 1;
20309
- const alpha = a1 + (a2 - a1) * ratio;
20310
- return Math.abs(alpha - 1) > 1e-4 ? [r, g, b, alpha] : [r, g, b];
20956
+ const c1Achromatic = c1.C < 1e-6;
20957
+ const c2Achromatic = c2.C < 1e-6;
20958
+ let H;
20959
+ if (c1Achromatic && c2Achromatic) H = c1.H;
20960
+ else if (c1Achromatic) H = c2.H;
20961
+ else if (c2Achromatic) H = c1.H;
20962
+ else {
20963
+ let dh = c2.H - c1.H;
20964
+ if (dh > 180) dh -= 360;
20965
+ if (dh < -180) dh += 360;
20966
+ H = c1.H + dh * ratio;
20967
+ if (H < 0) H += 360;
20968
+ if (H >= 360) H -= 360;
20969
+ }
20970
+ const L = c1.L + (c2.L - c1.L) * ratio;
20971
+ const C = c1.C + (c2.C - c1.C) * ratio;
20972
+ const a1 = c1.alpha ?? 1;
20973
+ const a2 = c2.alpha ?? 1;
20974
+ const alpha = normalizeAlpha(a1 + (a2 - a1) * ratio);
20975
+ return alpha !== void 0 ? [L, C, H, alpha] : [L, C, H];
20311
20976
  },
20312
20977
  colorContrast(bg, fg) {
20313
20978
  return apca(toRgb255(bg), toRgb255(fg));
@@ -20315,11 +20980,11 @@ ${lines.join("\n")}`;
20315
20980
  contrastingColor(bg, fg1, fg2) {
20316
20981
  const bgRgb = toRgb255(bg);
20317
20982
  if (fg1 !== void 0 && fg2 !== void 0) {
20318
- return packedToArray(
20983
+ return packedToOklch(
20319
20984
  contrastingColor({ bg: bgRgb, fg1: toRgb255(fg1), fg2: toRgb255(fg2) })
20320
20985
  );
20321
20986
  }
20322
- return packedToArray(contrastingColor(bgRgb));
20987
+ return packedToOklch(contrastingColor(bgRgb));
20323
20988
  },
20324
20989
  colorToColorspace(input, space) {
20325
20990
  const rgb = toRgb255(input);
@@ -20348,7 +21013,7 @@ ${lines.join("\n")}`;
20348
21013
  default:
20349
21014
  throw new Error(`Unknown color space: ${space}`);
20350
21015
  }
20351
- if (alpha !== void 0 && Math.abs(alpha - 1) > 1e-4) result.push(alpha);
21016
+ if (alpha !== void 0) result.push(alpha);
20352
21017
  return result;
20353
21018
  },
20354
21019
  colormap(name, arg) {
@@ -20360,7 +21025,7 @@ ${lines.join("\n")}`;
20360
21025
  const palette = allPalettes[name];
20361
21026
  if (!palette) throw new Error(`Unknown palette: ${name}`);
20362
21027
  const colors = palette.map(
20363
- (hex) => parseColorToRgb01(hex)
21028
+ (hex) => packedToOklch(parseColor(hex))
20364
21029
  );
20365
21030
  if (arg === void 0) return colors;
20366
21031
  if (Number.isInteger(arg) && arg >= 2) {
@@ -20384,62 +21049,128 @@ ${lines.join("\n")}`;
20384
21049
  const frac = pos - i;
20385
21050
  if (frac === 0 || i >= colors.length - 1)
20386
21051
  return [...colors[Math.min(i, colors.length - 1)]];
20387
- const rgb1 = {
20388
- r: colors[i][0] * 255,
20389
- g: colors[i][1] * 255,
20390
- b: colors[i][2] * 255
20391
- };
20392
- const rgb2 = {
20393
- r: colors[i + 1][0] * 255,
20394
- g: colors[i + 1][1] * 255,
20395
- b: colors[i + 1][2] * 255
20396
- };
20397
- const c1 = rgbToOklch(rgb1);
20398
- const c2 = rgbToOklch(rgb2);
20399
- let dh = c2.H - c1.H;
20400
- if (dh > 180) dh -= 360;
20401
- if (dh < -180) dh += 360;
20402
- let H = c1.H + dh * frac;
20403
- if (H < 0) H += 360;
20404
- if (H >= 360) H -= 360;
20405
- const mixed = oklchToRgb({
20406
- L: c1.L + (c2.L - c1.L) * frac,
20407
- C: c1.C + (c2.C - c1.C) * frac,
20408
- H
20409
- });
20410
- return [mixed.r / 255, mixed.g / 255, mixed.b / 255];
21052
+ const [L1, C1, H1] = colors[i];
21053
+ const [L2, C2, H2] = colors[i + 1];
21054
+ const c1Achromatic = C1 < 1e-6;
21055
+ const c2Achromatic = C2 < 1e-6;
21056
+ let H;
21057
+ if (c1Achromatic && c2Achromatic) H = H1;
21058
+ else if (c1Achromatic) H = H2;
21059
+ else if (c2Achromatic) H = H1;
21060
+ else {
21061
+ let dh = H2 - H1;
21062
+ if (dh > 180) dh -= 360;
21063
+ if (dh < -180) dh += 360;
21064
+ H = H1 + dh * frac;
21065
+ if (H < 0) H += 360;
21066
+ if (H >= 360) H -= 360;
21067
+ }
21068
+ return [L1 + (L2 - L1) * frac, C1 + (C2 - C1) * frac, H];
20411
21069
  },
20412
21070
  colorFromColorspace(components, space) {
20413
21071
  const c0 = components[0];
20414
21072
  const c1 = components[1];
20415
21073
  const c2 = components[2];
20416
21074
  const alpha = components.length >= 4 ? components[3] : void 0;
20417
- let result;
21075
+ let oklch2;
20418
21076
  switch (space.toLowerCase()) {
20419
21077
  case "rgb":
20420
- result = [c0, c1, c2];
21078
+ oklch2 = rgbToOklch({ r: c0 * 255, g: c1 * 255, b: c2 * 255 });
20421
21079
  break;
20422
21080
  case "hsl": {
20423
- const r = hslToRgb(c0, c1, c2);
20424
- result = [r.r / 255, r.g / 255, r.b / 255];
21081
+ const rgb = hslToRgb(c0, c1, c2);
21082
+ oklch2 = rgbToOklch(rgb);
20425
21083
  break;
20426
21084
  }
20427
- case "oklch": {
20428
- const r = oklchToRgb({ L: c0, C: c1, H: c2 });
20429
- result = [r.r / 255, r.g / 255, r.b / 255];
21085
+ case "oklch":
21086
+ oklch2 = { L: c0, C: c1, H: c2 };
20430
21087
  break;
20431
- }
20432
21088
  case "oklab":
20433
- case "lab": {
20434
- const r = oklabToRgb({ L: c0, a: c1, b: c2 });
20435
- result = [r.r / 255, r.g / 255, r.b / 255];
21089
+ case "lab":
21090
+ oklch2 = oklabToOklch({ L: c0, a: c1, b: c2 });
20436
21091
  break;
20437
- }
20438
21092
  default:
20439
21093
  throw new Error(`Unknown color space: ${space}`);
20440
21094
  }
20441
- if (alpha !== void 0 && Math.abs(alpha - 1) > 1e-4) result.push(alpha);
20442
- return result;
21095
+ return alpha !== void 0 ? [oklch2.L, oklch2.C, oklch2.H, alpha] : [oklch2.L, oklch2.C, oklch2.H];
21096
+ },
21097
+ // -----------------------------------------------------------------------
21098
+ // Color constructors. Each accepts components in its colorspace's natural
21099
+ // units and returns the canonical OKLCh array `[L, C, H]` (or with alpha).
21100
+ // -----------------------------------------------------------------------
21101
+ rgb(r, g, b, alpha) {
21102
+ const c = rgbToOklch({ r: r * 255, g: g * 255, b: b * 255 });
21103
+ const a = normalizeAlpha(alpha);
21104
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
21105
+ },
21106
+ hsv(h, s, v, alpha) {
21107
+ const rgb = hsvToRgb(h, s, v);
21108
+ const c = rgbToOklch(rgb);
21109
+ const a = normalizeAlpha(alpha);
21110
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
21111
+ },
21112
+ hsl(h, s, l, alpha) {
21113
+ const rgb = hslToRgb(h, s, l);
21114
+ const c = rgbToOklch({ r: rgb.r, g: rgb.g, b: rgb.b });
21115
+ const a = normalizeAlpha(alpha);
21116
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
21117
+ },
21118
+ oklab(L, a, b, alpha) {
21119
+ const c = oklabToOklch({ L, a, b });
21120
+ const al = normalizeAlpha(alpha);
21121
+ return al !== void 0 ? [c.L, c.C, c.H, al] : [c.L, c.C, c.H];
21122
+ },
21123
+ oklch(L, C, H, alpha) {
21124
+ const a = normalizeAlpha(alpha);
21125
+ return a !== void 0 ? [L, C, H, a] : [L, C, H];
21126
+ },
21127
+ // -----------------------------------------------------------------------
21128
+ // As* converters. Inputs are anything `toOklch` accepts (string, packed
21129
+ // int, or OKLCh array). Outputs are 3- or 4-element arrays in the named
21130
+ // space. sRGB-based outputs (asRgb/asHsv/asHsl) use 0-1 channels for
21131
+ // consistency with the GPU target's shader convention.
21132
+ // -----------------------------------------------------------------------
21133
+ asRgb(input) {
21134
+ const rgb = toRgb255(input);
21135
+ const r = rgb.r / 255;
21136
+ const g = rgb.g / 255;
21137
+ const b = rgb.b / 255;
21138
+ return rgb.alpha !== void 0 ? [r, g, b, rgb.alpha] : [r, g, b];
21139
+ },
21140
+ asHsv(input) {
21141
+ const rgb = toRgb255(input);
21142
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
21143
+ return rgb.alpha !== void 0 ? [hsv.h, hsv.s, hsv.v, rgb.alpha] : [hsv.h, hsv.s, hsv.v];
21144
+ },
21145
+ asHsl(input) {
21146
+ const rgb = toRgb255(input);
21147
+ const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
21148
+ return rgb.alpha !== void 0 ? [hsl.h, hsl.s, hsl.l, rgb.alpha] : [hsl.h, hsl.s, hsl.l];
21149
+ },
21150
+ asOklab(input) {
21151
+ const c = toOklch(input);
21152
+ const lab = oklchToOklab({ L: c.L, C: c.C, H: c.H });
21153
+ return c.alpha !== void 0 ? [lab.L, lab.a, lab.b, c.alpha] : [lab.L, lab.a, lab.b];
21154
+ },
21155
+ // asOklch is identity — handled at compile time as a pass-through
21156
+ // Perceptual color difference (ΔE_OK).
21157
+ colorDelta(a, b) {
21158
+ const labA = oklchToOklab(toOklch(a));
21159
+ const labB = oklchToOklab(toOklch(b));
21160
+ return oklabDeltaE(labA, labB);
21161
+ },
21162
+ // Euclidean distance between two tuples. Plain numeric — not a color
21163
+ // operation despite living in the same helpers block.
21164
+ distance(a, b) {
21165
+ if (!Array.isArray(a) || !Array.isArray(b))
21166
+ throw new Error("Distance: expected two arrays");
21167
+ if (a.length !== b.length) throw new Error("Distance: dimension mismatch");
21168
+ let sumSq = 0;
21169
+ for (let i = 0; i < a.length; i++) {
21170
+ const d = a[i] - b[i];
21171
+ sumSq += d * d;
21172
+ }
21173
+ return Math.sqrt(sumSq);
20443
21174
  }
20444
21175
  };
20445
21176
  var SYS_HELPERS = {
@@ -20878,6 +21609,13 @@ ${lines.join("\n")}`;
20878
21609
  function gpuVec2(target) {
20879
21610
  return target?.language === "wgsl" ? "vec2f" : "vec2";
20880
21611
  }
21612
+ function gpuVec3(target) {
21613
+ return target?.language === "wgsl" ? "vec3f" : "vec3";
21614
+ }
21615
+ function readStringLiteral(expr) {
21616
+ if (!isString(expr)) return null;
21617
+ return expr.string?.toLowerCase() ?? null;
21618
+ }
20881
21619
  function compileIntArg(expr, compile2, target) {
20882
21620
  const c = tryGetConstant(expr);
20883
21621
  if (c !== void 0 && Number.isInteger(c)) return c.toString();
@@ -20936,7 +21674,7 @@ ${lines.join("\n")}`;
20936
21674
  `for (${indexDecl} = ${lowerStr}; ${index} <= ${upperStr}; ${index}++) {`,
20937
21675
  ` ${acc} ${op}= ${body};`,
20938
21676
  `}`,
20939
- `return ${acc}`
21677
+ `return ${acc};`
20940
21678
  ];
20941
21679
  return lines.join("\n");
20942
21680
  }
@@ -20990,8 +21728,7 @@ ${lines.join("\n")}`;
20990
21728
  const iScale = isSymbol2(iFactor, "ImaginaryUnit") ? 1 : iFactor.im;
20991
21729
  const realFactors = args.filter((_, i) => i !== iIndex);
20992
21730
  const v2 = gpuVec2(target);
20993
- if (realFactors.length === 0)
20994
- return `${v2}(0.0, ${formatFloat(iScale)})`;
21731
+ if (realFactors.length === 0) return `${v2}(0.0, ${formatFloat(iScale)})`;
20995
21732
  const factors = realFactors.map((f) => compile2(f));
20996
21733
  if (iScale !== 1) factors.unshift(formatFloat(iScale));
20997
21734
  const imCode = foldTerms(factors, "1.0", "*");
@@ -21044,8 +21781,7 @@ ${lines.join("\n")}`;
21044
21781
  if (isNumber(x) && x.im !== 0) {
21045
21782
  return `${gpuVec2(target)}(${formatFloat(-x.re)}, ${formatFloat(-x.im)})`;
21046
21783
  }
21047
- if (isSymbol2(x, "ImaginaryUnit"))
21048
- return `${gpuVec2(target)}(0.0, -1.0)`;
21784
+ if (isSymbol2(x, "ImaginaryUnit")) return `${gpuVec2(target)}(0.0, -1.0)`;
21049
21785
  return `(-${compile2(x)})`;
21050
21786
  },
21051
21787
  // Standard math functions with complex dispatch
@@ -21418,17 +22154,127 @@ ${lines.join("\n")}`;
21418
22154
  }
21419
22155
  const isWGSL = target?.language === "wgsl";
21420
22156
  const v3 = isWGSL ? "vec3f" : "vec3";
21421
- return `((_gpu_apca(${bg}, ${v3}(0.0)) > 50.0) ? ${v3}(0.0) : ${v3}(1.0))`;
22157
+ const black = `${v3}(0.0)`;
22158
+ const white = `${v3}(1.0, 0.0, 0.0)`;
22159
+ return `((_gpu_apca(${bg}, ${black}) > 50.0) ? ${black} : ${white})`;
21422
22160
  },
21423
22161
  ColorToColorspace: ([color, space], compile2) => {
21424
22162
  if (color === null || space === null)
21425
22163
  throw new Error("ColorToColorspace: need color and space");
21426
- return `_gpu_srgb_to_oklab(${compile2(color)})`;
22164
+ const spaceName = readStringLiteral(space);
22165
+ if (spaceName === null)
22166
+ throw new Error("ColorToColorspace: space must be a string literal");
22167
+ const c = compile2(color);
22168
+ switch (spaceName) {
22169
+ case "oklch":
22170
+ return c;
22171
+ case "oklab":
22172
+ case "lab":
22173
+ return `_gpu_oklch_to_oklab(${c})`;
22174
+ case "rgb":
22175
+ return `_gpu_oklch_to_srgb(${c})`;
22176
+ case "hsl":
22177
+ return `_gpu_rgb_to_hsl(_gpu_oklch_to_srgb(${c}))`;
22178
+ case "hsv":
22179
+ return `_gpu_rgb_to_hsv(_gpu_oklch_to_srgb(${c}))`;
22180
+ default:
22181
+ throw new Error(
22182
+ `ColorToColorspace: unsupported space "${spaceName}" on GPU target`
22183
+ );
22184
+ }
21427
22185
  },
21428
22186
  ColorFromColorspace: ([components, space], compile2) => {
21429
22187
  if (components === null || space === null)
21430
22188
  throw new Error("ColorFromColorspace: need components and space");
21431
- return `_gpu_oklab_to_srgb(${compile2(components)})`;
22189
+ const spaceName = readStringLiteral(space);
22190
+ if (spaceName === null)
22191
+ throw new Error("ColorFromColorspace: space must be a string literal");
22192
+ const c = compile2(components);
22193
+ switch (spaceName) {
22194
+ case "oklch":
22195
+ return c;
22196
+ case "oklab":
22197
+ case "lab":
22198
+ return `_gpu_oklab_to_oklch(${c})`;
22199
+ case "rgb":
22200
+ return `_gpu_srgb_to_oklch(${c})`;
22201
+ case "hsl":
22202
+ return `_gpu_srgb_to_oklch(_gpu_hsl_to_rgb(${c}))`;
22203
+ case "hsv":
22204
+ return `_gpu_srgb_to_oklch(_gpu_hsv_to_rgb(${c}))`;
22205
+ default:
22206
+ throw new Error(
22207
+ `ColorFromColorspace: unsupported space "${spaceName}" on GPU target`
22208
+ );
22209
+ }
22210
+ },
22211
+ // ---------------------------------------------------------------------------
22212
+ // Color literals. Each typed head compiles to a canonical OKLCh vec3.
22213
+ // Alpha (4th argument) is dropped — GPU color values are vec3 only. Pass
22214
+ // alpha as a separate uniform if it's needed at the framebuffer boundary.
22215
+ // ---------------------------------------------------------------------------
22216
+ Color: ([s], _compile, target) => {
22217
+ if (s === null) throw new Error("Color: no argument");
22218
+ const str = readStringLiteral(s);
22219
+ if (str === null)
22220
+ throw new Error("Color: argument must be a string literal on GPU target");
22221
+ const packed = parseColor(str);
22222
+ if (packed === 0 && str.trim().toLowerCase() !== "transparent")
22223
+ throw new Error(`Color: invalid color string "${str}"`);
22224
+ const r = packed >>> 24 & 255;
22225
+ const g = packed >>> 16 & 255;
22226
+ const b = packed >>> 8 & 255;
22227
+ const oklch2 = rgbToOklch({ r, g, b });
22228
+ return `${gpuVec3(target)}(${formatFloat(oklch2.L)}, ${formatFloat(oklch2.C)}, ${formatFloat(oklch2.H)})`;
22229
+ },
22230
+ Rgb: (args, compile2, target) => {
22231
+ if (args.length < 3) throw new Error("Rgb: need 3 components");
22232
+ const v3 = gpuVec3(target);
22233
+ return `_gpu_srgb_to_oklch(${v3}(${compile2(args[0])}, ${compile2(args[1])}, ${compile2(args[2])}))`;
22234
+ },
22235
+ Hsv: (args, compile2, target) => {
22236
+ if (args.length < 3) throw new Error("Hsv: need 3 components");
22237
+ const v3 = gpuVec3(target);
22238
+ return `_gpu_srgb_to_oklch(_gpu_hsv_to_rgb(${v3}(${compile2(args[0])}, ${compile2(args[1])}, ${compile2(args[2])})))`;
22239
+ },
22240
+ Hsl: (args, compile2, target) => {
22241
+ if (args.length < 3) throw new Error("Hsl: need 3 components");
22242
+ const v3 = gpuVec3(target);
22243
+ return `_gpu_srgb_to_oklch(_gpu_hsl_to_rgb(${v3}(${compile2(args[0])}, ${compile2(args[1])}, ${compile2(args[2])})))`;
22244
+ },
22245
+ Oklab: (args, compile2, target) => {
22246
+ if (args.length < 3) throw new Error("Oklab: need 3 components");
22247
+ const v3 = gpuVec3(target);
22248
+ return `_gpu_oklab_to_oklch(${v3}(${compile2(args[0])}, ${compile2(args[1])}, ${compile2(args[2])}))`;
22249
+ },
22250
+ Oklch: (args, compile2, target) => {
22251
+ if (args.length < 3) throw new Error("Oklch: need 3 components");
22252
+ const v3 = gpuVec3(target);
22253
+ return `${v3}(${compile2(args[0])}, ${compile2(args[1])}, ${compile2(args[2])})`;
22254
+ },
22255
+ // ---------------------------------------------------------------------------
22256
+ // As* operators. AsOklch is identity (canonical). The other As* return
22257
+ // components in the named space, equivalent to ColorToColorspace(c, 'x').
22258
+ // ---------------------------------------------------------------------------
22259
+ AsOklch: ([c], compile2) => {
22260
+ if (c === null) throw new Error("AsOklch: no argument");
22261
+ return compile2(c);
22262
+ },
22263
+ AsOklab: ([c], compile2) => {
22264
+ if (c === null) throw new Error("AsOklab: no argument");
22265
+ return `_gpu_oklch_to_oklab(${compile2(c)})`;
22266
+ },
22267
+ AsRgb: ([c], compile2) => {
22268
+ if (c === null) throw new Error("AsRgb: no argument");
22269
+ return `_gpu_oklch_to_srgb(${compile2(c)})`;
22270
+ },
22271
+ AsHsv: ([c], compile2) => {
22272
+ if (c === null) throw new Error("AsHsv: no argument");
22273
+ return `_gpu_rgb_to_hsv(_gpu_oklch_to_srgb(${compile2(c)}))`;
22274
+ },
22275
+ AsHsl: ([c], compile2) => {
22276
+ if (c === null) throw new Error("AsHsl: no argument");
22277
+ return `_gpu_rgb_to_hsl(_gpu_oklch_to_srgb(${compile2(c)}))`;
21432
22278
  },
21433
22279
  // Fractal functions
21434
22280
  Mandelbrot: ([c, maxIter], compile2, target) => {
@@ -22121,28 +22967,124 @@ vec3 _gpu_oklab_to_srgb(vec3 lab) {
22121
22967
 
22122
22968
  vec3 _gpu_oklab_to_oklch(vec3 lab) {
22123
22969
  float C = length(lab.yz);
22124
- float H = atan(lab.z, lab.y);
22970
+ float H = atan(lab.z, lab.y) * (180.0 / 3.14159265359);
22971
+ if (H < 0.0) H += 360.0;
22125
22972
  return vec3(lab.x, C, H);
22126
22973
  }
22127
22974
 
22128
22975
  vec3 _gpu_oklch_to_oklab(vec3 lch) {
22129
- return vec3(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));
22976
+ float h_rad = lch.z * (3.14159265359 / 180.0);
22977
+ return vec3(lch.x, lch.y * cos(h_rad), lch.y * sin(h_rad));
22978
+ }
22979
+
22980
+ vec3 _gpu_srgb_to_oklch(vec3 rgb) {
22981
+ return _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb));
22982
+ }
22983
+
22984
+ vec3 _gpu_oklch_to_srgb(vec3 lch) {
22985
+ return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(lch));
22986
+ }
22987
+
22988
+ // HSL conversion. Hue in degrees, saturation/lightness in 0-1.
22989
+ vec3 _gpu_hsl_to_rgb(vec3 hsl) {
22990
+ float h = hsl.x;
22991
+ float s = hsl.y;
22992
+ float l = hsl.z;
22993
+ float c = (1.0 - abs(2.0 * l - 1.0)) * s;
22994
+ float h6 = h / 60.0;
22995
+ float x = c * (1.0 - abs(mod(h6, 2.0) - 1.0));
22996
+ float r = 0.0;
22997
+ float g = 0.0;
22998
+ float b = 0.0;
22999
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
23000
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
23001
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
23002
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
23003
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
23004
+ else { r = c; g = 0.0; b = x; }
23005
+ float m = l - c / 2.0;
23006
+ return vec3(r + m, g + m, b + m);
23007
+ }
23008
+
23009
+ vec3 _gpu_rgb_to_hsl(vec3 rgb) {
23010
+ float maxc = max(max(rgb.x, rgb.y), rgb.z);
23011
+ float minc = min(min(rgb.x, rgb.y), rgb.z);
23012
+ float l = (maxc + minc) / 2.0;
23013
+ float d = maxc - minc;
23014
+ if (d < 1e-6) return vec3(0.0, 0.0, l);
23015
+ float s = d / (1.0 - abs(2.0 * l - 1.0));
23016
+ float h;
23017
+ if (maxc == rgb.x) h = mod((rgb.y - rgb.z) / d, 6.0);
23018
+ else if (maxc == rgb.y) h = (rgb.z - rgb.x) / d + 2.0;
23019
+ else h = (rgb.x - rgb.y) / d + 4.0;
23020
+ h *= 60.0;
23021
+ if (h < 0.0) h += 360.0;
23022
+ return vec3(h, s, l);
23023
+ }
23024
+
23025
+ // HSV conversion. Hue in degrees, saturation/value in 0-1.
23026
+ vec3 _gpu_hsv_to_rgb(vec3 hsv) {
23027
+ float h = hsv.x;
23028
+ float s = hsv.y;
23029
+ float v = hsv.z;
23030
+ float c = v * s;
23031
+ float h6 = h / 60.0;
23032
+ float x = c * (1.0 - abs(mod(h6, 2.0) - 1.0));
23033
+ float r = 0.0;
23034
+ float g = 0.0;
23035
+ float b = 0.0;
23036
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
23037
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
23038
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
23039
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
23040
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
23041
+ else { r = c; g = 0.0; b = x; }
23042
+ float m = v - c;
23043
+ return vec3(r + m, g + m, b + m);
23044
+ }
23045
+
23046
+ vec3 _gpu_rgb_to_hsv(vec3 rgb) {
23047
+ float maxc = max(max(rgb.x, rgb.y), rgb.z);
23048
+ float minc = min(min(rgb.x, rgb.y), rgb.z);
23049
+ float v = maxc;
23050
+ float d = maxc - minc;
23051
+ if (d < 1e-6) return vec3(0.0, 0.0, v);
23052
+ float s = (maxc < 1e-6) ? 0.0 : d / maxc;
23053
+ float h;
23054
+ if (maxc == rgb.x) h = mod((rgb.y - rgb.z) / d, 6.0);
23055
+ else if (maxc == rgb.y) h = (rgb.z - rgb.x) / d + 2.0;
23056
+ else h = (rgb.x - rgb.y) / d + 4.0;
23057
+ h *= 60.0;
23058
+ if (h < 0.0) h += 360.0;
23059
+ return vec3(h, s, v);
22130
23060
  }
22131
23061
 
22132
- vec3 _gpu_color_mix(vec3 rgb1, vec3 rgb2, float t) {
22133
- vec3 lch1 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb1));
22134
- vec3 lch2 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb2));
23062
+ vec3 _gpu_color_mix(vec3 lch1, vec3 lch2, float t) {
22135
23063
  float L = mix(lch1.x, lch2.x, t);
22136
23064
  float C = mix(lch1.y, lch2.y, t);
22137
- float dh = lch2.z - lch1.z;
22138
- const float PI = 3.14159265359;
22139
- if (dh > PI) dh -= 2.0 * PI;
22140
- if (dh < -PI) dh += 2.0 * PI;
22141
- float H = lch1.z + dh * t;
22142
- return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(vec3(L, C, H)));
23065
+ bool a1 = lch1.y < 1e-6;
23066
+ bool a2 = lch2.y < 1e-6;
23067
+ float H;
23068
+ if (a1 && a2) {
23069
+ H = lch1.z;
23070
+ } else if (a1) {
23071
+ H = lch2.z;
23072
+ } else if (a2) {
23073
+ H = lch1.z;
23074
+ } else {
23075
+ float dh = lch2.z - lch1.z;
23076
+ if (dh > 180.0) dh -= 360.0;
23077
+ if (dh < -180.0) dh += 360.0;
23078
+ H = lch1.z + dh * t;
23079
+ if (H < 0.0) H += 360.0;
23080
+ if (H >= 360.0) H -= 360.0;
23081
+ }
23082
+ return vec3(L, C, H);
22143
23083
  }
22144
23084
 
22145
- float _gpu_apca(vec3 bg, vec3 fg) {
23085
+ float _gpu_apca(vec3 lch_bg, vec3 lch_fg) {
23086
+ vec3 bg = _gpu_oklch_to_srgb(lch_bg);
23087
+ vec3 fg = _gpu_oklch_to_srgb(lch_fg);
22146
23088
  float bgR = _gpu_srgb_to_linear(bg.x);
22147
23089
  float bgG = _gpu_srgb_to_linear(bg.y);
22148
23090
  float bgB = _gpu_srgb_to_linear(bg.z);
@@ -22153,9 +23095,7 @@ float _gpu_apca(vec3 bg, vec3 fg) {
22153
23095
  float fgY = 0.2126729 * fgR + 0.7151522 * fgG + 0.0721750 * fgB;
22154
23096
  float bgC = pow(bgY, 0.56);
22155
23097
  float fgC = pow(fgY, 0.57);
22156
- float contrast = (bgC > fgC)
22157
- ? (bgC - fgC) * 1.14
22158
- : (bgC - fgC) * 1.14;
23098
+ float contrast = (bgC - fgC) * 1.14;
22159
23099
  return contrast * 100.0;
22160
23100
  }
22161
23101
  `;
@@ -22199,28 +23139,133 @@ fn _gpu_oklab_to_srgb(lab: vec3f) -> vec3f {
22199
23139
 
22200
23140
  fn _gpu_oklab_to_oklch(lab: vec3f) -> vec3f {
22201
23141
  let C = length(lab.yz);
22202
- let H = atan2(lab.z, lab.y);
23142
+ var H = atan2(lab.z, lab.y) * (180.0 / 3.14159265359);
23143
+ if (H < 0.0) { H = H + 360.0; }
22203
23144
  return vec3f(lab.x, C, H);
22204
23145
  }
22205
23146
 
22206
23147
  fn _gpu_oklch_to_oklab(lch: vec3f) -> vec3f {
22207
- return vec3f(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));
23148
+ let h_rad = lch.z * (3.14159265359 / 180.0);
23149
+ return vec3f(lch.x, lch.y * cos(h_rad), lch.y * sin(h_rad));
23150
+ }
23151
+
23152
+ fn _gpu_srgb_to_oklch(rgb: vec3f) -> vec3f {
23153
+ return _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb));
23154
+ }
23155
+
23156
+ fn _gpu_oklch_to_srgb(lch: vec3f) -> vec3f {
23157
+ return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(lch));
23158
+ }
23159
+
23160
+ fn _gpu_hsl_to_rgb(hsl: vec3f) -> vec3f {
23161
+ let h = hsl.x;
23162
+ let s = hsl.y;
23163
+ let l = hsl.z;
23164
+ let c = (1.0 - abs(2.0 * l - 1.0)) * s;
23165
+ let h6 = h / 60.0;
23166
+ let x = c * (1.0 - abs((h6 - 2.0 * floor(h6 / 2.0)) - 1.0));
23167
+ var r: f32 = 0.0;
23168
+ var g: f32 = 0.0;
23169
+ var b: f32 = 0.0;
23170
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
23171
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
23172
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
23173
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
23174
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
23175
+ else { r = c; g = 0.0; b = x; }
23176
+ let m = l - c / 2.0;
23177
+ return vec3f(r + m, g + m, b + m);
23178
+ }
23179
+
23180
+ fn _gpu_rgb_to_hsl(rgb: vec3f) -> vec3f {
23181
+ let maxc = max(max(rgb.x, rgb.y), rgb.z);
23182
+ let minc = min(min(rgb.x, rgb.y), rgb.z);
23183
+ let l = (maxc + minc) / 2.0;
23184
+ let d = maxc - minc;
23185
+ if (d < 1e-6) { return vec3f(0.0, 0.0, l); }
23186
+ let s = d / (1.0 - abs(2.0 * l - 1.0));
23187
+ var h: f32;
23188
+ if (maxc == rgb.x) {
23189
+ let v = (rgb.y - rgb.z) / d;
23190
+ h = v - 6.0 * floor(v / 6.0);
23191
+ } else if (maxc == rgb.y) {
23192
+ h = (rgb.z - rgb.x) / d + 2.0;
23193
+ } else {
23194
+ h = (rgb.x - rgb.y) / d + 4.0;
23195
+ }
23196
+ h = h * 60.0;
23197
+ if (h < 0.0) { h = h + 360.0; }
23198
+ return vec3f(h, s, l);
23199
+ }
23200
+
23201
+ fn _gpu_hsv_to_rgb(hsv: vec3f) -> vec3f {
23202
+ let h = hsv.x;
23203
+ let s = hsv.y;
23204
+ let v = hsv.z;
23205
+ let c = v * s;
23206
+ let h6 = h / 60.0;
23207
+ let x = c * (1.0 - abs((h6 - 2.0 * floor(h6 / 2.0)) - 1.0));
23208
+ var r: f32 = 0.0;
23209
+ var g: f32 = 0.0;
23210
+ var b: f32 = 0.0;
23211
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
23212
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
23213
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
23214
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
23215
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
23216
+ else { r = c; g = 0.0; b = x; }
23217
+ let m = v - c;
23218
+ return vec3f(r + m, g + m, b + m);
23219
+ }
23220
+
23221
+ fn _gpu_rgb_to_hsv(rgb: vec3f) -> vec3f {
23222
+ let maxc = max(max(rgb.x, rgb.y), rgb.z);
23223
+ let minc = min(min(rgb.x, rgb.y), rgb.z);
23224
+ let v = maxc;
23225
+ let d = maxc - minc;
23226
+ if (d < 1e-6) { return vec3f(0.0, 0.0, v); }
23227
+ var s: f32 = 0.0;
23228
+ if (maxc >= 1e-6) { s = d / maxc; }
23229
+ var h: f32;
23230
+ if (maxc == rgb.x) {
23231
+ let q = (rgb.y - rgb.z) / d;
23232
+ h = q - 6.0 * floor(q / 6.0);
23233
+ } else if (maxc == rgb.y) {
23234
+ h = (rgb.z - rgb.x) / d + 2.0;
23235
+ } else {
23236
+ h = (rgb.x - rgb.y) / d + 4.0;
23237
+ }
23238
+ h = h * 60.0;
23239
+ if (h < 0.0) { h = h + 360.0; }
23240
+ return vec3f(h, s, v);
22208
23241
  }
22209
23242
 
22210
- fn _gpu_color_mix(rgb1: vec3f, rgb2: vec3f, t: f32) -> vec3f {
22211
- let lch1 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb1));
22212
- let lch2 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb2));
23243
+ fn _gpu_color_mix(lch1: vec3f, lch2: vec3f, t: f32) -> vec3f {
22213
23244
  let L = mix(lch1.x, lch2.x, t);
22214
23245
  let C = mix(lch1.y, lch2.y, t);
22215
- let PI = 3.14159265359;
22216
- var dh = lch2.z - lch1.z;
22217
- if (dh > PI) { dh -= 2.0 * PI; }
22218
- if (dh < -PI) { dh += 2.0 * PI; }
22219
- let H = lch1.z + dh * t;
22220
- return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(vec3f(L, C, H)));
23246
+ let a1 = lch1.y < 1e-6;
23247
+ let a2 = lch2.y < 1e-6;
23248
+ var H: f32;
23249
+ if (a1 && a2) {
23250
+ H = lch1.z;
23251
+ } else if (a1) {
23252
+ H = lch2.z;
23253
+ } else if (a2) {
23254
+ H = lch1.z;
23255
+ } else {
23256
+ var dh = lch2.z - lch1.z;
23257
+ if (dh > 180.0) { dh = dh - 360.0; }
23258
+ if (dh < -180.0) { dh = dh + 360.0; }
23259
+ H = lch1.z + dh * t;
23260
+ if (H < 0.0) { H = H + 360.0; }
23261
+ if (H >= 360.0) { H = H - 360.0; }
23262
+ }
23263
+ return vec3f(L, C, H);
22221
23264
  }
22222
23265
 
22223
- fn _gpu_apca(bg: vec3f, fg: vec3f) -> f32 {
23266
+ fn _gpu_apca(lch_bg: vec3f, lch_fg: vec3f) -> f32 {
23267
+ let bg = _gpu_oklch_to_srgb(lch_bg);
23268
+ let fg = _gpu_oklch_to_srgb(lch_fg);
22224
23269
  let bgR = _gpu_srgb_to_linear(bg.x);
22225
23270
  let bgG = _gpu_srgb_to_linear(bg.y);
22226
23271
  let bgB = _gpu_srgb_to_linear(bg.z);
@@ -22508,7 +23553,7 @@ fn _gpu_apca(bg: vec3f, fg: vec3f) -> f32 {
22508
23553
  if (stmts.length === 0) return "";
22509
23554
  const last = stmts.length - 1;
22510
23555
  stmts[last] = `return ${stmts[last]}`;
22511
- return stmts.join(";\n");
23556
+ return stmts.join(";\n") + ";";
22512
23557
  },
22513
23558
  ...options
22514
23559
  };
@@ -22607,7 +23652,7 @@ fn _gpu_apca(bg: vec3f, fg: vec3f) -> f32 {
22607
23652
  if (body.includes("\n")) {
22608
23653
  const indented = body.split("\n").map((l) => ` ${l}`).join("\n");
22609
23654
  return `${returnType} ${functionName}(${params}) {
22610
- ${indented};
23655
+ ${indented}
22611
23656
  }`;
22612
23657
  }
22613
23658
  return `${returnType} ${functionName}(${params}) {
@@ -22718,7 +23763,7 @@ ${indented};
22718
23763
  return `fn ${functionName}(${params}) -> ${toWGSLType(
22719
23764
  returnType
22720
23765
  )} {
22721
- ${indented};
23766
+ ${indented}
22722
23767
  }`;
22723
23768
  }
22724
23769
  return `fn ${functionName}(${params}) -> ${toWGSLType(returnType)} {
@@ -24897,7 +25942,7 @@ ${code}`;
24897
25942
  }
24898
25943
 
24899
25944
  // src/compile.ts
24900
- var version = "0.55.6";
25945
+ var version = "0.57.0";
24901
25946
  return __toCommonJS(compile_exports);
24902
25947
  })();
24903
25948
  /*! Bundled license information: