Skip to content
Moku Labs
@moku-labs/editor pages

Configuration

Every option of every plugin of the three cores, set through pluginConfigs.

On this page

How config works

Every option belongs to a plugin. The three global configs, AgentConfig, ServerConfig and ToolsConfig, are empty. Options are set through pluginConfigs and shallow-merged over the defaults. An array you pass replaces the default array, and an object option such as flowView.layout replaces the default object as a whole.

A bad value throws at createApp, with a [moku-editor] <plugin>.<field> … message and a fix line.

src/editor-config.ts
import { createApp as createAgent } from "@moku-labs/editor/agent";
import { createApp as createServer } from "@moku-labs/editor/server";
import { createApp as createTools } from "@moku-labs/editor/tools";
import { app } from "./game";

// agent: a QA build with the overlay card open at start, docked left
export const editor = createAgent({
  pluginConfigs: { registry: { game: app }, overlay: { mode: "card", dock: "left" } }
});

// server: open files in Cursor instead of VS Code
export const server = createServer({
  pluginConfigs: {
    files: { root: `${import.meta.dir}/..` },
    pages: { editorUrl: "cursor://file/{path}:{line}" }
  }
});

// tools: start on the Flow workspace (Game is the default)
export const tools = createTools({ pluginConfigs: { workspace: { defaultWorkspace: "flow" } } });

Agent

PluginOptionDefaultMeaning
registrygameundefinedRequired. The app the game made with createApp.
registrymodules[]The game's .dev modules, merged after the doors.
registrynameundefinedManifest.game. Falls back to document.title, then "game".
channelheartbeatMs1000Ms between two beats. Whole number ≥ 100.
perfreadEveryMs250How often perf reads the monitor's frame ring, 50 to 1000.
perfwindowMs6000The window the graph and every spike count cover, 1000 to 30000.
perfframes1024Rows perf keeps: at least windowMs at 120 Hz. 64 to 16384.
perffeedPassesfalseRead the engine's pass ring and send the pass rows.
perffeedSystemstrueRead and send the top 5 systems of each frame.
perffeedNodesfalseRead and send the demand marks of each frame.
recorderautoStartfalsefalse: nothing records until someone starts it. "device": a log starts by itself on a debug build. true: on every page.
recorderkeepMb64Most MB in memory. 1 to 512.
recorderflushEveryMs1000How often the queue is serialized, 100 to 10000.
recorderpersistEveryMs5000How often text is written to the store, 1000 to 60000.
recorderstorage"auto""auto": OPFS when the page has it, else memory. "memory": never on disk.
recorderkeepFiles10Finished logs kept. 1 to 100.
recordermaxLogMb32The size of one log; at it the recorder rotates to the next log. 1 to 512.
overlaymode"hidden""hidden", "pill" or "card" at start when the device remembers none.
overlaydock"right""left" or "right": the edge the window docks to.
overlayremembertrueRemember place, mode and tab in localStorage.
overlaymountundefinedCSS selector of the host's parent; undefined is document.body.
bridgehello"/__editor/hello"Hello route: a same-origin path or an absolute URL.
bridgeretryMs1000First reconnect delay; doubles up to 30 s, ±20 % jitter.
bridgecallTimeoutMs5000Deadline of one read or run.
bridgedeviceundefinedDevice mode at this computer address (host:port). undefined: page mode on a served page; device mode with __MOKU_GAME_EDITOR__ or on a native page. __MOKU_GAME_EDITOR__ = "off" wins: no link at all.
bridgelinesPerBatch200Most log lines in one perf.lines message, 1 to 1000.
capturemaxDurationMs20000Longest series accepted.
captureminIntervalMs16Shortest series interval accepted.

Server

