@simonklee/opentui-tex 0.2.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.
- package/LICENSE +21 -0
- package/README.md +238 -0
- package/dist/backend.d.ts +23 -0
- package/dist/binding-tex-renderable.d.ts +24 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1379 -0
- package/dist/math-layout.d.ts +3 -0
- package/dist/math-parser.d.ts +4 -0
- package/dist/math-symbols.d.ts +11 -0
- package/dist/math-types.d.ts +59 -0
- package/dist/native/ffi.d.ts +18 -0
- package/dist/native/native-renderer.d.ts +15 -0
- package/dist/native/native-tex-backend.d.ts +8 -0
- package/dist/native/platform.d.ts +1 -0
- package/dist/native.bun.js +273 -0
- package/dist/native.d.ts +2 -0
- package/dist/native.js +273 -0
- package/dist/react.d.ts +8 -0
- package/dist/react.js +1501 -0
- package/dist/solid.d.ts +8 -0
- package/dist/solid.js +1501 -0
- package/dist/tex-renderable.d.ts +67 -0
- package/dist/unicode-tex-backend.d.ts +11 -0
- package/docs/native.md +32 -0
- package/docs/releasing.md +130 -0
- package/package.json +103 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OpenTUI Contributors
|
|
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,238 @@
|
|
|
1
|
+
# OpenTUI TeX
|
|
2
|
+
|
|
3
|
+
OpenTUI TeX renders TeX math in an ordinary renderable tree from
|
|
4
|
+
[OpenTUI](https://github.com/anomalyco/opentui):
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { TexRenderable, UnicodeTexBackend } from "@simonklee/opentui-tex";
|
|
8
|
+
|
|
9
|
+
container.add(
|
|
10
|
+
new TexRenderable(renderer, {
|
|
11
|
+
formula: String.raw`\sum_{i=1}^{n} i^2`,
|
|
12
|
+
display: true,
|
|
13
|
+
foreground: "#ffffff",
|
|
14
|
+
background: "#000000",
|
|
15
|
+
backend: new UnicodeTexBackend(),
|
|
16
|
+
}),
|
|
17
|
+
);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The terminal shows selectable text cells:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
n
|
|
24
|
+
∑ i²
|
|
25
|
+
i = 1
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
One package supplies two output types:
|
|
29
|
+
|
|
30
|
+
- `@simonklee/opentui-tex` renders formulas as semantic Unicode cells without
|
|
31
|
+
loading the TeX native library.
|
|
32
|
+
- `@simonklee/opentui-tex/native` renders formulas as images (Kitty, Sixel, or
|
|
33
|
+
block cells) through a prebuilt shared library.
|
|
34
|
+
|
|
35
|
+
Both backends run on Bun and Node. Native rendering requires Node 26.4 or
|
|
36
|
+
newer and experimental FFI flags. See [Images](#images).
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
Starting with the npm release of 0.2.0, install one package:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
npm install @simonklee/opentui-tex
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
You can also use `bun add`. Like `@opentui/core`, the package uses optional
|
|
47
|
+
dependencies to select a prebuilt library for the host platform. No local
|
|
48
|
+
native build is required. Prebuilt libraries exist for
|
|
49
|
+
x64 and arm64 on macOS, Windows, Linux glibc 2.17, and Linux musl.
|
|
50
|
+
On Linux, Bun 1.3.14 installs both libc variants; the loader selects one at runtime.
|
|
51
|
+
|
|
52
|
+
`@opentui/core` is a required peer dependency, not a bundled copy. Use the same
|
|
53
|
+
version across your application and its OpenTUI bindings. This release requires
|
|
54
|
+
`0.0.0-20260812-1d34234c`; compatibility with other Core versions is not yet
|
|
55
|
+
verified. npm installs required peers automatically.
|
|
56
|
+
|
|
57
|
+
The JavaScript package is MIT-licensed. The optional native binaries are
|
|
58
|
+
GPL-3.0-only because they link ZigTeX. Each binary package includes its license
|
|
59
|
+
notices, and `@simonklee/opentui-tex-native-source` contains the corresponding
|
|
60
|
+
source at the same version. Review those licenses before redistributing native
|
|
61
|
+
rendering. The source package is not a runtime dependency.
|
|
62
|
+
|
|
63
|
+
For applications upgrading from the 0.1.0 GitHub tarballs, replace imports from
|
|
64
|
+
`@simonklee/opentui-tex-native` with `@simonklee/opentui-tex/native` and remove
|
|
65
|
+
the separate native dependency. The existing 0.1.0 release assets are unchanged.
|
|
66
|
+
|
|
67
|
+
## TexRenderable
|
|
68
|
+
|
|
69
|
+
`TexRenderable` is the primary application component. It is a backend-neutral
|
|
70
|
+
`BoxRenderable`, not an image subclass. You must select a backend:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const formula = new TexRenderable(renderer, {
|
|
74
|
+
formula: String.raw`\frac{-b \pm \sqrt{b^2-4ac}}{2a}`,
|
|
75
|
+
display: true,
|
|
76
|
+
foreground: "#ffffff",
|
|
77
|
+
background: "#000000",
|
|
78
|
+
widthMax: 60,
|
|
79
|
+
heightMax: 12,
|
|
80
|
+
backend: new UnicodeTexBackend(),
|
|
81
|
+
fallback: "unicode",
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
container.add(formula);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Options beyond `BoxOptions`:
|
|
88
|
+
|
|
89
|
+
- `formula` (required): TeX source, at most 4,096 UTF-8 bytes.
|
|
90
|
+
- `foreground`, `background` (required): six-digit hex colors (`#rrggbb`).
|
|
91
|
+
- `backend` (required): the `TexBackend` that renders the formula.
|
|
92
|
+
- `display`: display style instead of inline style. The default is `false`.
|
|
93
|
+
- `widthMax`, `heightMax`: output limits in cells. The defaults are 80 and 24.
|
|
94
|
+
- `fallback`: behavior after a failure. The default is `"message"`.
|
|
95
|
+
- `streaming`: preview updates for incomplete input. The default is `false`.
|
|
96
|
+
- `imageOptions`: options for the installed `ImageRenderable`.
|
|
97
|
+
- `onError`: receives backend errors.
|
|
98
|
+
|
|
99
|
+
When you assign `formula.formula`, `TexRenderable` installs a synchronous
|
|
100
|
+
Unicode preview. It then starts a request for the selected backend. A native
|
|
101
|
+
result replaces the preview with an image in the same `TexRenderable`.
|
|
102
|
+
|
|
103
|
+
`formula.whenReady()` tracks replacement requests. It resolves after
|
|
104
|
+
`TexRenderable` installs the latest result. `formula.ready` exposes the
|
|
105
|
+
current request. `setColors()` renders the formula again after a terminal
|
|
106
|
+
theme change. `TexRenderable` aborts requests for stale or destroyed nodes.
|
|
107
|
+
|
|
108
|
+
With `streaming: true`, only the synchronous Unicode preview changes. The
|
|
109
|
+
layout shows incomplete constructs at the end as `□` placeholders.
|
|
110
|
+
|
|
111
|
+
The `fallback` option controls behavior after a failure. `"unicode"` keeps the
|
|
112
|
+
semantic preview. `"retain"` restores the previous successful backend result.
|
|
113
|
+
`"message"` displays an error. `"throw"` rejects readiness. The default is
|
|
114
|
+
`"message"`.
|
|
115
|
+
|
|
116
|
+
Share one backend across multiple `TexRenderable` instances. A `TexBackend`
|
|
117
|
+
transfers ownership of each image output to the receiver. The receiver must
|
|
118
|
+
dispose the image. `TexRenderable` manages all images that its backend returns.
|
|
119
|
+
This includes stale outputs and outputs kept by the `"retain"` fallback. Thus,
|
|
120
|
+
most applications do not manage images directly.
|
|
121
|
+
|
|
122
|
+
## React and Solid
|
|
123
|
+
|
|
124
|
+
Use the same registration pattern as other OpenTUI extension packages:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import { registerTex } from "@simonklee/opentui-tex/react"; // or @simonklee/opentui-tex/solid
|
|
128
|
+
|
|
129
|
+
registerTex();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`registerTex()` registers a `<tex>` component. Its reactive props are
|
|
133
|
+
`formula`, `streaming`, `display`, `foreground`, and `background`. The
|
|
134
|
+
component passes the other `TexRenderable` options without changes:
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<tex
|
|
138
|
+
formula={String.raw`e^{i\pi} + 1 = 0`}
|
|
139
|
+
foreground="#ffffff"
|
|
140
|
+
background="#000000"
|
|
141
|
+
backend={backend}
|
|
142
|
+
/>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`@opentui/react` and `@opentui/solid` are optional peer dependencies. Install
|
|
146
|
+
the one that matches your renderer.
|
|
147
|
+
|
|
148
|
+
## Backends
|
|
149
|
+
|
|
150
|
+
A `TexBackend` returns an owned `NativeImage` or semantic Unicode text.
|
|
151
|
+
The Unicode backend installs a `TextRenderable`. The native backend installs
|
|
152
|
+
an `ImageRenderable`.
|
|
153
|
+
|
|
154
|
+
### Unicode cells
|
|
155
|
+
|
|
156
|
+
`UnicodeTexBackend` parses a bounded subset of TeX math into an abstract syntax
|
|
157
|
+
tree (AST). It lays out fractions, roots, scripts, accents, aligned equations,
|
|
158
|
+
matrices, and cases as two-dimensional terminal cells. The output remains
|
|
159
|
+
selectable terminal text. `string-width` measures the output. The backend is
|
|
160
|
+
stateless and synchronous, and `renderSync` is public. It needs no cache or
|
|
161
|
+
explicit destruction.
|
|
162
|
+
|
|
163
|
+
### Images
|
|
164
|
+
|
|
165
|
+
Import the native backend explicitly. The package root of
|
|
166
|
+
`@simonklee/opentui-tex` never loads native code. The platform shared library
|
|
167
|
+
loads during the first native render:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import { NativeTexBackend } from "@simonklee/opentui-tex/native";
|
|
171
|
+
|
|
172
|
+
const backend = new NativeTexBackend();
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
On Linux musl, set `OPENTUI_LIBC=musl` before starting the application so both
|
|
176
|
+
OpenTUI and TeX select musl libraries. See [Native rendering](docs/native.md)
|
|
177
|
+
for library overrides and standalone executables.
|
|
178
|
+
|
|
179
|
+
MicroTeX parses a TeX-math dialect and computes glyph and rule positions.
|
|
180
|
+
ZigTeX records SVG paths for the embedded glyph outlines from Latin Modern
|
|
181
|
+
Math. NanoSVG rasterizes only the SVG that ZigTeX generates. It does not
|
|
182
|
+
rasterize arbitrary external SVG.
|
|
183
|
+
|
|
184
|
+
MicroTeX uses one process-wide font context. The native library initializes
|
|
185
|
+
this context once through `texInit`. It keeps the context for the process
|
|
186
|
+
lifetime. The renderer supports only the main JavaScript thread. If you
|
|
187
|
+
construct `NativeTexRenderer` in a Worker, the constructor fails immediately.
|
|
188
|
+
|
|
189
|
+
Ownership rules for direct use:
|
|
190
|
+
|
|
191
|
+
- Direct callers of `NativeTexRenderer.renderAsync()` must dispose each
|
|
192
|
+
returned image. Cached results use independent retained references. When you
|
|
193
|
+
dispose one result, the other results stay valid.
|
|
194
|
+
- `NativeImage.takeRaw()` requires exclusive ownership. Before you call it,
|
|
195
|
+
dispose all retained references. These references include the renderer cache
|
|
196
|
+
and renderable references.
|
|
197
|
+
|
|
198
|
+
### Custom backends
|
|
199
|
+
|
|
200
|
+
`TexBackend` is a public interface with one method:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
interface TexBackend {
|
|
204
|
+
render(request: TexRenderRequest): Promise<TexRenderOutput>;
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
The request contains `formula`, `display`, `foreground`, `background`,
|
|
209
|
+
`widthMax`, `heightMax`, and an `AbortSignal`. The output is either
|
|
210
|
+
`{ kind: "image", image }` or `{ kind: "unicode", text, columns, rows }`.
|
|
211
|
+
|
|
212
|
+
## Node
|
|
213
|
+
|
|
214
|
+
Native rendering requires Node 26.4 or newer. Start Node with these options:
|
|
215
|
+
|
|
216
|
+
```sh
|
|
217
|
+
node --permission --allow-fs-read=<application> --allow-ffi --experimental-ffi app.js
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Development
|
|
221
|
+
|
|
222
|
+
You can develop the package without the native toolchain.
|
|
223
|
+
|
|
224
|
+
```sh
|
|
225
|
+
bun run test
|
|
226
|
+
bun run typecheck
|
|
227
|
+
bun run build:package
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Native builds require Zig 0.16.0 and `curl`. Use this command to test a native
|
|
231
|
+
build:
|
|
232
|
+
|
|
233
|
+
```sh
|
|
234
|
+
bun run test:native
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
For npm authentication, release checks, and publishing, see
|
|
238
|
+
[Releasing](docs/releasing.md).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { NativeImage } from "@opentui/core";
|
|
2
|
+
export interface TexRenderRequest {
|
|
3
|
+
formula: string;
|
|
4
|
+
display: boolean;
|
|
5
|
+
foreground: string;
|
|
6
|
+
background: string;
|
|
7
|
+
widthMax: number;
|
|
8
|
+
heightMax: number;
|
|
9
|
+
signal: AbortSignal;
|
|
10
|
+
}
|
|
11
|
+
export type TexRenderOutput = {
|
|
12
|
+
kind: "image";
|
|
13
|
+
image: NativeImage;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "unicode";
|
|
16
|
+
text: string;
|
|
17
|
+
columns: number;
|
|
18
|
+
rows: number;
|
|
19
|
+
};
|
|
20
|
+
export interface TexBackend {
|
|
21
|
+
/** The receiver owns image outputs and must dispose them. */
|
|
22
|
+
render(request: TexRenderRequest): Promise<TexRenderOutput>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RenderContext } from "@opentui/core";
|
|
2
|
+
import { TexRenderable, type TexRenderableOptions } from "./tex-renderable.js";
|
|
3
|
+
export declare class BindingTexRenderable extends TexRenderable {
|
|
4
|
+
private bindingFormula;
|
|
5
|
+
private bindingStreaming;
|
|
6
|
+
private bindingDisplay;
|
|
7
|
+
private bindingForeground;
|
|
8
|
+
private bindingBackground;
|
|
9
|
+
private updateQueued;
|
|
10
|
+
constructor(context: RenderContext, options: TexRenderableOptions);
|
|
11
|
+
get formula(): string;
|
|
12
|
+
set formula(value: string);
|
|
13
|
+
get streaming(): boolean;
|
|
14
|
+
set streaming(value: boolean);
|
|
15
|
+
get display(): boolean;
|
|
16
|
+
set display(value: boolean);
|
|
17
|
+
get foreground(): string;
|
|
18
|
+
set foreground(value: string);
|
|
19
|
+
get background(): string;
|
|
20
|
+
set background(value: string);
|
|
21
|
+
setColors(foreground: string, background: string): void;
|
|
22
|
+
private queueUpdate;
|
|
23
|
+
private flushUpdate;
|
|
24
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { TexBackend, TexRenderOutput, TexRenderRequest, } from "./backend.js";
|
|
2
|
+
export { measureTex, TexRenderable } from "./tex-renderable.js";
|
|
3
|
+
export type { TexDimensions, TexFallback, TexRenderableOptions } from "./tex-renderable.js";
|
|
4
|
+
export { UnicodeTexBackend } from "./unicode-tex-backend.js";
|