Getting Started
What you need
The compiler and a browser. On Windows, lpsc.exe and the runtime directory are in one folder.
There is no npm install. A project does not need package.json or node_modules. An LPScript program depends only on the runtime that ships with the compiler.
Node.js is used in two cases: lpsc run, which runs a program without a browser, and the development server that serves a screen while you work on it. Node.js 18 or later is required.
A VS Code extension is included. It provides diagnostics, hover, go-to-definition, completion, find-references, and rename. It is a thin client for the language server and has no dependencies.
Getting the binaries
The binaries (compiler, language server, runtime, and editor extension) are provided free of charge and as-is. On Windows they are in one directory. There is no warranty. See "License and Contact" on the front page.
LPScript is not open source. Source code is disclosed to partner companies under NDA, as part of a paid engagement.
The compiler is written in OCaml and built with dune build. It requires OCaml 5, dune, and menhir. The runtime and the test suite have no package dependencies.
Compiler commands
lpsc check orders.lps # parse and type-check only
lpsc emit orders.lps # print the entry module's JavaScript
lpsc build orders.lps # write .mjs and .mjs.map per module
lpsc build orders.lps --minify # same, with short local names and no whitespace
lpsc run orders.lps # build and run with source maps
lpsc version # the git tag this binary was built from
The file you name is the entry point. Modules named in imports: are loaded too, and the whole program is type-checked together. Output is per module: one .lps produces one .mjs. References between modules are ES imports.
The version is a date, such as v2026.9.8, taken from the git tag at build time. A binary built after a tag gets a version like v2026.9.8-13-g1937fa4, which distinguishes a release from a working build.
A first program
module Hello.
Object subclass: #Greeting fields: (who : Str).
Greeting class >> to: name = Greeting fields: { who: name }.
Greeting >> line = 'こんにちは、' , who , 'さん'.
(Greeting to: '東海精機') line printNl.
lpsc run hello.lps prints one line.
Values cannot be modified. with: returns a new value with the named fields replaced.
A first screen
A screen is an actor that is responsible for one region of an HTML page written by a designer.
<!-- index.html, written by the designer -->
<div id="app">
<p class="count">0</p>
<button class="up">増やす</button>
</div>module Counter page: 'index.html'.
Actor subclass: #Screen fields: (n : Int).
Screen class >> new = Screen fields: { n: 0 }.
Screen >> up = self with: { n: n + 1 }.
Screen >> view = self reply: (
(Html clone: '#app' fill: { '.count' -> n asString })
at: '.up' on: #click send: #up).
App mount: Screen new at: '#app'.
page: 'index.html' tells the compiler which HTML file this screen uses. The compiler reads the file and checks that every selector in the program ('#app', '.count', '.up') exists in it. If the designer renames class="count", the build fails.
Html clone: '#app' fill: {...} clones the #app element and replaces the content of .count with the string form of n. at: '.up' on: #click send: #up sends the up message to this actor when .up is clicked. The up handler returns a new state with n incremented. The state changed, so the region is redrawn.
Next
Actors — state lives in actors, and a handler returns the next state for each message. Redrawing and server communication are built on this.
Views — using the designer's HTML, why events are specified by handler name, and the cost of drawing a ten-thousand-row list.
Design — money, dates, JSON, and what the type system does and does not guarantee.
JavaScript — the JavaScript the compiler produces, and how to call browser APIs.
Examples — the screens that ship with the distribution.