PluginOptionDefaultMeaning
filesroot"."Project root; must be an existing folder.
filesallow["**/*.ts", "**/*.tsx", "**/*.json", "**/*.md", "**/*.css", ".moku/**"]Globs a file must match. Case-sensitive.
filesdeny["**/node_modules/**", "**/.git/**", "**/dist/**", "**/.env*"]Globs never listed, read or written. Case-insensitive.
filesprojecttrueOpen the project index of root on start. false: off with reason disabled.
hubpath"/__editor"URL prefix of every editor route.
huballowOrigins[]Extra exact origins allowed.
hubcallTimeoutMs5000Deadline of a forwarded call.
hubsilentAfterMs6000No heartbeat this long marks a session silent.
hubdevicePort47600Port of the device listeners. 0 picks a free port.
hubdeviceLanfalseAlso listen on the computer's LAN address for paired phones.
hublanAddressundefinedThe LAN address to bind; undefined picks the first non-internal IPv4 of an en*, wl* or eth* interface.
hubdeviceOrigins["tauri://localhost", "https://tauri.localhost", "http://tauri.localhost"]Exact Origins a phone's WebView sends.
hubpairing"lan""lan": only a LAN phone is asked for its code. "always": every phone is asked.
hubpairTimeoutMs60000How long a pairing waits before it is refused.
connectadb"adb"The adb command: a name on PATH or a path.
connectadbTimeoutMs5000One adb call is killed after this, 500 to 60000.
connectscanEveryMs2000adb devices -l period while the Connect panel is open or device mode runs.
connectanswerTimeoutMs20000A ready phone with no session after this reads "No debug game answered".
connectleaseMs10000A scan or watch lease the tools page does not renew for this long ends.
connecttelemetryEveryMs1000The wired telemetry tick, 250 to 10000.
connectmeminfoEveryMs5000dumpsys meminfo period, 1000 to 60000.
connectheapEveryMs250CDP Runtime.getHeapUsage period, 100 to 5000.
connectgcDropMb0.5A heap drop of at least this is an inferred GC.
connectgcTracefalseAllows CDP tracing of GCs.
connectwire"manual""auto": the adb listener on at start when adb version answers and the port is free.
collectorout".moku/perf"Folder of the device logs, relative to the files root or absolute.
collectoreveryS10Seconds between two adb readings of heat and system frames, 1 to 3600.
collectorreverseEveryMs2000Ms between two adb devices and adb reverse rounds, ≥ 500.
collectoradb"adb"The adb command: a name on PATH or a path.
collectoradbTimeoutMs5000The longest one adb command may run, ≥ 500.
collectorappIdundefinedThe game's Android package; <appId>.debug is preferred when installed.
pagestitle"moku editor"Tools page <title>.
pageseditorUrl"vscode://file/{path}:{line}"The "Open in editor" link template.
pagespageDirundefinedBuilt page folder; undefined is dist/tools next to the module.
pagesgameUrl"/"Same-origin URL of the game page the tools page embeds.
pagestoolsPagetrueServe the tools page and its assets.

The switches of moku-editor perf are not options of their own. They map onto the fields above: --port to hub.devicePort, --lan to hub.deviceLan, --out to collector.out, --every to collector.everyS, --no-ui to pages.toolsPage: false.

Tools

PluginOptionDefaultMeaning
linkretryMs1000Base of the reconnect backoff, capped at 8 s.
linkboot"#moku-editor-boot"Selector of the boot JSON tag.
linkrole"page""page": the editor page, which publishes the selection. "tools": a plain tools client, such as a headless test.
linkreloadGraceMs8000How long an expected reload reads as "reloading" before a game that has not come back reads as lost.
activeSourceautoUsetrueA phone that links while the local preview is the source becomes the source.
activeSourcepauseLocaltruePause the local preview while a phone is the source.
activeSourcerejoinMs15000A lost phone that comes back within this is the source again; 0: never.
activeSourcenoticeMs12000How long the disconnect notice shows.
activeSourcerenewMs4000How often the scan and watch leases are renewed.
activeSourcemarkers32Source-switch markers kept for the timeline.
workspacedefaultWorkspace"game"Shown at start when the hash names none.
workspacestorageKey"moku-editor"localStorage key of the preferences.
workspacereloadTimeoutMs15000How long reload() waits for the new session.
workspacehotReloadWaitMs1500After a save with hot reload on: how long the reload waits for Bun before it reloads the frame itself.
workspacetoastMs2600How long one toast stays.
panelsnone{}No options.
flowViewhistoryLast, trailLength, rejectedOutcomes20, 6, ["rejected"]History watched, trail edges, rejection outcomes.
flowViewlayout{ file: ".moku/editor/layout.json", worker: true, saveDelayMs: 400 }Saved positions, ELK in a worker, save debounce. Replaced as a whole.
flowViewzoom{ min: 0.08, max: 3, defaultMin: 0.8 }Zoom range and default camera floor. Replaced as a whole.
flowViewhub{ minOutcomes: 6, minReturns: 4 }The hub rule. Replaced as a whole.
gameViewcapturesDir".moku/captures"Where captures and pick shots go, each in a day folder. .moku/captures or a folder under it.
gameViewcaptureCardMs, seriesWarnShots10000, 200Capture card timeout, series warning.
gameViewseriesDurationsMs, seriesIntervalsMs[1000, 2000, 5000, 10000, 20000], [16, 50, 100, 250, 500, 1000]Series popover chips.
renderViewreleaseLogMax50Release log entries kept. Mission control has no option: its history is 2 minutes.
stateViewexpandDepth, maxPatches, pageSize2, 200, 100Tree depth open, patches kept, children per page.
filesViewmaxFiles, maxHighlightChars5000, 512000Index cap, highlight cap.
filesViewreloadExtensions, revalidateMs[".ts", ".tsx", ".css", ".json"], 2000Saves that reload the game, tab re-read age.
consoleViewmaxLines, preserveLog5000, falseLines kept, Preserve log at start.
consoleViewfreshMs, summaryChars1200, 160Fresh-error highlight, inline data length.
  • registry.game has no default. The agent's onInit throws without it.
  • An object option is replaced, not merged. Pass the whole flowView.layout, zoom or hub object.
  • gameView.capturesDir is .moku/captures or a folder under it. Captures and pick shots go into day folders there.