@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
@@ -1,4 +1,4 @@
1
- /** Compute Engine 0.55.6 */
1
+ /** Compute Engine 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.ComputeEngine = {}));})(this, (function (exports) { 'use strict';
3
3
  var ComputeEngine = (() => {
4
4
  var __defProp = Object.defineProperty;
@@ -2316,6 +2316,7 @@ var ComputeEngine = (() => {
2316
2316
  ];
2317
2317
  var VALUE_TYPES = [
2318
2318
  "value",
2319
+ "color",
2319
2320
  ...COLLECTION_TYPES,
2320
2321
  ...SCALAR_TYPES
2321
2322
  ];
@@ -4015,6 +4016,7 @@ var ComputeEngine = (() => {
4015
4016
  symbol: [],
4016
4017
  boolean: [],
4017
4018
  string: [],
4019
+ color: [],
4018
4020
  expression: EXPRESSION_TYPES
4019
4021
  };
4020
4022
  function isPrimitiveSubtype(lhs, rhs) {
@@ -7898,9 +7900,10 @@ var ComputeEngine = (() => {
7898
7900
  if (!materialized.isLazyCollection) return materialized.latex;
7899
7901
  }
7900
7902
  const syntax = this.engine._requireLatexSyntax();
7901
- return syntax.serialize(
7902
- this.toMathJson({ prettify: true, fractionalDigits: "auto" })
7903
- );
7903
+ const json = this.toMathJson({ prettify: true, fractionalDigits: "auto" });
7904
+ const latexOpts = this.engine.latexOptions;
7905
+ if (Object.keys(latexOpts).length === 0) return syntax.serialize(json);
7906
+ return syntax.serialize(json, { ...latexOpts });
7904
7907
  }
7905
7908
  /**
7906
7909
  * Return a LaTeX representation of this expression with custom
@@ -7924,9 +7927,13 @@ var ComputeEngine = (() => {
7924
7927
  fractionalDigits: "auto"
7925
7928
  });
7926
7929
  const syntax = this.engine._requireLatexSyntax();
7927
- if (!options || Object.keys(options).length === 0)
7928
- return syntax.serialize(json);
7929
- return syntax.serialize(json, options);
7930
+ const latexOpts = this.engine.latexOptions;
7931
+ const haveEngineOpts = Object.keys(latexOpts).length > 0;
7932
+ const haveCallOpts = options && Object.keys(options).length > 0;
7933
+ if (!haveEngineOpts && !haveCallOpts) return syntax.serialize(json);
7934
+ if (!haveEngineOpts) return syntax.serialize(json, options);
7935
+ if (!haveCallOpts) return syntax.serialize(json, { ...latexOpts });
7936
+ return syntax.serialize(json, { ...latexOpts, ...options });
7930
7937
  }
7931
7938
  /** Called by `JSON.stringify()` when serializing to json.
7932
7939
  *
@@ -7970,11 +7977,13 @@ var ComputeEngine = (() => {
7970
7977
  "number",
7971
7978
  "dictionary"
7972
7979
  ];
7973
- }
7974
- if (Array.isArray(options.shorthands))
7980
+ } else if (Array.isArray(options.shorthands)) {
7975
7981
  defaultOptions.shorthands = options.shorthands;
7982
+ }
7976
7983
  if (typeof options.metadata === "string" && options.metadata === "all" || options.metadata?.includes("all")) {
7977
7984
  defaultOptions.metadata = ["latex", "wikidata"];
7985
+ } else if (Array.isArray(options.metadata)) {
7986
+ defaultOptions.metadata = options.metadata;
7978
7987
  }
7979
7988
  if (options.fractionalDigits === "auto")
7980
7989
  defaultOptions.fractionalDigits = -this.engine.precision;
@@ -13696,6 +13705,8 @@ var ComputeEngine = (() => {
13696
13705
  precedence: DIVISION_PRECEDENCE,
13697
13706
  parse: "Mod"
13698
13707
  },
13708
+ // Function-style alias: `\operatorname{mod}(a, b)`
13709
+ { latexTrigger: "\\operatorname{mod}", parse: "Mod" },
13699
13710
  {
13700
13711
  latexTrigger: "\\pmod",
13701
13712
  kind: "prefix",
@@ -13936,6 +13947,13 @@ var ComputeEngine = (() => {
13936
13947
  const rhs = serializer.wrap(operand(expr2, 2), ADDITION_PRECEDENCE + 3);
13937
13948
  return joinLatex([lhs, "-", rhs]);
13938
13949
  }
13950
+ },
13951
+ // Euclidean distance between two points (tuples of numbers).
13952
+ {
13953
+ name: "Distance",
13954
+ latexTrigger: ["\\operatorname{distance}"],
13955
+ kind: "function",
13956
+ serialize: (serializer, expr2) => "\\operatorname{distance}" + serializer.wrapArguments(expr2)
13939
13957
  }
13940
13958
  ];
13941
13959
  function getIndexAssignment(expr2, upper) {
@@ -15360,7 +15378,9 @@ var ComputeEngine = (() => {
15360
15378
  if (!expr2 || !symbol(expr2)) return null;
15361
15379
  return ["Mean", expr2];
15362
15380
  }
15363
- }
15381
+ },
15382
+ // Function-style alias: `\operatorname{var}(...)`
15383
+ { latexTrigger: "\\operatorname{var}", parse: "Variance" }
15364
15384
  ];
15365
15385
 
15366
15386
  // src/compute-engine/numerics/unit-data.ts
@@ -16461,7 +16481,7 @@ var ComputeEngine = (() => {
16461
16481
  36: "\\qquad"
16462
16482
  }[v] ?? "";
16463
16483
  }
16464
- }
16484
+ },
16465
16485
  // if (
16466
16486
  // [
16467
16487
  // '\\!',
@@ -16485,6 +16505,121 @@ var ComputeEngine = (() => {
16485
16505
  // name: '',
16486
16506
  // trigger: '\\check',
16487
16507
  // },
16508
+ // ---------------------------------------------------------------------------
16509
+ // Function-style aliases for collection / random operators that some
16510
+ // notations write in lowercase (e.g. `\operatorname{shuffle}(L)`).
16511
+ // The capitalized library entries already exist; these are pure parse
16512
+ // aliases so the lowercase names don't land in `unsupported-operator`.
16513
+ // ---------------------------------------------------------------------------
16514
+ { latexTrigger: "\\operatorname{random}", parse: "Random" },
16515
+ { latexTrigger: "\\operatorname{shuffle}", parse: "Shuffle" },
16516
+ { latexTrigger: "\\operatorname{repeat}", parse: "Repeat" },
16517
+ { latexTrigger: "\\operatorname{join}", parse: "Join" },
16518
+ // ---------------------------------------------------------------------------
16519
+ // Geometric primitive heads. Registered as known typed heads so consumers
16520
+ // can branch on the operator name; CE itself doesn't render them. The
16521
+ // library entries (with no evaluator) live in `library/core.ts`.
16522
+ // ---------------------------------------------------------------------------
16523
+ {
16524
+ name: "Triangle",
16525
+ latexTrigger: ["\\operatorname{triangle}"],
16526
+ kind: "function",
16527
+ serialize: (serializer, expr2) => "\\operatorname{triangle}" + serializer.wrapArguments(expr2)
16528
+ },
16529
+ // Desmos's geometric `vector(p1, p2)` — a directed segment between two
16530
+ // points. Routed to a dedicated head (not the existing column-vector
16531
+ // `Vector`, which has a narrower `(number+) -> vector` signature).
16532
+ {
16533
+ name: "GeometricVector",
16534
+ latexTrigger: ["\\operatorname{vector}"],
16535
+ kind: "function",
16536
+ serialize: (serializer, expr2) => "\\operatorname{vector}" + serializer.wrapArguments(expr2)
16537
+ },
16538
+ {
16539
+ name: "Sphere",
16540
+ latexTrigger: ["\\operatorname{sphere}"],
16541
+ kind: "function",
16542
+ serialize: (serializer, expr2) => "\\operatorname{sphere}" + serializer.wrapArguments(expr2)
16543
+ },
16544
+ {
16545
+ name: "Segment",
16546
+ latexTrigger: ["\\operatorname{segment}"],
16547
+ kind: "function",
16548
+ serialize: (serializer, expr2) => "\\operatorname{segment}" + serializer.wrapArguments(expr2)
16549
+ }
16550
+ ];
16551
+
16552
+ // src/compute-engine/latex-syntax/dictionary/definitions-colors.ts
16553
+ var DEFINITIONS_COLORS = [
16554
+ // Color constructors (one per colorspace, preserves space on evaluation)
16555
+ {
16556
+ name: "Rgb",
16557
+ latexTrigger: ["\\operatorname{rgb}"],
16558
+ kind: "function",
16559
+ serialize: (serializer, expr2) => "\\operatorname{rgb}" + serializer.wrapArguments(expr2)
16560
+ },
16561
+ {
16562
+ name: "Hsv",
16563
+ latexTrigger: ["\\operatorname{hsv}"],
16564
+ kind: "function",
16565
+ serialize: (serializer, expr2) => "\\operatorname{hsv}" + serializer.wrapArguments(expr2)
16566
+ },
16567
+ {
16568
+ name: "Hsl",
16569
+ latexTrigger: ["\\operatorname{hsl}"],
16570
+ kind: "function",
16571
+ serialize: (serializer, expr2) => "\\operatorname{hsl}" + serializer.wrapArguments(expr2)
16572
+ },
16573
+ {
16574
+ name: "Oklab",
16575
+ latexTrigger: ["\\operatorname{oklab}"],
16576
+ kind: "function",
16577
+ serialize: (serializer, expr2) => "\\operatorname{oklab}" + serializer.wrapArguments(expr2)
16578
+ },
16579
+ {
16580
+ name: "Oklch",
16581
+ latexTrigger: ["\\operatorname{oklch}"],
16582
+ kind: "function",
16583
+ serialize: (serializer, expr2) => "\\operatorname{oklch}" + serializer.wrapArguments(expr2)
16584
+ },
16585
+ // Conversion functions (color → color in the named space)
16586
+ {
16587
+ name: "AsRgb",
16588
+ latexTrigger: ["\\operatorname{asRgb}"],
16589
+ kind: "function",
16590
+ serialize: (serializer, expr2) => "\\operatorname{asRgb}" + serializer.wrapArguments(expr2)
16591
+ },
16592
+ {
16593
+ name: "AsHsv",
16594
+ latexTrigger: ["\\operatorname{asHsv}"],
16595
+ kind: "function",
16596
+ serialize: (serializer, expr2) => "\\operatorname{asHsv}" + serializer.wrapArguments(expr2)
16597
+ },
16598
+ {
16599
+ name: "AsHsl",
16600
+ latexTrigger: ["\\operatorname{asHsl}"],
16601
+ kind: "function",
16602
+ serialize: (serializer, expr2) => "\\operatorname{asHsl}" + serializer.wrapArguments(expr2)
16603
+ },
16604
+ {
16605
+ name: "AsOklab",
16606
+ latexTrigger: ["\\operatorname{asOklab}"],
16607
+ kind: "function",
16608
+ serialize: (serializer, expr2) => "\\operatorname{asOklab}" + serializer.wrapArguments(expr2)
16609
+ },
16610
+ {
16611
+ name: "AsOklch",
16612
+ latexTrigger: ["\\operatorname{asOklch}"],
16613
+ kind: "function",
16614
+ serialize: (serializer, expr2) => "\\operatorname{asOklch}" + serializer.wrapArguments(expr2)
16615
+ },
16616
+ // Perceptual difference (returns a scalar in [0, ~1])
16617
+ {
16618
+ name: "ColorDelta",
16619
+ latexTrigger: ["\\operatorname{colorDelta}"],
16620
+ kind: "function",
16621
+ serialize: (serializer, expr2) => "\\operatorname{colorDelta}" + serializer.wrapArguments(expr2)
16622
+ }
16488
16623
  ];
16489
16624
 
16490
16625
  // src/compute-engine/latex-syntax/dictionary/default-dictionary.ts
@@ -16515,7 +16650,8 @@ var ComputeEngine = (() => {
16515
16650
  ...DEFINITIONS_STATISTICS,
16516
16651
  ...DEFINITIONS_UNITS,
16517
16652
  ...DEFINITIONS_OTHERS,
16518
- ...DEFINITIONS_PHYSICS
16653
+ ...DEFINITIONS_PHYSICS,
16654
+ ...DEFINITIONS_COLORS
16519
16655
  ];
16520
16656
 
16521
16657
  // src/math-json/symbols.ts
@@ -16680,6 +16816,17 @@ var ComputeEngine = (() => {
16680
16816
  } else if (Array.isArray(openTrigger) && openTrigger.length > 0) {
16681
16817
  openTokens.push(openTrigger[0]);
16682
16818
  }
16819
+ const closeTrigger = indexedEntry.closeTrigger;
16820
+ const closeTokens = /* @__PURE__ */ new Set();
16821
+ if (typeof closeTrigger === "string") {
16822
+ const variants = DELIMITER_SHORTHAND[closeTrigger];
16823
+ if (variants) for (const v of variants) closeTokens.add(v);
16824
+ else closeTokens.add(closeTrigger);
16825
+ if (closeTrigger === "||") closeTokens.add("|");
16826
+ } else if (Array.isArray(closeTrigger) && closeTrigger.length > 0) {
16827
+ closeTokens.add(closeTrigger[0]);
16828
+ }
16829
+ indexedEntry.closeTokens = closeTokens;
16683
16830
  for (const token of openTokens) {
16684
16831
  const existing = result.matchfixByOpen.get(token);
16685
16832
  if (existing) {
@@ -16871,11 +17018,7 @@ var ComputeEngine = (() => {
16871
17018
  if (style === "scaled")
16872
17019
  return joinLatex([`\\left${openDelim}`, inner, `\\right${closeDelim}`]);
16873
17020
  if (style === "big")
16874
- return joinLatex([
16875
- `\\Bigl${openDelim}`,
16876
- inner,
16877
- `\\Bigr${closeDelim}`
16878
- ]);
17021
+ return joinLatex([`\\Bigl${openDelim}`, inner, `\\Bigr${closeDelim}`]);
16879
17022
  return joinLatex([openDelim, inner, closeDelim]);
16880
17023
  };
16881
17024
  }
@@ -18226,7 +18369,7 @@ var ComputeEngine = (() => {
18226
18369
  }
18227
18370
  if (this.match("\\hskip") || this.match("\\kern")) {
18228
18371
  this.skipSpace();
18229
- this.match("-") || this.match("+");
18372
+ if (!this.match("-")) this.match("+");
18230
18373
  while (/^[\d.]$/.test(this.peek)) this.nextToken();
18231
18374
  for (const unit of [
18232
18375
  "pt",
@@ -18740,6 +18883,19 @@ var ComputeEngine = (() => {
18740
18883
  }
18741
18884
  for (const def of defs) {
18742
18885
  this.index = start;
18886
+ if (def.closeTokens.size > 0) {
18887
+ let found = false;
18888
+ const tokens = this._tokens;
18889
+ for (let i = start; i < tokens.length; i++) {
18890
+ if (def.closeTokens.has(tokens[i])) {
18891
+ found = true;
18892
+ break;
18893
+ }
18894
+ }
18895
+ if (!found) continue;
18896
+ }
18897
+ if (typeof def.openTrigger === "string" && def.openTrigger === "." && !OPEN_DELIMITER_PREFIX[currentToken])
18898
+ continue;
18743
18899
  const matched = this.matchDelimiter(def.openTrigger, def.closeTrigger);
18744
18900
  if (!matched) continue;
18745
18901
  const bodyStart = this.index;
@@ -32302,6 +32458,29 @@ ${lines.join("\n")}`;
32302
32458
  signature: "(value*) -> number | list",
32303
32459
  evaluate: (xs, { engine }) => evaluateMinMax(engine, xs, "Infimum")
32304
32460
  },
32461
+ Distance: {
32462
+ description: "Euclidean distance between two points (tuples of numbers).",
32463
+ complexity: 6e3,
32464
+ signature: "(tuple, tuple) -> number",
32465
+ evaluate: ([a, b], { engine: ce }) => {
32466
+ if (!isFunction2(a) || !isFunction2(b))
32467
+ return ce.error("incompatible-type");
32468
+ if (a.operator !== "Tuple" || b.operator !== "Tuple")
32469
+ return ce.error("incompatible-type");
32470
+ if (a.ops.length !== b.ops.length || a.ops.length === 0)
32471
+ return ce.error("incompatible-type");
32472
+ let sumSq = 0;
32473
+ for (let i = 0; i < a.ops.length; i++) {
32474
+ const ai = a.ops[i].re;
32475
+ const bi = b.ops[i].re;
32476
+ if (!Number.isFinite(ai) || !Number.isFinite(bi))
32477
+ return ce.error("expected-value");
32478
+ const d = ai - bi;
32479
+ sumSq += d * d;
32480
+ }
32481
+ return ce.number(Math.sqrt(sumSq));
32482
+ }
32483
+ },
32305
32484
  Product: {
32306
32485
  description: "`Product(f, a, b)` computes the product of `f` from `a` to `b`",
32307
32486
  wikidata: "Q901718",
@@ -32834,16 +33013,11 @@ ${lines.join("\n")}`;
32834
33013
  );
32835
33014
  let condFn;
32836
33015
  if (typeof condition === "string") {
32837
- const latex = asLatexString(condition);
32838
- if (latex) {
32839
- const condPattern = ce.parse(latex, {
32840
- form: options?.canonical ? "canonical" : "raw"
32841
- }) ?? ce.expr("Nothing");
32842
- condFn = (x, _ce) => {
32843
- const evaluated = condPattern.subs(x).evaluate();
32844
- return isSymbol2(evaluated, "True");
32845
- };
32846
- }
33016
+ const condPattern = ce.parse(condition) ?? ce.expr("Nothing");
33017
+ condFn = (x, _ce) => {
33018
+ const evaluated = condPattern.subs(x).evaluate();
33019
+ return isSymbol2(evaluated, "True");
33020
+ };
32847
33021
  } else {
32848
33022
  if (condition !== void 0 && typeof condition !== "function")
32849
33023
  throw new Error(
@@ -32945,6 +33119,15 @@ ${e.message}
32945
33119
  function applyRule(rule, expr2, substitution, options) {
32946
33120
  if (!rule) return null;
32947
33121
  let canonical2 = options?.canonical ?? (expr2.isCanonical || expr2.isStructural);
33122
+ let { match: match2, replace: replace2, condition, id, onMatch, onBeforeMatch } = rule;
33123
+ const because = id ?? "";
33124
+ const ce = expr2.engine;
33125
+ if (canonical2 && match2) {
33126
+ const awc = getWildcards(match2);
33127
+ const canonicalMatch = match2.canonical;
33128
+ const bwc = getWildcards(canonicalMatch);
33129
+ if (!awc.every((x) => bwc.includes(x))) return null;
33130
+ }
32948
33131
  let operandsMatched = false;
32949
33132
  if (isFunction2(expr2) && options?.recursive) {
32950
33133
  const newOps = expr2.ops.map((op) => {
@@ -32956,20 +33139,11 @@ ${e.message}
32956
33139
  if (operandsMatched) {
32957
33140
  if (!canonical2 && options?.canonical === void 0 && newOps.every((x) => x.isCanonical))
32958
33141
  canonical2 = true;
32959
- expr2 = expr2.engine.function(expr2.operator, newOps, {
33142
+ expr2 = ce.function(expr2.operator, newOps, {
32960
33143
  form: canonical2 ? "canonical" : "raw"
32961
33144
  });
32962
33145
  }
32963
33146
  }
32964
- let { match: match2, replace: replace2, condition, id, onMatch, onBeforeMatch } = rule;
32965
- const because = id ?? "";
32966
- if (canonical2 && match2) {
32967
- const awc = getWildcards(match2);
32968
- const canonicalMatch = match2.canonical;
32969
- const bwc = getWildcards(canonicalMatch);
32970
- if (!awc.every((x) => bwc.includes(x)))
32971
- return operandsMatched ? { value: expr2, because } : null;
32972
- }
32973
33147
  const useVariations = rule.useVariations ?? options?.useVariations ?? false;
32974
33148
  const matchPermutations = options?.matchPermutations ?? true;
32975
33149
  onBeforeMatch?.(rule, expr2);
@@ -32988,7 +33162,7 @@ ${e.message}
32988
33162
  ...sub2
32989
33163
  };
32990
33164
  try {
32991
- if (!condition(conditionSub, expr2.engine))
33165
+ if (!condition(conditionSub, ce))
32992
33166
  return operandsMatched ? { value: expr2, because } : null;
32993
33167
  } catch (e) {
32994
33168
  console.error(
@@ -33003,7 +33177,8 @@ ${e.message}
33003
33177
  if (!canonical2 && options?.canonical === void 0 && replace2 instanceof _BoxedExpression && replace2.isCanonical)
33004
33178
  canonical2 = true;
33005
33179
  const result = typeof replace2 === "function" ? replace2(expr2, sub2) : replace2.subs(sub2, { canonical: canonical2 });
33006
- if (!result) return null;
33180
+ if (!result)
33181
+ return operandsMatched ? { value: canonical2 ? expr2.canonical : expr2, because } : null;
33007
33182
  onMatch?.(rule, expr2, result);
33008
33183
  if (isRuleStep(result))
33009
33184
  return canonical2 ? { ...result, value: result.value.canonical } : result;
@@ -38577,6 +38752,40 @@ ${e.message}
38577
38752
  else h = ((r - g) / d + 4) / 6;
38578
38753
  return { h: h * 360, s, l };
38579
38754
  }
38755
+ function hsvToRgb(h, s, v) {
38756
+ h = (h % 360 + 360) % 360;
38757
+ s = Math.max(0, Math.min(1, s));
38758
+ v = Math.max(0, Math.min(1, v));
38759
+ const c = v * s;
38760
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
38761
+ const m = v - c;
38762
+ let r = 0, g = 0, b = 0;
38763
+ if (h < 60) [r, g, b] = [c, x, 0];
38764
+ else if (h < 120) [r, g, b] = [x, c, 0];
38765
+ else if (h < 180) [r, g, b] = [0, c, x];
38766
+ else if (h < 240) [r, g, b] = [0, x, c];
38767
+ else if (h < 300) [r, g, b] = [x, 0, c];
38768
+ else [r, g, b] = [c, 0, x];
38769
+ return { r: (r + m) * 255, g: (g + m) * 255, b: (b + m) * 255 };
38770
+ }
38771
+ function rgbToHsv(r, g, b) {
38772
+ r /= 255;
38773
+ g /= 255;
38774
+ b /= 255;
38775
+ const max2 = Math.max(r, g, b);
38776
+ const min2 = Math.min(r, g, b);
38777
+ const d = max2 - min2;
38778
+ let h = 0;
38779
+ if (d > 0) {
38780
+ if (max2 === r) h = (g - b) / d % 6;
38781
+ else if (max2 === g) h = (b - r) / d + 2;
38782
+ else h = (r - g) / d + 4;
38783
+ h *= 60;
38784
+ if (h < 0) h += 360;
38785
+ }
38786
+ const s = max2 === 0 ? 0 : d / max2;
38787
+ return { h, s, v: max2 };
38788
+ }
38580
38789
  function parseHexColor(s) {
38581
38790
  const hex = s.startsWith("#") ? s.substring(1) : s;
38582
38791
  let r, g, b;
@@ -38601,6 +38810,12 @@ ${e.message}
38601
38810
  if (alpha !== void 0) result.alpha = alpha;
38602
38811
  return result;
38603
38812
  }
38813
+ function asOklch(color) {
38814
+ if (typeof color === "string") return rgbToOklch(parseHexColor(color));
38815
+ if ("C" in color) return color;
38816
+ if ("a" in color && "b" in color) return oklabToOklch(color);
38817
+ return rgbToOklch(color);
38818
+ }
38604
38819
  function asRgb(color) {
38605
38820
  if (typeof color === "number") {
38606
38821
  return {
@@ -39032,6 +39247,13 @@ ${e.message}
39032
39247
  };
39033
39248
  function parseColor(s, darkMode) {
39034
39249
  const str = s.trim().toLowerCase();
39250
+ const opacityMatch = str.match(/^(.+?)\s*\/\s*(\d+(?:\.\d+)?)%?\s*$/);
39251
+ if (opacityMatch) {
39252
+ const base = parseColor(opacityMatch[1].trim(), darkMode);
39253
+ const opacity = Math.max(0, Math.min(100, parseFloat(opacityMatch[2])));
39254
+ const alpha = Math.round(opacity / 100 * 255);
39255
+ return base & 4294967040 | alpha;
39256
+ }
39035
39257
  if (str.startsWith("#")) {
39036
39258
  const hex = str.substring(1);
39037
39259
  let r, g, b, a = 255;
@@ -39164,14 +39386,6 @@ ${e.message}
39164
39386
  console.warn(`parseColor: unrecognized color "${s}"`);
39165
39387
  return 0;
39166
39388
  }
39167
- function parseColorToRgb01(s, darkMode) {
39168
- const color = parseColor(s, darkMode);
39169
- return [
39170
- (color >>> 24 & 255) / 255,
39171
- (color >>> 16 & 255) / 255,
39172
- (color >>> 8 & 255) / 255
39173
- ];
39174
- }
39175
39389
  function apca(bgColor, fgColor) {
39176
39390
  const bgRgb = asRgb(bgColor);
39177
39391
  const fgRgb = asRgb(fgColor);
@@ -39230,6 +39444,12 @@ ${e.message}
39230
39444
  const contrast2 = Math.abs(apca(fg2, bg));
39231
39445
  return contrast1 >= contrast2 ? asColorNumber(fg1) : asColorNumber(fg2);
39232
39446
  }
39447
+ function oklabDeltaE(a, b) {
39448
+ const dL = a.L - b.L;
39449
+ const da = a.a - b.a;
39450
+ const db = a.b - b.b;
39451
+ return Math.sqrt(dL * dL + da * da + db * db);
39452
+ }
39233
39453
  function lerpOklch(c1, c2, f) {
39234
39454
  const L = c1.L + (c2.L - c1.L) * f;
39235
39455
  const C = c1.C + (c2.C - c1.C) * f;
@@ -41991,14 +42211,30 @@ ${e.message}
41991
42211
  };
41992
42212
 
41993
42213
  // src/compute-engine/library/colors.ts
41994
- function colorNumberToTuple(ce, color) {
41995
- const r = (color >>> 24 & 255) / 255;
41996
- const g = (color >>> 16 & 255) / 255;
41997
- const b = (color >>> 8 & 255) / 255;
41998
- const a = (color & 255) / 255;
41999
- if (Math.abs(a - 1) < 1e-4)
42000
- return ce.tuple(ce.number(r), ce.number(g), ce.number(b));
42001
- return ce.tuple(ce.number(r), ce.number(g), ce.number(b), ce.number(a));
42214
+ function normalizeAlpha(a) {
42215
+ if (a === void 0) return void 0;
42216
+ if (!Number.isFinite(a)) return void 0;
42217
+ if (Math.abs(a - 1) < 1e-9) return void 0;
42218
+ return a;
42219
+ }
42220
+ function normalizeColorHead(ce, expr2) {
42221
+ if (!isFunction2(expr2) || !expr2.ops || expr2.ops.length < 4) return expr2;
42222
+ const alphaExpr = expr2.ops[3];
42223
+ if (!isNumber(alphaExpr)) return expr2;
42224
+ if (normalizeAlpha(alphaExpr.re) === void 0) {
42225
+ return ce.function(expr2.operator, [expr2.ops[0], expr2.ops[1], expr2.ops[2]]);
42226
+ }
42227
+ return expr2;
42228
+ }
42229
+ function colorNumberToOklch(ce, color) {
42230
+ const r = color >>> 24 & 255;
42231
+ const g = color >>> 16 & 255;
42232
+ const b = color >>> 8 & 255;
42233
+ const a = normalizeAlpha((color & 255) / 255);
42234
+ const c = rgbToOklch({ r, g, b });
42235
+ const args = [ce.number(c.L), ce.number(c.C), ce.number(c.H)];
42236
+ if (a !== void 0) args.push(ce.number(a));
42237
+ return ce.function("Oklch", args);
42002
42238
  }
42003
42239
  var ALL_PALETTES = {
42004
42240
  ...SEQUENTIAL_PALETTES,
@@ -42009,45 +42245,139 @@ ${e.message}
42009
42245
  t = Math.max(0, Math.min(1, t));
42010
42246
  const n = palette.length;
42011
42247
  if (n === 0) return ce.error("expected-value");
42012
- if (n === 1) return colorNumberToTuple(ce, parseColor(palette[0]));
42248
+ if (n === 1) return colorNumberToOklch(ce, parseColor(palette[0]));
42013
42249
  const pos = t * (n - 1);
42014
42250
  const i = Math.floor(pos);
42015
42251
  const frac = pos - i;
42016
- if (i >= n - 1) return colorNumberToTuple(ce, parseColor(palette[n - 1]));
42017
- if (frac < 1e-9) return colorNumberToTuple(ce, parseColor(palette[i]));
42018
- const rgb = interpolateOklch(palette[i], palette[i + 1], frac);
42019
- const r = rgb.r / 255;
42020
- const g = rgb.g / 255;
42021
- const b = rgb.b / 255;
42022
- return ce.tuple(ce.number(r), ce.number(g), ce.number(b));
42252
+ if (i >= n - 1) return colorNumberToOklch(ce, parseColor(palette[n - 1]));
42253
+ if (frac < 1e-9) return colorNumberToOklch(ce, parseColor(palette[i]));
42254
+ return oklchToExpr(
42255
+ ce,
42256
+ asOklch(interpolateOklch(palette[i], palette[i + 1], frac))
42257
+ );
42258
+ }
42259
+ var COLOR_OPERATORS = /* @__PURE__ */ new Set(["Rgb", "Hsv", "Hsl", "Oklab", "Oklch"]);
42260
+ function readColorExpr(arg) {
42261
+ if (!isFunction2(arg)) return null;
42262
+ if (!COLOR_OPERATORS.has(arg.operator)) return null;
42263
+ if (!arg.ops || arg.ops.length < 3) return null;
42264
+ const c0 = arg.ops[0].re;
42265
+ const c1 = arg.ops[1].re;
42266
+ const c2 = arg.ops[2].re;
42267
+ if (!Number.isFinite(c0) || !Number.isFinite(c1) || !Number.isFinite(c2))
42268
+ return null;
42269
+ const alpha = arg.ops.length >= 4 ? normalizeAlpha(arg.ops[3].re) : void 0;
42270
+ return { space: arg.operator, c0, c1, c2, alpha };
42271
+ }
42272
+ function colorExprToRgb(arg) {
42273
+ const c = readColorExpr(arg);
42274
+ if (!c) return null;
42275
+ const withAlpha = (rgb) => c.alpha !== void 0 ? { ...rgb, alpha: c.alpha } : rgb;
42276
+ switch (c.space) {
42277
+ case "Rgb":
42278
+ return withAlpha({ r: c.c0 * 255, g: c.c1 * 255, b: c.c2 * 255 });
42279
+ case "Hsv":
42280
+ return withAlpha(hsvToRgb(c.c0, c.c1, c.c2));
42281
+ case "Hsl":
42282
+ return withAlpha(hslToRgb(c.c0, c.c1, c.c2));
42283
+ case "Oklab":
42284
+ return withAlpha(oklabToRgb({ L: c.c0, a: c.c1, b: c.c2 }));
42285
+ case "Oklch":
42286
+ return withAlpha(oklchToRgb({ L: c.c0, C: c.c1, H: c.c2 }));
42287
+ }
42288
+ return null;
42289
+ }
42290
+ function colorExprToOklch(arg) {
42291
+ const c = readColorExpr(arg);
42292
+ if (!c) return null;
42293
+ switch (c.space) {
42294
+ case "Oklch":
42295
+ return asOklch({ L: c.c0, C: c.c1, H: c.c2, alpha: c.alpha });
42296
+ case "Oklab":
42297
+ return asOklch({ L: c.c0, a: c.c1, b: c.c2, alpha: c.alpha });
42298
+ case "Rgb":
42299
+ return asOklch({
42300
+ r: c.c0 * 255,
42301
+ g: c.c1 * 255,
42302
+ b: c.c2 * 255,
42303
+ alpha: c.alpha
42304
+ });
42305
+ case "Hsv": {
42306
+ const rgb = hsvToRgb(c.c0, c.c1, c.c2);
42307
+ return asOklch({ ...rgb, alpha: c.alpha });
42308
+ }
42309
+ case "Hsl": {
42310
+ const rgb = hslToRgb(c.c0, c.c1, c.c2);
42311
+ return asOklch({ r: rgb.r, g: rgb.g, b: rgb.b, alpha: c.alpha });
42312
+ }
42313
+ }
42314
+ return null;
42315
+ }
42316
+ function toOklch(ce, arg) {
42317
+ const direct = colorExprToOklch(arg);
42318
+ if (direct) return direct;
42319
+ const rgb = extractRgb(ce, arg);
42320
+ return rgb ? asOklch(rgb) : null;
42321
+ }
42322
+ function lerpOklchColor(a, b, t) {
42323
+ const L = a.L + (b.L - a.L) * t;
42324
+ const C = a.C + (b.C - a.C) * t;
42325
+ const aAchromatic = a.C < 1e-6;
42326
+ const bAchromatic = b.C < 1e-6;
42327
+ let H;
42328
+ if (aAchromatic && bAchromatic) H = a.H;
42329
+ else if (aAchromatic) H = b.H;
42330
+ else if (bAchromatic) H = a.H;
42331
+ else {
42332
+ let dH = b.H - a.H;
42333
+ if (dH > 180) dH -= 360;
42334
+ if (dH < -180) dH += 360;
42335
+ H = a.H + dH * t;
42336
+ if (H < 0) H += 360;
42337
+ if (H >= 360) H -= 360;
42338
+ }
42339
+ const alphaA = a.alpha ?? 1;
42340
+ const alphaB = b.alpha ?? 1;
42341
+ return { L, C, H, alpha: normalizeAlpha(alphaA + (alphaB - alphaA) * t) };
42342
+ }
42343
+ function oklchToExpr(ce, c) {
42344
+ const args = [ce.number(c.L), ce.number(c.C), ce.number(c.H)];
42345
+ if (c.alpha !== void 0) args.push(ce.number(c.alpha));
42346
+ return ce.function("Oklch", args);
42023
42347
  }
42024
42348
  function extractRgb(ce, arg) {
42025
42349
  if (isString(arg)) {
42026
42350
  const s = arg.string;
42027
42351
  if (!s) return void 0;
42028
42352
  const color = parseColor(s);
42029
- return {
42353
+ const rgb = {
42030
42354
  r: color >>> 24 & 255,
42031
42355
  g: color >>> 16 & 255,
42032
- b: color >>> 8 & 255,
42033
- alpha: (color & 255) / 255
42356
+ b: color >>> 8 & 255
42034
42357
  };
42358
+ const alpha = normalizeAlpha((color & 255) / 255);
42359
+ if (alpha !== void 0) rgb.alpha = alpha;
42360
+ return rgb;
42035
42361
  }
42362
+ const fromTyped = colorExprToRgb(arg);
42363
+ if (fromTyped) return fromTyped;
42036
42364
  if (arg.operator === "Tuple" && arg.ops && arg.ops.length >= 3) {
42037
42365
  const rgb = {
42038
42366
  r: arg.ops[0].re * 255,
42039
42367
  g: arg.ops[1].re * 255,
42040
42368
  b: arg.ops[2].re * 255
42041
42369
  };
42042
- if (arg.ops.length >= 4) rgb.alpha = arg.ops[3].re;
42370
+ if (arg.ops.length >= 4) {
42371
+ const alpha = normalizeAlpha(arg.ops[3].re);
42372
+ if (alpha !== void 0) rgb.alpha = alpha;
42373
+ }
42043
42374
  return rgb;
42044
42375
  }
42045
42376
  return void 0;
42046
42377
  }
42047
42378
  function componentsTuple(ce, components, alpha) {
42048
42379
  const args = components.map((v) => ce.number(v));
42049
- if (alpha !== void 0 && Math.abs(alpha - 1) > 1e-4)
42050
- args.push(ce.number(alpha));
42380
+ if (alpha !== void 0) args.push(ce.number(alpha));
42051
42381
  return ce.tuple(...args);
42052
42382
  }
42053
42383
  function rgbToHex(rgb) {
@@ -42055,7 +42385,7 @@ ${e.message}
42055
42385
  const g = Math.round(Math.max(0, Math.min(255, rgb.g)));
42056
42386
  const b = Math.round(Math.max(0, Math.min(255, rgb.b)));
42057
42387
  const hex = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
42058
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4) {
42388
+ if (rgb.alpha !== void 0) {
42059
42389
  const a = Math.round(Math.max(0, Math.min(255, rgb.alpha * 255)));
42060
42390
  return hex + a.toString(16).padStart(2, "0");
42061
42391
  }
@@ -42063,22 +42393,29 @@ ${e.message}
42063
42393
  }
42064
42394
  var COLORS_LIBRARY = {
42065
42395
  Color: {
42066
- description: "Convert a color string to a canonical sRGB tuple",
42396
+ description: "Parse a CSS-style color string to an Oklch color",
42067
42397
  complexity: 8e3,
42068
- signature: "(string) -> tuple",
42398
+ signature: "(string) -> color",
42069
42399
  evaluate: (ops, { engine: ce }) => {
42070
42400
  const input = isString(ops[0]) ? ops[0].string : void 0;
42071
42401
  if (!input) return ce.error("incompatible-type");
42072
42402
  const color = parseColor(input);
42073
42403
  if (color === 0 && input.trim().toLowerCase() !== "transparent")
42074
42404
  return ce.error("incompatible-type");
42075
- return colorNumberToTuple(ce, color);
42405
+ const r = color >>> 24 & 255;
42406
+ const g = color >>> 16 & 255;
42407
+ const b = color >>> 8 & 255;
42408
+ const a = normalizeAlpha((color & 255) / 255);
42409
+ const c = rgbToOklch({ r, g, b });
42410
+ const args = [ce.number(c.L), ce.number(c.C), ce.number(c.H)];
42411
+ if (a !== void 0) args.push(ce.number(a));
42412
+ return ce.function("Oklch", args);
42076
42413
  }
42077
42414
  },
42078
42415
  ColorToString: {
42079
42416
  description: "Convert a color to a string in the specified format",
42080
42417
  complexity: 8e3,
42081
- signature: "(any, string?) -> string",
42418
+ signature: "(color | string | tuple, string?) -> string",
42082
42419
  evaluate: (ops, { engine: ce }) => {
42083
42420
  const rgb = extractRgb(ce, ops[0]);
42084
42421
  if (!rgb) return ce.error("incompatible-type");
@@ -42090,7 +42427,7 @@ ${e.message}
42090
42427
  const r = Math.round(rgb.r);
42091
42428
  const g = Math.round(rgb.g);
42092
42429
  const b = Math.round(rgb.b);
42093
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
42430
+ if (rgb.alpha !== void 0)
42094
42431
  return ce.string(`rgb(${r} ${g} ${b} / ${rgb.alpha})`);
42095
42432
  return ce.string(`rgb(${r} ${g} ${b})`);
42096
42433
  }
@@ -42099,17 +42436,17 @@ ${e.message}
42099
42436
  const h = Math.round(hsl.h * 10) / 10;
42100
42437
  const s = Math.round(hsl.s * 1e3) / 10;
42101
42438
  const l = Math.round(hsl.l * 1e3) / 10;
42102
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
42439
+ if (rgb.alpha !== void 0)
42103
42440
  return ce.string(`hsl(${h} ${s}% ${l}% / ${rgb.alpha})`);
42104
42441
  return ce.string(`hsl(${h} ${s}% ${l}%)`);
42105
42442
  }
42106
42443
  case "oklch": {
42107
- const c = rgbToOklch(rgb);
42444
+ const c = colorExprToOklch(ops[0]) ?? asOklch(rgb);
42108
42445
  const L = Math.round(c.L * 1e3) / 1e3;
42109
42446
  const C = Math.round(c.C * 1e3) / 1e3;
42110
42447
  const H = Math.round(c.H * 10) / 10;
42111
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
42112
- return ce.string(`oklch(${L} ${C} ${H} / ${rgb.alpha})`);
42448
+ if (c.alpha !== void 0)
42449
+ return ce.string(`oklch(${L} ${C} ${H} / ${c.alpha})`);
42113
42450
  return ce.string(`oklch(${L} ${C} ${H})`);
42114
42451
  }
42115
42452
  default:
@@ -42120,60 +42457,44 @@ ${e.message}
42120
42457
  ColorMix: {
42121
42458
  description: "Mix two colors in OKLCh space",
42122
42459
  complexity: 8e3,
42123
- signature: "(any, any, number?) -> tuple",
42460
+ signature: "(color | string | tuple, color | string | tuple, number?) -> color",
42124
42461
  evaluate: (ops, { engine: ce }) => {
42125
- const rgb1 = extractRgb(ce, ops[0]);
42126
- const rgb2 = extractRgb(ce, ops[1]);
42127
- if (!rgb1 || !rgb2) return ce.error("incompatible-type");
42128
42462
  let ratio = 0.5;
42129
42463
  if (ops.length >= 3 && ops[2] !== void 0) {
42130
42464
  ratio = ops[2].re;
42131
42465
  if (!Number.isFinite(ratio)) return ce.error("expected-value");
42132
42466
  ratio = Math.max(0, Math.min(1, ratio));
42133
42467
  }
42134
- const c1 = rgbToOklch(rgb1);
42135
- const c2 = rgbToOklch(rgb2);
42136
- const mixed = oklchToRgb(lerpOklch(c1, c2, ratio));
42137
- const r = mixed.r / 255;
42138
- const g = mixed.g / 255;
42139
- const b = mixed.b / 255;
42140
- const a1 = rgb1.alpha ?? 1;
42141
- const a2 = rgb2.alpha ?? 1;
42142
- const alpha = a1 + (a2 - a1) * ratio;
42143
- if (Math.abs(alpha - 1) > 1e-4)
42144
- return ce.tuple(
42145
- ce.number(r),
42146
- ce.number(g),
42147
- ce.number(b),
42148
- ce.number(alpha)
42149
- );
42150
- return ce.tuple(ce.number(r), ce.number(g), ce.number(b));
42468
+ const oklch1 = toOklch(ce, ops[0]);
42469
+ const oklch2 = toOklch(ce, ops[1]);
42470
+ if (!oklch1 || !oklch2) return ce.error("incompatible-type");
42471
+ return oklchToExpr(ce, lerpOklchColor(oklch1, oklch2, ratio));
42151
42472
  }
42152
42473
  },
42153
42474
  Colormap: {
42154
42475
  description: "Sample colors from a named palette",
42155
42476
  complexity: 8e3,
42156
- signature: "(string, number?) -> any",
42477
+ signature: "(string, number?) -> color | list<color>",
42157
42478
  evaluate: (ops, { engine: ce }) => {
42158
42479
  const name = isString(ops[0]) ? ops[0].string : void 0;
42159
42480
  if (!name) return ce.error("incompatible-type");
42160
42481
  const palette = ALL_PALETTES[name];
42161
42482
  if (!palette) return ce.error("expected-value", name);
42162
42483
  if (ops.length < 2 || ops[1] === void 0) {
42163
- const tuples = palette.map(
42164
- (hex) => colorNumberToTuple(ce, parseColor(hex))
42484
+ const colors = palette.map(
42485
+ (hex) => colorNumberToOklch(ce, parseColor(hex))
42165
42486
  );
42166
- return ce.function("List", tuples);
42487
+ return ce.function("List", colors);
42167
42488
  }
42168
42489
  const val = ops[1].re;
42169
42490
  if (!Number.isFinite(val)) return ce.error("expected-value");
42170
42491
  if (Number.isInteger(val) && val >= 2) {
42171
42492
  const n = val;
42172
- const tuples = [];
42493
+ const colors = [];
42173
42494
  for (let i = 0; i < n; i++) {
42174
- tuples.push(samplePalette(ce, palette, i / (n - 1)));
42495
+ colors.push(samplePalette(ce, palette, i / (n - 1)));
42175
42496
  }
42176
- return ce.function("List", tuples);
42497
+ return ce.function("List", colors);
42177
42498
  }
42178
42499
  return samplePalette(ce, palette, val);
42179
42500
  }
@@ -42181,12 +42502,25 @@ ${e.message}
42181
42502
  ColorToColorspace: {
42182
42503
  description: "Convert a color to components in a target color space",
42183
42504
  complexity: 8e3,
42184
- signature: "(any, string) -> tuple",
42505
+ signature: "(color | string | tuple, string) -> tuple",
42185
42506
  evaluate: (ops, { engine: ce }) => {
42186
- const rgb = extractRgb(ce, ops[0]);
42187
- if (!rgb) return ce.error("incompatible-type");
42188
42507
  const space = isString(ops[1]) ? ops[1].string?.toLowerCase() : void 0;
42189
42508
  if (!space) return ce.error("incompatible-type");
42509
+ if (space === "oklch" || space === "oklab" || space === "lab") {
42510
+ const oklch2 = colorExprToOklch(ops[0]);
42511
+ if (oklch2) {
42512
+ if (space === "oklch")
42513
+ return componentsTuple(
42514
+ ce,
42515
+ [oklch2.L, oklch2.C, oklch2.H],
42516
+ oklch2.alpha
42517
+ );
42518
+ const lab = oklchToOklab(oklch2);
42519
+ return componentsTuple(ce, [lab.L, lab.a, lab.b], lab.alpha);
42520
+ }
42521
+ }
42522
+ const rgb = extractRgb(ce, ops[0]);
42523
+ if (!rgb) return ce.error("incompatible-type");
42190
42524
  const alpha = rgb.alpha;
42191
42525
  switch (space) {
42192
42526
  case "rgb":
@@ -42216,17 +42550,27 @@ ${e.message}
42216
42550
  ColorFromColorspace: {
42217
42551
  description: "Convert color space components to a canonical sRGB tuple",
42218
42552
  complexity: 8e3,
42219
- signature: "(tuple, string) -> tuple",
42553
+ signature: "(color | tuple, string) -> tuple",
42220
42554
  evaluate: (ops, { engine: ce }) => {
42221
- const tuple = ops[0];
42222
- if (!isFunction2(tuple) || tuple.operator !== "Tuple" || tuple.ops.length < 3)
42223
- return ce.error("incompatible-type");
42224
- const c0 = tuple.ops[0].re;
42225
- const c1 = tuple.ops[1].re;
42226
- const c2 = tuple.ops[2].re;
42227
- const alpha = tuple.ops.length >= 4 ? tuple.ops[3].re : void 0;
42228
42555
  const space = isString(ops[1]) ? ops[1].string?.toLowerCase() : void 0;
42229
42556
  if (!space) return ce.error("incompatible-type");
42557
+ let c0, c1, c2;
42558
+ let alpha;
42559
+ const arg = ops[0];
42560
+ const typed = readColorExpr(arg);
42561
+ if (typed) {
42562
+ c0 = typed.c0;
42563
+ c1 = typed.c1;
42564
+ c2 = typed.c2;
42565
+ alpha = typed.alpha;
42566
+ } else if (isFunction2(arg) && arg.operator === "Tuple" && arg.ops.length >= 3) {
42567
+ c0 = arg.ops[0].re;
42568
+ c1 = arg.ops[1].re;
42569
+ c2 = arg.ops[2].re;
42570
+ alpha = arg.ops.length >= 4 ? arg.ops[3].re : void 0;
42571
+ } else {
42572
+ return ce.error("incompatible-type");
42573
+ }
42230
42574
  let rgb;
42231
42575
  switch (space) {
42232
42576
  case "rgb":
@@ -42262,7 +42606,7 @@ ${e.message}
42262
42606
  ColorContrast: {
42263
42607
  description: "APCA contrast ratio between two colors",
42264
42608
  complexity: 8e3,
42265
- signature: "(any, any) -> number",
42609
+ signature: "(color | string | tuple, color | string | tuple) -> number",
42266
42610
  evaluate: (ops, { engine: ce }) => {
42267
42611
  const bgRgb = extractRgb(ce, ops[0]);
42268
42612
  const fgRgb = extractRgb(ce, ops[1]);
@@ -42273,19 +42617,186 @@ ${e.message}
42273
42617
  ContrastingColor: {
42274
42618
  description: "Choose the foreground color with better APCA contrast against a background",
42275
42619
  complexity: 8e3,
42276
- signature: "(any, any?, any?) -> tuple",
42620
+ signature: "(color | string | tuple, (color | string | tuple)?, (color | string | tuple)?) -> color",
42277
42621
  evaluate: (ops, { engine: ce }) => {
42278
42622
  const bgRgb = extractRgb(ce, ops[0]);
42279
42623
  if (!bgRgb) return ce.error("incompatible-type");
42624
+ let packed;
42280
42625
  if (ops.length >= 3 && ops[1] !== void 0 && ops[2] !== void 0) {
42281
42626
  const fg1 = extractRgb(ce, ops[1]);
42282
42627
  const fg2 = extractRgb(ce, ops[2]);
42283
42628
  if (!fg1 || !fg2) return ce.error("incompatible-type");
42284
- const result2 = contrastingColor({ bg: bgRgb, fg1, fg2 });
42285
- return colorNumberToTuple(ce, result2);
42629
+ packed = contrastingColor({ bg: bgRgb, fg1, fg2 });
42630
+ } else {
42631
+ packed = contrastingColor(bgRgb);
42632
+ }
42633
+ const r = (packed >>> 24 & 255) / 255;
42634
+ const g = (packed >>> 16 & 255) / 255;
42635
+ const b = (packed >>> 8 & 255) / 255;
42636
+ const alpha = normalizeAlpha((packed & 255) / 255);
42637
+ const args = [ce.number(r), ce.number(g), ce.number(b)];
42638
+ if (alpha !== void 0) args.push(ce.number(alpha));
42639
+ return ce.function("Rgb", args);
42640
+ }
42641
+ },
42642
+ // ---------------------------------------------------------------------------
42643
+ // Color constructors. Each preserves its colorspace on evaluation; the
42644
+ // operator name is the discriminator. Components are interpreted per
42645
+ // colorspace conventions (Rgb channels 0-1, Hsv/Hsl hue in degrees with
42646
+ // sat/value 0-1, Oklab/Oklch L 0-1 with standard a/b/C/H ranges). The
42647
+ // optional 4th argument is alpha in [0, 1]. No clamping at evaluation time.
42648
+ // ---------------------------------------------------------------------------
42649
+ Rgb: {
42650
+ description: "sRGB color (channels 0-1, optional alpha 0-1)",
42651
+ complexity: 8e3,
42652
+ signature: "(number, number, number, number?) -> color"
42653
+ },
42654
+ Hsv: {
42655
+ description: "HSV color (hue degrees, saturation/value 0-1, optional alpha)",
42656
+ complexity: 8e3,
42657
+ signature: "(number, number, number, number?) -> color"
42658
+ },
42659
+ Hsl: {
42660
+ description: "HSL color (hue degrees, saturation/lightness 0-1, optional alpha)",
42661
+ complexity: 8e3,
42662
+ signature: "(number, number, number, number?) -> color"
42663
+ },
42664
+ Oklab: {
42665
+ description: "OKLab color (L 0-1, a/b ~ -0.4..0.4, optional alpha)",
42666
+ complexity: 8e3,
42667
+ signature: "(number, number, number, number?) -> color"
42668
+ },
42669
+ Oklch: {
42670
+ description: "OKLCh color (L 0-1, C 0-~0.4, hue degrees, optional alpha)",
42671
+ complexity: 8e3,
42672
+ signature: "(number, number, number, number?) -> color"
42673
+ },
42674
+ // ---------------------------------------------------------------------------
42675
+ // Color-space conversions. Each accepts any of the five color heads and
42676
+ // returns the same color in the named space. If the input is already in
42677
+ // the target space, returns the input unchanged.
42678
+ // ---------------------------------------------------------------------------
42679
+ AsRgb: {
42680
+ description: "Convert any color to sRGB (channels 0-1)",
42681
+ complexity: 8e3,
42682
+ signature: "(color) -> color",
42683
+ evaluate: (ops, { engine: ce }) => {
42684
+ const arg = ops[0];
42685
+ if (isFunction2(arg) && arg.operator === "Rgb")
42686
+ return normalizeColorHead(ce, arg);
42687
+ const rgb = colorExprToRgb(arg);
42688
+ if (!rgb) return ce.error("incompatible-type");
42689
+ const args = [
42690
+ ce.number(rgb.r / 255),
42691
+ ce.number(rgb.g / 255),
42692
+ ce.number(rgb.b / 255)
42693
+ ];
42694
+ if (rgb.alpha !== void 0) args.push(ce.number(rgb.alpha));
42695
+ return ce.function("Rgb", args);
42696
+ }
42697
+ },
42698
+ AsHsv: {
42699
+ description: "Convert any color to HSV (hue degrees, s/v 0-1)",
42700
+ complexity: 8e3,
42701
+ signature: "(color) -> color",
42702
+ evaluate: (ops, { engine: ce }) => {
42703
+ const arg = ops[0];
42704
+ if (isFunction2(arg) && arg.operator === "Hsv")
42705
+ return normalizeColorHead(ce, arg);
42706
+ const rgb = colorExprToRgb(arg);
42707
+ if (!rgb) return ce.error("incompatible-type");
42708
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
42709
+ const args = [ce.number(hsv.h), ce.number(hsv.s), ce.number(hsv.v)];
42710
+ if (rgb.alpha !== void 0) args.push(ce.number(rgb.alpha));
42711
+ return ce.function("Hsv", args);
42712
+ }
42713
+ },
42714
+ AsHsl: {
42715
+ description: "Convert any color to HSL (hue degrees, s/l 0-1)",
42716
+ complexity: 8e3,
42717
+ signature: "(color) -> color",
42718
+ evaluate: (ops, { engine: ce }) => {
42719
+ const arg = ops[0];
42720
+ if (isFunction2(arg) && arg.operator === "Hsl")
42721
+ return normalizeColorHead(ce, arg);
42722
+ const rgb = colorExprToRgb(arg);
42723
+ if (!rgb) return ce.error("incompatible-type");
42724
+ const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
42725
+ const args = [ce.number(hsl.h), ce.number(hsl.s), ce.number(hsl.l)];
42726
+ if (rgb.alpha !== void 0) args.push(ce.number(rgb.alpha));
42727
+ return ce.function("Hsl", args);
42728
+ }
42729
+ },
42730
+ AsOklab: {
42731
+ description: "Convert any color to OKLab",
42732
+ complexity: 8e3,
42733
+ signature: "(color) -> color",
42734
+ evaluate: (ops, { engine: ce }) => {
42735
+ const arg = ops[0];
42736
+ if (isFunction2(arg) && arg.operator === "Oklab")
42737
+ return normalizeColorHead(ce, arg);
42738
+ if (isFunction2(arg) && arg.operator === "Oklch") {
42739
+ const c = readColorExpr(arg);
42740
+ if (!c) return ce.error("incompatible-type");
42741
+ const lab2 = oklchToOklab({ L: c.c0, C: c.c1, H: c.c2, alpha: c.alpha });
42742
+ const args2 = [ce.number(lab2.L), ce.number(lab2.a), ce.number(lab2.b)];
42743
+ if (lab2.alpha !== void 0) args2.push(ce.number(lab2.alpha));
42744
+ return ce.function("Oklab", args2);
42745
+ }
42746
+ const rgb = colorExprToRgb(arg);
42747
+ if (!rgb) return ce.error("incompatible-type");
42748
+ const lab = rgbToOklab(rgb);
42749
+ const args = [ce.number(lab.L), ce.number(lab.a), ce.number(lab.b)];
42750
+ if (rgb.alpha !== void 0) args.push(ce.number(rgb.alpha));
42751
+ return ce.function("Oklab", args);
42752
+ }
42753
+ },
42754
+ AsOklch: {
42755
+ description: "Convert any color to OKLCh",
42756
+ complexity: 8e3,
42757
+ signature: "(color) -> color",
42758
+ evaluate: (ops, { engine: ce }) => {
42759
+ const arg = ops[0];
42760
+ if (isFunction2(arg) && arg.operator === "Oklch")
42761
+ return normalizeColorHead(ce, arg);
42762
+ if (isFunction2(arg) && arg.operator === "Oklab") {
42763
+ const c2 = readColorExpr(arg);
42764
+ if (!c2) return ce.error("incompatible-type");
42765
+ const oklch2 = oklabToOklch({
42766
+ L: c2.c0,
42767
+ a: c2.c1,
42768
+ b: c2.c2,
42769
+ alpha: c2.alpha
42770
+ });
42771
+ const args2 = [
42772
+ ce.number(oklch2.L),
42773
+ ce.number(oklch2.C),
42774
+ ce.number(oklch2.H)
42775
+ ];
42776
+ if (oklch2.alpha !== void 0) args2.push(ce.number(oklch2.alpha));
42777
+ return ce.function("Oklch", args2);
42286
42778
  }
42287
- const result = contrastingColor(bgRgb);
42288
- return colorNumberToTuple(ce, result);
42779
+ const rgb = colorExprToRgb(arg);
42780
+ if (!rgb) return ce.error("incompatible-type");
42781
+ const c = rgbToOklch(rgb);
42782
+ const args = [ce.number(c.L), ce.number(c.C), ce.number(c.H)];
42783
+ if (rgb.alpha !== void 0) args.push(ce.number(rgb.alpha));
42784
+ return ce.function("Oklch", args);
42785
+ }
42786
+ },
42787
+ // ---------------------------------------------------------------------------
42788
+ // Perceptual difference. Returns ΔE_OK (Euclidean distance in OKLab),
42789
+ // an approximately perceptually uniform scalar.
42790
+ // ---------------------------------------------------------------------------
42791
+ ColorDelta: {
42792
+ description: "Perceptual color difference (\u0394E_OK) between two colors",
42793
+ complexity: 8e3,
42794
+ signature: "(color | string | tuple, color | string | tuple) -> number",
42795
+ evaluate: (ops, { engine: ce }) => {
42796
+ const a = toOklch(ce, ops[0]);
42797
+ const b = toOklch(ce, ops[1]);
42798
+ if (!a || !b) return ce.error("incompatible-type");
42799
+ return ce.number(oklabDeltaE(oklchToOklab(a), oklchToOklab(b)));
42289
42800
  }
42290
42801
  }
42291
42802
  };
@@ -44765,6 +45276,34 @@ ${e.message}
44765
45276
  signature: "() -> expression",
44766
45277
  evaluate: (_ops, { engine }) => engine.expr(randomExpression())
44767
45278
  }
45279
+ },
45280
+ // ---------------------------------------------------------------------------
45281
+ // Opaque typed heads — registered so the names are in the standard set
45282
+ // (consumers can branch on the operator name); CE itself does not evaluate
45283
+ // them. Geometric primitives `Triangle`/`Sphere`/`Segment` and the action
45284
+ // arrow `To` (`a \to b`).
45285
+ // ---------------------------------------------------------------------------
45286
+ {
45287
+ Triangle: {
45288
+ description: "Triangle primitive \u2014 opaque typed head.",
45289
+ signature: "(any+) -> expression"
45290
+ },
45291
+ GeometricVector: {
45292
+ description: "Geometric vector (directed segment between two points) \u2014 opaque typed head. Distinct from the column-vector `Vector` operator.",
45293
+ signature: "(any, any) -> expression"
45294
+ },
45295
+ Sphere: {
45296
+ description: "Sphere primitive \u2014 opaque typed head.",
45297
+ signature: "(any+) -> expression"
45298
+ },
45299
+ Segment: {
45300
+ description: "Segment primitive \u2014 opaque typed head.",
45301
+ signature: "(any+) -> expression"
45302
+ },
45303
+ To: {
45304
+ description: "Action arrow / mapping (`a \\to b`) \u2014 opaque typed head.",
45305
+ signature: "(any, any) -> nothing"
45306
+ }
44768
45307
  }
44769
45308
  ];
44770
45309
 
@@ -51901,6 +52440,7 @@ Error in definition of "${name}"`,
51901
52440
 
51902
52441
  // src/compute-engine/boxed-expression/cache.ts
51903
52442
  function cachedValue(v, generation, fn) {
52443
+ if (v.generation === generation && v.value !== null) return v.value;
51904
52444
  v.generation = generation;
51905
52445
  v.value = fn();
51906
52446
  return v.value;
@@ -53678,6 +54218,12 @@ Error in definition of "${name}"`,
53678
54218
  function _escapeJsonString(s) {
53679
54219
  return s;
53680
54220
  }
54221
+ function _serializeLatexMetadata(ce, expr2) {
54222
+ const syntax = ce.latexSyntax;
54223
+ const opts = ce.latexOptions;
54224
+ if (Object.keys(opts).length === 0) return syntax.serialize(expr2);
54225
+ return syntax.serialize(expr2, { ...opts });
54226
+ }
53681
54227
  function serializeSubtract(ce, a, b, options, metadata) {
53682
54228
  if (isNumber(a) && a.isNegative) {
53683
54229
  const v = a.numericValue;
@@ -53982,7 +54528,7 @@ Error in definition of "${name}"`,
53982
54528
  ];
53983
54529
  const md = { ...metadata ?? {} };
53984
54530
  if (options.metadata.includes("latex") && ce.latexSyntax) {
53985
- md.latex = _escapeJsonString(md.latex ?? ce.latexSyntax.serialize(fn));
54531
+ md.latex = _escapeJsonString(md.latex ?? _serializeLatexMetadata(ce, fn));
53986
54532
  } else md.latex = "";
53987
54533
  if (!options.metadata.includes("wikidata")) md.wikidata = "";
53988
54534
  if (!md.latex && !md.wikidata && options.shorthands.includes("function"))
@@ -54007,7 +54553,7 @@ Error in definition of "${name}"`,
54007
54553
  }
54008
54554
  metadata = { ...metadata };
54009
54555
  if (options.metadata.includes("latex") && ce.latexSyntax) {
54010
- metadata.latex = metadata.latex ?? ce.latexSyntax.serialize(sym2);
54556
+ metadata.latex = metadata.latex ?? _serializeLatexMetadata(ce, sym2);
54011
54557
  if (metadata.latex !== void 0)
54012
54558
  metadata.latex = _escapeJsonString(metadata.latex);
54013
54559
  } else metadata.latex = void 0;
@@ -54169,7 +54715,7 @@ Error in definition of "${name}"`,
54169
54715
  }
54170
54716
  }
54171
54717
  if (options.metadata.includes("latex") && ce.latexSyntax)
54172
- metadata.latex = metadata.latex ?? ce.latexSyntax.serialize(result2 ?? { num });
54718
+ metadata.latex = metadata.latex ?? _serializeLatexMetadata(ce, result2 ?? { num });
54173
54719
  if (result2) {
54174
54720
  if (metadata.latex !== void 0)
54175
54721
  return { sym: result2, latex: metadata.latex };
@@ -54185,7 +54731,7 @@ Error in definition of "${name}"`,
54185
54731
  if (value.isNaN()) {
54186
54732
  num = "NaN";
54187
54733
  if (options.metadata.includes("latex") && ce.latexSyntax)
54188
- metadata.latex = metadata.latex ?? ce.latexSyntax.serialize({ num });
54734
+ metadata.latex = metadata.latex ?? _serializeLatexMetadata(ce, { num });
54189
54735
  return metadata.latex !== void 0 ? { num, latex: metadata.latex } : { num };
54190
54736
  }
54191
54737
  return serializeJsonFunction(
@@ -54219,7 +54765,7 @@ Error in definition of "${name}"`,
54219
54765
  value = Number(value);
54220
54766
  } else {
54221
54767
  if (options.metadata.includes("latex") && ce.latexSyntax)
54222
- metadata.latex = metadata.latex ?? ce.latexSyntax.serialize({
54768
+ metadata.latex = metadata.latex ?? _serializeLatexMetadata(ce, {
54223
54769
  num: value.toString()
54224
54770
  });
54225
54771
  if (metadata.latex !== void 0)
@@ -54233,7 +54779,7 @@ Error in definition of "${name}"`,
54233
54779
  result = value > 0 ? "PositiveInfinity" : "NegativeInfinity";
54234
54780
  else num = serializeRepeatingDecimals(value.toString(), options);
54235
54781
  if (options.metadata.includes("latex") && ce.latexSyntax)
54236
- metadata.latex = metadata.latex ?? ce.latexSyntax.serialize({ num });
54782
+ metadata.latex = metadata.latex ?? _serializeLatexMetadata(ce, { num });
54237
54783
  if (result) {
54238
54784
  if (metadata.latex !== void 0)
54239
54785
  return { sym: result, latex: metadata.latex };
@@ -54998,8 +55544,7 @@ Error in definition of "${name}"`,
54998
55544
  ce.pushScope();
54999
55545
  try {
55000
55546
  if (vars && typeof vars === "object") {
55001
- for (const [k, v] of Object.entries(vars))
55002
- ce.assign(k, v);
55547
+ for (const [k, v] of Object.entries(vars)) ce.assign(k, v);
55003
55548
  }
55004
55549
  return expr2.evaluate().re;
55005
55550
  } finally {
@@ -60229,8 +60774,7 @@ Error in definition of "${name}"`,
60229
60774
  return { re: null, im: formatFloat(iScale) };
60230
60775
  }
60231
60776
  const compiledFactors = remaining.map((r) => compile3(r));
60232
- if (iScale !== 1)
60233
- compiledFactors.unshift(formatFloat(iScale));
60777
+ if (iScale !== 1) compiledFactors.unshift(formatFloat(iScale));
60234
60778
  const imCode = foldTerms(compiledFactors, "1.0", "*");
60235
60779
  return { re: null, im: imCode };
60236
60780
  }
@@ -60834,39 +61378,130 @@ Error in definition of "${name}"`,
60834
61378
  if (args.length >= 2)
60835
61379
  return `_SYS.colormap(${compile3(args[0])}, ${compile3(args[1])})`;
60836
61380
  return `_SYS.colormap(${compile3(args[0])})`;
61381
+ },
61382
+ // -----------------------------------------------------------------------
61383
+ // Color constructor heads. All compile to OKLCh arrays at runtime — the
61384
+ // canonical color representation in this target. The constructors take
61385
+ // their own colorspace's components and convert internally.
61386
+ // (Mirrors the GPU target's design: color values are vec3 OKLCh.)
61387
+ // -----------------------------------------------------------------------
61388
+ Rgb: (args, compile3) => {
61389
+ if (args.length < 3) throw new Error("Rgb: need 3 components");
61390
+ return `_SYS.rgb(${args.map(compile3).join(", ")})`;
61391
+ },
61392
+ Hsv: (args, compile3) => {
61393
+ if (args.length < 3) throw new Error("Hsv: need 3 components");
61394
+ return `_SYS.hsv(${args.map(compile3).join(", ")})`;
61395
+ },
61396
+ Hsl: (args, compile3) => {
61397
+ if (args.length < 3) throw new Error("Hsl: need 3 components");
61398
+ return `_SYS.hsl(${args.map(compile3).join(", ")})`;
61399
+ },
61400
+ Oklab: (args, compile3) => {
61401
+ if (args.length < 3) throw new Error("Oklab: need 3 components");
61402
+ return `_SYS.oklab(${args.map(compile3).join(", ")})`;
61403
+ },
61404
+ Oklch: (args, compile3) => {
61405
+ if (args.length < 3) throw new Error("Oklch: need 3 components");
61406
+ return `_SYS.oklch(${args.map(compile3).join(", ")})`;
61407
+ },
61408
+ // -----------------------------------------------------------------------
61409
+ // As* converters. Compile-time output convention matches the engine and
61410
+ // the GPU target: each returns components in the named space as a 3- or
61411
+ // 4-element array. `AsRgb` uses 0-1 sRGB channels (consistent across all
61412
+ // layers). `AsOklch` is the identity (canonical form).
61413
+ // -----------------------------------------------------------------------
61414
+ AsRgb: ([c], compile3) => {
61415
+ if (c === null) throw new Error("AsRgb: no argument");
61416
+ return `_SYS.asRgb(${compile3(c)})`;
61417
+ },
61418
+ AsHsv: ([c], compile3) => {
61419
+ if (c === null) throw new Error("AsHsv: no argument");
61420
+ return `_SYS.asHsv(${compile3(c)})`;
61421
+ },
61422
+ AsHsl: ([c], compile3) => {
61423
+ if (c === null) throw new Error("AsHsl: no argument");
61424
+ return `_SYS.asHsl(${compile3(c)})`;
61425
+ },
61426
+ AsOklab: ([c], compile3) => {
61427
+ if (c === null) throw new Error("AsOklab: no argument");
61428
+ return `_SYS.asOklab(${compile3(c)})`;
61429
+ },
61430
+ AsOklch: ([c], compile3) => {
61431
+ if (c === null) throw new Error("AsOklch: no argument");
61432
+ return compile3(c);
61433
+ },
61434
+ // Perceptual color difference (ΔE_OK).
61435
+ ColorDelta: ([a, b], compile3) => {
61436
+ if (a === null || b === null)
61437
+ throw new Error("ColorDelta: need two colors");
61438
+ return `_SYS.colorDelta(${compile3(a)}, ${compile3(b)})`;
61439
+ },
61440
+ // Euclidean distance between two tuples (any positive dimension).
61441
+ // The GPU target maps `Distance` to the GLSL/WGSL `distance()` builtin
61442
+ // (vec-only); this JS handler works on plain arrays of any length.
61443
+ Distance: ([a, b], compile3) => {
61444
+ if (a === null || b === null) throw new Error("Distance: need two points");
61445
+ return `_SYS.distance(${compile3(a)}, ${compile3(b)})`;
60837
61446
  }
60838
61447
  };
60839
61448
  function toRI(c) {
60840
61449
  return { re: c.re, im: c.im };
60841
61450
  }
61451
+ function normalizeAlpha2(a) {
61452
+ if (a === void 0) return void 0;
61453
+ if (!Number.isFinite(a)) return void 0;
61454
+ if (Math.abs(a - 1) < 1e-9) return void 0;
61455
+ return a;
61456
+ }
60842
61457
  function toRgb255(input) {
60843
61458
  if (typeof input === "string") {
60844
61459
  const c = parseColor(input);
60845
- return {
61460
+ const rgb2 = {
60846
61461
  r: c >>> 24 & 255,
60847
61462
  g: c >>> 16 & 255,
60848
- b: c >>> 8 & 255,
60849
- alpha: (c & 255) / 255
61463
+ b: c >>> 8 & 255
60850
61464
  };
61465
+ const alpha = normalizeAlpha2((c & 255) / 255);
61466
+ if (alpha !== void 0) rgb2.alpha = alpha;
61467
+ return rgb2;
61468
+ }
61469
+ const rgb = oklchToRgb({ L: input[0], C: input[1], H: input[2] });
61470
+ if (input.length >= 4) {
61471
+ const alpha = normalizeAlpha2(input[3]);
61472
+ if (alpha !== void 0) rgb.alpha = alpha;
60851
61473
  }
60852
- const rgb = {
60853
- r: input[0] * 255,
60854
- g: input[1] * 255,
60855
- b: input[2] * 255
60856
- };
60857
- if (input.length >= 4) rgb.alpha = input[3];
60858
61474
  return rgb;
60859
61475
  }
60860
- function packedToArray(c) {
60861
- const r = (c >>> 24 & 255) / 255;
60862
- const g = (c >>> 16 & 255) / 255;
60863
- const b = (c >>> 8 & 255) / 255;
60864
- const a = (c & 255) / 255;
60865
- return Math.abs(a - 1) < 1e-4 ? [r, g, b] : [r, g, b, a];
61476
+ function toOklch2(input) {
61477
+ if (typeof input === "string") {
61478
+ const c = parseColor(input);
61479
+ const r = c >>> 24 & 255;
61480
+ const g = c >>> 16 & 255;
61481
+ const b = c >>> 8 & 255;
61482
+ const oklch2 = rgbToOklch({ r, g, b });
61483
+ const alpha = normalizeAlpha2((c & 255) / 255);
61484
+ if (alpha !== void 0) oklch2.alpha = alpha;
61485
+ return oklch2;
61486
+ }
61487
+ return {
61488
+ L: input[0],
61489
+ C: input[1],
61490
+ H: input[2],
61491
+ alpha: input.length >= 4 ? normalizeAlpha2(input[3]) : void 0
61492
+ };
61493
+ }
61494
+ function packedToOklch(c) {
61495
+ const r = c >>> 24 & 255;
61496
+ const g = c >>> 16 & 255;
61497
+ const b = c >>> 8 & 255;
61498
+ const oklch2 = rgbToOklch({ r, g, b });
61499
+ const alpha = normalizeAlpha2((c & 255) / 255);
61500
+ return alpha !== void 0 ? [oklch2.L, oklch2.C, oklch2.H, alpha] : [oklch2.L, oklch2.C, oklch2.H];
60866
61501
  }
60867
61502
  var colorHelpers = {
60868
61503
  color(input) {
60869
- return packedToArray(parseColor(input));
61504
+ return packedToOklch(parseColor(input));
60870
61505
  },
60871
61506
  colorToString(input, format) {
60872
61507
  const rgb = toRgb255(input);
@@ -60877,7 +61512,7 @@ Error in definition of "${name}"`,
60877
61512
  const g = Math.round(Math.max(0, Math.min(255, rgb.g)));
60878
61513
  const b = Math.round(Math.max(0, Math.min(255, rgb.b)));
60879
61514
  let hex = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
60880
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4) {
61515
+ if (rgb.alpha !== void 0) {
60881
61516
  const a = Math.round(Math.max(0, Math.min(255, rgb.alpha * 255)));
60882
61517
  hex += a.toString(16).padStart(2, "0");
60883
61518
  }
@@ -60887,7 +61522,7 @@ Error in definition of "${name}"`,
60887
61522
  const r = Math.round(rgb.r);
60888
61523
  const g = Math.round(rgb.g);
60889
61524
  const b = Math.round(rgb.b);
60890
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
61525
+ if (rgb.alpha !== void 0)
60891
61526
  return `rgb(${r} ${g} ${b} / ${rgb.alpha})`;
60892
61527
  return `rgb(${r} ${g} ${b})`;
60893
61528
  }
@@ -60896,7 +61531,7 @@ Error in definition of "${name}"`,
60896
61531
  const h = Math.round(hsl.h * 10) / 10;
60897
61532
  const s = Math.round(hsl.s * 1e3) / 10;
60898
61533
  const l = Math.round(hsl.l * 1e3) / 10;
60899
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
61534
+ if (rgb.alpha !== void 0)
60900
61535
  return `hsl(${h} ${s}% ${l}% / ${rgb.alpha})`;
60901
61536
  return `hsl(${h} ${s}% ${l}%)`;
60902
61537
  }
@@ -60905,7 +61540,7 @@ Error in definition of "${name}"`,
60905
61540
  const L = Math.round(c.L * 1e3) / 1e3;
60906
61541
  const C = Math.round(c.C * 1e3) / 1e3;
60907
61542
  const H = Math.round(c.H * 10) / 10;
60908
- if (rgb.alpha !== void 0 && Math.abs(rgb.alpha - 1) > 1e-4)
61543
+ if (rgb.alpha !== void 0)
60909
61544
  return `oklch(${L} ${C} ${H} / ${rgb.alpha})`;
60910
61545
  return `oklch(${L} ${C} ${H})`;
60911
61546
  }
@@ -60914,29 +61549,29 @@ Error in definition of "${name}"`,
60914
61549
  }
60915
61550
  },
60916
61551
  colorMix(input1, input2, ratio = 0.5) {
60917
- const rgb1 = toRgb255(input1);
60918
- const rgb2 = toRgb255(input2);
61552
+ const c1 = toOklch2(input1);
61553
+ const c2 = toOklch2(input2);
60919
61554
  ratio = Math.max(0, Math.min(1, ratio));
60920
- const c1 = rgbToOklch(rgb1);
60921
- const c2 = rgbToOklch(rgb2);
60922
- let dh = c2.H - c1.H;
60923
- if (dh > 180) dh -= 360;
60924
- if (dh < -180) dh += 360;
60925
- let H = c1.H + dh * ratio;
60926
- if (H < 0) H += 360;
60927
- if (H >= 360) H -= 360;
60928
- const mixed = oklchToRgb({
60929
- L: c1.L + (c2.L - c1.L) * ratio,
60930
- C: c1.C + (c2.C - c1.C) * ratio,
60931
- H
60932
- });
60933
- const r = mixed.r / 255;
60934
- const g = mixed.g / 255;
60935
- const b = mixed.b / 255;
60936
- const a1 = rgb1.alpha ?? 1;
60937
- const a2 = rgb2.alpha ?? 1;
60938
- const alpha = a1 + (a2 - a1) * ratio;
60939
- return Math.abs(alpha - 1) > 1e-4 ? [r, g, b, alpha] : [r, g, b];
61555
+ const c1Achromatic = c1.C < 1e-6;
61556
+ const c2Achromatic = c2.C < 1e-6;
61557
+ let H;
61558
+ if (c1Achromatic && c2Achromatic) H = c1.H;
61559
+ else if (c1Achromatic) H = c2.H;
61560
+ else if (c2Achromatic) H = c1.H;
61561
+ else {
61562
+ let dh = c2.H - c1.H;
61563
+ if (dh > 180) dh -= 360;
61564
+ if (dh < -180) dh += 360;
61565
+ H = c1.H + dh * ratio;
61566
+ if (H < 0) H += 360;
61567
+ if (H >= 360) H -= 360;
61568
+ }
61569
+ const L = c1.L + (c2.L - c1.L) * ratio;
61570
+ const C = c1.C + (c2.C - c1.C) * ratio;
61571
+ const a1 = c1.alpha ?? 1;
61572
+ const a2 = c2.alpha ?? 1;
61573
+ const alpha = normalizeAlpha2(a1 + (a2 - a1) * ratio);
61574
+ return alpha !== void 0 ? [L, C, H, alpha] : [L, C, H];
60940
61575
  },
60941
61576
  colorContrast(bg, fg) {
60942
61577
  return apca(toRgb255(bg), toRgb255(fg));
@@ -60944,11 +61579,11 @@ Error in definition of "${name}"`,
60944
61579
  contrastingColor(bg, fg1, fg2) {
60945
61580
  const bgRgb = toRgb255(bg);
60946
61581
  if (fg1 !== void 0 && fg2 !== void 0) {
60947
- return packedToArray(
61582
+ return packedToOklch(
60948
61583
  contrastingColor({ bg: bgRgb, fg1: toRgb255(fg1), fg2: toRgb255(fg2) })
60949
61584
  );
60950
61585
  }
60951
- return packedToArray(contrastingColor(bgRgb));
61586
+ return packedToOklch(contrastingColor(bgRgb));
60952
61587
  },
60953
61588
  colorToColorspace(input, space) {
60954
61589
  const rgb = toRgb255(input);
@@ -60977,7 +61612,7 @@ Error in definition of "${name}"`,
60977
61612
  default:
60978
61613
  throw new Error(`Unknown color space: ${space}`);
60979
61614
  }
60980
- if (alpha !== void 0 && Math.abs(alpha - 1) > 1e-4) result.push(alpha);
61615
+ if (alpha !== void 0) result.push(alpha);
60981
61616
  return result;
60982
61617
  },
60983
61618
  colormap(name, arg) {
@@ -60989,7 +61624,7 @@ Error in definition of "${name}"`,
60989
61624
  const palette = allPalettes[name];
60990
61625
  if (!palette) throw new Error(`Unknown palette: ${name}`);
60991
61626
  const colors = palette.map(
60992
- (hex) => parseColorToRgb01(hex)
61627
+ (hex) => packedToOklch(parseColor(hex))
60993
61628
  );
60994
61629
  if (arg === void 0) return colors;
60995
61630
  if (Number.isInteger(arg) && arg >= 2) {
@@ -61013,62 +61648,128 @@ Error in definition of "${name}"`,
61013
61648
  const frac = pos - i;
61014
61649
  if (frac === 0 || i >= colors.length - 1)
61015
61650
  return [...colors[Math.min(i, colors.length - 1)]];
61016
- const rgb1 = {
61017
- r: colors[i][0] * 255,
61018
- g: colors[i][1] * 255,
61019
- b: colors[i][2] * 255
61020
- };
61021
- const rgb2 = {
61022
- r: colors[i + 1][0] * 255,
61023
- g: colors[i + 1][1] * 255,
61024
- b: colors[i + 1][2] * 255
61025
- };
61026
- const c1 = rgbToOklch(rgb1);
61027
- const c2 = rgbToOklch(rgb2);
61028
- let dh = c2.H - c1.H;
61029
- if (dh > 180) dh -= 360;
61030
- if (dh < -180) dh += 360;
61031
- let H = c1.H + dh * frac;
61032
- if (H < 0) H += 360;
61033
- if (H >= 360) H -= 360;
61034
- const mixed = oklchToRgb({
61035
- L: c1.L + (c2.L - c1.L) * frac,
61036
- C: c1.C + (c2.C - c1.C) * frac,
61037
- H
61038
- });
61039
- return [mixed.r / 255, mixed.g / 255, mixed.b / 255];
61651
+ const [L1, C1, H1] = colors[i];
61652
+ const [L2, C2, H2] = colors[i + 1];
61653
+ const c1Achromatic = C1 < 1e-6;
61654
+ const c2Achromatic = C2 < 1e-6;
61655
+ let H;
61656
+ if (c1Achromatic && c2Achromatic) H = H1;
61657
+ else if (c1Achromatic) H = H2;
61658
+ else if (c2Achromatic) H = H1;
61659
+ else {
61660
+ let dh = H2 - H1;
61661
+ if (dh > 180) dh -= 360;
61662
+ if (dh < -180) dh += 360;
61663
+ H = H1 + dh * frac;
61664
+ if (H < 0) H += 360;
61665
+ if (H >= 360) H -= 360;
61666
+ }
61667
+ return [L1 + (L2 - L1) * frac, C1 + (C2 - C1) * frac, H];
61040
61668
  },
61041
61669
  colorFromColorspace(components, space) {
61042
61670
  const c0 = components[0];
61043
61671
  const c1 = components[1];
61044
61672
  const c2 = components[2];
61045
61673
  const alpha = components.length >= 4 ? components[3] : void 0;
61046
- let result;
61674
+ let oklch2;
61047
61675
  switch (space.toLowerCase()) {
61048
61676
  case "rgb":
61049
- result = [c0, c1, c2];
61677
+ oklch2 = rgbToOklch({ r: c0 * 255, g: c1 * 255, b: c2 * 255 });
61050
61678
  break;
61051
61679
  case "hsl": {
61052
- const r = hslToRgb(c0, c1, c2);
61053
- result = [r.r / 255, r.g / 255, r.b / 255];
61680
+ const rgb = hslToRgb(c0, c1, c2);
61681
+ oklch2 = rgbToOklch(rgb);
61054
61682
  break;
61055
61683
  }
61056
- case "oklch": {
61057
- const r = oklchToRgb({ L: c0, C: c1, H: c2 });
61058
- result = [r.r / 255, r.g / 255, r.b / 255];
61684
+ case "oklch":
61685
+ oklch2 = { L: c0, C: c1, H: c2 };
61059
61686
  break;
61060
- }
61061
61687
  case "oklab":
61062
- case "lab": {
61063
- const r = oklabToRgb({ L: c0, a: c1, b: c2 });
61064
- result = [r.r / 255, r.g / 255, r.b / 255];
61688
+ case "lab":
61689
+ oklch2 = oklabToOklch({ L: c0, a: c1, b: c2 });
61065
61690
  break;
61066
- }
61067
61691
  default:
61068
61692
  throw new Error(`Unknown color space: ${space}`);
61069
61693
  }
61070
- if (alpha !== void 0 && Math.abs(alpha - 1) > 1e-4) result.push(alpha);
61071
- return result;
61694
+ return alpha !== void 0 ? [oklch2.L, oklch2.C, oklch2.H, alpha] : [oklch2.L, oklch2.C, oklch2.H];
61695
+ },
61696
+ // -----------------------------------------------------------------------
61697
+ // Color constructors. Each accepts components in its colorspace's natural
61698
+ // units and returns the canonical OKLCh array `[L, C, H]` (or with alpha).
61699
+ // -----------------------------------------------------------------------
61700
+ rgb(r, g, b, alpha) {
61701
+ const c = rgbToOklch({ r: r * 255, g: g * 255, b: b * 255 });
61702
+ const a = normalizeAlpha2(alpha);
61703
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
61704
+ },
61705
+ hsv(h, s, v, alpha) {
61706
+ const rgb = hsvToRgb(h, s, v);
61707
+ const c = rgbToOklch(rgb);
61708
+ const a = normalizeAlpha2(alpha);
61709
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
61710
+ },
61711
+ hsl(h, s, l, alpha) {
61712
+ const rgb = hslToRgb(h, s, l);
61713
+ const c = rgbToOklch({ r: rgb.r, g: rgb.g, b: rgb.b });
61714
+ const a = normalizeAlpha2(alpha);
61715
+ return a !== void 0 ? [c.L, c.C, c.H, a] : [c.L, c.C, c.H];
61716
+ },
61717
+ oklab(L, a, b, alpha) {
61718
+ const c = oklabToOklch({ L, a, b });
61719
+ const al = normalizeAlpha2(alpha);
61720
+ return al !== void 0 ? [c.L, c.C, c.H, al] : [c.L, c.C, c.H];
61721
+ },
61722
+ oklch(L, C, H, alpha) {
61723
+ const a = normalizeAlpha2(alpha);
61724
+ return a !== void 0 ? [L, C, H, a] : [L, C, H];
61725
+ },
61726
+ // -----------------------------------------------------------------------
61727
+ // As* converters. Inputs are anything `toOklch` accepts (string, packed
61728
+ // int, or OKLCh array). Outputs are 3- or 4-element arrays in the named
61729
+ // space. sRGB-based outputs (asRgb/asHsv/asHsl) use 0-1 channels for
61730
+ // consistency with the GPU target's shader convention.
61731
+ // -----------------------------------------------------------------------
61732
+ asRgb(input) {
61733
+ const rgb = toRgb255(input);
61734
+ const r = rgb.r / 255;
61735
+ const g = rgb.g / 255;
61736
+ const b = rgb.b / 255;
61737
+ return rgb.alpha !== void 0 ? [r, g, b, rgb.alpha] : [r, g, b];
61738
+ },
61739
+ asHsv(input) {
61740
+ const rgb = toRgb255(input);
61741
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
61742
+ return rgb.alpha !== void 0 ? [hsv.h, hsv.s, hsv.v, rgb.alpha] : [hsv.h, hsv.s, hsv.v];
61743
+ },
61744
+ asHsl(input) {
61745
+ const rgb = toRgb255(input);
61746
+ const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
61747
+ return rgb.alpha !== void 0 ? [hsl.h, hsl.s, hsl.l, rgb.alpha] : [hsl.h, hsl.s, hsl.l];
61748
+ },
61749
+ asOklab(input) {
61750
+ const c = toOklch2(input);
61751
+ const lab = oklchToOklab({ L: c.L, C: c.C, H: c.H });
61752
+ return c.alpha !== void 0 ? [lab.L, lab.a, lab.b, c.alpha] : [lab.L, lab.a, lab.b];
61753
+ },
61754
+ // asOklch is identity — handled at compile time as a pass-through
61755
+ // Perceptual color difference (ΔE_OK).
61756
+ colorDelta(a, b) {
61757
+ const labA = oklchToOklab(toOklch2(a));
61758
+ const labB = oklchToOklab(toOklch2(b));
61759
+ return oklabDeltaE(labA, labB);
61760
+ },
61761
+ // Euclidean distance between two tuples. Plain numeric — not a color
61762
+ // operation despite living in the same helpers block.
61763
+ distance(a, b) {
61764
+ if (!Array.isArray(a) || !Array.isArray(b))
61765
+ throw new Error("Distance: expected two arrays");
61766
+ if (a.length !== b.length) throw new Error("Distance: dimension mismatch");
61767
+ let sumSq = 0;
61768
+ for (let i = 0; i < a.length; i++) {
61769
+ const d = a[i] - b[i];
61770
+ sumSq += d * d;
61771
+ }
61772
+ return Math.sqrt(sumSq);
61072
61773
  }
61073
61774
  };
61074
61775
  var SYS_HELPERS = {
@@ -61507,6 +62208,13 @@ Error in definition of "${name}"`,
61507
62208
  function gpuVec2(target) {
61508
62209
  return target?.language === "wgsl" ? "vec2f" : "vec2";
61509
62210
  }
62211
+ function gpuVec3(target) {
62212
+ return target?.language === "wgsl" ? "vec3f" : "vec3";
62213
+ }
62214
+ function readStringLiteral(expr2) {
62215
+ if (!isString(expr2)) return null;
62216
+ return expr2.string?.toLowerCase() ?? null;
62217
+ }
61510
62218
  function compileIntArg(expr2, compile3, target) {
61511
62219
  const c = tryGetConstant(expr2);
61512
62220
  if (c !== void 0 && Number.isInteger(c)) return c.toString();
@@ -61565,7 +62273,7 @@ Error in definition of "${name}"`,
61565
62273
  `for (${indexDecl} = ${lowerStr}; ${index} <= ${upperStr}; ${index}++) {`,
61566
62274
  ` ${acc} ${op}= ${body};`,
61567
62275
  `}`,
61568
- `return ${acc}`
62276
+ `return ${acc};`
61569
62277
  ];
61570
62278
  return lines.join("\n");
61571
62279
  }
@@ -61619,8 +62327,7 @@ Error in definition of "${name}"`,
61619
62327
  const iScale = isSymbol2(iFactor, "ImaginaryUnit") ? 1 : iFactor.im;
61620
62328
  const realFactors = args.filter((_, i) => i !== iIndex);
61621
62329
  const v2 = gpuVec2(target);
61622
- if (realFactors.length === 0)
61623
- return `${v2}(0.0, ${formatFloat(iScale)})`;
62330
+ if (realFactors.length === 0) return `${v2}(0.0, ${formatFloat(iScale)})`;
61624
62331
  const factors = realFactors.map((f) => compile3(f));
61625
62332
  if (iScale !== 1) factors.unshift(formatFloat(iScale));
61626
62333
  const imCode = foldTerms(factors, "1.0", "*");
@@ -61673,8 +62380,7 @@ Error in definition of "${name}"`,
61673
62380
  if (isNumber(x) && x.im !== 0) {
61674
62381
  return `${gpuVec2(target)}(${formatFloat(-x.re)}, ${formatFloat(-x.im)})`;
61675
62382
  }
61676
- if (isSymbol2(x, "ImaginaryUnit"))
61677
- return `${gpuVec2(target)}(0.0, -1.0)`;
62383
+ if (isSymbol2(x, "ImaginaryUnit")) return `${gpuVec2(target)}(0.0, -1.0)`;
61678
62384
  return `(-${compile3(x)})`;
61679
62385
  },
61680
62386
  // Standard math functions with complex dispatch
@@ -62047,17 +62753,127 @@ Error in definition of "${name}"`,
62047
62753
  }
62048
62754
  const isWGSL = target?.language === "wgsl";
62049
62755
  const v3 = isWGSL ? "vec3f" : "vec3";
62050
- return `((_gpu_apca(${bg}, ${v3}(0.0)) > 50.0) ? ${v3}(0.0) : ${v3}(1.0))`;
62756
+ const black = `${v3}(0.0)`;
62757
+ const white = `${v3}(1.0, 0.0, 0.0)`;
62758
+ return `((_gpu_apca(${bg}, ${black}) > 50.0) ? ${black} : ${white})`;
62051
62759
  },
62052
62760
  ColorToColorspace: ([color, space], compile3) => {
62053
62761
  if (color === null || space === null)
62054
62762
  throw new Error("ColorToColorspace: need color and space");
62055
- return `_gpu_srgb_to_oklab(${compile3(color)})`;
62763
+ const spaceName = readStringLiteral(space);
62764
+ if (spaceName === null)
62765
+ throw new Error("ColorToColorspace: space must be a string literal");
62766
+ const c = compile3(color);
62767
+ switch (spaceName) {
62768
+ case "oklch":
62769
+ return c;
62770
+ case "oklab":
62771
+ case "lab":
62772
+ return `_gpu_oklch_to_oklab(${c})`;
62773
+ case "rgb":
62774
+ return `_gpu_oklch_to_srgb(${c})`;
62775
+ case "hsl":
62776
+ return `_gpu_rgb_to_hsl(_gpu_oklch_to_srgb(${c}))`;
62777
+ case "hsv":
62778
+ return `_gpu_rgb_to_hsv(_gpu_oklch_to_srgb(${c}))`;
62779
+ default:
62780
+ throw new Error(
62781
+ `ColorToColorspace: unsupported space "${spaceName}" on GPU target`
62782
+ );
62783
+ }
62056
62784
  },
62057
62785
  ColorFromColorspace: ([components, space], compile3) => {
62058
62786
  if (components === null || space === null)
62059
62787
  throw new Error("ColorFromColorspace: need components and space");
62060
- return `_gpu_oklab_to_srgb(${compile3(components)})`;
62788
+ const spaceName = readStringLiteral(space);
62789
+ if (spaceName === null)
62790
+ throw new Error("ColorFromColorspace: space must be a string literal");
62791
+ const c = compile3(components);
62792
+ switch (spaceName) {
62793
+ case "oklch":
62794
+ return c;
62795
+ case "oklab":
62796
+ case "lab":
62797
+ return `_gpu_oklab_to_oklch(${c})`;
62798
+ case "rgb":
62799
+ return `_gpu_srgb_to_oklch(${c})`;
62800
+ case "hsl":
62801
+ return `_gpu_srgb_to_oklch(_gpu_hsl_to_rgb(${c}))`;
62802
+ case "hsv":
62803
+ return `_gpu_srgb_to_oklch(_gpu_hsv_to_rgb(${c}))`;
62804
+ default:
62805
+ throw new Error(
62806
+ `ColorFromColorspace: unsupported space "${spaceName}" on GPU target`
62807
+ );
62808
+ }
62809
+ },
62810
+ // ---------------------------------------------------------------------------
62811
+ // Color literals. Each typed head compiles to a canonical OKLCh vec3.
62812
+ // Alpha (4th argument) is dropped — GPU color values are vec3 only. Pass
62813
+ // alpha as a separate uniform if it's needed at the framebuffer boundary.
62814
+ // ---------------------------------------------------------------------------
62815
+ Color: ([s], _compile2, target) => {
62816
+ if (s === null) throw new Error("Color: no argument");
62817
+ const str = readStringLiteral(s);
62818
+ if (str === null)
62819
+ throw new Error("Color: argument must be a string literal on GPU target");
62820
+ const packed = parseColor(str);
62821
+ if (packed === 0 && str.trim().toLowerCase() !== "transparent")
62822
+ throw new Error(`Color: invalid color string "${str}"`);
62823
+ const r = packed >>> 24 & 255;
62824
+ const g = packed >>> 16 & 255;
62825
+ const b = packed >>> 8 & 255;
62826
+ const oklch2 = rgbToOklch({ r, g, b });
62827
+ return `${gpuVec3(target)}(${formatFloat(oklch2.L)}, ${formatFloat(oklch2.C)}, ${formatFloat(oklch2.H)})`;
62828
+ },
62829
+ Rgb: (args, compile3, target) => {
62830
+ if (args.length < 3) throw new Error("Rgb: need 3 components");
62831
+ const v3 = gpuVec3(target);
62832
+ return `_gpu_srgb_to_oklch(${v3}(${compile3(args[0])}, ${compile3(args[1])}, ${compile3(args[2])}))`;
62833
+ },
62834
+ Hsv: (args, compile3, target) => {
62835
+ if (args.length < 3) throw new Error("Hsv: need 3 components");
62836
+ const v3 = gpuVec3(target);
62837
+ return `_gpu_srgb_to_oklch(_gpu_hsv_to_rgb(${v3}(${compile3(args[0])}, ${compile3(args[1])}, ${compile3(args[2])})))`;
62838
+ },
62839
+ Hsl: (args, compile3, target) => {
62840
+ if (args.length < 3) throw new Error("Hsl: need 3 components");
62841
+ const v3 = gpuVec3(target);
62842
+ return `_gpu_srgb_to_oklch(_gpu_hsl_to_rgb(${v3}(${compile3(args[0])}, ${compile3(args[1])}, ${compile3(args[2])})))`;
62843
+ },
62844
+ Oklab: (args, compile3, target) => {
62845
+ if (args.length < 3) throw new Error("Oklab: need 3 components");
62846
+ const v3 = gpuVec3(target);
62847
+ return `_gpu_oklab_to_oklch(${v3}(${compile3(args[0])}, ${compile3(args[1])}, ${compile3(args[2])}))`;
62848
+ },
62849
+ Oklch: (args, compile3, target) => {
62850
+ if (args.length < 3) throw new Error("Oklch: need 3 components");
62851
+ const v3 = gpuVec3(target);
62852
+ return `${v3}(${compile3(args[0])}, ${compile3(args[1])}, ${compile3(args[2])})`;
62853
+ },
62854
+ // ---------------------------------------------------------------------------
62855
+ // As* operators. AsOklch is identity (canonical). The other As* return
62856
+ // components in the named space, equivalent to ColorToColorspace(c, 'x').
62857
+ // ---------------------------------------------------------------------------
62858
+ AsOklch: ([c], compile3) => {
62859
+ if (c === null) throw new Error("AsOklch: no argument");
62860
+ return compile3(c);
62861
+ },
62862
+ AsOklab: ([c], compile3) => {
62863
+ if (c === null) throw new Error("AsOklab: no argument");
62864
+ return `_gpu_oklch_to_oklab(${compile3(c)})`;
62865
+ },
62866
+ AsRgb: ([c], compile3) => {
62867
+ if (c === null) throw new Error("AsRgb: no argument");
62868
+ return `_gpu_oklch_to_srgb(${compile3(c)})`;
62869
+ },
62870
+ AsHsv: ([c], compile3) => {
62871
+ if (c === null) throw new Error("AsHsv: no argument");
62872
+ return `_gpu_rgb_to_hsv(_gpu_oklch_to_srgb(${compile3(c)}))`;
62873
+ },
62874
+ AsHsl: ([c], compile3) => {
62875
+ if (c === null) throw new Error("AsHsl: no argument");
62876
+ return `_gpu_rgb_to_hsl(_gpu_oklch_to_srgb(${compile3(c)}))`;
62061
62877
  },
62062
62878
  // Fractal functions
62063
62879
  Mandelbrot: ([c, maxIter], compile3, target) => {
@@ -62750,28 +63566,124 @@ vec3 _gpu_oklab_to_srgb(vec3 lab) {
62750
63566
 
62751
63567
  vec3 _gpu_oklab_to_oklch(vec3 lab) {
62752
63568
  float C = length(lab.yz);
62753
- float H = atan(lab.z, lab.y);
63569
+ float H = atan(lab.z, lab.y) * (180.0 / 3.14159265359);
63570
+ if (H < 0.0) H += 360.0;
62754
63571
  return vec3(lab.x, C, H);
62755
63572
  }
62756
63573
 
62757
63574
  vec3 _gpu_oklch_to_oklab(vec3 lch) {
62758
- return vec3(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));
63575
+ float h_rad = lch.z * (3.14159265359 / 180.0);
63576
+ return vec3(lch.x, lch.y * cos(h_rad), lch.y * sin(h_rad));
63577
+ }
63578
+
63579
+ vec3 _gpu_srgb_to_oklch(vec3 rgb) {
63580
+ return _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb));
63581
+ }
63582
+
63583
+ vec3 _gpu_oklch_to_srgb(vec3 lch) {
63584
+ return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(lch));
63585
+ }
63586
+
63587
+ // HSL conversion. Hue in degrees, saturation/lightness in 0-1.
63588
+ vec3 _gpu_hsl_to_rgb(vec3 hsl) {
63589
+ float h = hsl.x;
63590
+ float s = hsl.y;
63591
+ float l = hsl.z;
63592
+ float c = (1.0 - abs(2.0 * l - 1.0)) * s;
63593
+ float h6 = h / 60.0;
63594
+ float x = c * (1.0 - abs(mod(h6, 2.0) - 1.0));
63595
+ float r = 0.0;
63596
+ float g = 0.0;
63597
+ float b = 0.0;
63598
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
63599
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
63600
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
63601
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
63602
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
63603
+ else { r = c; g = 0.0; b = x; }
63604
+ float m = l - c / 2.0;
63605
+ return vec3(r + m, g + m, b + m);
63606
+ }
63607
+
63608
+ vec3 _gpu_rgb_to_hsl(vec3 rgb) {
63609
+ float maxc = max(max(rgb.x, rgb.y), rgb.z);
63610
+ float minc = min(min(rgb.x, rgb.y), rgb.z);
63611
+ float l = (maxc + minc) / 2.0;
63612
+ float d = maxc - minc;
63613
+ if (d < 1e-6) return vec3(0.0, 0.0, l);
63614
+ float s = d / (1.0 - abs(2.0 * l - 1.0));
63615
+ float h;
63616
+ if (maxc == rgb.x) h = mod((rgb.y - rgb.z) / d, 6.0);
63617
+ else if (maxc == rgb.y) h = (rgb.z - rgb.x) / d + 2.0;
63618
+ else h = (rgb.x - rgb.y) / d + 4.0;
63619
+ h *= 60.0;
63620
+ if (h < 0.0) h += 360.0;
63621
+ return vec3(h, s, l);
63622
+ }
63623
+
63624
+ // HSV conversion. Hue in degrees, saturation/value in 0-1.
63625
+ vec3 _gpu_hsv_to_rgb(vec3 hsv) {
63626
+ float h = hsv.x;
63627
+ float s = hsv.y;
63628
+ float v = hsv.z;
63629
+ float c = v * s;
63630
+ float h6 = h / 60.0;
63631
+ float x = c * (1.0 - abs(mod(h6, 2.0) - 1.0));
63632
+ float r = 0.0;
63633
+ float g = 0.0;
63634
+ float b = 0.0;
63635
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
63636
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
63637
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
63638
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
63639
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
63640
+ else { r = c; g = 0.0; b = x; }
63641
+ float m = v - c;
63642
+ return vec3(r + m, g + m, b + m);
62759
63643
  }
62760
63644
 
62761
- vec3 _gpu_color_mix(vec3 rgb1, vec3 rgb2, float t) {
62762
- vec3 lch1 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb1));
62763
- vec3 lch2 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb2));
63645
+ vec3 _gpu_rgb_to_hsv(vec3 rgb) {
63646
+ float maxc = max(max(rgb.x, rgb.y), rgb.z);
63647
+ float minc = min(min(rgb.x, rgb.y), rgb.z);
63648
+ float v = maxc;
63649
+ float d = maxc - minc;
63650
+ if (d < 1e-6) return vec3(0.0, 0.0, v);
63651
+ float s = (maxc < 1e-6) ? 0.0 : d / maxc;
63652
+ float h;
63653
+ if (maxc == rgb.x) h = mod((rgb.y - rgb.z) / d, 6.0);
63654
+ else if (maxc == rgb.y) h = (rgb.z - rgb.x) / d + 2.0;
63655
+ else h = (rgb.x - rgb.y) / d + 4.0;
63656
+ h *= 60.0;
63657
+ if (h < 0.0) h += 360.0;
63658
+ return vec3(h, s, v);
63659
+ }
63660
+
63661
+ vec3 _gpu_color_mix(vec3 lch1, vec3 lch2, float t) {
62764
63662
  float L = mix(lch1.x, lch2.x, t);
62765
63663
  float C = mix(lch1.y, lch2.y, t);
62766
- float dh = lch2.z - lch1.z;
62767
- const float PI = 3.14159265359;
62768
- if (dh > PI) dh -= 2.0 * PI;
62769
- if (dh < -PI) dh += 2.0 * PI;
62770
- float H = lch1.z + dh * t;
62771
- return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(vec3(L, C, H)));
63664
+ bool a1 = lch1.y < 1e-6;
63665
+ bool a2 = lch2.y < 1e-6;
63666
+ float H;
63667
+ if (a1 && a2) {
63668
+ H = lch1.z;
63669
+ } else if (a1) {
63670
+ H = lch2.z;
63671
+ } else if (a2) {
63672
+ H = lch1.z;
63673
+ } else {
63674
+ float dh = lch2.z - lch1.z;
63675
+ if (dh > 180.0) dh -= 360.0;
63676
+ if (dh < -180.0) dh += 360.0;
63677
+ H = lch1.z + dh * t;
63678
+ if (H < 0.0) H += 360.0;
63679
+ if (H >= 360.0) H -= 360.0;
63680
+ }
63681
+ return vec3(L, C, H);
62772
63682
  }
62773
63683
 
62774
- float _gpu_apca(vec3 bg, vec3 fg) {
63684
+ float _gpu_apca(vec3 lch_bg, vec3 lch_fg) {
63685
+ vec3 bg = _gpu_oklch_to_srgb(lch_bg);
63686
+ vec3 fg = _gpu_oklch_to_srgb(lch_fg);
62775
63687
  float bgR = _gpu_srgb_to_linear(bg.x);
62776
63688
  float bgG = _gpu_srgb_to_linear(bg.y);
62777
63689
  float bgB = _gpu_srgb_to_linear(bg.z);
@@ -62782,9 +63694,7 @@ float _gpu_apca(vec3 bg, vec3 fg) {
62782
63694
  float fgY = 0.2126729 * fgR + 0.7151522 * fgG + 0.0721750 * fgB;
62783
63695
  float bgC = pow(bgY, 0.56);
62784
63696
  float fgC = pow(fgY, 0.57);
62785
- float contrast = (bgC > fgC)
62786
- ? (bgC - fgC) * 1.14
62787
- : (bgC - fgC) * 1.14;
63697
+ float contrast = (bgC - fgC) * 1.14;
62788
63698
  return contrast * 100.0;
62789
63699
  }
62790
63700
  `;
@@ -62828,28 +63738,133 @@ fn _gpu_oklab_to_srgb(lab: vec3f) -> vec3f {
62828
63738
 
62829
63739
  fn _gpu_oklab_to_oklch(lab: vec3f) -> vec3f {
62830
63740
  let C = length(lab.yz);
62831
- let H = atan2(lab.z, lab.y);
63741
+ var H = atan2(lab.z, lab.y) * (180.0 / 3.14159265359);
63742
+ if (H < 0.0) { H = H + 360.0; }
62832
63743
  return vec3f(lab.x, C, H);
62833
63744
  }
62834
63745
 
62835
63746
  fn _gpu_oklch_to_oklab(lch: vec3f) -> vec3f {
62836
- return vec3f(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));
63747
+ let h_rad = lch.z * (3.14159265359 / 180.0);
63748
+ return vec3f(lch.x, lch.y * cos(h_rad), lch.y * sin(h_rad));
63749
+ }
63750
+
63751
+ fn _gpu_srgb_to_oklch(rgb: vec3f) -> vec3f {
63752
+ return _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb));
62837
63753
  }
62838
63754
 
62839
- fn _gpu_color_mix(rgb1: vec3f, rgb2: vec3f, t: f32) -> vec3f {
62840
- let lch1 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb1));
62841
- let lch2 = _gpu_oklab_to_oklch(_gpu_srgb_to_oklab(rgb2));
63755
+ fn _gpu_oklch_to_srgb(lch: vec3f) -> vec3f {
63756
+ return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(lch));
63757
+ }
63758
+
63759
+ fn _gpu_hsl_to_rgb(hsl: vec3f) -> vec3f {
63760
+ let h = hsl.x;
63761
+ let s = hsl.y;
63762
+ let l = hsl.z;
63763
+ let c = (1.0 - abs(2.0 * l - 1.0)) * s;
63764
+ let h6 = h / 60.0;
63765
+ let x = c * (1.0 - abs((h6 - 2.0 * floor(h6 / 2.0)) - 1.0));
63766
+ var r: f32 = 0.0;
63767
+ var g: f32 = 0.0;
63768
+ var b: f32 = 0.0;
63769
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
63770
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
63771
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
63772
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
63773
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
63774
+ else { r = c; g = 0.0; b = x; }
63775
+ let m = l - c / 2.0;
63776
+ return vec3f(r + m, g + m, b + m);
63777
+ }
63778
+
63779
+ fn _gpu_rgb_to_hsl(rgb: vec3f) -> vec3f {
63780
+ let maxc = max(max(rgb.x, rgb.y), rgb.z);
63781
+ let minc = min(min(rgb.x, rgb.y), rgb.z);
63782
+ let l = (maxc + minc) / 2.0;
63783
+ let d = maxc - minc;
63784
+ if (d < 1e-6) { return vec3f(0.0, 0.0, l); }
63785
+ let s = d / (1.0 - abs(2.0 * l - 1.0));
63786
+ var h: f32;
63787
+ if (maxc == rgb.x) {
63788
+ let v = (rgb.y - rgb.z) / d;
63789
+ h = v - 6.0 * floor(v / 6.0);
63790
+ } else if (maxc == rgb.y) {
63791
+ h = (rgb.z - rgb.x) / d + 2.0;
63792
+ } else {
63793
+ h = (rgb.x - rgb.y) / d + 4.0;
63794
+ }
63795
+ h = h * 60.0;
63796
+ if (h < 0.0) { h = h + 360.0; }
63797
+ return vec3f(h, s, l);
63798
+ }
63799
+
63800
+ fn _gpu_hsv_to_rgb(hsv: vec3f) -> vec3f {
63801
+ let h = hsv.x;
63802
+ let s = hsv.y;
63803
+ let v = hsv.z;
63804
+ let c = v * s;
63805
+ let h6 = h / 60.0;
63806
+ let x = c * (1.0 - abs((h6 - 2.0 * floor(h6 / 2.0)) - 1.0));
63807
+ var r: f32 = 0.0;
63808
+ var g: f32 = 0.0;
63809
+ var b: f32 = 0.0;
63810
+ if (h6 < 1.0) { r = c; g = x; b = 0.0; }
63811
+ else if (h6 < 2.0) { r = x; g = c; b = 0.0; }
63812
+ else if (h6 < 3.0) { r = 0.0; g = c; b = x; }
63813
+ else if (h6 < 4.0) { r = 0.0; g = x; b = c; }
63814
+ else if (h6 < 5.0) { r = x; g = 0.0; b = c; }
63815
+ else { r = c; g = 0.0; b = x; }
63816
+ let m = v - c;
63817
+ return vec3f(r + m, g + m, b + m);
63818
+ }
63819
+
63820
+ fn _gpu_rgb_to_hsv(rgb: vec3f) -> vec3f {
63821
+ let maxc = max(max(rgb.x, rgb.y), rgb.z);
63822
+ let minc = min(min(rgb.x, rgb.y), rgb.z);
63823
+ let v = maxc;
63824
+ let d = maxc - minc;
63825
+ if (d < 1e-6) { return vec3f(0.0, 0.0, v); }
63826
+ var s: f32 = 0.0;
63827
+ if (maxc >= 1e-6) { s = d / maxc; }
63828
+ var h: f32;
63829
+ if (maxc == rgb.x) {
63830
+ let q = (rgb.y - rgb.z) / d;
63831
+ h = q - 6.0 * floor(q / 6.0);
63832
+ } else if (maxc == rgb.y) {
63833
+ h = (rgb.z - rgb.x) / d + 2.0;
63834
+ } else {
63835
+ h = (rgb.x - rgb.y) / d + 4.0;
63836
+ }
63837
+ h = h * 60.0;
63838
+ if (h < 0.0) { h = h + 360.0; }
63839
+ return vec3f(h, s, v);
63840
+ }
63841
+
63842
+ fn _gpu_color_mix(lch1: vec3f, lch2: vec3f, t: f32) -> vec3f {
62842
63843
  let L = mix(lch1.x, lch2.x, t);
62843
63844
  let C = mix(lch1.y, lch2.y, t);
62844
- let PI = 3.14159265359;
62845
- var dh = lch2.z - lch1.z;
62846
- if (dh > PI) { dh -= 2.0 * PI; }
62847
- if (dh < -PI) { dh += 2.0 * PI; }
62848
- let H = lch1.z + dh * t;
62849
- return _gpu_oklab_to_srgb(_gpu_oklch_to_oklab(vec3f(L, C, H)));
63845
+ let a1 = lch1.y < 1e-6;
63846
+ let a2 = lch2.y < 1e-6;
63847
+ var H: f32;
63848
+ if (a1 && a2) {
63849
+ H = lch1.z;
63850
+ } else if (a1) {
63851
+ H = lch2.z;
63852
+ } else if (a2) {
63853
+ H = lch1.z;
63854
+ } else {
63855
+ var dh = lch2.z - lch1.z;
63856
+ if (dh > 180.0) { dh = dh - 360.0; }
63857
+ if (dh < -180.0) { dh = dh + 360.0; }
63858
+ H = lch1.z + dh * t;
63859
+ if (H < 0.0) { H = H + 360.0; }
63860
+ if (H >= 360.0) { H = H - 360.0; }
63861
+ }
63862
+ return vec3f(L, C, H);
62850
63863
  }
62851
63864
 
62852
- fn _gpu_apca(bg: vec3f, fg: vec3f) -> f32 {
63865
+ fn _gpu_apca(lch_bg: vec3f, lch_fg: vec3f) -> f32 {
63866
+ let bg = _gpu_oklch_to_srgb(lch_bg);
63867
+ let fg = _gpu_oklch_to_srgb(lch_fg);
62853
63868
  let bgR = _gpu_srgb_to_linear(bg.x);
62854
63869
  let bgG = _gpu_srgb_to_linear(bg.y);
62855
63870
  let bgB = _gpu_srgb_to_linear(bg.z);
@@ -63137,7 +64152,7 @@ fn _gpu_apca(bg: vec3f, fg: vec3f) -> f32 {
63137
64152
  if (stmts.length === 0) return "";
63138
64153
  const last = stmts.length - 1;
63139
64154
  stmts[last] = `return ${stmts[last]}`;
63140
- return stmts.join(";\n");
64155
+ return stmts.join(";\n") + ";";
63141
64156
  },
63142
64157
  ...options
63143
64158
  };
@@ -63236,7 +64251,7 @@ fn _gpu_apca(bg: vec3f, fg: vec3f) -> f32 {
63236
64251
  if (body.includes("\n")) {
63237
64252
  const indented = body.split("\n").map((l) => ` ${l}`).join("\n");
63238
64253
  return `${returnType} ${functionName}(${params}) {
63239
- ${indented};
64254
+ ${indented}
63240
64255
  }`;
63241
64256
  }
63242
64257
  return `${returnType} ${functionName}(${params}) {
@@ -63347,7 +64362,7 @@ ${indented};
63347
64362
  return `fn ${functionName}(${params}) -> ${toWGSLType(
63348
64363
  returnType
63349
64364
  )} {
63350
- ${indented};
64365
+ ${indented}
63351
64366
  }`;
63352
64367
  }
63353
64368
  return `fn ${functionName}(${params}) -> ${toWGSLType(returnType)} {
@@ -67754,6 +68769,7 @@ ${code}`;
67754
68769
  this.pushScope(void 0, "global");
67755
68770
  this._compilationTargets.registerDefaults();
67756
68771
  if (options?.latexSyntax) this._latexSyntax = options.latexSyntax;
68772
+ if (options?.latexOptions) this._latexOptions = { ...options.latexOptions };
67757
68773
  hidePrivateProperties(this);
67758
68774
  }
67759
68775
  toJSON() {
@@ -68414,6 +69430,29 @@ ${code}`;
68414
69430
  );
68415
69431
  return this._latexSyntax;
68416
69432
  }
69433
+ /** @internal Engine-wide LaTeX parse/serialize options (e.g. decimalSeparator).
69434
+ * Merged into every `parse()` and `toLatex()` call between the LatexSyntax
69435
+ * instance defaults and any per-call overrides. */
69436
+ _latexOptions = {};
69437
+ /** Engine-wide LaTeX parse/serialize options.
69438
+ *
69439
+ * These options are merged into every `parse()` and `toLatex()` call.
69440
+ * Precedence (most-specific wins):
69441
+ * 1. LatexSyntax instance defaults (set at its construction)
69442
+ * 2. `ce.latexOptions` (this property)
69443
+ * 3. Per-call options passed to `ce.parse()` / `expr.toLatex()`
69444
+ *
69445
+ * Assigning replaces the whole bag. Use spread to merge:
69446
+ * ```ts
69447
+ * ce.latexOptions = { ...ce.latexOptions, decimalSeparator: '{,}' };
69448
+ * ```
69449
+ */
69450
+ get latexOptions() {
69451
+ return this._latexOptions;
69452
+ }
69453
+ set latexOptions(options) {
69454
+ this._latexOptions = { ...options };
69455
+ }
68417
69456
  parse(latex, options) {
68418
69457
  if (latex === null || latex === void 0) return null;
68419
69458
  if (typeof latex !== "string")
@@ -68421,7 +69460,6 @@ ${code}`;
68421
69460
  const syntax = this._requireLatexSyntax();
68422
69461
  const { form, ...parseOpts } = options ?? {};
68423
69462
  const result = syntax.parse(latex, {
68424
- decimalSeparator: ".",
68425
69463
  getSymbolType: (id) => {
68426
69464
  const def = this.lookupDefinition(id);
68427
69465
  if (!def) return BoxedType.unknown;
@@ -68433,6 +69471,7 @@ ${code}`;
68433
69471
  const def = this.lookupDefinition(id);
68434
69472
  return !!(isValueDef(def) && def.value.subscriptEvaluate);
68435
69473
  },
69474
+ ...this._latexOptions,
68436
69475
  ...parseOpts
68437
69476
  });
68438
69477
  if (result === null) return null;
@@ -68596,14 +69635,14 @@ ${code}`;
68596
69635
  _setDefaultEngineFactory(() => new ComputeEngine());
68597
69636
 
68598
69637
  // src/compute-engine.ts
68599
- var version = "0.55.6";
69638
+ var version = "0.56.0";
68600
69639
  ComputeEngine._latexSyntaxFactory = () => new LatexSyntax();
68601
69640
  _setDefaultEngineFactory(
68602
69641
  () => new ComputeEngine({ latexSyntax: new LatexSyntax() })
68603
69642
  );
68604
69643
  globalThis[/* @__PURE__ */ Symbol.for("io.cortexjs.compute-engine")] = {
68605
69644
  ComputeEngine: ComputeEngine.prototype.constructor,
68606
- version: "0.55.6"
69645
+ version: "0.56.0"
68607
69646
  };
68608
69647
  return __toCommonJS(compute_engine_exports);
68609
69648
  })();