JSEE. Computational Documents for the Web
Turn code into a shareable, offline-capable web app. Describe inputs/outputs once (JSON), run JS/Python in a Worker or via API, and ship as a single HTML file.
Minimal example:
<html>
<div id="jsee-container">
<script src="https://cdn.jsdelivr.net/npm/@jseeio/jsee@latest/dist/jsee.runtime.js"></script>
<script>
function mul (a, b) {
return a * b
}
new JSEE(mul, '#jsee-container')
</script>
</html>
↳ Result
Installation
Browser (CDN):
<script src="https://cdn.jsdelivr.net/npm/@jseeio/jsee@latest/dist/jsee.runtime.js"></script>
npm (for CLI or Node.js projects):
npm install @jseeio/jsee
CLI (generate standalone apps):
npx @jseeio/jsee schema.json -o app.html
Run jsee --help for all CLI options.
Inputs and outputs
JSEE works best with functional tasks and one-way flow from inputs to outputs (i.e., inputs → processing → outputs). You can also extend it to more complex scenarios, like inputs → preprocessing → updated inputs → processing → outputs or inputs → processing → outputs → custom renderer. Even though many computational tasks have a functional form, some problems require more complex interactions between a user interface and code. For such cases, JSEE is probably too constrained. That makes it not as universal as R’s shiny or Python’s streamlit.
How it works
JSEE turns a JSON schema into a working web app. Instead of writing HTML, event handlers and output renderers, you describe inputs, outputs and a model in a single JSON object. JSEE reads that schema, generates a reactive Vue 3 GUI, loads dependencies, and runs your code in a Web Worker (or on the main thread, or as an API call). In many cases it can build the schema automatically by analysing a function’s arguments.
Schema Model View/Render* Imports*
DEV -► json js/py js js/css
| | | |
┌──▼───────▼──────────▼────────────▼──┐
│ new JSEE(schema) │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Import loader │ │Schema parser │ │
│ └──────┬───────┘ └──────┬───────┘ │
└─────────┼─────────────────┼─────────┘
| |
┌──────▼──┐ ┌──────▼──────┐ ◄~ pyodide
USER ◄-► │ GUI │ ◄--► │ Pipeline │ ◄~ tf.js
│ Vue 3 │ │ Model(s) │ ◄~ wasm
└─────────┘ └─────────────┘
WebWorker*
* - optional
Initialization
- Schema is loaded from a URL, DOM element, function, or JS object
- Validation checks schema structure and logs warnings for issues
- Imports are resolved — JS scripts are loaded in sequence, CSS files are injected as
<link>tags. In the browser, relative paths resolve against the page URL. In--fetchmode, the CLI checks the local filesystem first - Models initialize — code is loaded from
url,code, or a hidden DOM cache (data-srcelements used by--fetchbundles anddownload()) - GUI is created — a Vue 3 app with reactive inputs, output cards, run/stop buttons and progress bar
- URL params are applied — query string values (
?name=value) set matching inputs, includingaliasmatches. File URL params auto-load on init
Execution
- Run: user clicks Run (or autorun/reactive triggers it). Inputs are collected and sent to the model
- Pipeline: when
modelis an array, models execute sequentially — each receives the merged output of the previous one. Return{ stop: true }to halt early - Worker context: worker models receive a runtime context (
ctx) withctx.log(),ctx.progress(value)(0–100 ornullfor indeterminate), andctx.isCancelled()for cooperative cancellation - Cancellation:
jsee.cancelCurrentRun()or the Stop button sets a flag that workers and stream readers check - Output: results flow to the output cards — JSON trees, HTML, SVG, code blocks, or custom render functions
Offline & bundling
jsee --fetchbundles everything into a single HTML file: the JSEE runtime, model/view/render code, and all imports are stored in hidden<script data-src="...">elements. The result works with no networkjsee.download(title)does the same at runtime — exports the current app as a self-contained HTML file
Schema blocks
JSEE takes a schema object that contains three main blocks:
model— describes a model/script/API (its location, is it a function or class, should it be called automatically on every GUI change or not)inputs— list of inputs and their descriptionsoutputs— list of outputs and their descriptions
Extra blocks can be provided for further customization:
render/view— visualization part (optional). Defines custom rendering codedesign— overall appearance (optional). Defines how the app looks overwriting defaults-
imports— a list of scripts and stylesheets to load before the model is initialized. CSS files (.cssextension) are injected as<link rel="stylesheet">in<head>, JS files are loaded as scripts. In the browser, relative paths (e.g.dist/core.js,./lib.js) resolve against the page URL. With--fetch, the CLI resolves imports by checking the local filesystem first — if a file exists on disk it is bundled; otherwise it is fetched from CDN"imports": [ "https://cdn.jsdelivr.net/npm/@tensorflow/tfjs", "dist/my-lib.js", "styles/app.css" ] -
examples— a list of examples (optional). Defines a list of examples that can be used to overwrite inputs"examples": [ { "input": "My name is Anton and I am" } ]
Playground
Schema
model— Contains main parameters of the model/scripturl(string) — URL of a JS/Python script or POST/GET APIcode(function) — It’s possible to pass code directly to JSEE instead of using an URLname(string) — Name of the executed object. Default value is taken fromurlorcodetype(string, default —function) — What kind of script is loaded. Influences how the code is initialized. Possible values:functionclassasync-functionasync-initpytf- Inference note: when
codeis present (including code loaded from a.jsURL), JSEE treats the model asfunctionunlesstypeis explicitly set
method(string) — Iftypeisclass,methoddefines the name of the class method to call during evaluationcontainer(string) — How input values are passed to the function/method:object(default) — Pass inputs wrapped in an object, i.e.{'x': 1, 'y': 2}args— Pass inputs as separate arguments
worker(boolean) — Iftrue, JSEE initializes a Web Worker to run the script- For
container: 'object', model functions receive a second runtime context argument (ctx) ctx.log(...args)— Write runtime logsctx.progress(value)— Report progress (0..100ornullfor indeterminate)ctx.isCancelled()— Check cooperative cancellation state (useful in long loops/streams)
- For
timeout(number, default:30000) — Worker execution timeout in milliseconds. Only applies whenworker: true. Does not apply during model initialization (loading can be slow). If exceeded, the worker is terminated with an errorimports(array) — Per-model imports loaded before this model’s code executes. Accepts URLs as strings or objects{ url: "..." }. Top-levelimportsare moved to the first model internallymodelcan also be an array of model objects to create a pipeline. Models execute sequentially — each receives the merged output of the previous one. First model defaults toworker: true, others toworker: false. Return{ stop: true }from any model to halt the pipeline early
render— Custom rendering script. Instead of relying on JSEE for output visualization, you can provide a custom script that visualizes the results. That can be useful if you rely on custom libs for plottingdesign— Design parameterslayout— Layout for the model/input/output blocks. If it’s empty and the JSEE container is not, JSEE uses inner HTML as a template. If the container is empty too, it uses the defaultblockstemplateframework— Design framework to use. If a JavaScript object with the same name is present in a global context, JSEE loads it too (using Vue’susemethod)
inputs— Inputs definitionname* — Name of the inputtype* — Type. Possible types:int,floatornumber— Numberstring— Stringtext— Textareacheckboxorbool— Checkboxselectorcategorical— Select (one of manyoptions)file— File Inputactionorbutton— Button (itsnamewill be passed as acallerto the model)
default— Default valuealias(string or array of strings) — Alternative names for URL parameter matching. E.g."alias": ["f", "file"]allows?f=valueor?file=valueto set this inputdisplay(string) — Filtrex expression to conditionally show/hide this input. Evaluated against current input values. E.g."display": "mode == 'advanced'"shows the input only whenmodeis"advanced". Supportslen()for string lengthdisabled(boolean) — Disables the input in the UI. When combined withreactive: true, triggers an initial model run on page load (useful for server-populated values)raw(boolean, file input only) — Iftrue, pass the raw source to the model instead of reading text in the UI (Fileobject for disk files or{ kind: 'url', url: '...' }for URL input)stream(boolean, file input only) — Iftrue, pass an async iterableChunkedReaderto the model instead of raw source handles. Supportsfor await (const chunk of reader),await reader.text(),await reader.bytes(), andfor await (const line of reader.lines()). Works in both main-thread and worker execution. Reader metadata (reader.name,reader.size,reader.type) is preserved and remains available in downstream pipeline models- URL params for file inputs (e.g.
?file=https://...) auto-load on init, so bookmarkable links run without an extra Load click
outputs— Outputs definition. Outputs also supportalias(string) for matching model result keys by alternative namesname* — Name of the outputtype* — Type. Possible types:file— File output (not displayer, but downloaded)object— JavaScript Objecthtmlorsvg— SVG elementcode— Code blockfunction— Render function. Rather than returning a value, a model returns a function that JSEE will call passing the container elementblank— Blank block (can be alternative tofunctionand useful for custom renderers)
examples— List of examplesautorun(boolean, default:false) — Run the model automatically on first loadreactive(boolean, default:false) — Re-run the model on any input change (debounced). For per-input reactivity, setreactive: trueon individual inputs insteadinterval(number, default:0) — Defines the interval between script evaluations (in milliseconds). If set to0, the script is evaluated only once- Runtime cancellation: call
jsee.cancelCurrentRun()on the JSEE instance to request stop of the active run. Long-running models should checkctx.isCancelled()and return early - Schema validation — JSEE validates schema structure during initialization and logs warnings for non-critical issues (e.g. unknown input types, malformed aliases)
jsee.download(title)— Downloads a self-contained HTML file that works offline. All external scripts are inlined and the schema/model/imports are cached.titledefaults to'output'page(CLI only) — Page metadata for generated HTML:title(string) — Page titleurl(string) — Page URLga(string) — Google Analytics measurement ID (e.g."G-XXXXXXXXXX")social(object) — Social media links:twitter,github,facebook,linkedin,instagram,youtube(values are usernames/handles)org(object) — Organization footer:name,url,description
JSEE is a reactive branch of StatSim’s Port. It’s still work in progress. Expect API changes.
CLI
--inputs,-i— Input schema JSON file (default:schema.json)--outputs,-o— Output file path(s), comma-separated (HTML, JSON, or both)--description,-d— Markdown file to include as app description--port,-p— Dev server port (default:3000)--version,-v— JSEE runtime version (latest,dev, or semver)--fetch,-f— Bundle everything into a single offline HTML: fetches the JSEE runtime, readsmodel/view/rendercode from disk, and resolves imports. Local files are detected by checking the filesystem (so bare paths likedist/core.jswork alongside./relative.js); anything not found locally is fetched from CDN. All code is stored in hidden<script data-src="...">elements--runtime,-r— Select runtime source for generated HTML:auto(default):inlinewhen--fetchis used, otherwisecdnfor file output andlocalfor dev server modelocal: usehttp://localhost:<port>/dist/...cdn: use jsdelivr runtime URLinline: embed runtime code directly in HTML- Any other value is used as a custom
<script src="...">path/URL (e.g../node_modules/@jseeio/jsee/dist/jsee.js)
--cdn,-c— Rewrite model URLs for CDN deployment (can be a base URL string or boolean to infer frompackage.json)--execute,-e— Run models server-side (see below)--verbose— Enable verbose logging--help,-h— Show usage info
Server-side execution
With --execute (-e), JSEE loads each model’s JS file on the server (via require()), rewrites the schema to point at a POST endpoint, and starts an Express server. The browser GUI sends inputs to the server, which runs the model and returns results as JSON. This is useful for models that need Node.js APIs or heavy computation that shouldn’t run in the browser.
jsee schema.json -e -p 3000
Changelog
See CHANGELOG.md.