Rayact Dev Platform
Create a new app
RELEASE=https://github.com/raythings/rayact/releases/download/v0.0.5
npx "$RELEASE/create-rayact-app-0.0.5.tgz" my-app --release-url "$RELEASE"
cd my-app
npm run devOr from the monorepo:
rayact init my-app
cd my-app && npm installQuick start (monorepo)
# Start dev server + Ink TUI
npm run dev
# With Android adb reverse for the development server (8081)
npm run rayact -- dev --android
# Build debug APK with embedded dev launcher
npm run rayact -- build --debug --android --install
# Build release with minify + bytecode
npm run rayact -- build --release --android
# Verify desktop / Android / Web
npm run verify
npm run verify:android
npm run verify:webConfiguration
Project settings live in rayact.config.json:
rayactAppKey— manifest identity for pairingdevServer.host/devServer.port/devServer.cdpPorttransform.minify/transform.bytecodeper mode (dev, debug, release)
CLI flags override config in development/debug: --minify, --no-minify, --bytecode, --no-bytecode. Release bytecode cannot be disabled.
Dev client
Debug Android, iOS, and desktop custom dev-client builds embed @rayact/dev-client; the prebuilt dev app uses the same launcher UI:
- Connect — enter dev server URL or scan QR
- Recent — persisted URLs with reachability
- Discover — mDNS
_rayact._tcp(Android NSD, Apple Bonjour, and Avahi's DNS-SD compatibility API on Linux)
When discovery resolves a server, native clients prefetch its revision-tagged bootstrap, entry module, and bounded startup assets. The project transition keeps a loading surface visible while the runtime swaps, and cached files are only consumed when the current manifest revision still matches.
Web browsers cannot open raw mDNS sockets. The web dev URL therefore carries the already-resolved server in ?dev=<origin>; the shell starts the equivalent manifest-first prefetch immediately, before WASM initialization. Only the bootstrap and entry module gate startup, while bounded asset warming continues in the background.
Native bridge: global devCall(method, data, callback) is wired to the platform dev-client bridge on Android/iOS. The About tab prefers native getAppInfo (bundle id, app version, Rayact runtime) and falls back to values injected from rayact.config.json / package.json when the host bridge is missing.
Custom iOS clients link @rayact/prebuilt-ios-arm64's RayactEngine.xcframework, which keeps rayactDevFetch and devCall available for Debug live-connect (matching Android's jni-debug librayact).
Native-module selection
Every package manifest marked officialDevApp is collected into packages/first-party-modules.json; the generated catalog is the canonical input for the official Dev App. Its capability/config files are generated from that catalog, and the publication workflow invokes every catalog smoke test on an iOS simulator. Publication fails if a wrapper/artifact is missing or the recorded on-device evidence is stale or incomplete.
rayact prebuild follows the project's installed dependency graph and resolves packages that declare package.json#rayact.manifest and a rayact.module.json manifest. Android .so files, iOS .xcframework/.framework/.a files, and macOS/Linux shared libraries and Windows DLL/adjacent runtimes are copied into the generated client automatically. Explicit nativeModules entries in rayact.config.json can add configuration or narrow the generated capability manifest.
Web/WASM cannot load mobile or desktop dynamic libraries. A module selected for Web must list web in platforms and provide a JS/WASM implementation already linked into the Web host; builds fail when a selected module does not advertise Web support.
Platform-specific bundles and direct launch
One server owns revisioned desktop, Android, iOS, and Web contexts. Each context has its own transformed entry, native-module requirements, browser scripts/WASM, CSS/assets, and route tree, while connected clients share HMR and diagnostics.
Desktop and dev-app launch commands honor RAYACT_DEV_SERVER. On macOS or Windows this opens the active project directly; use the server machine's LAN URL when the client is on another computer. The TUI's desktop shortcut supplies both the argument and environment form for compatibility with older hosts.
Release mode
Release Android and iOS builds use dedicated embedded-project entry points. They do not start the launcher or register discovery, HMR, inspector, or remote debug transports. Android additionally removes local-network/cleartext permissions and its QR-scanner dependency. Web release hosts are built with npm run build:web-release-host; the dev loader, manifest/HMR fetches, URL bootstrap, and fallback demo are compiled out, while static exports also fail closed if their generated HTML contains a development marker. Desktop release hosts are built separately without discovery/dev-loader sources and start the embedded project bundle directly.
Run rayact doctor before prebuilding or releasing to check native toolchains, prebuilt manifests and module ABI compatibility, signing prerequisites, and WebGPU/COOP/COEP hosting requirements.
HMR
- WebSocket
/rayact/hmr— primary transport - HTTP
/rayact/statuspoll — fallback - Bytecode incompatible with React Fast Refresh; dev server serves JS when HMR clients are connected
Scripted / agent-driven reloads
Saving a file is normally all it takes: the dev server pushes a hot update and the connected app applies it in place, keeping app state. Nothing needs to be rebuilt, reinstalled, or relaunched for a JS change.
Two HTTP endpoints cover everything else, so scripts and AI agents never need the interactive TUI or a raw websocket client:
POST /rayact/reload— rebuild the bundles and full-reload every connected client. This restarts the JS entry (fresh state) without restarting the app process; use it after config/asset changes or when you want a clean re-run.GET /rayact/status—ok: true+ current revision, orok: falsewith the build error when the last save didn't compile.
If the app hit a build error or an uncaught render error, it shows the red error screen; the next save that evaluates cleanly (or a POST /rayact/reload) clears it and remounts the app — no restart required. Scaffolded projects ship an AGENTS.md documenting this loop for coding agents working in the repo.
Chrome DevTools (CDP)
The development server binds its InspectorProxy to 127.0.0.1:9229 (falling back to Chrome's other default discovery port, 9222). Android and iOS project sessions connect outbound to /rayact/devtools/device; no device-side CDP port or ADB forward/reverse for 9229 is used.
Open chrome://inspect with Discover network targets enabled. Rayact serves /json/list and /json/version from the loopback InspectorProxy, and every connected project session appears as a separate target.
Rayact DevTools
The dev server exposes a pinned React-Native-derived DevTools frontend at /rayact/devtools/rn_fusebox.html. The dev TUI opens it with t and the development manifest publishes devtoolsFrontendUrl. It connects to the same loopback CDP target as chrome://inspect, but is the supported frontend for Rayact's non-browser renderer.
Elements contains native Rayact host nodes only; the developer overlay is excluded. Sources shows the exact transformed modules currently evaluated by QuickJS (including HMR revisions) and is read-only until QuickJS gains real breakpoint/step support. Performance exposes live frame and QuickJS heap metrics rather than a sampling flame chart.
Inspector
In-app element tree via getNodeTree() native API. Toggle from dev menu. Selected nodes highlight with a magenta border.