@cortex-js/compute-engine 0.55.6 → 0.56.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 +776 -139
  2. package/dist/compile.min.esm.js +277 -78
  3. package/dist/compile.min.umd.cjs +277 -78
  4. package/dist/compile.umd.cjs +776 -139
  5. package/dist/compute-engine.esm.js +1299 -260
  6. package/dist/compute-engine.min.esm.js +298 -99
  7. package/dist/compute-engine.min.umd.cjs +298 -99
  8. package/dist/compute-engine.umd.cjs +1299 -260
  9. package/dist/core.esm.js +1298 -259
  10. package/dist/core.min.esm.js +297 -98
  11. package/dist/core.min.umd.cjs +297 -98
  12. package/dist/core.umd.cjs +1298 -259
  13. package/dist/interval.esm.js +134 -5
  14. package/dist/interval.min.esm.js +6 -6
  15. package/dist/interval.min.umd.cjs +6 -6
  16. package/dist/interval.umd.cjs +134 -5
  17. package/dist/latex-syntax.esm.js +160 -11
  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 +160 -11
  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 +1 -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 +1 -1
  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 +22 -2
  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 +1 -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 +1 -1
  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 +6 -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
package/dist/core.umd.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /** ComputeEngineCore 0.55.6 */
1
+ /** ComputeEngineCore 0.56.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.ComputeEngineCore = {}));})(this, (function (exports) { 'use strict';
3
3
  var ComputeEngineCore = (() => {
4
4
  var __defProp = Object.defineProperty;
@@ -2287,6 +2287,7 @@ var ComputeEngineCore = (() => {
2287
2287
  ];
2288
2288
  var VALUE_TYPES = [
2289
2289
  "value",
2290
+ "color",
2290
2291
  ...COLLECTION_TYPES,
2291
2292
  ...SCALAR_TYPES
2292
2293
  ];
@@ -3986,6 +3987,7 @@ var ComputeEngineCore = (() => {
3986
3987
  symbol: [],
3987
3988
  boolean: [],
3988
3989
  string: [],
3990
+ color: [],
3989
3991
  expression: EXPRESSION_TYPES
3990
3992
  };
3991
3993
  function isPrimitiveSubtype(lhs, rhs) {
@@ -7869,9 +7871,10 @@ var ComputeEngineCore = (() => {
7869
7871
  if (!materialized.isLazyCollection) return materialized.latex;
7870
7872
  }
7871
7873
  const syntax = this.engine._requireLatexSyntax();
7872
- return syntax.serialize(
7873
- this.toMathJson({ prettify: true, fractionalDigits: "auto" })
7874
- );
7874
+ const json = this.toMathJson({ prettify: true, fractionalDigits: "auto" });
7875
+ const latexOpts = this.engine.latexOptions;
7876
+ if (Object.keys(latexOpts).length === 0) return syntax.serialize(json);
7877
+ return syntax.serialize(json, { ...latexOpts });
7875
7878
  }
7876
7879
  /**
7877
7880
  * Return a LaTeX representation of this expression with custom
@@ -7895,9 +7898,13 @@ var ComputeEngineCore = (() => {
7895
7898
  fractionalDigits: "auto"
7896
7899
  });
7897
7900
  const syntax = this.engine._requireLatexSyntax();
7898
- if (!options || Object.keys(options).length === 0)
7899
- return syntax.serialize(json);
7900
- return syntax.serialize(json, options);
7901
+ const latexOpts = this.engine.latexOptions;
7902
+ const haveEngineOpts = Object.keys(latexOpts).length > 0;
7903
+ const haveCallOpts = options && Object.keys(options).length > 0;
7904
+ if (!haveEngineOpts && !haveCallOpts) return syntax.serialize(json);
7905
+ if (!haveEngineOpts) return syntax.serialize(json, options);
7906
+ if (!haveCallOpts) return syntax.serialize(json, { ...latexOpts });
7907
+ return syntax.serialize(json, { ...latexOpts, ...options });
7901
7908
  }
7902
7909
  /** Called by `JSON.stringify()` when serializing to json.
7903
7910
  *
@@ -7941,11 +7948,13 @@ var ComputeEngineCore = (() => {
7941
7948
  "number",
7942
7949
  "dictionary"
7943
7950
  ];
7944
- }
7945
- if (Array.isArray(options.shorthands))
7951
+ } else if (Array.isArray(options.shorthands)) {
7946
7952
  defaultOptions.shorthands = options.shorthands;
7953
+ }
7947
7954
  if (typeof options.metadata === "string" && options.metadata === "all" || options.metadata?.includes("all")) {
7948
7955
  defaultOptions.metadata = ["latex", "wikidata"];
7956
+ } else if (Array.isArray(options.metadata)) {
7957
+ defaultOptions.metadata = options.metadata;
7949
7958
  }
7950
7959
  if (options.fractionalDigits === "auto")
7951
7960
  defaultOptions.fractionalDigits = -this.engine.precision;
@@ -13667,6 +13676,8 @@ var ComputeEngineCore = (() => {
13667
13676
  precedence: DIVISION_PRECEDENCE,
13668
13677
  parse: "Mod"
13669
13678
  },
13679
+ // Function-style alias: `\operatorname{mod}(a, b)`
13680
+ { latexTrigger: "\\operatorname{mod}", parse: "Mod" },
13670
13681
  {
13671
13682
  latexTrigger: "\\pmod",
13672
13683
  kind: "prefix",
@@ -13907,6 +13918,13 @@ var ComputeEngineCore = (() => {
13907
13918
  const rhs = serializer.wrap(operand(expr2, 2), ADDITION_PRECEDENCE + 3);
13908
13919
  return joinLatex([lhs, "-", rhs]);
13909
13920
  }
13921
+ },
13922
+ // Euclidean distance between two points (tuples of numbers).
13923
+ {
13924
+ name: "Distance",
13925
+ latexTrigger: ["\\operatorname{distance}"],
13926
+ kind: "function",
13927
+ serialize: (serializer, expr2) => "\\operatorname{distance}" + serializer.wrapArguments(expr2)
13910
13928
  }
13911
13929
  ];
13912
13930
  function getIndexAssignment(expr2, upper) {
@@ -15331,7 +15349,9 @@ var ComputeEngineCore = (() => {
15331
15349
  if (!expr2 || !symbol(expr2)) return null;
15332
15350
  return ["Mean", expr2];
15333
15351
  }
15334
- }
15352
+ },
15353
+ // Function-style alias: `\operatorname{var}(...)`
15354
+ { latexTrigger: "\\operatorname{var}", parse: "Variance" }
15335
15355
  ];
15336
15356
 
15337
15357
  // src/compute-engine/numerics/unit-data.ts
@@ -16432,7 +16452,7 @@ var ComputeEngineCore = (() => {
16432
16452
  36: "\\qquad"
16433
16453
  }[v] ?? "";
16434
16454
  }
16435
- }
16455
+ },
16436
16456
  // if (
16437
16457
  // [
16438
16458
  // '\\!',
@@ -16456,6 +16476,121 @@ var ComputeEngineCore = (() => {
16456
16476
  // name: '',
16457
16477
  // trigger: '\\check',
16458
16478
  // },
16479
+ // ---------------------------------------------------------------------------
16480
+ // Function-style aliases for collection / random operators that some
16481
+ // notations write in lowercase (e.g. `\operatorname{shuffle}(L)`).
16482
+ // The capitalized library entries already exist; these are pure parse
16483
+ // aliases so the lowercase names don't land in `unsupported-operator`.
16484
+ // ---------------------------------------------------------------------------
16485
+ { latexTrigger: "\\operatorname{random}", parse: "Random" },
16486
+ { latexTrigger: "\\operatorname{shuffle}", parse: "Shuffle" },
16487
+ { latexTrigger: "\\operatorname{repeat}", parse: "Repeat" },
16488
+ { latexTrigger: "\\operatorname{join}", parse: "Join" },
16489
+ // ---------------------------------------------------------------------------
16490
+ // Geometric primitive heads. Registered as known typed heads so consumers
16491
+ // can branch on the operator name; CE itself doesn't render them. The
16492
+ // library entries (with no evaluator) live in `library/core.ts`.
16493
+ // ---------------------------------------------------------------------------
16494
+ {
16495
+ name: "Triangle",
16496
+ latexTrigger: ["\\operatorname{triangle}"],
16497
+ kind: "function",
16498
+ serialize: (serializer, expr2) => "\\operatorname{triangle}" + serializer.wrapArguments(expr2)
16499
+ },
16500
+ // Desmos's geometric `vector(p1, p2)` — a directed segment between two
16501
+ // points. Routed to a dedicated head (not the existing column-vector
16502
+ // `Vector`, which has a narrower `(number+) -> vector` signature).
16503
+ {
16504
+ name: "GeometricVector",
16505
+ latexTrigger: ["\\operatorname{vector}"],
16506
+ kind: "function",
16507
+ serialize: (serializer, expr2) => "\\operatorname{vector}" + serializer.wrapArguments(expr2)
16508
+ },
16509
+ {
16510
+ name: "Sphere",
16511
+ latexTrigger: ["\\operatorname{sphere}"],
16512
+ kind: "function",
16513
+ serialize: (serializer, expr2) => "\\operatorname{sphere}" + serializer.wrapArguments(expr2)
16514
+ },
16515
+ {
16516
+ name: "Segment",
16517
+ latexTrigger: ["\\operatorname{segment}"],
16518
+ kind: "function",
16519
+ serialize: (serializer, expr2) => "\\operatorname{segment}" + serializer.wrapArguments(expr2)
16520
+ }
16521
+ ];
16522
+
16523
+ // src/compute-engine/latex-syntax/dictionary/definitions-colors.ts
16524
+ var DEFINITIONS_COLORS = [
16525
+ // Color constructors (one per colorspace, preserves space on evaluation)
16526
+ {
16527
+ name: "Rgb",
16528
+ latexTrigger: ["\\operatorname{rgb}"],
16529
+ kind: "function",
16530
+ serialize: (serializer, expr2) => "\\operatorname{rgb}" + serializer.wrapArguments(expr2)
16531
+ },
16532
+ {
16533
+ name: "Hsv",
16534
+ latexTrigger: ["\\operatorname{hsv}"],
16535
+ kind: "function",
16536
+ serialize: (serializer, expr2) => "\\operatorname{hsv}" + serializer.wrapArguments(expr2)
16537
+ },
16538
+ {
16539
+ name: "Hsl",
16540
+ latexTrigger: ["\\operatorname{hsl}"],
16541
+ kind: "function",
16542
+ serialize: (serializer, expr2) => "\\operatorname{hsl}" + serializer.wrapArguments(expr2)
16543
+ },
16544
+ {
16545
+ name: "Oklab",
16546
+ latexTrigger: ["\\operatorname{oklab}"],
16547
+ kind: "function",
16548
+ serialize: (serializer, expr2) => "\\operatorname{oklab}" + serializer.wrapArguments(expr2)
16549
+ },
16550
+ {
16551
+ name: "Oklch",
16552
+ latexTrigger: ["\\operatorname{oklch}"],
16553
+ kind: "function",
16554
+ serialize: (serializer, expr2) => "\\operatorname{oklch}" + serializer.wrapArguments(expr2)
16555
+ },
16556
+ // Conversion functions (color → color in the named space)
16557
+ {
16558
+ name: "AsRgb",
16559
+ latexTrigger: ["\\operatorname{asRgb}"],
16560
+ kind: "function",
16561
+ serialize: (serializer, expr2) => "\\operatorname{asRgb}" + serializer.wrapArguments(expr2)
16562
+ },
16563
+ {
16564
+ name: "AsHsv",
16565
+ latexTrigger: ["\\operatorname{asHsv}"],
16566
+ kind: "function",
16567
+ serialize: (serializer, expr2) => "\\operatorname{asHsv}" + serializer.wrapArguments(expr2)
16568
+ },
16569
+ {
16570
+ name: "AsHsl",
16571
+ latexTrigger: ["\\operatorname{asHsl}"],
16572
+ kind: "function",
16573
+ serialize: (serializer, expr2) => "\\operatorname{asHsl}" + serializer.wrapArguments(expr2)
16574
+ },
16575
+ {
16576
+ name: "AsOklab",
16577
+ latexTrigger: ["\\operatorname{asOklab}"],
16578
+ kind: "function",
16579
+ serialize: (serializer, expr2) => "\\operatorname{asOklab}" + serializer.wrapArguments(expr2)
16580
+ },
16581
+ {
16582
+ name: "AsOklch",
16583
+ latexTrigger: ["\\operatorname{asOklch}"],
16584
+ kind: "function",
16585
+ serialize: (serializer, expr2) => "\\operatorname{asOklch}" + serializer.wrapArguments(expr2)
16586
+ },
16587
+ // Perceptual difference (returns a scalar in [0, ~1])
16588
+ {
16589
+ name: "ColorDelta",
16590
+ latexTrigger: ["\\operatorname{colorDelta}"],
16591
+ kind: "function",
16592
+ serialize: (serializer, expr2) => "\\operatorname{colorDelta}" + serializer.wrapArguments(expr2)
16593
+ }
16459
16594
  ];
16460
16595
 
16461
16596
  // src/compute-engine/latex-syntax/dictionary/default-dictionary.ts
@@ -16486,7 +16621,8 @@ var ComputeEngineCore = (() => {
16486
16621
  ...DEFINITIONS_STATISTICS,
16487
16622
  ...DEFINITIONS_UNITS,
16488
16623
  ...DEFINITIONS_OTHERS,
16489
- ...DEFINITIONS_PHYSICS
16624
+ ...DEFINITIONS_PHYSICS,
16625
+ ...DEFINITIONS_COLORS
16490
16626
  ];
16491
16627
 
16492
16628
  // src/math-json/symbols.ts
@@ -16651,6 +16787,17 @@ var ComputeEngineCore = (() => {
16651
16787
  } else if (Array.isArray(openTrigger) && openTrigger.length > 0) {
16652
16788
  openTokens.push(openTrigger[0]);
16653
16789
  }
16790
+ const closeTrigger = indexedEntry.closeTrigger;
16791
+ const closeTokens = /* @__PURE__ */ new Set();
16792
+ if (typeof closeTrigger === "string") {
16793
+ const variants = DELIMITER_SHORTHAND[closeTrigger];
16794
+ if (variants) for (const v of variants) closeTokens.add(v);
16795
+ else closeTokens.add(closeTrigger);
16796
+ if (closeTrigger === "||") closeTokens.add("|");
16797
+ } else if (Array.isArray(closeTrigger) && closeTrigger.length > 0) {
16798
+ closeTokens.add(closeTrigger[0]);
16799
+ }
16800
+ indexedEntry.closeTokens = closeTokens;
16654
16801
  for (const token of openTokens) {
16655
16802
  const existing = result.matchfixByOpen.get(token);
16656
16803
  if (existing) {
@@ -16842,11 +16989,7 @@ var ComputeEngineCore = (() => {
16842
16989
  if (style === "scaled")
16843
16990
  return joinLatex([`\\left${openDelim}`, inner, `\\right${closeDelim}`]);
16844
16991
  if (style === "big")
16845
- return joinLatex([
16846
- `\\Bigl${openDelim}`,
16847
- inner,
16848
- `\\Bigr${closeDelim}`
16849
- ]);
16992
+ return joinLatex([`\\Bigl${openDelim}`, inner, `\\Bigr${closeDelim}`]);
16850
16993
  return joinLatex([openDelim, inner, closeDelim]);
16851
16994
  };
16852
16995
  }
@@ -18197,7 +18340,7 @@ var ComputeEngineCore = (() => {
18197
18340
  }
18198
18341
  if (this.match("\\hskip") || this.match("\\kern")) {
18199
18342
  this.skipSpace();
18200
- this.match("-") || this.match("+");
18343
+ if (!this.match("-")) this.match("+");
18201
18344
  while (/^[\d.]$/.test(this.peek)) this.nextToken();
18202
18345
  for (const unit of [
18203
18346
  "pt",
@@ -18711,6 +18854,19 @@ var ComputeEngineCore = (() => {
18711
18854
  }
18712
18855
  for (const def of defs) {
18713
18856
  this.index = start;
18857
+ if (def.closeTokens.size > 0) {
18858
+ let found = false;
18859
+ const tokens = this._tokens;
18860
+ for (let i = start; i < tokens.length; i++) {
18861
+ if (def.closeTokens.has(tokens[i])) {
18862
+ found = true;
18863
+ break;
18864
+ }
18865
+ }
18866
+ if (!found) continue;
18867
+ }
18868
+ if (typeof def.openTrigger === "string" && def.openTrigger === "." && !OPEN_DELIMITER_PREFIX[currentToken])
18869
+ continue;
18714
18870
  const matched = this.matchDelimiter(def.openTrigger, def.closeTrigger);
18715
18871
  if (!matched) continue;
18716
18872
  const bodyStart = this.index;
@@ -32273,6 +32429,29 @@ ${lines.join("\n")}`;
32273
32429
  signature: "(value*) -> number | list",
32274
32430
  evaluate: (xs, { engine }) => evaluateMinMax(engine, xs, "Infimum")
32275
32431
  },
32432
+ Distance: {
32433
+ description: "Euclidean distance between two points (tuples of numbers).",
32434
+ complexity: 6e3,
32435
+ signature: "(tuple, tuple) -> number",
32436
+ evaluate: ([a, b], { engine: ce }) => {
32437
+ if (!isFunction2(a) || !isFunction2(b))
32438
+ return ce.error("incompatible-type");
32439
+ if (a.operator !== "Tuple" || b.operator !== "Tuple")
32440
+ return ce.error("incompatible-type");
32441
+ if (a.ops.length !== b.ops.length || a.ops.length === 0)
32442
+ return ce.error("incompatible-type");
32443
+ let sumSq = 0;
32444
+ for (let i = 0; i < a.ops.length; i++) {
32445
+ const ai = a.ops[i].re;
32446
+ const bi = b.ops[i].re;
32447
+ if (!Number.isFinite(ai) || !Number.isFinite(bi))
32448
+ return ce.error("expected-value");
32449
+ const d = ai - bi;
32450
+ sumSq += d * d;
32451
+ }
32452
+ return ce.number(Math.sqrt(sumSq));
32453
+ }
32454
+ },
32276
32455
  Product: {
32277
32456
  description: "`Product(f, a, b)` computes the product of `f` from `a` to `b`",
32278
32457
  wikidata: "Q901718",
@@ -32805,16 +32984,11 @@ ${lines.join("\n")}`;
32805
32984
  );
32806
32985
  let condFn;
32807
32986
  if (typeof condition === "string") {
32808
- const latex = asLatexString(condition);
32809
- if (latex) {
32810
- const condPattern = ce.parse(latex, {
32811
- form: options?.canonical ? "canonical" : "raw"
32812
- }) ?? ce.expr("Nothing");
32813
- condFn = (x, _ce) => {
32814
- const evaluated = condPattern.subs(x).evaluate();
32815
- return isSymbol2(evaluated, "True");
32816
- };
32817
- }
32987
+ const condPattern = ce.parse(condition) ?? ce.expr("Nothing");
32988
+ condFn = (x, _ce) => {
32989
+ const evaluated = condPattern.subs(x).evaluate();
32990
+ return isSymbol2(evaluated, "True");
32991
+ };
32818
32992
  } else {
32819
32993
  if (condition !== void 0 && typeof condition !== "function")
32820
32994
  throw new Error(
@@ -32916,6 +33090,15 @@ ${e.message}
32916
33090
  function applyRule(rule, expr2, substitution, options) {
32917
33091
  if (!rule) return null;
32918
33092
  let canonical2 = options?.canonical ?? (expr2.isCanonical || expr2.isStructural);
33093
+ let { match: match2, replace: replace2, condition, id, onMatch, onBeforeMatch } = rule;
33094
+ const because = id ?? "";
33095
+ const ce = expr2.engine;
33096
+ if (canonical2 && match2) {
33097
+ const awc = getWildcards(match2);
33098
+ const canonicalMatch = match2.canonical;
33099
+ const bwc = getWildcards(canonicalMatch);
33100
+ if (!awc.every((x) => bwc.includes(x))) return null;
33101
+ }
32919
33102
  let operandsMatched = false;
32920
33103
  if (isFunction2(expr2) && options?.recursive) {
32921
33104
  const newOps = expr2.ops.map((op) => {
@@ -32927,20 +33110,11 @@ ${e.message}
32927
33110
  if (operandsMatched) {
32928
33111
  if (!canonical2 && options?.canonical === void 0 && newOps.every((x) => x.isCanonical))
32929
33112
  canonical2 = true;
32930
- expr2 = expr2.engine.function(expr2.operator, newOps, {
33113
+ expr2 = ce.function(expr2.operator, newOps, {
32931
33114
  form: canonical2 ? "canonical" : "raw"
32932
33115
  });
32933
33116
  }
32934
33117
  }
32935
- let { match: match2, replace: replace2, condition, id, onMatch, onBeforeMatch } = rule;
32936
- const because = id ?? "";
32937
- if (canonical2 && match2) {
32938
- const awc = getWildcards(match2);
32939
- const canonicalMatch = match2.canonical;
32940
- const bwc = getWildcards(canonicalMatch);
32941
- if (!awc.every((x) => bwc.includes(x)))
32942
- return operandsMatched ? { value: expr2, because } : null;
32943
- }
32944
33118
  const useVariations = rule.useVariations ?? options?.useVariations ?? false;
32945
33119
  const matchPermutations = options?.matchPermutations ?? true;
32946
33120
  onBeforeMatch?.(rule, expr2);
@@ -32959,7 +33133,7 @@ ${e.message}
32959
33133
  ...sub2
32960
33134
  };
32961
33135
  try {
32962
- if (!condition(conditionSub, expr2.engine))
33136
+ if (!condition(conditionSub, ce))
32963
33137
  return operandsMatched ? { value: expr2, because } : null;
32964
33138
  } catch (e) {
32965
33139
  console.error(
@@ -32974,7 +33148,8 @@ ${e.message}
32974
33148
  if (!canonical2 && options?.canonical === void 0 && replace2 instanceof _BoxedExpression && replace2.isCanonical)
32975
33149
  canonical2 = true;
32976
33150
  const result = typeof replace2 === "function" ? replace2(expr2, sub2) : replace2.subs(sub2, { canonical: canonical2 });
32977
- if (!result) return null;
33151
+ if (!result)
33152
+ return operandsMatched ? { value: canonical2 ? expr2.canonical : expr2, because } : null;
32978
33153
  onMatch?.(rule, expr2, result);
32979
33154
  if (isRuleStep(result))
32980
33155
  return canonical2 ? { ...result, value: result.value.canonical } : result;
@@ -38548,6 +38723,40 @@ ${e.message}
38548
38723
  else h = ((r - g) / d + 4) / 6;
38549
38724
  return { h: h * 360, s, l };
38550
38725
  }
38726
+ function hsvToRgb(h, s, v) {
38727
+ h = (h % 360 + 360) % 360;
38728
+ s = Math.max(0, Math.min(1, s));
38729
+ v = Math.max(0, Math.min(1, v));
38730
+ const c = v * s;
38731
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
38732
+ const m = v - c;
38733
+ let r = 0, g = 0, b = 0;
38734
+ if (h < 60) [r, g, b] = [c, x, 0];
38735
+ else if (h < 120) [r, g, b] = [x, c, 0];
38736
+ else if (h < 180) [r, g, b] = [0, c, x];
38737
+ else if (h < 240) [r, g, b] = [0, x, c];
38738
+ else if (h < 300) [r, g, b] = [x, 0, c];
38739
+ else [r, g, b] = [c, 0, x];
38740
+ return { r: (r + m) * 255, g: (g + m) * 255, b: (b + m) * 255 };
38741
+ }
38742
+ function rgbToHsv(r, g, b) {
38743
+ r /= 255;
38744
+ g /= 255;
38745
+ b /= 255;
38746
+ const max2 = Math.max(r, g, b);
38747
+ const min2 = Math.min(r, g, b);
38748
+ const d = max2 - min2;
38749
+ let h = 0;
38750
+ if (d > 0) {
38751
+ if (max2 === r) h = (g - b) / d % 6;
38752
+ else if (max2 === g) h = (b - r) / d + 2;
38753
+ else h = (r - g) / d + 4;
38754
+ h *= 60;
38755
+ if (h < 0) h += 360;
38756
+ }
38757
+ const s = max2 === 0 ? 0 : d / max2;
38758
+ return { h, s, v: max2 };
38759
+ }
38551
38760
  function parseHexColor(s) {
38552
38761
  const hex = s.startsWith("#") ? s.substring(1) : s;
38553
38762
  let r, g, b;
@@ -38572,6 +38781,12 @@ ${e.message}
38572
38781
  if (alpha !== void 0) result.alpha = alpha;
38573
38782
  return result;
38574
38783
  }
38784
+ function asOklch(color) {
38785
+ if (typeof color === "string") return rgbToOklch(parseHexColor(color));
38786
+ if ("C" in color) return color;
38787
+ if ("a" in color && "b" in color) return oklabToOklch(color);
38788
+ return rgbToOklch(color);
38789
+ }
38575
38790
  function asRgb(color) {
38576
38791
  if (typeof color === "number") {
38577
38792
  return {
@@ -39003,6 +39218,13 @@ ${e.message}
39003
39218
  };
39004
39219
  function parseColor(s, darkMode) {
39005
39220
  const str = s.trim().toLowerCase();
39221
+ const opacityMatch = str.match(/^(.+?)\s*\/\s*(\d+(?:\.\d+)?)%?\s*$/);
39222
+ if (opacityMatch) {
39223
+ const base = parseColor(opacityMatch[1].trim(), darkMode);
39224
+ const opacity = Math.max(0, Math.min(100, parseFloat(opacityMatch[2])));
39225
+ const alpha = Math.round(opacity / 100 * 255);
39226
+ return base & 4294967040 | alpha;
39227
+ }
39006
39228
  if (str.startsWith("#")) {
39007
39229
  const hex = str.substring(1);
39008
39230
  let r, g, b, a = 255;
@@ -39135,14 +39357,6 @@ ${e.message}
39135
39357
  console.warn(`parseColor: unrecognized color "${s}"`);
39136
39358
  return 0;
39137
39359
  }
39138
- function parseColorToRgb01(s, darkMode) {
39139
- const color = parseColor(s, darkMode);
39140
- return [
39141
- (color >>> 24 & 255) / 255,
39142
- (color >>> 16 & 255) / 255,
39143
- (color >>> 8 & 255) / 255
39144
- ];
39145
- }
39146
39360
  function apca(bgColor, fgColor) {
39147
39361
  const bgRgb = asRgb(bgColor);
39148
39362
  const fgRgb = asRgb(fgColor);
@@ -39201,6 +39415,12 @@ ${e.message}
39201
39415
  const contrast2 = Math.abs(apca(fg2, bg));
39202
39416
  return contrast1 >= contrast2 ? asColorNumber(fg1) : asColorNumber(fg2);
39203
39417
  }
39418
+ function oklabDeltaE(a, b) {
39419
+ const dL = a.L - b.L;
39420
+ const da = a.a - b.a;
39421
+ const db = a.b - b.b;
39422
+ return Math.sqrt(dL * dL + da * da + db * db);
39423
+ }
39204
39424
  function lerpOklch(c1, c2, f) {
39205
39425
  const L = c1.L + (c2.L - c1.L) * f;
39206
39426
  const C = c1.C + (c2.C - c1.C) * f;
@@ -41962,14 +42182,30 @@ ${e.message}
41962
42182
  };
41963
42183
 
41964
42184
  // src/compute-engine/library/colors.ts
41965
- function colorNumberToTuple(ce, color) {
41966
- const r = (color >>> 24 & 255) / 255;
41967
- const g = (color >>> 16 & 255) / 255;
41968
- const b = (color >>> 8 & 255) / 255;
41969
- const a = (color & 255) / 255;
41970
- if (Math.abs(a - 1) < 1e-4)
41971
- return ce.tuple(ce.number(r), ce.number(g), ce.number(b));
41972
- return ce.tuple(ce.number(r), ce.number(g), ce.number(b), ce.number(a));
42185
+ function normalizeAlpha(a) {
42186
+ if (a === void 0) return void 0;
42187
+ if (!Number.isFinite(a)) return void 0;
42188
+ if (Math.abs(a - 1) < 1e-9) return void 0;
42189
+ return a;
42190
+ }
42191
+ function normalizeColorHead(ce, expr2) {
42192
+ if (!isFunction2(expr2) || !expr2.ops || expr2.ops.length < 4) return expr2;
42193
+ const alphaExpr = expr2.ops[3];
42194
+ if (!isNumber(alphaExpr)) return expr2;
42195
+ if (normalizeAlpha(alphaExpr.re) === void 0) {
42196
+ return ce.function(expr2.operator, [expr2.ops[0], expr2.ops[1], expr2.ops[2]]);
42197
+ }
42198
+ return expr2;
42199
+ }
42200
+ function colorNumberToOklch(ce, color) {
42201
+ const r = color >>> 24 & 255;
42202
+ const g = color >>> 16 & 255;
42203
+ const b = color >>> 8 & 255;
42204
+ const a = normalizeAlpha((color & 255) / 255);
42205
+ const c = rgbToOklch({ r, g, b });
42206
+ const args = [ce.number(c.L), ce.number(c.C), ce.number(c.H)];
42207
+ if (a !== void 0) args.push(ce.number(a));
42208
+ return ce.function("Oklch", args);
41973
42209
  }
41974
42210
  var ALL_PALETTES = {
41975
42211
  ...SEQUENTIAL_PALETTES,
@@ -41980,45 +42216,139 @@ ${e.message}
41980
42216
  t = Math.max(0, Math.min(1, t));
41981
42217
  const n = palette.length;
41982
42218
  if (n === 0) return ce.error("expected-value");
41983
- if (n === 1) return colorNumberToTuple(ce, parseColor(palette[0]));
42219
+ if (n === 1) return colorNumberToOklch(ce, parseColor(palette[0]));
41984
42220
  const pos = t * (n - 1);
41985
42221
  const i = Math.floor(pos);
41986
42222
  const frac = pos - i;
41987
- if (i >= n - 1) return colorNumberToTuple(ce, parseColor(palette[n - 1]));
41988
- if (frac < 1e-9) return colorNumberToTuple(ce, parseColor(palette[i]));
41989
- const rgb = interpolateOklch(palette[i], palette[i + 1], frac);
41990
- const r = rgb.r / 255;
41991
- const g = rgb.g / 255;
41992
- const b = rgb.b / 255;
41993
- return ce.tuple(ce.number(r), ce.number(g), ce.number(b));
42223
+ if (i >= n - 1) return colorNumberToOklch(ce, parseColor(palette[n - 1]));
42224
+ if (frac < 1e-9) return colorNumberToOklch(ce, parseColor(palette[i]));
42225
+ return oklchToExpr(
42226
+ ce,
42227
+ asOklch(interpolateOklch(palette[i], palette[i + 1], frac))
42228
+ );
42229
+ }
42230
+ var COLOR_OPERATORS = /* @__PURE__ */ new Set(["Rgb", "Hsv", "Hsl", "Oklab", "Oklch"]);
42231
+ function readColorExpr(arg) {
42232
+ if (!isFunction2(arg)) return null;
42233
+ if (!COLOR_OPERATORS.has(arg.operator)) return null;
42234
+ if (!arg.ops || arg.ops.length < 3) return null;
42235
+ const c0 = arg.ops[0].re;
42236
+ const c1 = arg.ops[1].re;
42237
+ const c2 = arg.ops[2].re;
42238
+ if (!Number.isFinite(c0) || !Number.isFinite(c1) || !Number.isFinite(c2))
42239
+ return null;
42240
+ const alpha = arg.ops.length >= 4 ? normalizeAlpha(arg.ops[3].re) : void 0;
42241
+ return { space: arg.operator, c0, c1, c2, alpha };
42242
+ }
42243
+ function colorExprToRgb(arg) {
42244
+ const c = readColorExpr(arg);
42245
+ if (!c) return null;
42246
+ const withAlpha = (rgb) => c.alpha !== void 0 ? { ...rgb, alpha: c.alpha } : rgb;
42247
+ switch (c.space) {
42248
+ case "Rgb":
42249
+ return withAlpha({ r: c.c0 * 255, g: c.c1 * 255, b: c.c2 * 255 });
42250
+ case "Hsv":
42251
+ return withAlpha(hsvToRgb(c.c0, c.c1, c.c2));
42252
+ case "Hsl":
42253
+ return withAlpha(hslToRgb(c.c0, c.c1, c.c2));
42254
+ case "Oklab":
42255
+ return withAlpha(oklabToRgb({ L: c.c0, a: c.c1, b: c.c2 }));
42256
+ case "Oklch":
42257
+ return withAlpha(oklchToRgb({ L: c.c0, C: c.c1, H: c.c2 }));
42258
+ }
42259
+ return null;
42260
+ }
42261
+ function colorExprToOklch(arg) {
42262
+ const c = readColorExpr(arg);
42263
+ if (!c) return null;
42264
+ switch (c.space) {
42265
+ case "Oklch":
42266
+ return asOklch({ L: c.c0, C: c.c1, H: c.c2, alpha: c.alpha });
42267
+ case "Oklab":
42268
+ return asOklch({ L: c.c0, a: c.c1, b: c.c2, alpha: c.alpha });
42269
+ case "Rgb":
42270
+ return asOklch({
42271
+ r: c.c0 * 255,
42272
+ g: c.c1 * 255,
42273
+ b: c.c2 * 255,
42274
+ alpha: c.alpha
42275
+ });
42276
+ case "Hsv": {
42277
+ const rgb = hsvToRgb(c.c0, c.c1, c.c2);
42278
+ return asOklch({ ...rgb, alpha: c.alpha });
42279
+ }
42280
+ case "Hsl": {
42281
+ const rgb = hslToRgb(c.c0, c.c1, c.c2);
42282
+ return asOklch({ r: rgb.r, g: rgb.g, b: rgb.b, alpha: c.alpha });
42283
+ }
42284
+ }
42285
+ return null;
42286
+ }
42287
+ function toOklch(ce, arg) {
42288
+ const direct = colorExprToOklch(arg);
42289
+ if (direct) return direct;
42290
+ const rgb = extractRgb(ce, arg);
42291
+ return rgb ? asOklch(rgb) : null;
42292
+ }
42293
+ function lerpOklchColor(a, b, t) {
42294
+ const L = a.L + (b.L - a.L) * t;
42295
+ const C = a.C + (b.C - a.C) * t;
42296
+ const aAchromatic = a.C < 1e-6;
42297
+ const bAchromatic = b.C < 1e-6;
42298
+ let H;
42299
+ if (aAchromatic && bAchromatic) H = a.H;
42300
+ else if (aAchromatic) H = b.H;
42301
+ else if (bAchromatic) H = a.H;
42302
+ else {
42303
+ let dH = b.H - a.H;
42304
+ if (dH > 180) dH -= 360;
42305
+ if (dH < -180) dH += 360;
42306
+ H = a.H + dH * t;
42307
+ if (H < 0) H += 360;
42308
+ if (H >= 360) H -= 360;
42309
+ }
42310
+ const alphaA = a.alpha ?? 1;
42311
+ const alphaB = b.alpha ?? 1;
42312
+ return { L, C, H, alpha: normalizeAlpha(alphaA + (alphaB - alphaA) * t) };
42313
+ }
42314
+ function oklchToExpr(ce, c) {
42315
+ const args = [ce.number(c.L), ce.number(c.C), ce.number(c.H)];
42316
+ if (c.alpha !== void 0) args.push(ce.number(c.alpha));
42317
+ return ce.function("Oklch", args);
41994
42318
  }
41995
42319
  function extractRgb(ce, arg) {
41996
42320
  if (isString(arg)) {
41997
42321
  const s = arg.string;
41998
42322
  if (!s) return void 0;
41999
42323
  const color = parseColor(s);
42000
- return {
42324
+ const rgb = {
42001
42325
  r: color >>> 24 & 255,
42002
42326
  g: color >>> 16 & 255,
42003
- b: color >>> 8 & 255,
42004
- alpha: (color & 255) / 255
42327
+ b: color >>> 8 & 255
42005
42328
  };
42329
+ const alpha = normalizeAlpha((color & 255) / 255);
42330
+ if (alpha !== void 0) rgb.alpha = alpha;
42331
+ return rgb;
42006
42332
  }
42333
+ const fromTyped = colorExprToRgb(arg);
42334
+ if (fromTyped) return fromTyped;
42007
42335
  if (arg.operator === "Tuple" && arg.ops && arg.ops.length >= 3) {
42008
42336
  const rgb = {
42009
42337
  r: arg.ops[0].re * 255,
42010
42338
  g: arg.ops[1].re * 255,
42011
42339
  b: arg.ops[2].re * 255
42012
42340
  };
42013
- if (arg.ops.length >= 4) rgb.alpha = arg.ops[3].re;
42341
+ if (arg.ops.length >= 4) {
42342
+ const alpha = normalizeAlpha(arg.ops[3].re);
42343
+ if (alpha !== void 0) rgb.alpha = alpha;
42344
+ }
42014
42345
  return rgb;
42015
42346
  }
42016
42347
  return void 0;
42017
42348
  }
42018
42349
  function componentsTuple(ce, components, alpha) {
42019
42350
  const args = components.map((v) => ce.number(v));
42020
- if (alpha !== void 0 && Math.abs(alpha - 1) > 1e-4)
42021
- args.push(ce.number(alpha));
42351
+ if (alpha !== void 0) args.push(ce.number(alpha));
42022
42352
  return ce.tuple(...args);
42023
42353
  }
42024
42354
  function rgbToHex(rgb) {
@@ -42026,7 +42356,7 @@ ${e.message}
42026
42356
  const g = Math.round(Math.max(0, Math.min(255, rgb.g)));
42027
42357
  const b = Math.round(Math.max(0, Math.min(255, rgb.b)));
42028
42358
  const hex = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
42029
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4) {
42359
+ if (rgb.alpha !== void 0) {
42030
42360
  const a = Math.round(Math.max(0, Math.min(255, rgb.alpha * 255)));
42031
42361
  return hex + a.toString(16).padStart(2, "0");
42032
42362
  }
@@ -42034,22 +42364,29 @@ ${e.message}
42034
42364
  }
42035
42365
  var COLORS_LIBRARY = {
42036
42366
  Color: {
42037
- description: "Convert a color string to a canonical sRGB tuple",
42367
+ description: "Parse a CSS-style color string to an Oklch color",
42038
42368
  complexity: 8e3,
42039
- signature: "(string) -> tuple",
42369
+ signature: "(string) -> color",
42040
42370
  evaluate: (ops, { engine: ce }) => {
42041
42371
  const input = isString(ops[0]) ? ops[0].string : void 0;
42042
42372
  if (!input) return ce.error("incompatible-type");
42043
42373
  const color = parseColor(input);
42044
42374
  if (color === 0 && input.trim().toLowerCase() !== "transparent")
42045
42375
  return ce.error("incompatible-type");
42046
- return colorNumberToTuple(ce, color);
42376
+ const r = color >>> 24 & 255;
42377
+ const g = color >>> 16 & 255;
42378
+ const b = color >>> 8 & 255;
42379
+ const a = normalizeAlpha((color & 255) / 255);
42380
+ const c = rgbToOklch({ r, g, b });
42381
+ const args = [ce.number(c.L), ce.number(c.C), ce.number(c.H)];
42382
+ if (a !== void 0) args.push(ce.number(a));
42383
+ return ce.function("Oklch", args);
42047
42384
  }
42048
42385
  },
42049
42386
  ColorToString: {
42050
42387
  description: "Convert a color to a string in the specified format",
42051
42388
  complexity: 8e3,
42052
- signature: "(any, string?) -> string",
42389
+ signature: "(color | string | tuple, string?) -> string",
42053
42390
  evaluate: (ops, { engine: ce }) => {
42054
42391
  const rgb = extractRgb(ce, ops[0]);
42055
42392
  if (!rgb) return ce.error("incompatible-type");
@@ -42061,7 +42398,7 @@ ${e.message}
42061
42398
  const r = Math.round(rgb.r);
42062
42399
  const g = Math.round(rgb.g);
42063
42400
  const b = Math.round(rgb.b);
42064
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
42401
+ if (rgb.alpha !== void 0)
42065
42402
  return ce.string(`rgb(${r} ${g} ${b} / ${rgb.alpha})`);
42066
42403
  return ce.string(`rgb(${r} ${g} ${b})`);
42067
42404
  }
@@ -42070,17 +42407,17 @@ ${e.message}
42070
42407
  const h = Math.round(hsl.h * 10) / 10;
42071
42408
  const s = Math.round(hsl.s * 1e3) / 10;
42072
42409
  const l = Math.round(hsl.l * 1e3) / 10;
42073
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
42410
+ if (rgb.alpha !== void 0)
42074
42411
  return ce.string(`hsl(${h} ${s}% ${l}% / ${rgb.alpha})`);
42075
42412
  return ce.string(`hsl(${h} ${s}% ${l}%)`);
42076
42413
  }
42077
42414
  case "oklch": {
42078
- const c = rgbToOklch(rgb);
42415
+ const c = colorExprToOklch(ops[0]) ?? asOklch(rgb);
42079
42416
  const L = Math.round(c.L * 1e3) / 1e3;
42080
42417
  const C = Math.round(c.C * 1e3) / 1e3;
42081
42418
  const H = Math.round(c.H * 10) / 10;
42082
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
42083
- return ce.string(`oklch(${L} ${C} ${H} / ${rgb.alpha})`);
42419
+ if (c.alpha !== void 0)
42420
+ return ce.string(`oklch(${L} ${C} ${H} / ${c.alpha})`);
42084
42421
  return ce.string(`oklch(${L} ${C} ${H})`);
42085
42422
  }
42086
42423
  default:
@@ -42091,60 +42428,44 @@ ${e.message}
42091
42428
  ColorMix: {
42092
42429
  description: "Mix two colors in OKLCh space",
42093
42430
  complexity: 8e3,
42094
- signature: "(any, any, number?) -> tuple",
42431
+ signature: "(color | string | tuple, color | string | tuple, number?) -> color",
42095
42432
  evaluate: (ops, { engine: ce }) => {
42096
- const rgb1 = extractRgb(ce, ops[0]);
42097
- const rgb2 = extractRgb(ce, ops[1]);
42098
- if (!rgb1 || !rgb2) return ce.error("incompatible-type");
42099
42433
  let ratio = 0.5;
42100
42434
  if (ops.length >= 3 && ops[2] !== void 0) {
42101
42435
  ratio = ops[2].re;
42102
42436
  if (!Number.isFinite(ratio)) return ce.error("expected-value");
42103
42437
  ratio = Math.max(0, Math.min(1, ratio));
42104
42438
  }
42105
- const c1 = rgbToOklch(rgb1);
42106
- const c2 = rgbToOklch(rgb2);
42107
- const mixed = oklchToRgb(lerpOklch(c1, c2, ratio));
42108
- const r = mixed.r / 255;
42109
- const g = mixed.g / 255;
42110
- const b = mixed.b / 255;
42111
- const a1 = rgb1.alpha ?? 1;
42112
- const a2 = rgb2.alpha ?? 1;
42113
- const alpha = a1 + (a2 - a1) * ratio;
42114
- if (Math.abs(alpha - 1) > 1e-4)
42115
- return ce.tuple(
42116
- ce.number(r),
42117
- ce.number(g),
42118
- ce.number(b),
42119
- ce.number(alpha)
42120
- );
42121
- return ce.tuple(ce.number(r), ce.number(g), ce.number(b));
42439
+ const oklch1 = toOklch(ce, ops[0]);
42440
+ const oklch2 = toOklch(ce, ops[1]);
42441
+ if (!oklch1 || !oklch2) return ce.error("incompatible-type");
42442
+ return oklchToExpr(ce, lerpOklchColor(oklch1, oklch2, ratio));
42122
42443
  }
42123
42444
  },
42124
42445
  Colormap: {
42125
42446
  description: "Sample colors from a named palette",
42126
42447
  complexity: 8e3,
42127
- signature: "(string, number?) -> any",
42448
+ signature: "(string, number?) -> color | list<color>",
42128
42449
  evaluate: (ops, { engine: ce }) => {
42129
42450
  const name = isString(ops[0]) ? ops[0].string : void 0;
42130
42451
  if (!name) return ce.error("incompatible-type");
42131
42452
  const palette = ALL_PALETTES[name];
42132
42453
  if (!palette) return ce.error("expected-value", name);
42133
42454
  if (ops.length < 2 || ops[1] === void 0) {
42134
- const tuples = palette.map(
42135
- (hex) => colorNumberToTuple(ce, parseColor(hex))
42455
+ const colors = palette.map(
42456
+ (hex) => colorNumberToOklch(ce, parseColor(hex))
42136
42457
  );
42137
- return ce.function("List", tuples);
42458
+ return ce.function("List", colors);
42138
42459
  }
42139
42460
  const val = ops[1].re;
42140
42461
  if (!Number.isFinite(val)) return ce.error("expected-value");
42141
42462
  if (Number.isInteger(val) && val >= 2) {
42142
42463
  const n = val;
42143
- const tuples = [];
42464
+ const colors = [];
42144
42465
  for (let i = 0; i < n; i++) {
42145
- tuples.push(samplePalette(ce, palette, i / (n - 1)));
42466
+ colors.push(samplePalette(ce, palette, i / (n - 1)));
42146
42467
  }
42147
- return ce.function("List", tuples);
42468
+ return ce.function("List", colors);
42148
42469
  }
42149
42470
  return samplePalette(ce, palette, val);
42150
42471
  }
@@ -42152,12 +42473,25 @@ ${e.message}
42152
42473
  ColorToColorspace: {
42153
42474
  description: "Convert a color to components in a target color space",
42154
42475
  complexity: 8e3,
42155
- signature: "(any, string) -> tuple",
42476
+ signature: "(color | string | tuple, string) -> tuple",
42156
42477
  evaluate: (ops, { engine: ce }) => {
42157
- const rgb = extractRgb(ce, ops[0]);
42158
- if (!rgb) return ce.error("incompatible-type");
42159
42478
  const space = isString(ops[1]) ? ops[1].string?.toLowerCase() : void 0;
42160
42479
  if (!space) return ce.error("incompatible-type");
42480
+ if (space === "oklch" || space === "oklab" || space === "lab") {
42481
+ const oklch2 = colorExprToOklch(ops[0]);
42482
+ if (oklch2) {
42483
+ if (space === "oklch")
42484
+ return componentsTuple(
42485
+ ce,
42486
+ [oklch2.L, oklch2.C, oklch2.H],
42487
+ oklch2.alpha
42488
+ );
42489
+ const lab = oklchToOklab(oklch2);
42490
+ return componentsTuple(ce, [lab.L, lab.a, lab.b], lab.alpha);
42491
+ }
42492
+ }
42493
+ const rgb = extractRgb(ce, ops[0]);
42494
+ if (!rgb) return ce.error("incompatible-type");
42161
42495
  const alpha = rgb.alpha;
42162
42496
  switch (space) {
42163
42497
  case "rgb":
@@ -42187,17 +42521,27 @@ ${e.message}
42187
42521
  ColorFromColorspace: {
42188
42522
  description: "Convert color space components to a canonical sRGB tuple",
42189
42523
  complexity: 8e3,
42190
- signature: "(tuple, string) -> tuple",
42524
+ signature: "(color | tuple, string) -> tuple",
42191
42525
  evaluate: (ops, { engine: ce }) => {
42192
- const tuple = ops[0];
42193
- if (!isFunction2(tuple) || tuple.operator !== "Tuple" || tuple.ops.length < 3)
42194
- return ce.error("incompatible-type");
42195
- const c0 = tuple.ops[0].re;
42196
- const c1 = tuple.ops[1].re;
42197
- const c2 = tuple.ops[2].re;
42198
- const alpha = tuple.ops.length >= 4 ? tuple.ops[3].re : void 0;
42199
42526
  const space = isString(ops[1]) ? ops[1].string?.toLowerCase() : void 0;
42200
42527
  if (!space) return ce.error("incompatible-type");
42528
+ let c0, c1, c2;
42529
+ let alpha;
42530
+ const arg = ops[0];
42531
+ const typed = readColorExpr(arg);
42532
+ if (typed) {
42533
+ c0 = typed.c0;
42534
+ c1 = typed.c1;
42535
+ c2 = typed.c2;
42536
+ alpha = typed.alpha;
42537
+ } else if (isFunction2(arg) && arg.operator === "Tuple" && arg.ops.length >= 3) {
42538
+ c0 = arg.ops[0].re;
42539
+ c1 = arg.ops[1].re;
42540
+ c2 = arg.ops[2].re;
42541
+ alpha = arg.ops.length >= 4 ? arg.ops[3].re : void 0;
42542
+ } else {
42543
+ return ce.error("incompatible-type");
42544
+ }
42201
42545
  let rgb;
42202
42546
  switch (space) {
42203
42547
  case "rgb":
@@ -42233,7 +42577,7 @@ ${e.message}
42233
42577
  ColorContrast: {
42234
42578
  description: "APCA contrast ratio between two colors",
42235
42579
  complexity: 8e3,
42236
- signature: "(any, any) -> number",
42580
+ signature: "(color | string | tuple, color | string | tuple) -> number",
42237
42581
  evaluate: (ops, { engine: ce }) => {
42238
42582
  const bgRgb = extractRgb(ce, ops[0]);
42239
42583
  const fgRgb = extractRgb(ce, ops[1]);
@@ -42244,19 +42588,186 @@ ${e.message}
42244
42588
  ContrastingColor: {
42245
42589
  description: "Choose the foreground color with better APCA contrast against a background",
42246
42590
  complexity: 8e3,
42247
- signature: "(any, any?, any?) -> tuple",
42591
+ signature: "(color | string | tuple, (color | string | tuple)?, (color | string | tuple)?) -> color",
42248
42592
  evaluate: (ops, { engine: ce }) => {
42249
42593
  const bgRgb = extractRgb(ce, ops[0]);
42250
42594
  if (!bgRgb) return ce.error("incompatible-type");
42595
+ let packed;
42251
42596
  if (ops.length >= 3 && ops[1] !== void 0 && ops[2] !== void 0) {
42252
42597
  const fg1 = extractRgb(ce, ops[1]);
42253
42598
  const fg2 = extractRgb(ce, ops[2]);
42254
42599
  if (!fg1 || !fg2) return ce.error("incompatible-type");
42255
- const result2 = contrastingColor({ bg: bgRgb, fg1, fg2 });
42256
- return colorNumberToTuple(ce, result2);
42600
+ packed = contrastingColor({ bg: bgRgb, fg1, fg2 });
42601
+ } else {
42602
+ packed = contrastingColor(bgRgb);
42603
+ }
42604
+ const r = (packed >>> 24 & 255) / 255;
42605
+ const g = (packed >>> 16 & 255) / 255;
42606
+ const b = (packed >>> 8 & 255) / 255;
42607
+ const alpha = normalizeAlpha((packed & 255) / 255);
42608
+ const args = [ce.number(r), ce.number(g), ce.number(b)];
42609
+ if (alpha !== void 0) args.push(ce.number(alpha));
42610
+ return ce.function("Rgb", args);
42611
+ }
42612
+ },
42613
+ // ---------------------------------------------------------------------------
42614
+ // Color constructors. Each preserves its colorspace on evaluation; the
42615
+ // operator name is the discriminator. Components are interpreted per
42616
+ // colorspace conventions (Rgb channels 0-1, Hsv/Hsl hue in degrees with
42617
+ // sat/value 0-1, Oklab/Oklch L 0-1 with standard a/b/C/H ranges). The
42618
+ // optional 4th argument is alpha in [0, 1]. No clamping at evaluation time.
42619
+ // ---------------------------------------------------------------------------
42620
+ Rgb: {
42621
+ description: "sRGB color (channels 0-1, optional alpha 0-1)",
42622
+ complexity: 8e3,
42623
+ signature: "(number, number, number, number?) -> color"
42624
+ },
42625
+ Hsv: {
42626
+ description: "HSV color (hue degrees, saturation/value 0-1, optional alpha)",
42627
+ complexity: 8e3,
42628
+ signature: "(number, number, number, number?) -> color"
42629
+ },
42630
+ Hsl: {
42631
+ description: "HSL color (hue degrees, saturation/lightness 0-1, optional alpha)",
42632
+ complexity: 8e3,
42633
+ signature: "(number, number, number, number?) -> color"
42634
+ },
42635
+ Oklab: {
42636
+ description: "OKLab color (L 0-1, a/b ~ -0.4..0.4, optional alpha)",
42637
+ complexity: 8e3,
42638
+ signature: "(number, number, number, number?) -> color"
42639
+ },
42640
+ Oklch: {
42641
+ description: "OKLCh color (L 0-1, C 0-~0.4, hue degrees, optional alpha)",
42642
+ complexity: 8e3,
42643
+ signature: "(number, number, number, number?) -> color"
42644
+ },
42645
+ // ---------------------------------------------------------------------------
42646
+ // Color-space conversions. Each accepts any of the five color heads and
42647
+ // returns the same color in the named space. If the input is already in
42648
+ // the target space, returns the input unchanged.
42649
+ // ---------------------------------------------------------------------------
42650
+ AsRgb: {
42651
+ description: "Convert any color to sRGB (channels 0-1)",
42652
+ complexity: 8e3,
42653
+ signature: "(color) -> color",
42654
+ evaluate: (ops, { engine: ce }) => {
42655
+ const arg = ops[0];
42656
+ if (isFunction2(arg) && arg.operator === "Rgb")
42657
+ return normalizeColorHead(ce, arg);
42658
+ const rgb = colorExprToRgb(arg);
42659
+ if (!rgb) return ce.error("incompatible-type");
42660
+ const args = [
42661
+ ce.number(rgb.r / 255),
42662
+ ce.number(rgb.g / 255),
42663
+ ce.number(rgb.b / 255)
42664
+ ];
42665
+ if (rgb.alpha !== void 0) args.push(ce.number(rgb.alpha));
42666
+ return ce.function("Rgb", args);
42667
+ }
42668
+ },
42669
+ AsHsv: {
42670
+ description: "Convert any color to HSV (hue degrees, s/v 0-1)",
42671
+ complexity: 8e3,
42672
+ signature: "(color) -> color",
42673
+ evaluate: (ops, { engine: ce }) => {
42674
+ const arg = ops[0];
42675
+ if (isFunction2(arg) && arg.operator === "Hsv")
42676
+ return normalizeColorHead(ce, arg);
42677
+ const rgb = colorExprToRgb(arg);
42678
+ if (!rgb) return ce.error("incompatible-type");
42679
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
42680
+ const args = [ce.number(hsv.h), ce.number(hsv.s), ce.number(hsv.v)];
42681
+ if (rgb.alpha !== void 0) args.push(ce.number(rgb.alpha));
42682
+ return ce.function("Hsv", args);
42683
+ }
42684
+ },
42685
+ AsHsl: {
42686
+ description: "Convert any color to HSL (hue degrees, s/l 0-1)",
42687
+ complexity: 8e3,
42688
+ signature: "(color) -> color",
42689
+ evaluate: (ops, { engine: ce }) => {
42690
+ const arg = ops[0];
42691
+ if (isFunction2(arg) && arg.operator === "Hsl")
42692
+ return normalizeColorHead(ce, arg);
42693
+ const rgb = colorExprToRgb(arg);
42694
+ if (!rgb) return ce.error("incompatible-type");
42695
+ const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
42696
+ const args = [ce.number(hsl.h), ce.number(hsl.s), ce.number(hsl.l)];
42697
+ if (rgb.alpha !== void 0) args.push(ce.number(rgb.alpha));
42698
+ return ce.function("Hsl", args);
42699
+ }
42700
+ },
42701
+ AsOklab: {
42702
+ description: "Convert any color to OKLab",
42703
+ complexity: 8e3,
42704
+ signature: "(color) -> color",
42705
+ evaluate: (ops, { engine: ce }) => {
42706
+ const arg = ops[0];
42707
+ if (isFunction2(arg) && arg.operator === "Oklab")
42708
+ return normalizeColorHead(ce, arg);
42709
+ if (isFunction2(arg) && arg.operator === "Oklch") {
42710
+ const c = readColorExpr(arg);
42711
+ if (!c) return ce.error("incompatible-type");
42712
+ const lab2 = oklchToOklab({ L: c.c0, C: c.c1, H: c.c2, alpha: c.alpha });
42713
+ const args2 = [ce.number(lab2.L), ce.number(lab2.a), ce.number(lab2.b)];
42714
+ if (lab2.alpha !== void 0) args2.push(ce.number(lab2.alpha));
42715
+ return ce.function("Oklab", args2);
42716
+ }
42717
+ const rgb = colorExprToRgb(arg);
42718
+ if (!rgb) return ce.error("incompatible-type");
42719
+ const lab = rgbToOklab(rgb);
42720
+ const args = [ce.number(lab.L), ce.number(lab.a), ce.number(lab.b)];
42721
+ if (rgb.alpha !== void 0) args.push(ce.number(rgb.alpha));
42722
+ return ce.function("Oklab", args);
42723
+ }
42724
+ },
42725
+ AsOklch: {
42726
+ description: "Convert any color to OKLCh",
42727
+ complexity: 8e3,
42728
+ signature: "(color) -> color",
42729
+ evaluate: (ops, { engine: ce }) => {
42730
+ const arg = ops[0];
42731
+ if (isFunction2(arg) && arg.operator === "Oklch")
42732
+ return normalizeColorHead(ce, arg);
42733
+ if (isFunction2(arg) && arg.operator === "Oklab") {
42734
+ const c2 = readColorExpr(arg);
42735
+ if (!c2) return ce.error("incompatible-type");
42736
+ const oklch2 = oklabToOklch({
42737
+ L: c2.c0,
42738
+ a: c2.c1,
42739
+ b: c2.c2,
42740
+ alpha: c2.alpha
42741
+ });
42742
+ const args2 = [
42743
+ ce.number(oklch2.L),
42744
+ ce.number(oklch2.C),
42745
+ ce.number(oklch2.H)
42746
+ ];
42747
+ if (oklch2.alpha !== void 0) args2.push(ce.number(oklch2.alpha));
42748
+ return ce.function("Oklch", args2);
42257
42749
  }
42258
- const result = contrastingColor(bgRgb);
42259
- return colorNumberToTuple(ce, result);
42750
+ const rgb = colorExprToRgb(arg);
42751
+ if (!rgb) return ce.error("incompatible-type");
42752
+ const c = rgbToOklch(rgb);
42753
+ const args = [ce.number(c.L), ce.number(c.C), ce.number(c.H)];
42754
+ if (rgb.alpha !== void 0) args.push(ce.number(rgb.alpha));
42755
+ return ce.function("Oklch", args);
42756
+ }
42757
+ },
42758
+ // ---------------------------------------------------------------------------
42759
+ // Perceptual difference. Returns ΔE_OK (Euclidean distance in OKLab),
42760
+ // an approximately perceptually uniform scalar.
42761
+ // ---------------------------------------------------------------------------
42762
+ ColorDelta: {
42763
+ description: "Perceptual color difference (\u0394E_OK) between two colors",
42764
+ complexity: 8e3,
42765
+ signature: "(color | string | tuple, color | string | tuple) -> number",
42766
+ evaluate: (ops, { engine: ce }) => {
42767
+ const a = toOklch(ce, ops[0]);
42768
+ const b = toOklch(ce, ops[1]);
42769
+ if (!a || !b) return ce.error("incompatible-type");
42770
+ return ce.number(oklabDeltaE(oklchToOklab(a), oklchToOklab(b)));
42260
42771
  }
42261
42772
  }
42262
42773
  };
@@ -44736,6 +45247,34 @@ ${e.message}
44736
45247
  signature: "() -> expression",
44737
45248
  evaluate: (_ops, { engine }) => engine.expr(randomExpression())
44738
45249
  }
45250
+ },
45251
+ // ---------------------------------------------------------------------------
45252
+ // Opaque typed heads — registered so the names are in the standard set
45253
+ // (consumers can branch on the operator name); CE itself does not evaluate
45254
+ // them. Geometric primitives `Triangle`/`Sphere`/`Segment` and the action
45255
+ // arrow `To` (`a \to b`).
45256
+ // ---------------------------------------------------------------------------
45257
+ {
45258
+ Triangle: {
45259
+ description: "Triangle primitive \u2014 opaque typed head.",
45260
+ signature: "(any+) -> expression"
45261
+ },
45262
+ GeometricVector: {
45263
+ description: "Geometric vector (directed segment between two points) \u2014 opaque typed head. Distinct from the column-vector `Vector` operator.",
45264
+ signature: "(any, any) -> expression"
45265
+ },
45266
+ Sphere: {
45267
+ description: "Sphere primitive \u2014 opaque typed head.",
45268
+ signature: "(any+) -> expression"
45269
+ },
45270
+ Segment: {
45271
+ description: "Segment primitive \u2014 opaque typed head.",
45272
+ signature: "(any+) -> expression"
45273
+ },
45274
+ To: {
45275
+ description: "Action arrow / mapping (`a \\to b`) \u2014 opaque typed head.",
45276
+ signature: "(any, any) -> nothing"
45277
+ }
44739
45278
  }
44740
45279
  ];
44741
45280
 
@@ -51872,6 +52411,7 @@ Error in definition of "${name}"`,
51872
52411
 
51873
52412
  // src/compute-engine/boxed-expression/cache.ts
51874
52413
  function cachedValue(v, generation, fn) {
52414
+ if (v.generation === generation && v.value !== null) return v.value;
51875
52415
  v.generation = generation;
51876
52416
  v.value = fn();
51877
52417
  return v.value;
@@ -53649,6 +54189,12 @@ Error in definition of "${name}"`,
53649
54189
  function _escapeJsonString(s) {
53650
54190
  return s;
53651
54191
  }
54192
+ function _serializeLatexMetadata(ce, expr2) {
54193
+ const syntax = ce.latexSyntax;
54194
+ const opts = ce.latexOptions;
54195
+ if (Object.keys(opts).length === 0) return syntax.serialize(expr2);
54196
+ return syntax.serialize(expr2, { ...opts });
54197
+ }
53652
54198
  function serializeSubtract(ce, a, b, options, metadata) {
53653
54199
  if (isNumber(a) && a.isNegative) {
53654
54200
  const v = a.numericValue;
@@ -53953,7 +54499,7 @@ Error in definition of "${name}"`,
53953
54499
  ];
53954
54500
  const md = { ...metadata ?? {} };
53955
54501
  if (options.metadata.includes("latex") && ce.latexSyntax) {
53956
- md.latex = _escapeJsonString(md.latex ?? ce.latexSyntax.serialize(fn));
54502
+ md.latex = _escapeJsonString(md.latex ?? _serializeLatexMetadata(ce, fn));
53957
54503
  } else md.latex = "";
53958
54504
  if (!options.metadata.includes("wikidata")) md.wikidata = "";
53959
54505
  if (!md.latex && !md.wikidata && options.shorthands.includes("function"))
@@ -53978,7 +54524,7 @@ Error in definition of "${name}"`,
53978
54524
  }
53979
54525
  metadata = { ...metadata };
53980
54526
  if (options.metadata.includes("latex") && ce.latexSyntax) {
53981
- metadata.latex = metadata.latex ?? ce.latexSyntax.serialize(sym2);
54527
+ metadata.latex = metadata.latex ?? _serializeLatexMetadata(ce, sym2);
53982
54528
  if (metadata.latex !== void 0)
53983
54529
  metadata.latex = _escapeJsonString(metadata.latex);
53984
54530
  } else metadata.latex = void 0;
@@ -54140,7 +54686,7 @@ Error in definition of "${name}"`,
54140
54686
  }
54141
54687
  }
54142
54688
  if (options.metadata.includes("latex") && ce.latexSyntax)
54143
- metadata.latex = metadata.latex ?? ce.latexSyntax.serialize(result2 ?? { num });
54689
+ metadata.latex = metadata.latex ?? _serializeLatexMetadata(ce, result2 ?? { num });
54144
54690
  if (result2) {
54145
54691
  if (metadata.latex !== void 0)
54146
54692
  return { sym: result2, latex: metadata.latex };
@@ -54156,7 +54702,7 @@ Error in definition of "${name}"`,
54156
54702
  if (value.isNaN()) {
54157
54703
  num = "NaN";
54158
54704
  if (options.metadata.includes("latex") && ce.latexSyntax)
54159
- metadata.latex = metadata.latex ?? ce.latexSyntax.serialize({ num });
54705
+ metadata.latex = metadata.latex ?? _serializeLatexMetadata(ce, { num });
54160
54706
  return metadata.latex !== void 0 ? { num, latex: metadata.latex } : { num };
54161
54707
  }
54162
54708
  return serializeJsonFunction(
@@ -54190,7 +54736,7 @@ Error in definition of "${name}"`,
54190
54736
  value = Number(value);
54191
54737
  } else {
54192
54738
  if (options.metadata.includes("latex") && ce.latexSyntax)
54193
- metadata.latex = metadata.latex ?? ce.latexSyntax.serialize({
54739
+ metadata.latex = metadata.latex ?? _serializeLatexMetadata(ce, {
54194
54740
  num: value.toString()
54195
54741
  });
54196
54742
  if (metadata.latex !== void 0)
@@ -54204,7 +54750,7 @@ Error in definition of "${name}"`,
54204
54750
  result = value > 0 ? "PositiveInfinity" : "NegativeInfinity";
54205
54751
  else num = serializeRepeatingDecimals(value.toString(), options);
54206
54752
  if (options.metadata.includes("latex") && ce.latexSyntax)
54207
- metadata.latex = metadata.latex ?? ce.latexSyntax.serialize({ num });
54753
+ metadata.latex = metadata.latex ?? _serializeLatexMetadata(ce, { num });
54208
54754
  if (result) {
54209
54755
  if (metadata.latex !== void 0)
54210
54756
  return { sym: result, latex: metadata.latex };
@@ -54969,8 +55515,7 @@ Error in definition of "${name}"`,
54969
55515
  ce.pushScope();
54970
55516
  try {
54971
55517
  if (vars && typeof vars === "object") {
54972
- for (const [k, v] of Object.entries(vars))
54973
- ce.assign(k, v);
55518
+ for (const [k, v] of Object.entries(vars)) ce.assign(k, v);
54974
55519
  }
54975
55520
  return expr2.evaluate().re;
54976
55521
  } finally {
@@ -60200,8 +60745,7 @@ Error in definition of "${name}"`,
60200
60745
  return { re: null, im: formatFloat(iScale) };
60201
60746
  }
60202
60747
  const compiledFactors = remaining.map((r) => compile3(r));
60203
- if (iScale !== 1)
60204
- compiledFactors.unshift(formatFloat(iScale));
60748
+ if (iScale !== 1) compiledFactors.unshift(formatFloat(iScale));
60205
60749
  const imCode = foldTerms(compiledFactors, "1.0", "*");
60206
60750
  return { re: null, im: imCode };
60207
60751
  }
@@ -60805,39 +61349,130 @@ Error in definition of "${name}"`,
60805
61349
  if (args.length >= 2)
60806
61350
  return `_SYS.colormap(${compile3(args[0])}, ${compile3(args[1])})`;
60807
61351
  return `_SYS.colormap(${compile3(args[0])})`;
61352
+ },
61353
+ // -----------------------------------------------------------------------
61354
+ // Color constructor heads. All compile to OKLCh arrays at runtime — the
61355
+ // canonical color representation in this target. The constructors take
61356
+ // their own colorspace's components and convert internally.
61357
+ // (Mirrors the GPU target's design: color values are vec3 OKLCh.)
61358
+ // -----------------------------------------------------------------------
61359
+ Rgb: (args, compile3) => {
61360
+ if (args.length < 3) throw new Error("Rgb: need 3 components");
61361
+ return `_SYS.rgb(${args.map(compile3).join(", ")})`;
61362
+ },
61363
+ Hsv: (args, compile3) => {
61364
+ if (args.length < 3) throw new Error("Hsv: need 3 components");
61365
+ return `_SYS.hsv(${args.map(compile3).join(", ")})`;
61366
+ },
61367
+ Hsl: (args, compile3) => {
61368
+ if (args.length < 3) throw new Error("Hsl: need 3 components");
61369
+ return `_SYS.hsl(${args.map(compile3).join(", ")})`;
61370
+ },
61371
+ Oklab: (args, compile3) => {
61372
+ if (args.length < 3) throw new Error("Oklab: need 3 components");
61373
+ return `_SYS.oklab(${args.map(compile3).join(", ")})`;
61374
+ },
61375
+ Oklch: (args, compile3) => {
61376
+ if (args.length < 3) throw new Error("Oklch: need 3 components");
61377
+ return `_SYS.oklch(${args.map(compile3).join(", ")})`;
61378
+ },
61379
+ // -----------------------------------------------------------------------
61380
+ // As* converters. Compile-time output convention matches the engine and
61381
+ // the GPU target: each returns components in the named space as a 3- or
61382
+ // 4-element array. `AsRgb` uses 0-1 sRGB channels (consistent across all
61383
+ // layers). `AsOklch` is the identity (canonical form).
61384
+ // -----------------------------------------------------------------------
61385
+ AsRgb: ([c], compile3) => {
61386
+ if (c === null) throw new Error("AsRgb: no argument");
61387
+ return `_SYS.asRgb(${compile3(c)})`;
61388
+ },
61389
+ AsHsv: ([c], compile3) => {
61390
+ if (c === null) throw new Error("AsHsv: no argument");
61391
+ return `_SYS.asHsv(${compile3(c)})`;
61392
+ },
61393
+ AsHsl: ([c], compile3) => {
61394
+ if (c === null) throw new Error("AsHsl: no argument");
61395
+ return `_SYS.asHsl(${compile3(c)})`;
61396
+ },
61397
+ AsOklab: ([c], compile3) => {
61398
+ if (c === null) throw new Error("AsOklab: no argument");
61399
+ return `_SYS.asOklab(${compile3(c)})`;
61400
+ },
61401
+ AsOklch: ([c], compile3) => {
61402
+ if (c === null) throw new Error("AsOklch: no argument");
61403
+ return compile3(c);
61404
+ },
61405
+ // Perceptual color difference (ΔE_OK).
61406
+ ColorDelta: ([a, b], compile3) => {
61407
+ if (a === null || b === null)
61408
+ throw new Error("ColorDelta: need two colors");
61409
+ return `_SYS.colorDelta(${compile3(a)}, ${compile3(b)})`;
61410
+ },
61411
+ // Euclidean distance between two tuples (any positive dimension).
61412
+ // The GPU target maps `Distance` to the GLSL/WGSL `distance()` builtin
61413
+ // (vec-only); this JS handler works on plain arrays of any length.
61414
+ Distance: ([a, b], compile3) => {
61415
+ if (a === null || b === null) throw new Error("Distance: need two points");
61416
+ return `_SYS.distance(${compile3(a)}, ${compile3(b)})`;
60808
61417
  }
60809
61418
  };
60810
61419
  function toRI(c) {
60811
61420
  return { re: c.re, im: c.im };
60812
61421
  }
61422
+ function normalizeAlpha2(a) {
61423
+ if (a === void 0) return void 0;
61424
+ if (!Number.isFinite(a)) return void 0;
61425
+ if (Math.abs(a - 1) < 1e-9) return void 0;
61426
+ return a;
61427
+ }
60813
61428
  function toRgb255(input) {
60814
61429
  if (typeof input === "string") {
60815
61430
  const c = parseColor(input);
60816
- return {
61431
+ const rgb2 = {
60817
61432
  r: c >>> 24 & 255,
60818
61433
  g: c >>> 16 & 255,
60819
- b: c >>> 8 & 255,
60820
- alpha: (c & 255) / 255
61434
+ b: c >>> 8 & 255
60821
61435
  };
61436
+ const alpha = normalizeAlpha2((c & 255) / 255);
61437
+ if (alpha !== void 0) rgb2.alpha = alpha;
61438
+ return rgb2;
61439
+ }
61440
+ const rgb = oklchToRgb({ L: input[0], C: input[1], H: input[2] });
61441
+ if (input.length >= 4) {
61442
+ const alpha = normalizeAlpha2(input[3]);
61443
+ if (alpha !== void 0) rgb.alpha = alpha;
60822
61444
  }
60823
- const rgb = {
60824
- r: input[0] * 255,
60825
- g: input[1] * 255,
60826
- b: input[2] * 255
60827
- };
60828
- if (input.length >= 4) rgb.alpha = input[3];
60829
61445
  return rgb;
60830
61446
  }
60831
- function packedToArray(c) {
60832
- const r = (c >>> 24 & 255) / 255;
60833
- const g = (c >>> 16 & 255) / 255;
60834
- const b = (c >>> 8 & 255) / 255;
60835
- const a = (c & 255) / 255;
60836
- return Math.abs(a - 1) < 1e-4 ? [r, g, b] : [r, g, b, a];
61447
+ function toOklch2(input) {
61448
+ if (typeof input === "string") {
61449
+ const c = parseColor(input);
61450
+ const r = c >>> 24 & 255;
61451
+ const g = c >>> 16 & 255;
61452
+ const b = c >>> 8 & 255;
61453
+ const oklch2 = rgbToOklch({ r, g, b });
61454
+ const alpha = normalizeAlpha2((c & 255) / 255);
61455
+ if (alpha !== void 0) oklch2.alpha = alpha;
61456
+ return oklch2;
61457
+ }
61458
+ return {
61459
+ L: input[0],
61460
+ C: input[1],
61461
+ H: input[2],
61462
+ alpha: input.length >= 4 ? normalizeAlpha2(input[3]) : void 0
61463
+ };
61464
+ }
61465
+ function packedToOklch(c) {
61466
+ const r = c >>> 24 & 255;
61467
+ const g = c >>> 16 & 255;
61468
+ const b = c >>> 8 & 255;
61469
+ const oklch2 = rgbToOklch({ r, g, b });
61470
+ const alpha = normalizeAlpha2((c & 255) / 255);
61471
+ return alpha !== void 0 ? [oklch2.L, oklch2.C, oklch2.H, alpha] : [oklch2.L, oklch2.C, oklch2.H];
60837
61472
  }
60838
61473
  var colorHelpers = {
60839
61474
  color(input) {
60840
- return packedToArray(parseColor(input));
61475
+ return packedToOklch(parseColor(input));
60841
61476
  },
60842
61477
  colorToString(input, format) {
60843
61478
  const rgb = toRgb255(input);
@@ -60848,7 +61483,7 @@ Error in definition of "${name}"`,
60848
61483
  const g = Math.round(Math.max(0, Math.min(255, rgb.g)));
60849
61484
  const b = Math.round(Math.max(0, Math.min(255, rgb.b)));
60850
61485
  let hex = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
60851
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4) {
61486
+ if (rgb.alpha !== void 0) {
60852
61487
  const a = Math.round(Math.max(0, Math.min(255, rgb.alpha * 255)));
60853
61488
  hex += a.toString(16).padStart(2, "0");
60854
61489
  }
@@ -60858,7 +61493,7 @@ Error in definition of "${name}"`,
60858
61493
  const r = Math.round(rgb.r);
60859
61494
  const g = Math.round(rgb.g);
60860
61495
  const b = Math.round(rgb.b);
60861
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
61496
+ if (rgb.alpha !== void 0)
60862
61497
  return `rgb(${r} ${g} ${b} / ${rgb.alpha})`;
60863
61498
  return `rgb(${r} ${g} ${b})`;
60864
61499
  }
@@ -60867,7 +61502,7 @@ Error in definition of "${name}"`,
60867
61502
  const h = Math.round(hsl.h * 10) / 10;
60868
61503
  const s = Math.round(hsl.s * 1e3) / 10;
60869
61504
  const l = Math.round(hsl.l * 1e3) / 10;
60870
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
61505
+ if (rgb.alpha !== void 0)
60871
61506
  return `hsl(${h} ${s}% ${l}% / ${rgb.alpha})`;
60872
61507
  return `hsl(${h} ${s}% ${l}%)`;
60873
61508
  }
@@ -60876,7 +61511,7 @@ Error in definition of "${name}"`,
60876
61511
  const L = Math.round(c.L * 1e3) / 1e3;
60877
61512
  const C = Math.round(c.C * 1e3) / 1e3;
60878
61513
  const H = Math.round(c.H * 10) / 10;
60879
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
61514
+ if (rgb.alpha !== void 0)
60880
61515
  return `oklch(${L} ${C} ${H} / ${rgb.alpha})`;
60881
61516
  return `oklch(${L} ${C} ${H})`;
60882
61517
  }
@@ -60885,29 +61520,29 @@ Error in definition of "${name}"`,
60885
61520
  }
60886
61521
  },
60887
61522
  colorMix(input1, input2, ratio = 0.5) {
60888
- const rgb1 = toRgb255(input1);
60889
- const rgb2 = toRgb255(input2);
61523
+ const c1 = toOklch2(input1);
61524
+ const c2 = toOklch2(input2);
60890
61525
  ratio = Math.max(0, Math.min(1, ratio));
60891
- const c1 = rgbToOklch(rgb1);
60892
- const c2 = rgbToOklch(rgb2);
60893
- let dh = c2.H - c1.H;
60894
- if (dh > 180) dh -= 360;
60895
- if (dh < -180) dh += 360;
60896
- let H = c1.H + dh * ratio;
60897
- if (H < 0) H += 360;
60898
- if (H >= 360) H -= 360;
60899
- const mixed = oklchToRgb({
60900
- L: c1.L + (c2.L - c1.L) * ratio,
60901
- C: c1.C + (c2.C - c1.C) * ratio,
60902
- H
60903
- });
60904
- const r = mixed.r / 255;
60905
- const g = mixed.g / 255;
60906
- const b = mixed.b / 255;
60907
- const a1 = rgb1.alpha ?? 1;
60908
- const a2 = rgb2.alpha ?? 1;
60909
- const alpha = a1 + (a2 - a1) * ratio;
60910
- return Math.abs(alpha - 1) > 1e-4 ? [r, g, b, alpha] : [r, g, b];
61526
+ const c1Achromatic = c1.C < 1e-6;
61527
+ const c2Achromatic = c2.C < 1e-6;
61528
+ let H;
61529
+ if (c1Achromatic && c2Achromatic) H = c1.H;
61530
+ else if (c1Achromatic) H = c2.H;
61531
+ else if (c2Achromatic) H = c1.H;
61532
+ else {
61533
+ let dh = c2.H - c1.H;
61534
+ if (dh > 180) dh -= 360;
61535
+ if (dh < -180) dh += 360;
61536
+ H = c1.H + dh * ratio;
61537
+ if (H < 0) H += 360;
61538
+ if (H >= 360) H -= 360;
61539
+ }
61540
+ const L = c1.L + (c2.L - c1.L) * ratio;
61541
+ const C = c1.C + (c2.C - c1.C) * ratio;
61542
+ const a1 = c1.alpha ?? 1;
61543
+ const a2 = c2.alpha ?? 1;
61544
+ const alpha = normalizeAlpha2(a1 + (a2 - a1) * ratio);
61545
+ return alpha !== void 0 ? [L, C, H, alpha] : [L, C, H];
60911
61546
  },
60912
61547
  colorContrast(bg, fg) {
60913
61548
  return apca(toRgb255(bg), toRgb255(fg));
@@ -60915,11 +61550,11 @@ Error in definition of "${name}"`,
60915
61550
  contrastingColor(bg, fg1, fg2) {
60916
61551
  const bgRgb = toRgb255(bg);
60917
61552
  if (fg1 !== void 0 && fg2 !== void 0) {
60918
- return packedToArray(
61553
+ return packedToOklch(
60919
61554
  contrastingColor({ bg: bgRgb, fg1: toRgb255(fg1), fg2: toRgb255(fg2) })
60920
61555
  );
60921
61556
  }
60922
- return packedToArray(contrastingColor(bgRgb));
61557
+ return packedToOklch(contrastingColor(bgRgb));
60923
61558
  },
60924
61559
  colorToColorspace(input, space) {
60925
61560
  const rgb = toRgb255(input);
@@ -60948,7 +61583,7 @@ Error in definition of "${name}"`,
60948
61583
  default:
60949
61584
  throw new Error(`Unknown color space: ${space}`);
60950
61585
  }
60951
- if (alpha !== void 0 && Math.abs(alpha - 1) > 1e-4) result.push(alpha);
61586
+ if (alpha !== void 0) result.push(alpha);
60952
61587
  return result;
60953
61588
  },
60954
61589
  colormap(name, arg) {
@@ -60960,7 +61595,7 @@ Error in definition of "${name}"`,
60960
61595
  const palette = allPalettes[name];
60961
61596
  if (!palette) throw new Error(`Unknown palette: ${name}`);
60962
61597
  const colors = palette.map(
60963
- (hex) => parseColorToRgb01(hex)
61598
+ (hex) => packedToOklch(parseColor(hex))
60964
61599
  );
60965
61600
  if (arg === void 0) return colors;
60966
61601
  if (Number.isInteger(arg) && arg >= 2) {
@@ -60984,62 +61619,128 @@ Error in definition of "${name}"`,
60984
61619
  const frac = pos - i;
60985
61620
  if (frac === 0 || i >= colors.length - 1)
60986
61621
  return [...colors[Math.min(i, colors.length - 1)]];
60987
- const rgb1 = {
60988
- r: colors[i][0] * 255,
60989
- g: colors[i][1] * 255,
60990
- b: colors[i][2] * 255
60991
- };
60992
- const rgb2 = {
60993
- r: colors[i + 1][0] * 255,
60994
- g: colors[i + 1][1] * 255,
60995
- b: colors[i + 1][2] * 255
60996
- };
60997
- const c1 = rgbToOklch(rgb1);
60998
- const c2 = rgbToOklch(rgb2);
60999
- let dh = c2.H - c1.H;
61000
- if (dh > 180) dh -= 360;
61001
- if (dh < -180) dh += 360;
61002
- let H = c1.H + dh * frac;
61003
- if (H < 0) H += 360;
61004
- if (H >= 360) H -= 360;
61005
- const mixed = oklchToRgb({
61006
- L: c1.L + (c2.L - c1.L) * frac,
61007
- C: c1.C + (c2.C - c1.C) * frac,
61008
- H
61009
- });
61010
- return [mixed.r / 255, mixed.g / 255, mixed.b / 255];
61622
+ const [L1, C1, H1] = colors[i];
61623
+ const [L2, C2, H2] = colors[i + 1];
61624
+ const c1Achromatic = C1 < 1e-6;
61625
+ const c2Achromatic = C2 < 1e-6;
61626
+ let H;
61627
+ if (c1Achromatic && c2Achromatic) H = H1;
61628
+ else if (c1Achromatic) H = H2;
61629
+ else if (c2Achromatic) H = H1;
61630
+ else {
61631
+ let dh = H2 - H1;
61632
+ if (dh > 180) dh -= 360;
61633
+ if (dh < -180) dh += 360;
61634
+ H = H1 + dh * frac;
61635
+ if (H < 0) H += 360;
61636
+ if (H >= 360) H -= 360;
61637
+ }
61638
+ return [L1 + (L2 - L1) * frac, C1 + (C2 - C1) * frac, H];
61011
61639
  },
61012
61640
  colorFromColorspace(components, space) {
61013
61641
  const c0 = components[0];
61014
61642
  const c1 = components[1];
61015
61643
  const c2 = components[2];
61016
61644
  const alpha = components.length >= 4 ? components[3] : void 0;
61017
- let result;
61645
+ let oklch2;
61018
61646
  switch (space.toLowerCase()) {
61019
61647
  case "rgb":
61020
- result = [c0, c1, c2];
61648
+ oklch2 = rgbToOklch({ r: c0 * 255, g: c1 * 255, b: c2 * 255 });
61021
61649
  break;
61022
61650
  case "hsl": {
61023
- const r = hslToRgb(c0, c1, c2);
61024
- result = [r.r / 255, r.g / 255, r.b / 255];
61651
+ const rgb = hslToRgb(c0, c1, c2);
61652
+ oklch2 = rgbToOklch(rgb);
61025
61653
  break;
61026
61654
  }
61027
- case "oklch": {
61028
- const r = oklchToRgb({ L: c0, C: c1, H: c2 });
61029
- result = [r.r / 255, r.g / 255, r.b / 255];
61655
+ case "oklch":
61656
+ oklch2 = { L: c0, C: c1, H: c2 };
61030
61657
  break;
61031
- }
61032
61658
  case "oklab":
61033
- case "lab": {
61034
- const r = oklabToRgb({ L: c0, a: c1, b: c2 });
61035
- result = [r.r / 255, r.g / 255, r.b / 255];
61659
+ case "lab":
61660
+ oklch2 = oklabToOklch({ L: c0, a: c1, b: c2 });
61036
61661
  break;
61037
- }
61038
61662
  default:
61039
61663
  throw new Error(`Unknown color space: ${space}`);
61040
61664
  }
61041
- if (alpha !== void 0 && Math.abs(alpha - 1) > 1e-4) result.push(alpha);
61042
- return result;
61665
+ return alpha !== void 0 ? [oklch2.L, oklch2.C, oklch2.H, alpha] : [oklch2.L, oklch2.C, oklch2.H];
61666
+ },
61667
+ // -----------------------------------------------------------------------
61668
+ // Color constructors. Each accepts components in its colorspace's natural
61669
+ // units and returns the canonical OKLCh array `[L, C, H]` (or with alpha).
61670
+ // -----------------------------------------------------------------------
61671
+ rgb(r, g, b, alpha) {
61672
+ const c = rgbToOklch({ r: r * 255, g: g * 255, b: b * 255 });
61673
+ const a = normalizeAlpha2(alpha);
61674
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
61675
+ },
61676
+ hsv(h, s, v, alpha) {
61677
+ const rgb = hsvToRgb(h, s, v);
61678
+ const c = rgbToOklch(rgb);
61679
+ const a = normalizeAlpha2(alpha);
61680
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
61681
+ },
61682
+ hsl(h, s, l, alpha) {
61683
+ const rgb = hslToRgb(h, s, l);
61684
+ const c = rgbToOklch({ r: rgb.r, g: rgb.g, b: rgb.b });
61685
+ const a = normalizeAlpha2(alpha);
61686
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
61687
+ },
61688
+ oklab(L, a, b, alpha) {
61689
+ const c = oklabToOklch({ L, a, b });
61690
+ const al = normalizeAlpha2(alpha);
61691
+ return al !== void 0 ? [c.L, c.C, c.H, al] : [c.L, c.C, c.H];
61692
+ },
61693
+ oklch(L, C, H, alpha) {
61694
+ const a = normalizeAlpha2(alpha);
61695
+ return a !== void 0 ? [L, C, H, a] : [L, C, H];
61696
+ },
61697
+ // -----------------------------------------------------------------------
61698
+ // As* converters. Inputs are anything `toOklch` accepts (string, packed
61699
+ // int, or OKLCh array). Outputs are 3- or 4-element arrays in the named
61700
+ // space. sRGB-based outputs (asRgb/asHsv/asHsl) use 0-1 channels for
61701
+ // consistency with the GPU target's shader convention.
61702
+ // -----------------------------------------------------------------------
61703
+ asRgb(input) {
61704
+ const rgb = toRgb255(input);
61705
+ const r = rgb.r / 255;
61706
+ const g = rgb.g / 255;
61707
+ const b = rgb.b / 255;
61708
+ return rgb.alpha !== void 0 ? [r, g, b, rgb.alpha] : [r, g, b];
61709
+ },
61710
+ asHsv(input) {
61711
+ const rgb = toRgb255(input);
61712
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
61713
+ return rgb.alpha !== void 0 ? [hsv.h, hsv.s, hsv.v, rgb.alpha] : [hsv.h, hsv.s, hsv.v];
61714
+ },
61715
+ asHsl(input) {
61716
+ const rgb = toRgb255(input);
61717
+ const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
61718
+ return rgb.alpha !== void 0 ? [hsl.h, hsl.s, hsl.l, rgb.alpha] : [hsl.h, hsl.s, hsl.l];
61719
+ },
61720
+ asOklab(input) {
61721
+ const c = toOklch2(input);
61722
+ const lab = oklchToOklab({ L: c.L, C: c.C, H: c.H });
61723
+ return c.alpha !== void 0 ? [lab.L, lab.a, lab.b, c.alpha] : [lab.L, lab.a, lab.b];
61724
+ },
61725
+ // asOklch is identity — handled at compile time as a pass-through
61726
+ // Perceptual color difference (ΔE_OK).
61727
+ colorDelta(a, b) {
61728
+ const labA = oklchToOklab(toOklch2(a));
61729
+ const labB = oklchToOklab(toOklch2(b));
61730
+ return oklabDeltaE(labA, labB);
61731
+ },
61732
+ // Euclidean distance between two tuples. Plain numeric — not a color
61733
+ // operation despite living in the same helpers block.
61734
+ distance(a, b) {
61735
+ if (!Array.isArray(a) || !Array.isArray(b))
61736
+ throw new Error("Distance: expected two arrays");
61737
+ if (a.length !== b.length) throw new Error("Distance: dimension mismatch");
61738
+ let sumSq = 0;
61739
+ for (let i = 0; i < a.length; i++) {
61740
+ const d = a[i] - b[i];
61741
+ sumSq += d * d;
61742
+ }
61743
+ return Math.sqrt(sumSq);
61043
61744
  }
61044
61745
  };
61045
61746
  var SYS_HELPERS = {
@@ -61478,6 +62179,13 @@ Error in definition of "${name}"`,
61478
62179
  function gpuVec2(target) {
61479
62180
  return target?.language === "wgsl" ? "vec2f" : "vec2";
61480
62181
  }
62182
+ function gpuVec3(target) {
62183
+ return target?.language === "wgsl" ? "vec3f" : "vec3";
62184
+ }
62185
+ function readStringLiteral(expr2) {
62186
+ if (!isString(expr2)) return null;
62187
+ return expr2.string?.toLowerCase() ?? null;
62188
+ }
61481
62189
  function compileIntArg(expr2, compile3, target) {
61482
62190
  const c = tryGetConstant(expr2);
61483
62191
  if (c !== void 0 && Number.isInteger(c)) return c.toString();
@@ -61536,7 +62244,7 @@ Error in definition of "${name}"`,
61536
62244
  `for (${indexDecl} = ${lowerStr}; ${index} <= ${upperStr}; ${index}++) {`,
61537
62245
  ` ${acc} ${op}= ${body};`,
61538
62246
  `}`,
61539
- `return ${acc}`
62247
+ `return ${acc};`
61540
62248
  ];
61541
62249
  return lines.join("\n");
61542
62250
  }
@@ -61590,8 +62298,7 @@ Error in definition of "${name}"`,
61590
62298
  const iScale = isSymbol2(iFactor, "ImaginaryUnit") ? 1 : iFactor.im;
61591
62299
  const realFactors = args.filter((_, i) => i !== iIndex);
61592
62300
  const v2 = gpuVec2(target);
61593
- if (realFactors.length === 0)
61594
- return `${v2}(0.0, ${formatFloat(iScale)})`;
62301
+ if (realFactors.length === 0) return `${v2}(0.0, ${formatFloat(iScale)})`;
61595
62302
  const factors = realFactors.map((f) => compile3(f));
61596
62303
  if (iScale !== 1) factors.unshift(formatFloat(iScale));
61597
62304
  const imCode = foldTerms(factors, "1.0", "*");
@@ -61644,8 +62351,7 @@ Error in definition of "${name}"`,
61644
62351
  if (isNumber(x) && x.im !== 0) {
61645
62352
  return `${gpuVec2(target)}(${formatFloat(-x.re)}, ${formatFloat(-x.im)})`;
61646
62353
  }
61647
- if (isSymbol2(x, "ImaginaryUnit"))
61648
- return `${gpuVec2(target)}(0.0, -1.0)`;
62354
+ if (isSymbol2(x, "ImaginaryUnit")) return `${gpuVec2(target)}(0.0, -1.0)`;
61649
62355
  return `(-${compile3(x)})`;
61650
62356
  },
61651
62357
  // Standard math functions with complex dispatch
@@ -62018,17 +62724,127 @@ Error in definition of "${name}"`,
62018
62724
  }
62019
62725
  const isWGSL = target?.language === "wgsl";
62020
62726
  const v3 = isWGSL ? "vec3f" : "vec3";
62021
- return `((_gpu_apca(${bg}, ${v3}(0.0)) > 50.0) ? ${v3}(0.0) : ${v3}(1.0))`;
62727
+ const black = `${v3}(0.0)`;
62728
+ const white = `${v3}(1.0, 0.0, 0.0)`;
62729
+ return `((_gpu_apca(${bg}, ${black}) > 50.0) ? ${black} : ${white})`;
62022
62730
  },
62023
62731
  ColorToColorspace: ([color, space], compile3) => {
62024
62732
  if (color === null || space === null)
62025
62733
  throw new Error("ColorToColorspace: need color and space");
62026
- return `_gpu_srgb_to_oklab(${compile3(color)})`;
62734
+ const spaceName = readStringLiteral(space);
62735
+ if (spaceName === null)
62736
+ throw new Error("ColorToColorspace: space must be a string literal");
62737
+ const c = compile3(color);
62738
+ switch (spaceName) {
62739
+ case "oklch":
62740
+ return c;
62741
+ case "oklab":
62742
+ case "lab":
62743
+ return `_gpu_oklch_to_oklab(${c})`;
62744
+ case "rgb":
62745
+ return `_gpu_oklch_to_srgb(${c})`;
62746
+ case "hsl":
62747
+ return `_gpu_rgb_to_hsl(_gpu_oklch_to_srgb(${c}))`;
62748
+ case "hsv":
62749
+ return `_gpu_rgb_to_hsv(_gpu_oklch_to_srgb(${c}))`;
62750
+ default:
62751
+ throw new Error(
62752
+ `ColorToColorspace: unsupported space "${spaceName}" on GPU target`
62753
+ );
62754
+ }
62027
62755
  },
62028
62756
  ColorFromColorspace: ([components, space], compile3) => {
62029
62757
  if (components === null || space === null)
62030
62758
  throw new Error("ColorFromColorspace: need components and space");
62031
- return `_gpu_oklab_to_srgb(${compile3(components)})`;
62759
+ const spaceName = readStringLiteral(space);
62760
+ if (spaceName === null)
62761
+ throw new Error("ColorFromColorspace: space must be a string literal");
62762
+ const c = compile3(components);
62763
+ switch (spaceName) {
62764
+ case "oklch":
62765
+ return c;
62766
+ case "oklab":
62767
+ case "lab":
62768
+ return `_gpu_oklab_to_oklch(${c})`;
62769
+ case "rgb":
62770
+ return `_gpu_srgb_to_oklch(${c})`;
62771
+ case "hsl":
62772
+ return `_gpu_srgb_to_oklch(_gpu_hsl_to_rgb(${c}))`;
62773
+ case "hsv":
62774
+ return `_gpu_srgb_to_oklch(_gpu_hsv_to_rgb(${c}))`;
62775
+ default:
62776
+ throw new Error(
62777
+ `ColorFromColorspace: unsupported space "${spaceName}" on GPU target`
62778
+ );
62779
+ }
62780
+ },
62781
+ // ---------------------------------------------------------------------------
62782
+ // Color literals. Each typed head compiles to a canonical OKLCh vec3.
62783
+ // Alpha (4th argument) is dropped — GPU color values are vec3 only. Pass
62784
+ // alpha as a separate uniform if it's needed at the framebuffer boundary.
62785
+ // ---------------------------------------------------------------------------
62786
+ Color: ([s], _compile2, target) => {
62787
+ if (s === null) throw new Error("Color: no argument");
62788
+ const str = readStringLiteral(s);
62789
+ if (str === null)
62790
+ throw new Error("Color: argument must be a string literal on GPU target");
62791
+ const packed = parseColor(str);
62792
+ if (packed === 0 && str.trim().toLowerCase() !== "transparent")
62793
+ throw new Error(`Color: invalid color string "${str}"`);
62794
+ const r = packed >>> 24 & 255;
62795
+ const g = packed >>> 16 & 255;
62796
+ const b = packed >>> 8 & 255;
62797
+ const oklch2 = rgbToOklch({ r, g, b });
62798
+ return `${gpuVec3(target)}(${formatFloat(oklch2.L)}, ${formatFloat(oklch2.C)}, ${formatFloat(oklch2.H)})`;
62799
+ },
62800
+ Rgb: (args, compile3, target) => {
62801
+ if (args.length < 3) throw new Error("Rgb: need 3 components");
62802
+ const v3 = gpuVec3(target);
62803
+ return `_gpu_srgb_to_oklch(${v3}(${compile3(args[0])}, ${compile3(args[1])}, ${compile3(args[2])}))`;
62804
+ },
62805
+ Hsv: (args, compile3, target) => {
62806
+ if (args.length < 3) throw new Error("Hsv: need 3 components");
62807
+ const v3 = gpuVec3(target);
62808
+ return `_gpu_srgb_to_oklch(_gpu_hsv_to_rgb(${v3}(${compile3(args[0])}, ${compile3(args[1])}, ${compile3(args[2])})))`;
62809
+ },
62810
+ Hsl: (args, compile3, target) => {
62811
+ if (args.length < 3) throw new Error("Hsl: need 3 components");
62812
+ const v3 = gpuVec3(target);
62813
+ return `_gpu_srgb_to_oklch(_gpu_hsl_to_rgb(${v3}(${compile3(args[0])}, ${compile3(args[1])}, ${compile3(args[2])})))`;
62814
+ },
62815
+ Oklab: (args, compile3, target) => {
62816
+ if (args.length < 3) throw new Error("Oklab: need 3 components");
62817
+ const v3 = gpuVec3(target);
62818
+ return `_gpu_oklab_to_oklch(${v3}(${compile3(args[0])}, ${compile3(args[1])}, ${compile3(args[2])}))`;
62819
+ },
62820
+ Oklch: (args, compile3, target) => {
62821
+ if (args.length < 3) throw new Error("Oklch: need 3 components");
62822
+ const v3 = gpuVec3(target);
62823
+ return `${v3}(${compile3(args[0])}, ${compile3(args[1])}, ${compile3(args[2])})`;
62824
+ },
62825
+ // ---------------------------------------------------------------------------
62826
+ // As* operators. AsOklch is identity (canonical). The other As* return
62827
+ // components in the named space, equivalent to ColorToColorspace(c, 'x').
62828
+ // ---------------------------------------------------------------------------
62829
+ AsOklch: ([c], compile3) => {
62830
+ if (c === null) throw new Error("AsOklch: no argument");
62831
+ return compile3(c);
62832
+ },
62833
+ AsOklab: ([c], compile3) => {
62834
+ if (c === null) throw new Error("AsOklab: no argument");
62835
+ return `_gpu_oklch_to_oklab(${compile3(c)})`;
62836
+ },
62837
+ AsRgb: ([c], compile3) => {
62838
+ if (c === null) throw new Error("AsRgb: no argument");
62839
+ return `_gpu_oklch_to_srgb(${compile3(c)})`;
62840
+ },
62841
+ AsHsv: ([c], compile3) => {
62842
+ if (c === null) throw new Error("AsHsv: no argument");
62843
+ return `_gpu_rgb_to_hsv(_gpu_oklch_to_srgb(${compile3(c)}))`;
62844
+ },
62845
+ AsHsl: ([c], compile3) => {
62846
+ if (c === null) throw new Error("AsHsl: no argument");
62847
+ return `_gpu_rgb_to_hsl(_gpu_oklch_to_srgb(${compile3(c)}))`;
62032
62848
  },
62033
62849
  // Fractal functions
62034
62850
  Mandelbrot: ([c, maxIter], compile3, target) => {
@@ -62721,28 +63537,124 @@ vec3 _gpu_oklab_to_srgb(vec3 lab) {
62721
63537
 
62722
63538
  vec3 _gpu_oklab_to_oklch(vec3 lab) {
62723
63539
  float C = length(lab.yz);
62724
- float H = atan(lab.z, lab.y);
63540
+ float H = atan(lab.z, lab.y) * (180.0 / 3.14159265359);
63541
+ if (H < 0.0) H += 360.0;
62725
63542
  return vec3(lab.x, C, H);
62726
63543
  }
62727
63544
 
62728
63545
  vec3 _gpu_oklch_to_oklab(vec3 lch) {
62729
- return vec3(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));
63546
+ float h_rad = lch.z * (3.14159265359 / 180.0);
63547
+ return vec3(lch.x, lch.y * cos(h_rad), lch.y * sin(h_rad));
63548
+ }
63549
+
63550
+ vec3 _gpu_srgb_to_oklch(vec3 rgb) {
63551
+ return _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb));
63552
+ }
63553
+
63554
+ vec3 _gpu_oklch_to_srgb(vec3 lch) {
63555
+ return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(lch));
63556
+ }
63557
+
63558
+ // HSL conversion. Hue in degrees, saturation/lightness in 0-1.
63559
+ vec3 _gpu_hsl_to_rgb(vec3 hsl) {
63560
+ float h = hsl.x;
63561
+ float s = hsl.y;
63562
+ float l = hsl.z;
63563
+ float c = (1.0 - abs(2.0 * l - 1.0)) * s;
63564
+ float h6 = h / 60.0;
63565
+ float x = c * (1.0 - abs(mod(h6, 2.0) - 1.0));
63566
+ float r = 0.0;
63567
+ float g = 0.0;
63568
+ float b = 0.0;
63569
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
63570
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
63571
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
63572
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
63573
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
63574
+ else { r = c; g = 0.0; b = x; }
63575
+ float m = l - c / 2.0;
63576
+ return vec3(r + m, g + m, b + m);
63577
+ }
63578
+
63579
+ vec3 _gpu_rgb_to_hsl(vec3 rgb) {
63580
+ float maxc = max(max(rgb.x, rgb.y), rgb.z);
63581
+ float minc = min(min(rgb.x, rgb.y), rgb.z);
63582
+ float l = (maxc + minc) / 2.0;
63583
+ float d = maxc - minc;
63584
+ if (d < 1e-6) return vec3(0.0, 0.0, l);
63585
+ float s = d / (1.0 - abs(2.0 * l - 1.0));
63586
+ float h;
63587
+ if (maxc == rgb.x) h = mod((rgb.y - rgb.z) / d, 6.0);
63588
+ else if (maxc == rgb.y) h = (rgb.z - rgb.x) / d + 2.0;
63589
+ else h = (rgb.x - rgb.y) / d + 4.0;
63590
+ h *= 60.0;
63591
+ if (h < 0.0) h += 360.0;
63592
+ return vec3(h, s, l);
63593
+ }
63594
+
63595
+ // HSV conversion. Hue in degrees, saturation/value in 0-1.
63596
+ vec3 _gpu_hsv_to_rgb(vec3 hsv) {
63597
+ float h = hsv.x;
63598
+ float s = hsv.y;
63599
+ float v = hsv.z;
63600
+ float c = v * s;
63601
+ float h6 = h / 60.0;
63602
+ float x = c * (1.0 - abs(mod(h6, 2.0) - 1.0));
63603
+ float r = 0.0;
63604
+ float g = 0.0;
63605
+ float b = 0.0;
63606
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
63607
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
63608
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
63609
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
63610
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
63611
+ else { r = c; g = 0.0; b = x; }
63612
+ float m = v - c;
63613
+ return vec3(r + m, g + m, b + m);
62730
63614
  }
62731
63615
 
62732
- vec3 _gpu_color_mix(vec3 rgb1, vec3 rgb2, float t) {
62733
- vec3 lch1 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb1));
62734
- vec3 lch2 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb2));
63616
+ vec3 _gpu_rgb_to_hsv(vec3 rgb) {
63617
+ float maxc = max(max(rgb.x, rgb.y), rgb.z);
63618
+ float minc = min(min(rgb.x, rgb.y), rgb.z);
63619
+ float v = maxc;
63620
+ float d = maxc - minc;
63621
+ if (d < 1e-6) return vec3(0.0, 0.0, v);
63622
+ float s = (maxc < 1e-6) ? 0.0 : d / maxc;
63623
+ float h;
63624
+ if (maxc == rgb.x) h = mod((rgb.y - rgb.z) / d, 6.0);
63625
+ else if (maxc == rgb.y) h = (rgb.z - rgb.x) / d + 2.0;
63626
+ else h = (rgb.x - rgb.y) / d + 4.0;
63627
+ h *= 60.0;
63628
+ if (h < 0.0) h += 360.0;
63629
+ return vec3(h, s, v);
63630
+ }
63631
+
63632
+ vec3 _gpu_color_mix(vec3 lch1, vec3 lch2, float t) {
62735
63633
  float L = mix(lch1.x, lch2.x, t);
62736
63634
  float C = mix(lch1.y, lch2.y, t);
62737
- float dh = lch2.z - lch1.z;
62738
- const float PI = 3.14159265359;
62739
- if (dh > PI) dh -= 2.0 * PI;
62740
- if (dh < -PI) dh += 2.0 * PI;
62741
- float H = lch1.z + dh * t;
62742
- return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(vec3(L, C, H)));
63635
+ bool a1 = lch1.y < 1e-6;
63636
+ bool a2 = lch2.y < 1e-6;
63637
+ float H;
63638
+ if (a1 && a2) {
63639
+ H = lch1.z;
63640
+ } else if (a1) {
63641
+ H = lch2.z;
63642
+ } else if (a2) {
63643
+ H = lch1.z;
63644
+ } else {
63645
+ float dh = lch2.z - lch1.z;
63646
+ if (dh > 180.0) dh -= 360.0;
63647
+ if (dh < -180.0) dh += 360.0;
63648
+ H = lch1.z + dh * t;
63649
+ if (H < 0.0) H += 360.0;
63650
+ if (H >= 360.0) H -= 360.0;
63651
+ }
63652
+ return vec3(L, C, H);
62743
63653
  }
62744
63654
 
62745
- float _gpu_apca(vec3 bg, vec3 fg) {
63655
+ float _gpu_apca(vec3 lch_bg, vec3 lch_fg) {
63656
+ vec3 bg = _gpu_oklch_to_srgb(lch_bg);
63657
+ vec3 fg = _gpu_oklch_to_srgb(lch_fg);
62746
63658
  float bgR = _gpu_srgb_to_linear(bg.x);
62747
63659
  float bgG = _gpu_srgb_to_linear(bg.y);
62748
63660
  float bgB = _gpu_srgb_to_linear(bg.z);
@@ -62753,9 +63665,7 @@ float _gpu_apca(vec3 bg, vec3 fg) {
62753
63665
  float fgY = 0.2126729 * fgR + 0.7151522 * fgG + 0.0721750 * fgB;
62754
63666
  float bgC = pow(bgY, 0.56);
62755
63667
  float fgC = pow(fgY, 0.57);
62756
- float contrast = (bgC > fgC)
62757
- ? (bgC - fgC) * 1.14
62758
- : (bgC - fgC) * 1.14;
63668
+ float contrast = (bgC - fgC) * 1.14;
62759
63669
  return contrast * 100.0;
62760
63670
  }
62761
63671
  `;
@@ -62799,28 +63709,133 @@ fn _gpu_oklab_to_srgb(lab: vec3f) -> vec3f {
62799
63709
 
62800
63710
  fn _gpu_oklab_to_oklch(lab: vec3f) -> vec3f {
62801
63711
  let C = length(lab.yz);
62802
- let H = atan2(lab.z, lab.y);
63712
+ var H = atan2(lab.z, lab.y) * (180.0 / 3.14159265359);
63713
+ if (H < 0.0) { H = H + 360.0; }
62803
63714
  return vec3f(lab.x, C, H);
62804
63715
  }
62805
63716
 
62806
63717
  fn _gpu_oklch_to_oklab(lch: vec3f) -> vec3f {
62807
- return vec3f(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));
63718
+ let h_rad = lch.z * (3.14159265359 / 180.0);
63719
+ return vec3f(lch.x, lch.y * cos(h_rad), lch.y * sin(h_rad));
63720
+ }
63721
+
63722
+ fn _gpu_srgb_to_oklch(rgb: vec3f) -> vec3f {
63723
+ return _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb));
62808
63724
  }
62809
63725
 
62810
- fn _gpu_color_mix(rgb1: vec3f, rgb2: vec3f, t: f32) -> vec3f {
62811
- let lch1 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb1));
62812
- let lch2 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb2));
63726
+ fn _gpu_oklch_to_srgb(lch: vec3f) -> vec3f {
63727
+ return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(lch));
63728
+ }
63729
+
63730
+ fn _gpu_hsl_to_rgb(hsl: vec3f) -> vec3f {
63731
+ let h = hsl.x;
63732
+ let s = hsl.y;
63733
+ let l = hsl.z;
63734
+ let c = (1.0 - abs(2.0 * l - 1.0)) * s;
63735
+ let h6 = h / 60.0;
63736
+ let x = c * (1.0 - abs((h6 - 2.0 * floor(h6 / 2.0)) - 1.0));
63737
+ var r: f32 = 0.0;
63738
+ var g: f32 = 0.0;
63739
+ var b: f32 = 0.0;
63740
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
63741
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
63742
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
63743
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
63744
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
63745
+ else { r = c; g = 0.0; b = x; }
63746
+ let m = l - c / 2.0;
63747
+ return vec3f(r + m, g + m, b + m);
63748
+ }
63749
+
63750
+ fn _gpu_rgb_to_hsl(rgb: vec3f) -> vec3f {
63751
+ let maxc = max(max(rgb.x, rgb.y), rgb.z);
63752
+ let minc = min(min(rgb.x, rgb.y), rgb.z);
63753
+ let l = (maxc + minc) / 2.0;
63754
+ let d = maxc - minc;
63755
+ if (d < 1e-6) { return vec3f(0.0, 0.0, l); }
63756
+ let s = d / (1.0 - abs(2.0 * l - 1.0));
63757
+ var h: f32;
63758
+ if (maxc == rgb.x) {
63759
+ let v = (rgb.y - rgb.z) / d;
63760
+ h = v - 6.0 * floor(v / 6.0);
63761
+ } else if (maxc == rgb.y) {
63762
+ h = (rgb.z - rgb.x) / d + 2.0;
63763
+ } else {
63764
+ h = (rgb.x - rgb.y) / d + 4.0;
63765
+ }
63766
+ h = h * 60.0;
63767
+ if (h < 0.0) { h = h + 360.0; }
63768
+ return vec3f(h, s, l);
63769
+ }
63770
+
63771
+ fn _gpu_hsv_to_rgb(hsv: vec3f) -> vec3f {
63772
+ let h = hsv.x;
63773
+ let s = hsv.y;
63774
+ let v = hsv.z;
63775
+ let c = v * s;
63776
+ let h6 = h / 60.0;
63777
+ let x = c * (1.0 - abs((h6 - 2.0 * floor(h6 / 2.0)) - 1.0));
63778
+ var r: f32 = 0.0;
63779
+ var g: f32 = 0.0;
63780
+ var b: f32 = 0.0;
63781
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
63782
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
63783
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
63784
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
63785
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
63786
+ else { r = c; g = 0.0; b = x; }
63787
+ let m = v - c;
63788
+ return vec3f(r + m, g + m, b + m);
63789
+ }
63790
+
63791
+ fn _gpu_rgb_to_hsv(rgb: vec3f) -> vec3f {
63792
+ let maxc = max(max(rgb.x, rgb.y), rgb.z);
63793
+ let minc = min(min(rgb.x, rgb.y), rgb.z);
63794
+ let v = maxc;
63795
+ let d = maxc - minc;
63796
+ if (d < 1e-6) { return vec3f(0.0, 0.0, v); }
63797
+ var s: f32 = 0.0;
63798
+ if (maxc >= 1e-6) { s = d / maxc; }
63799
+ var h: f32;
63800
+ if (maxc == rgb.x) {
63801
+ let q = (rgb.y - rgb.z) / d;
63802
+ h = q - 6.0 * floor(q / 6.0);
63803
+ } else if (maxc == rgb.y) {
63804
+ h = (rgb.z - rgb.x) / d + 2.0;
63805
+ } else {
63806
+ h = (rgb.x - rgb.y) / d + 4.0;
63807
+ }
63808
+ h = h * 60.0;
63809
+ if (h < 0.0) { h = h + 360.0; }
63810
+ return vec3f(h, s, v);
63811
+ }
63812
+
63813
+ fn _gpu_color_mix(lch1: vec3f, lch2: vec3f, t: f32) -> vec3f {
62813
63814
  let L = mix(lch1.x, lch2.x, t);
62814
63815
  let C = mix(lch1.y, lch2.y, t);
62815
- let PI = 3.14159265359;
62816
- var dh = lch2.z - lch1.z;
62817
- if (dh > PI) { dh -= 2.0 * PI; }
62818
- if (dh < -PI) { dh += 2.0 * PI; }
62819
- let H = lch1.z + dh * t;
62820
- return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(vec3f(L, C, H)));
63816
+ let a1 = lch1.y < 1e-6;
63817
+ let a2 = lch2.y < 1e-6;
63818
+ var H: f32;
63819
+ if (a1 && a2) {
63820
+ H = lch1.z;
63821
+ } else if (a1) {
63822
+ H = lch2.z;
63823
+ } else if (a2) {
63824
+ H = lch1.z;
63825
+ } else {
63826
+ var dh = lch2.z - lch1.z;
63827
+ if (dh > 180.0) { dh = dh - 360.0; }
63828
+ if (dh < -180.0) { dh = dh + 360.0; }
63829
+ H = lch1.z + dh * t;
63830
+ if (H < 0.0) { H = H + 360.0; }
63831
+ if (H >= 360.0) { H = H - 360.0; }
63832
+ }
63833
+ return vec3f(L, C, H);
62821
63834
  }
62822
63835
 
62823
- fn _gpu_apca(bg: vec3f, fg: vec3f) -> f32 {
63836
+ fn _gpu_apca(lch_bg: vec3f, lch_fg: vec3f) -> f32 {
63837
+ let bg = _gpu_oklch_to_srgb(lch_bg);
63838
+ let fg = _gpu_oklch_to_srgb(lch_fg);
62824
63839
  let bgR = _gpu_srgb_to_linear(bg.x);
62825
63840
  let bgG = _gpu_srgb_to_linear(bg.y);
62826
63841
  let bgB = _gpu_srgb_to_linear(bg.z);
@@ -63108,7 +64123,7 @@ fn _gpu_apca(bg: vec3f, fg: vec3f) -> f32 {
63108
64123
  if (stmts.length === 0) return "";
63109
64124
  const last = stmts.length - 1;
63110
64125
  stmts[last] = `return ${stmts[last]}`;
63111
- return stmts.join(";\n");
64126
+ return stmts.join(";\n") + ";";
63112
64127
  },
63113
64128
  ...options
63114
64129
  };
@@ -63207,7 +64222,7 @@ fn _gpu_apca(bg: vec3f, fg: vec3f) -> f32 {
63207
64222
  if (body.includes("\n")) {
63208
64223
  const indented = body.split("\n").map((l) => ` ${l}`).join("\n");
63209
64224
  return `${returnType} ${functionName}(${params}) {
63210
- ${indented};
64225
+ ${indented}
63211
64226
  }`;
63212
64227
  }
63213
64228
  return `${returnType} ${functionName}(${params}) {
@@ -63318,7 +64333,7 @@ ${indented};
63318
64333
  return `fn ${functionName}(${params}) -> ${toWGSLType(
63319
64334
  returnType
63320
64335
  )} {
63321
- ${indented};
64336
+ ${indented}
63322
64337
  }`;
63323
64338
  }
63324
64339
  return `fn ${functionName}(${params}) -> ${toWGSLType(returnType)} {
@@ -67303,6 +68318,7 @@ ${workgroupAttr}fn main(${paramStr})${returnStr} {
67303
68318
  this.pushScope(void 0, "global");
67304
68319
  this._compilationTargets.registerDefaults();
67305
68320
  if (options?.latexSyntax) this._latexSyntax = options.latexSyntax;
68321
+ if (options?.latexOptions) this._latexOptions = { ...options.latexOptions };
67306
68322
  hidePrivateProperties(this);
67307
68323
  }
67308
68324
  toJSON() {
@@ -67963,6 +68979,29 @@ ${workgroupAttr}fn main(${paramStr})${returnStr} {
67963
68979
  );
67964
68980
  return this._latexSyntax;
67965
68981
  }
68982
+ /** @internal Engine-wide LaTeX parse/serialize options (e.g. decimalSeparator).
68983
+ * Merged into every `parse()` and `toLatex()` call between the LatexSyntax
68984
+ * instance defaults and any per-call overrides. */
68985
+ _latexOptions = {};
68986
+ /** Engine-wide LaTeX parse/serialize options.
68987
+ *
68988
+ * These options are merged into every `parse()` and `toLatex()` call.
68989
+ * Precedence (most-specific wins):
68990
+ * 1. LatexSyntax instance defaults (set at its construction)
68991
+ * 2. `ce.latexOptions` (this property)
68992
+ * 3. Per-call options passed to `ce.parse()` / `expr.toLatex()`
68993
+ *
68994
+ * Assigning replaces the whole bag. Use spread to merge:
68995
+ * ```ts
68996
+ * ce.latexOptions = { ...ce.latexOptions, decimalSeparator: '{,}' };
68997
+ * ```
68998
+ */
68999
+ get latexOptions() {
69000
+ return this._latexOptions;
69001
+ }
69002
+ set latexOptions(options) {
69003
+ this._latexOptions = { ...options };
69004
+ }
67966
69005
  parse(latex, options) {
67967
69006
  if (latex === null || latex === void 0) return null;
67968
69007
  if (typeof latex !== "string")
@@ -67970,7 +69009,6 @@ ${workgroupAttr}fn main(${paramStr})${returnStr} {
67970
69009
  const syntax = this._requireLatexSyntax();
67971
69010
  const { form, ...parseOpts } = options ?? {};
67972
69011
  const result = syntax.parse(latex, {
67973
- decimalSeparator: ".",
67974
69012
  getSymbolType: (id) => {
67975
69013
  const def = this.lookupDefinition(id);
67976
69014
  if (!def) return BoxedType.unknown;
@@ -67982,6 +69020,7 @@ ${workgroupAttr}fn main(${paramStr})${returnStr} {
67982
69020
  const def = this.lookupDefinition(id);
67983
69021
  return !!(isValueDef(def) && def.value.subscriptEvaluate);
67984
69022
  },
69023
+ ...this._latexOptions,
67985
69024
  ...parseOpts
67986
69025
  });
67987
69026
  if (result === null) return null;
@@ -68145,7 +69184,7 @@ ${workgroupAttr}fn main(${paramStr})${returnStr} {
68145
69184
  _setDefaultEngineFactory(() => new ComputeEngine());
68146
69185
 
68147
69186
  // src/core.ts
68148
- var version = "0.55.6";
69187
+ var version = "0.56.0";
68149
69188
  return __toCommonJS(core_exports);
68150
69189
  })();
68151
69190
  /*! Bundled license information: