@siglum/engine 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.
- package/LICENSE +21 -0
- package/README.md +318 -0
- package/package.json +55 -0
- package/src/bundles.js +545 -0
- package/src/compiler.js +1164 -0
- package/src/ctan.js +818 -0
- package/src/hash.js +102 -0
- package/src/index.js +32 -0
- package/src/storage.js +642 -0
- package/src/utils.js +33 -0
- package/src/worker.js +2217 -0
- package/types/bundles.d.ts +143 -0
- package/types/compiler.d.ts +288 -0
- package/types/ctan.d.ts +156 -0
- package/types/hash.d.ts +25 -0
- package/types/index.d.ts +5 -0
- package/types/storage.d.ts +124 -0
- package/types/utils.d.ts +16 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Siglum Project
|
|
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,318 @@
|
|
|
1
|
+
# Siglum
|
|
2
|
+
|
|
3
|
+
A browser-based LaTeX compiler. TeX Live 2025 running in WebAssembly, with lazy bundle loading and on-demand package fetching.
|
|
4
|
+
|
|
5
|
+
On initialization, the engine downloads:
|
|
6
|
+
- **WASM binary** (~29MB): the TeX engine
|
|
7
|
+
- **Core bundles** (~16MB for pdfLaTeX): format files, fonts, base packages
|
|
8
|
+
|
|
9
|
+
Common packages (amsmath, tikz, biblatex, etc.) are pre-bundled for fast loading. Less common packages are fetched from TexLive/CTAN automatically during compilation. Everything is cached in the browser for offline use.
|
|
10
|
+
|
|
11
|
+
The full bundle is ~195MB to deploy, but clients only download what their documents need.
|
|
12
|
+
|
|
13
|
+
**Guides:**
|
|
14
|
+
- [Examples & Playground Tutorial](examples/README.md) — Build a LaTeX editor UI
|
|
15
|
+
- [CTAN Proxy Guide](docs/CTAN_PROXY.md) — Self-host the package proxy for production
|
|
16
|
+
|
|
17
|
+
## Quick Start (Local Demo)
|
|
18
|
+
|
|
19
|
+
Clone the repo, download the WASM engine and pre-built bundles from [cdn.siglum.org](https://cdn.siglum.org) (or [GitHub Releases](https://github.com/SiglumProject/siglum-engine/releases)), then start the dev server.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
git clone git@github.com:SiglumProject/siglum-engine.git
|
|
23
|
+
cd siglum-engine
|
|
24
|
+
bun install
|
|
25
|
+
|
|
26
|
+
# Download WASM and bundles
|
|
27
|
+
mkdir -p busytex/build/wasm
|
|
28
|
+
curl -Lo busytex/build/wasm/busytex.wasm https://cdn.siglum.org/tl2025/busytex.wasm
|
|
29
|
+
curl -Lo busytex/build/wasm/busytex.js https://cdn.siglum.org/tl2025/busytex.js
|
|
30
|
+
curl -LO https://cdn.siglum.org/tl2025/siglum-bundles-v0.1.0.tar.gz
|
|
31
|
+
tar -xzf siglum-bundles-v0.1.0.tar.gz -C packages/
|
|
32
|
+
|
|
33
|
+
# Start dev server
|
|
34
|
+
bun serve-local.ts
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Open http://localhost:8787 to try the playground.
|
|
38
|
+
|
|
39
|
+
For disk-persistent package caching, run the CTAN proxy in a separate terminal:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bun packages/ctan-proxy.ts
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install @siglum/engine
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Download Runtime Assets
|
|
52
|
+
|
|
53
|
+
Download WASM and bundles from [cdn.siglum.org](https://cdn.siglum.org) or [GitHub Releases](https://github.com/SiglumProject/siglum-engine/releases/tag/v0.1.0):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
curl -LO https://cdn.siglum.org/tl2025/busytex.wasm
|
|
57
|
+
curl -LO https://cdn.siglum.org/tl2025/busytex.js
|
|
58
|
+
curl -LO https://cdn.siglum.org/tl2025/siglum-bundles-v0.1.0.tar.gz
|
|
59
|
+
|
|
60
|
+
# Extract to your public directory
|
|
61
|
+
tar -xzf siglum-bundles-v0.1.0.tar.gz -C public/
|
|
62
|
+
mv busytex.wasm busytex.js public/
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Then configure:
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
import { SiglumCompiler } from '@siglum/engine';
|
|
69
|
+
|
|
70
|
+
const compiler = new SiglumCompiler({
|
|
71
|
+
bundlesUrl: '/bundles',
|
|
72
|
+
wasmUrl: '/busytex.wasm',
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Or use the CDN directly (no self-hosting required):
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
const compiler = new SiglumCompiler({
|
|
80
|
+
bundlesUrl: 'https://cdn.siglum.org/tl2025/bundles',
|
|
81
|
+
wasmUrl: 'https://cdn.siglum.org/tl2025/busytex.wasm',
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Usage
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
import { SiglumCompiler } from '@siglum/engine';
|
|
89
|
+
|
|
90
|
+
const compiler = new SiglumCompiler({
|
|
91
|
+
bundlesUrl: '/bundles',
|
|
92
|
+
wasmUrl: '/wasm/busytex.wasm',
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
await compiler.init();
|
|
96
|
+
|
|
97
|
+
const result = await compiler.compile(`
|
|
98
|
+
\\documentclass{article}
|
|
99
|
+
\\begin{document}
|
|
100
|
+
Hello, World!
|
|
101
|
+
\\end{document}
|
|
102
|
+
`);
|
|
103
|
+
|
|
104
|
+
if (result.success) {
|
|
105
|
+
const blob = new Blob([result.pdf], { type: 'application/pdf' });
|
|
106
|
+
window.open(URL.createObjectURL(blob));
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## API
|
|
111
|
+
|
|
112
|
+
### `new SiglumCompiler(options)`
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
const compiler = new SiglumCompiler({
|
|
116
|
+
// URLs
|
|
117
|
+
bundlesUrl: '/bundles', // URL to bundle files
|
|
118
|
+
wasmUrl: '/wasm/busytex.wasm', // URL to WASM binary
|
|
119
|
+
jsUrl: null, // URL to busytex.js (derived from wasmUrl if null)
|
|
120
|
+
ctanProxyUrl: null, // CTAN proxy URL (enables CTAN fetching when set)
|
|
121
|
+
workerUrl: null, // Custom worker URL (uses embedded worker if null)
|
|
122
|
+
|
|
123
|
+
// Feature flags
|
|
124
|
+
enableCtan: false, // Auto-enabled when ctanProxyUrl is set
|
|
125
|
+
enableLazyFS: true, // Load files on-demand (faster startup)
|
|
126
|
+
enableDocCache: true, // Cache compiled documents by preamble hash
|
|
127
|
+
|
|
128
|
+
// Performance tuning
|
|
129
|
+
maxRetries: 15, // Max retries for CTAN/bundle fetches per compile
|
|
130
|
+
eagerBundles: {}, // Bundles to load immediately (see below)
|
|
131
|
+
verbose: false, // Log TeX stdout (disable for performance)
|
|
132
|
+
|
|
133
|
+
// Callbacks
|
|
134
|
+
onLog: (msg) => {}, // Log callback
|
|
135
|
+
onProgress: (stage, detail) => {}, // Progress callback
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### `eagerBundles`
|
|
140
|
+
|
|
141
|
+
By default, large bundles like `cm-super` (fonts) are loaded on-demand when TeX requests them. This saves bandwidth but adds latency on first use. To pre-load specific bundles:
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
// Load cm-super fonts eagerly for all engines
|
|
145
|
+
const compiler = new SiglumCompiler({
|
|
146
|
+
eagerBundles: ['cm-super'],
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Or per-engine configuration
|
|
150
|
+
const compiler = new SiglumCompiler({
|
|
151
|
+
eagerBundles: {
|
|
152
|
+
pdflatex: ['cm-super'],
|
|
153
|
+
xelatex: [], // XeLaTeX uses system fonts
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### `maxRetries`
|
|
159
|
+
|
|
160
|
+
Controls how many times the compiler retries when a package or bundle fetch fails. With pre-scanning (which batch-fetches most packages before compilation), retries are rare. Lower values fail faster if something is broken:
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
const compiler = new SiglumCompiler({
|
|
164
|
+
maxRetries: 5, // Fail fast (default: 15)
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### `verbose`
|
|
169
|
+
|
|
170
|
+
Controls whether TeX stdout is sent to the `onLog` callback. Disabled by default for performance—a typical compilation generates ~4,000 log lines, each requiring a `postMessage` call from the worker.
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
const compiler = new SiglumCompiler({
|
|
174
|
+
verbose: true, // Enable TeX stdout logging (default: false)
|
|
175
|
+
onLog: (msg) => console.log(msg),
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Can also be changed after instantiation
|
|
179
|
+
compiler.verbose = true; // Enable for next compile
|
|
180
|
+
await compiler.compile(source);
|
|
181
|
+
compiler.verbose = false; // Disable again
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
When `verbose: false`:
|
|
185
|
+
- TeX stdout (`[TeX] ...`) is suppressed
|
|
186
|
+
- TeX errors (`[TeX ERR] ...`) are always logged
|
|
187
|
+
- Worker status messages are always logged
|
|
188
|
+
- Error detection still works (stdout is captured internally)
|
|
189
|
+
|
|
190
|
+
### `compiler.compile(source, options?)`
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
const result = await compiler.compile(source, {
|
|
194
|
+
engine: 'pdflatex', // 'pdflatex' | 'xelatex' | 'auto'
|
|
195
|
+
additionalFiles: { // Include custom files
|
|
196
|
+
'mypackage.sty': '\\ProvidesPackage{mypackage}...',
|
|
197
|
+
'image.png': uint8Array,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// result.success — boolean
|
|
202
|
+
// result.pdf — Uint8Array (if successful)
|
|
203
|
+
// result.log — TeX log output
|
|
204
|
+
// result.error — error message (if failed)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### `compiler.clearCache()`
|
|
208
|
+
|
|
209
|
+
Clear all cached packages and compiled PDFs.
|
|
210
|
+
|
|
211
|
+
### `compiler.unload()`
|
|
212
|
+
|
|
213
|
+
Free memory by unloading the WASM module. Call `init()` again to reload.
|
|
214
|
+
|
|
215
|
+
### `createBatchedLogger(onFlush)`
|
|
216
|
+
|
|
217
|
+
Helper to batch log messages and avoid DOM thrashing. The TeX compiler emits hundreds of log lines during compilation and updating the DOM on each message can cause significant slowdowns.
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
import { SiglumCompiler, createBatchedLogger } from '@siglum/engine';
|
|
221
|
+
|
|
222
|
+
const compiler = new SiglumCompiler({
|
|
223
|
+
bundlesUrl: '/bundles',
|
|
224
|
+
wasmUrl: '/wasm/busytex.wasm',
|
|
225
|
+
onLog: createBatchedLogger((messages) => {
|
|
226
|
+
// Called once per animation frame with all buffered messages
|
|
227
|
+
logDiv.textContent += messages.join('\n') + '\n';
|
|
228
|
+
logDiv.scrollTop = logDiv.scrollHeight;
|
|
229
|
+
}),
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Performance Tips
|
|
234
|
+
|
|
235
|
+
### Batch log updates
|
|
236
|
+
|
|
237
|
+
If you're displaying compiler logs in the UI, always use `createBatchedLogger` or implement your own batching. Unbatched DOM updates can add 2-3 seconds to compilation time.
|
|
238
|
+
|
|
239
|
+
### Pre-warm the compiler
|
|
240
|
+
|
|
241
|
+
Call `compiler.init()` early (e.g., on page load) so bundles are ready when the user compiles:
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
// On page load
|
|
245
|
+
const compiler = new SiglumCompiler(options);
|
|
246
|
+
compiler.init(); // Fire and forget — bundles download in background
|
|
247
|
+
|
|
248
|
+
// Later, when user clicks compile
|
|
249
|
+
await compiler.compile(source); // Already warmed up
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Engines
|
|
253
|
+
|
|
254
|
+
| Engine | Status |
|
|
255
|
+
|--------|--------|
|
|
256
|
+
| pdfLaTeX | Full support, format caching |
|
|
257
|
+
| XeLaTeX | Full support, custom fonts via fontspec |
|
|
258
|
+
|
|
259
|
+
Use `engine: 'auto'` to auto-detect based on document content.
|
|
260
|
+
|
|
261
|
+
## Hosting / Production
|
|
262
|
+
|
|
263
|
+
Download assets from [cdn.siglum.org](https://cdn.siglum.org) or [GitHub Releases](https://github.com/SiglumProject/siglum-engine/releases/tag/v0.1.0):
|
|
264
|
+
|
|
265
|
+
| Asset | Size | Description |
|
|
266
|
+
|-------|------|-------------|
|
|
267
|
+
| `busytex.wasm` | 29 MB | WebAssembly TeX engine |
|
|
268
|
+
| `busytex.js` | 292 KB | Emscripten glue code |
|
|
269
|
+
| `siglum-bundles-v0.1.0.tar.gz` | ~195 MB | LaTeX packages & fonts |
|
|
270
|
+
|
|
271
|
+
Serve with these headers (required for SharedArrayBuffer):
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
Cross-Origin-Opener-Policy: same-origin
|
|
275
|
+
Cross-Origin-Embedder-Policy: require-corp
|
|
276
|
+
Access-Control-Allow-Origin: *
|
|
277
|
+
Cross-Origin-Resource-Policy: cross-origin
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Expected structure after extracting:
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
your-server.com/
|
|
284
|
+
├── busytex.wasm
|
|
285
|
+
├── busytex.js
|
|
286
|
+
└── bundles/
|
|
287
|
+
├── bundles.json
|
|
288
|
+
├── file-manifest.json
|
|
289
|
+
├── file-to-package.json
|
|
290
|
+
├── package-deps.json
|
|
291
|
+
└── *.data.gz (54 bundle files)
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### CTAN Proxy
|
|
295
|
+
|
|
296
|
+
The CTAN proxy fetches missing LaTeX packages on-demand:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
bun packages/ctan-proxy.ts
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Packages are cached permanently. The proxy tries TexLive 2025 archives first, then falls back to CTAN mirrors.
|
|
303
|
+
|
|
304
|
+
For configuration and deployment options, see **[docs/CTAN_PROXY.md](docs/CTAN_PROXY.md)**.
|
|
305
|
+
|
|
306
|
+
## Browser Requirements
|
|
307
|
+
|
|
308
|
+
- Modern browser with WebAssembly support
|
|
309
|
+
- SharedArrayBuffer (requires COOP/COEP headers)
|
|
310
|
+
- ~512MB RAM for compilation (max heap size)
|
|
311
|
+
|
|
312
|
+
## Acknowledgments
|
|
313
|
+
|
|
314
|
+
Built on [BusyTeX](https://github.com/AsciiHuang/busytex).
|
|
315
|
+
|
|
316
|
+
## License
|
|
317
|
+
|
|
318
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@siglum/engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A browser-based LaTeX compiler. TeX Live 2025 running in WebAssembly, with lazy bundle loading and on-demand package fetching.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"types": "types/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.js",
|
|
10
|
+
"./compiler": "./src/compiler.js",
|
|
11
|
+
"./bundles": "./src/bundles.js",
|
|
12
|
+
"./ctan": "./src/ctan.js",
|
|
13
|
+
"./storage": "./src/storage.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src/",
|
|
17
|
+
"types/"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "bun serve-local.ts",
|
|
21
|
+
"build:worker": "cp src/worker.js ../webtex/siglum-ui/app/public/worker.js && echo 'Copied worker.js to siglum-ui'",
|
|
22
|
+
"proxy": "cd packages && bun run ctan-proxy.ts",
|
|
23
|
+
"build:types": "tsc",
|
|
24
|
+
"prepublishOnly": "tsc"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/SiglumProject/siglum-engine.git"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"latex",
|
|
32
|
+
"tex",
|
|
33
|
+
"pdf",
|
|
34
|
+
"wasm",
|
|
35
|
+
"webassembly",
|
|
36
|
+
"browser",
|
|
37
|
+
"compilation"
|
|
38
|
+
],
|
|
39
|
+
"author": "Siglum Project",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/SiglumProject/siglum-engine/issues"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/SiglumProject/siglum-engine#readme",
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@siglum/filesystem": "^0.2.1",
|
|
47
|
+
"blake3-wasm": "2.1.5",
|
|
48
|
+
"xzwasm": "^0.1.2"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"fflate": "^0.8.2",
|
|
52
|
+
"jszip": "^3.10.1",
|
|
53
|
+
"typescript": "^5.0.0"
|
|
54
|
+
}
|
|
55
|
+
}
|