@wavelace/formula 0.1.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 (5) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/index.d.ts +49 -0
  4. package/index.js +1161 -0
  5. package/package.json +37 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright © 2026 Daniele Moraschi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # @wavelace/formula
2
+
3
+ Paste a formula as a textbook prints it, get a fast JavaScript function back. The formula layer of
4
+ [Wavelace](https://www.wavelace.com), the animated maths visualiser, published on its own: LaTeX in,
5
+ a plain expression out, a compiled function of real numbers, and a printer for showing it back.
6
+
7
+ ```js
8
+ import {compile, bindable, pretty} from "@wavelace/formula";
9
+
10
+ const f = compile("\\frac{\\sin(kx - \\omega t)}{x}", {k: 2, ω: 3});
11
+ f(0.7, 0, 0, 0, 0, 0, 0, 0.1); // a number
12
+
13
+ const wave = bindable("A \\sin(kx - \\omega t)");
14
+ wave.names; // ["A", "k", "ω"]: one slider each
15
+ const g = wave.bind({A: 2}); // rebinding is one call, never a recompile
16
+
17
+ pretty("\\int_0^x \\cos(u^2) du"); // "∫₀^x cos(u²) du"
18
+ ```
19
+
20
+ ## What it reads
21
+
22
+ `\frac`, `\sqrt`, powers in braces, `\sin x` without brackets, `\cos^2 x`, `\sin^{-1}`, the Greek
23
+ letters, subscripts (`x_0`, `\omega_0`), `90^\circ`, `\left( … \right)`, `\begin{cases}`,
24
+ `\int_a^b … du`, `\sum_{k=1}^{n}`, `\prod`, `\frac{d}{dx}`, `x!`, and the silent products a textbook
25
+ writes: `2x`, `2\pi x`, `\sin x \cos y`, `kx`. Pasted symbols work too: `π`, `θ`, `²`, `·`, `−`, `√`.
26
+ The whole language is documented at [wavelace.com/documentation](https://www.wavelace.com/documentation).
27
+
28
+ A single letter the language does not claim (`a`, `k`, `ω`, `x_0`) is a **free name**: it takes its
29
+ value from the values you pass, and is 1 until you do. A longer unknown name is refused rather than
30
+ guessed at, so a mistyped `sni(x)` says so instead of growing three free names.
31
+
32
+ ## The one signature
33
+
34
+ Every formula compiles to the same function, `(x, y, z, r, th, u, v, t) => number`, whatever it names:
35
+ `th` is the polar angle θ, and a caller feeds the variables it has. That is Wavelace's own choice, kept
36
+ as it is; `readsVars` says which of the eight a formula actually reads.
37
+
38
+ ## Beside the other libraries
39
+
40
+ Fifteen textbook formulas, each value checked against the arithmetic (27 September 2026; the script
41
+ that produced this is in this repository, so the numbers can be rerun rather than trusted):
42
+
43
+ | | right of 15 | size, minified and gzipped |
44
+ |---|---|---|
45
+ | @wavelace/formula | 15 | 10 KB |
46
+ | Compute Engine 0.138.0 | 15 | 974 KB |
47
+ | math-expressions 3.0.0-alpha.1 | 9 | 4 MB unpacked |
48
+ | evaluatex 2.2.0 | 5 | 3.6 KB |
49
+
50
+ Compute Engine does far more (symbolic algebra, simplification, units); this does the real-valued
51
+ case, and compiles about twenty times faster.
52
+
53
+ ## One thing to know
54
+
55
+ `compile` builds its function with `new Function`, which is what makes it fast. A page with a strict
56
+ Content Security Policy must allow `'unsafe-eval'` for it to run.
57
+
58
+ ## Licence
59
+
60
+ MIT. This package is generated from the Wavelace source, the same two files the site runs, byte for
61
+ byte; their comments speak of the app (its renderers, its rail, its plate) because that is where they
62
+ live. Changes are made there, so issues are welcome here and pull requests are ported upstream by hand.
package/index.d.ts ADDED
@@ -0,0 +1,49 @@
1
+ /* @wavelace/formula: the public API. tools/pkg.js reads the exported names off this file, so a name
2
+ * declared here is exported by the package and a name missing here is not. */
3
+
4
+ /** A compiled formula: every formula is a function of the same eight variables, and a caller feeds
5
+ * the ones it has. th is the polar angle θ; the rest are as named. */
6
+ export type Formula = (x: number, y: number, z: number, r: number, th: number, u: number, v: number, t: number) => number;
7
+
8
+ /** What the free names (a single letter the language does not claim, like a or ω) are worth. */
9
+ export type Values = Readonly<Record<string, number>>;
10
+
11
+ /** A formula compiled once with its free names still open. */
12
+ export interface Bindable {
13
+ /** The free names, in order of first appearance. */
14
+ readonly names: readonly string[];
15
+ /** The formula with each free name bound to values[name], or FREE_DEFAULT. Cheap: no recompile. */
16
+ bind(values?: Values): Formula;
17
+ /** The normalized source. */
18
+ readonly text: string;
19
+ }
20
+
21
+ /** A LaTeX subset translated into the formula language: \frac, \sqrt, \sin x, \int_a^b … du, \sum,
22
+ * \frac{d}{dx}, cases, and the silent products (2x, \sin x \cos y). Throws with a readable message. */
23
+ export function fromLatex(src: string): string;
24
+ /** fromLatex, with pasted symbols (π, θ, ², ·, −) read first and a run of letters like kx read as a
25
+ * product. What compile reads. Throws with a readable message. */
26
+ export function normalize(src: string): string;
27
+ /** The formula as it reads on a plate: 3x, θ, π, · for products, superscript powers, ∫ with limits. */
28
+ export function pretty(src: string): string;
29
+ /** One name as the plate prints it: th as θ, x_1 as x₁. */
30
+ export function prettyName(name: string): string;
31
+ /** Compile once, bind many times. Throws with a readable message. */
32
+ export function bindable(src: string): Bindable;
33
+ /** Compile and bind in one call. Throws with a readable message. */
34
+ export function compile(src: string, values?: Values): Formula;
35
+ /** Which of the eight variables a formula names. Conservative: a bound dummy called v counts as v. */
36
+ export function readsVars(src: string): Set<string>;
37
+ /** Whether a name would be a free name, and so take a value from Values. */
38
+ export function isFreeName(name: string): boolean;
39
+
40
+ /** The eight variables, in the order a Formula takes them. */
41
+ export const VARS: readonly ["x", "y", "z", "r", "th", "u", "v", "t"];
42
+ /** The functions and constants a formula may name, by name. */
43
+ export const ENV: Readonly<Record<string, unknown>>;
44
+ /** The four binders (integral, sum, prod, diff): their parts and the LaTeX that pastes as each. */
45
+ export const BINDERS: Readonly<Record<string, {readonly parts: readonly string[]; readonly paste: string}>>;
46
+ /** The Greek commands a formula may use as letters, and the glyph each becomes: \omega is ω. */
47
+ export const GREEK: Readonly<Record<string, string>>;
48
+ /** What a free name is worth until it is given a value. */
49
+ export const FREE_DEFAULT: number;