@mika/surface (0.1.1)
Installation
@mika:registry=npm install @mika/surface@0.1.1"@mika/surface": "0.1.1"About this package
Surface
Surface makes apps that are visual-agnostic. It will likely be used in web environments, but it does not require a browser, DOM, HTML, CSS, canvas, or any other specific renderer.
The package contract is the default export from index.js: an async generator that emits app objects. A renderer or host can consume those objects and decide how to present them.
Every emitted object must recursively contain only structured-cloneable values or JavaScript functions. Functions are allowed for active behavior such as callbacks when something is clicked, selected, submitted, or otherwise triggered by the host.
Start Here
This README is the canonical onboarding doc for setup and verification. AGENTS.md contains repo-local agent constraints, while .workflow/ points to the shared workflow repo.
If you are entering the repo for the first time, the default first pass is:
AGENTS.mdREADME.md.workflow/WORKFLOW.md.workflow/VERIFICATION.mdTEST.mdpackage.json
For staged change work such as specify, test, implement, or challenge, load .workflow/prompts/<stage>.md first and use changes/<slug>/YYYY-MM-DD_HHMM_<stage>.md as the per-change artifact path. See .workflow/WORKFLOW.md for the full staged workflow.
The shared workflow calls the landing prompt Deliver this, not Deploy this. If a user says either phrase, load .workflow/prompts/deliver.md and follow that prompt.
Usage
Import the default async generator and consume its emitted app objects:
import surface from 'surface'
for await (const app of surface()) {
console.log(app)
}
Run the minimal implementation directly:
npm start
Helpers
combine() turns an object of async generators into one async generator of state snapshots. It waits until every child has yielded an initial value, then emits a new snapshot each time any child yields again.
import { combine } from 'surface'
async function* a() {
yield 1
}
async function* b() {
let value = 2
while (true) {
await new Promise((resolve) => setTimeout(resolve, 1000))
yield value++
}
}
for await (const state of combine({ a: a(), b: b() })) {
console.log(state)
}
The first emitted state is { a: 1, b: 2 }, after b produces its first value. Later emissions keep the latest value from unchanged children.
Verification
npm test
The test script runs Node's built-in test runner with node --test.