@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 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
+ }