Get started with the Web¶
Use the Web path when the program lives in a browser, renders visual output, or needs to work alongside a page. Hara's Web runtime uses the same language model as the native CLI, but host-dependent work crosses browser and WebAssembly provider boundaries.
This page describes the project-oriented Web path. For a zero-install first session, use Playground. For a browser workspace attached to Chrome DevTools, use Hara Chrome as described below.
Understand the browser runtime¶
The Rust runtime is shared by the native CLI and the WebAssembly build. Reader, evaluator, protocols, persistent data structures, functions, atoms, iterators, promises, bytes, and other portable values behave consistently across those targets. The host adapters are different.
A browser kernel normally maps to one worker and one WebAssembly instance. A kernel can contain multiple isolated sessions. Each session owns its mutable language state and attached capabilities, while immutable runtime infrastructure can be shared.
The evaluator does not call browser or operating-system APIs directly. Files,
storage, networking, rendering, timers, and page access are supplied by host
providers. Unsupported operations return unsupported; operations that exist
but have not been granted return denied.
Choose the Web surface¶
There are three useful browser entry points:
| Surface | Use it for |
|---|---|
| Playground | Trying Hara immediately without installing an editor |
| Hara Chrome | Programming a page from a Chrome DevTools panel |
| Embedded kernel | Building Hara into another Web application or workspace |
All three should use .hal source and the same evaluate, inspect, change, and
keep rhythm. The difference is where the kernel lives and which host
capabilities it receives.
Create a browser project¶
Start with a small project directory:
orbit-game/
project.edn
workspace.edn
src/
game.hal
project.edn describes source roots and requested capabilities.
workspace.edn describes the files, areas, nodes, visualisers, controllers, and
connections that make up the workspace. New projects use these data manifests.
Create src/game.hal:
(ns orbit.game)
(def player
(atom {:x 40
:y 30
:score 0}))
(defn move-right [amount]
(swap! player
(fn [state]
(assoc state :x (+ (get state :x) amount)))))
(move-right 2)
The atom is the current state. The function describes one state transition. A browser visualiser can watch that state and render the result without changing the language-level model.
Load Hara Chrome¶
Hara Chrome currently ships as a developer build. Build it from the Hara workspace, then:
- Open
chrome://extensions. - Enable Developer mode.
- Choose Load unpacked.
- Select
extensions/hara-chrome. - Open DevTools for a page.
- Select the hara panel.
The panel combines a browser-resident Hara runtime, a file and space view, and a REPL that evaluates in the active kernel.
Connect the project directory¶
Inside the Hara panel:
- Select choose home.
- Grant access to the project directory.
- Open a
.halsource file. - Use run .hal file to load it into the active kernel.
- Evaluate smaller forms in the Studio REPL while the project remains alive.
The browser stores Studio spaces and files locally in IndexedDB. The chosen home directory bridges the browser workspace to the local source tree. Browser permission controls how long that directory remains available.
Keep the source tree authoritative. IndexedDB and a running session are useful working state, but they should not be the only copy of the project.
Connect state to a visualiser¶
A useful Web project separates three concerns:
- the atom or session value that owns current state;
- a controller that proposes or applies state changes;
- a visualiser that reads state and renders an output.
For example, a controller may call move-right, while a canvas visualiser reads
player and redraws the scene. The connection is part of the workspace rather
than hidden inside a monolithic event loop.
This is also a useful way to learn evaluation. A form can be shown entering the reader, expanding through macros, evaluating against a session, changing an atom, triggering a watch, and finally updating a visual surface.
Work safely with the page¶
Use Hara Chrome when the thing you are making lives in, observes, or controls a browser page. The panel exposes explicit host namespaces for Chrome API work. Treat page access and Chrome APIs as capabilities, not as ordinary portable functions.
The optional local RESP bridge is a privileged developer tool. A local process that connects may be able to evaluate code with the panel's granted Chrome capabilities. Keep the listener local, understand which session is active, and do not expose the bridge as an unauthenticated network service.
Embed a kernel in another Web application¶
An embedded application owns the host boundary. It creates the worker or WASM instance, starts a kernel, creates or selects sessions, and decides which providers each session can use.
A sound embedding should keep these layers separate:
Hara source and forms
↓
portable evaluator and session state
↓
provider interfaces
↓
browser storage, rendering, networking, and application APIs
The host should pass data through stable Hara values or explicit foreign handles. It should not make arbitrary JavaScript objects appear to be portable Hara collections.
Test portability¶
Keep pure state transitions independent of the browser. Test those functions on the CLI or JVM runtime, then test only the provider boundary in the browser.
A useful split is:
(ns orbit.logic)
(defn move [state dx dy]
(-> state
(assoc :x (+ (get state :x) dx))
(assoc :y (+ (get state :y) dy))))
The browser-specific namespace can call move, update an atom, and render. The
logic namespace remains portable and deterministic.
Continue¶
Build the first browser game, follow the deeper Hara Chrome project guide, read projects and visual workspaces, and use the Rust and WASM runtime mapping when implementing or embedding the browser host.