On this page
Where NuML runs
Manual contents | Tutorial | Model logic | Dashboard configuration | Platforms
The same NuML language serves three workflows: typed live into a DynSS app's editor, loaded from a preset, or embedded in a project definition so that an app is authored entirely as configuration. This chapter describes each home and the engine contract they share.
1. Three homes for NuML code
| Home | Who writes it | Where it lives |
|---|---|---|
| The DynSS Model Definition editor | the user (or the AI portal), interactively | the app's code input; saved into presets |
| Presets | saved sessions, shipped examples | the app's preset JSON (for example dynss2.json), under each preset's code property |
Project.model |
the app author | the project definition file (for example lorenzPrj.js) |
2. The DynSS apps: editor, presets, and the AI portal
In a DynSS app (dynss2 and relatives), clicking
Model Definition opens a NuML text area. Applying it compiles the model
logic, reconfigures the dashboard per the #= directives, and arms the
Run, Sensitivity, and Stochastic platforms.
Compile problems surface in a Numl Error(s) dialog.
Each app ships a set of presets — complete NuML programs with saved slider state and documentation, selectable from the preset menu and briefly cataloged in the app's RAM documentation summary. Presets are the best starting points for new models; the manual contents indexes the most instructive ones.
The AI portal, reached from the model editor, chats with a choice of LLMs that have been given a NuML system instruction (for the dynss2 app, NuML_dynss.md). A prompt describing a model in natural language returns NuML code plus documentation; the code drops into the editor, populates the dashboard, and can be saved as a preset. Each LLM session keeps an independent chat history; switching presets resets the histories so stale context does not leak between models.
3. NuML in Project.model
An app author can embed the model logic directly in the Project definition.
The shipped lorenz app declares its inputs
and displays as ordinary Project inputs/displays, then supplies the
equations as an array of NuML lines:
model: [
"deriv(x) @= sigma * (y - x);",
"deriv(y) @= x * (rho - z) - y;",
"deriv(z) @= x * y - beta * z;",
"initial(x) @= 10.0;",
"initial(y) @= 1.0;",
"initial(z) @= 1.0;",
"update(x,y,z) @= mainGraph;",
"update(x,z) @= phaseGraph;",
"update(x,y,z) @= xyzGraph;"
]
Three things differ from the DynSS workflow:
- Names come from the Project. Identifiers resolve against the Project's
own input codes (
sigma,rho,beta) and display codes (mainGraph,phaseGraph), not the DynSSSlider…/TimeGraph…inventory. - Configuration stays in the Project. Ranges, titles, palettes,
dt,method, andmaxTimeare regular Project settings, so#=statements are not needed. - The Main class is boilerplate. The entire lorenz.js model class is:
import {SDMain} from "@nwk/api/sdmain.js"
import {uberfy} from "@nwk/api/uberbuilder.js"
class Lorenz extends SDMain {
constructor() {super();}
init() {
super.init();
this.uber = uberfy(this.model, this);
}
setup() {
super.setup();
this.uber.update();
}
update() {
super.update();
this.uber.update();
}
get model() {return this.getParam("model");}
get sigma() {return this.getParam("sigma");}
// … one getter per Project input …
}
The runtime joins the model array into one source string, parses it, and
delivers it to the engine as the model parameter; uberfy compiles it
exactly as in a DynSS app. Only the input getters vary between such apps —
and when an app is created in Studio or Designer with the NuML pattern,
even those are generated automatically from the Project's inputs
(selector.js). An author using Studio
or Designer therefore configures only the Project.
4. The engine contract
However it arrives, NuML reaches the simulation engine as a parameter value, and two conventions make that work:
- The
'numl'header. A parameter whose string value begins with the line'numl'(or"numl") is recognized by the engine (SDMain.checkNuml) and parsed into code-plus-AST instead of being used as a plain value. The DynSS editor's normalizer adds the header if you omit it; include it anyway (rules).Project.modeltext is parsed by the hosting page before delivery, so the header is optional there. uberfy(code, main). The compiler (uberbuilder.js) builds the stocks, flows, memoized terms, and update routine onto the hostingSDMaininstance, as specified in how NuML becomes a running model. The DynSS main classes do the same with theircodeparameter:this.uber = uberfy(this.Code, this)(dynss2.js).
The #= directives never reach the engine; the hosting page consumes them
to reconfigure widgets, clock, and platforms before each run
(directive.js).
5. Sharing models as presets
Saving a model in a DynSS app serializes the NuML program together with the dashboard state (slider positions, ranges, and legends) into the app's preset JSON format. Preset files can be downloaded, shared, and loaded by other users of the same app — the shipped dynss2.json, dynsshs.json, dynsslvpp.json, and dynsspb1.json are exactly such files. Models produced through the AI portal additionally record the LLM identity and the prompt in their documentation, keeping generated models reproducible and attributable.