Skip to content

Releases: orktes/jsui

JSUI 0.11.0

Choose a tag to compare

@github-actions github-actions released this 27 Oct 06:40
de7cc87

JSUI 0.11.0 is a rendering performance release. Native GPU hosts now cache layers and reuse textures for scale and rotation animations, opaque screens stop paying for what they cover, image decoding leaves the frame thread on every platform, and Android moves to Skia Graphite on Vulkan.

Performance

  • Layer cache on native Graphite (Vulkan / Metal / Dawn): opacity layers, raster-cached subtrees and motion layers now draw from cached textures on native hosts too, not only on the web. In jsui-viewer on Metal the showcase renders 23–49% faster per frame and issues 25–64% fewer draws, for 4.5–19 MB of cache textures. JSUI_LAYER_CACHE=off turns it off (#193).
  • Motion layers: a cached layer or raster-cached subtree that keeps scaling or rotating is drawn from its texture under the changing matrix and repainted exactly once it rests. JSUI_MOTION_LAYERS=off turns it off (#188).
  • Occlusion culling: the painter skips what later opaque nodes fully cover. A full-screen opaque menu over a busy screen drops from ~2.6 ms to ~0.3 ms of paint; uncovered screens cost the same as before. JSUI_OCCLUSION=off turns it off (#185).
  • Image decoding off the frame thread: large images decode on a worker pool natively (#184) and in browser decode workers on the web (#194). Each frame spends at most ~1 ms of measured time decoding inline; the per-pixel cost estimate is learned at run time (#196).
  • Cheaper damage: a ringed box (0 0 0 1px shadow) no longer repaints its whole interior, which made the inventory's legendary pulse ~2x cheaper (#186); a hover's settling frame no longer switches the raster cache on and repaints the screen (~2 ms per hover, #190).

Platforms

  • Android on Skia Graphite / Vulkan, with Ganesh GLES 3 and CPU as fallbacks (--es jsui_renderer gl|cpu). On the emulator the launch stall is about halved; the library grows by ~1.2 MB. Real-device numbers are still to come (#195).
  • jsui_set_cache_dir(dir): new C API that sets where the pipeline, shader and Vulkan driver cache files go (#195).

Showcase

  • Runs in worker mode by default where the worker has WebGPU (?worker=0 opts out); the page's main thread does 86–95% less work (#191). The createJsui library default is unchanged for now.
  • Hamburger menu when the nav links don't fit (#189).

What's Changed

  • Site: hamburger menu when the nav links don't fit by @orktes in #189
  • painter: keep a ringed box's interior safe from damage growth (#160) by @orktes in #186
  • perf: don't switch the raster cache on in a hover's settling frame by @orktes in #190
  • perf: decode large images off the frame thread (native) by @orktes in #184
  • site: worker mode by default where the worker has WebGPU by @orktes in #191
  • Android: Skia Graphite on Vulkan, with GLES and CPU fallbacks by @orktes in #195
  • perf: spend the inline image decode budget in measured time by @orktes in #196
  • perf: skip painting what later opaque nodes cover (occlusion culling) by @orktes in #185
  • perf: motion layers for transform-only scale and rotation animations by @orktes in #188
  • perf(web): let the browser decode large images by @orktes in #194
  • perf: install the layer cache on native Graphite (Vulkan / Metal / Dawn) by @orktes in #193
  • Release 0.11.0 by @orktes in #199

Full Changelog: v0.10.0...v0.11.0

JSUI 0.10.0

Choose a tag to compare

@github-actions github-actions released this 26 Oct 18:43
3ecf33a

JSUI 0.10.0 brings three React Native libraries to every host: video with react-native-video's <Video>, vector drawing with react-native-svg and react-native-skia's <Canvas>, and react-native-worklets. It also makes hover frames on the web much cheaper, removes the first-visit pipeline stutter in browsers, and gives the Godot integration an optional UI thread.

Highlights

  • <Video> (react-native-video's API; react-native-video imports resolve to it): a host texture with a player behind it. JSUI still decodes nothing: the new JsuiConfig.on_video host interface gets open / set / seek / close commands and reports status back with jsui_video_status, the same API on every host. The browser host plays it with an HTML <video> (worker mode too) and jsui-viewer on macOS with AVFoundation. JS gets onLoad, onProgress, onEnd and friends, and progress bars can follow the <texture>.time host buffer without any JS (#175).
  • react-native-svg and react-native-skia <Canvas> on one native node, VectorView: paths, gradients, clips and masks, runtime effects, filters and path effects drawn with core Skia, parsed once per change. Drawing props animate as paint-only style keys, so Animated values and worklets drive them without React renders. react-native-svg, react-native-svg/css and @shopify/react-native-skia imports resolve to it. Not yet supported: SVG filters, Pattern, Marker, ForeignObject, per-shape touch; Skia Paragraph, Glyphs, Picture, Atlas, Vertices and backdrop filters (#177).
  • react-native-worklets: runOnUI, runOnJS, createWorkletRuntime, synchronizables and the rest of the API, on separate QuickJS runtimes on the UI thread inside jsui_tick. The worklets Babel plugin runs in jsui build, jsui dev and HMR. An Animated value captured in a worklet is a native handle, so a worklet can set it on the UI thread with no commit (#176).
  • Showcase: a new /vector page with SVG, Skia Canvas and worklet demos (#179); the cinematic screen plays its trailer through <Video> (#175). The showcase also runs natively in jsui-viewer, now on Skia Graphite on Metal on macOS, with browser-like trackpad scrolling (#170).
  • Godot UI thread: JsuiView.ui_thread (off by default, lockstep or pipelined) ticks the runtime and records each view's paint on a thread of its own, leaving only the replay to Godot's main thread (#147).

Performance

  • No first-visit stutter on the web: the GPU pipelines a page needs are built while it loads, from a shipped list (createJsui({ pipelines })) and the lists each browser built before (remembered in IndexedDB); the showcase intro no longer drops to ~13 fps on a cold shader cache (#169).
  • Cheaper hover frames: text color transitions repaint without rebuilding the paragraph (#146); scaling text draws from a tinted texture of its paint and is repainted exactly once the scale settles (#165); shadow masks are reused while inset shadows scale and panels slide (153 -> 9 masks blurred on the inventory hover sweep, #142); state styles step only the transitions under way (#161); Graphite storage buffers in browsers on Metal / D3D12 (#146).
  • Web idle sleep: the frame loop stops requesting animation frames when nothing moves and sleeps until the next JS timer or input (jsui_next_timer; idleSleep: false keeps the old loop) (#143).
  • Render targets a host keeps across frames are wrapped once on Dawn and Metal (#137). jsui-nav --hover-grid runs the hover benchmark on native hosts (#144).

Fixes

  • iOS Safari no longer pops up the on-screen keyboard when a page comes back (#164).
  • Site smoke test waits for the loading splash before screenshots (#174).

What's Changed

  • Web UI cost: wrap kept Graphite targets once, cheaper coverRects, profile breakdown by @orktes in #137
  • Halve showcase hover frames: stop re-blurring shadows while they scale or slide by @orktes in #142
  • web: pause the frame loop while idle (idleSleep, jsui_next_timer) by @orktes in #143
  • jsui-nav: --hover-grid, the hover benchmark's card grid on a native host by @orktes in #144
  • Cheaper hover frames: text recolor without rebuild, WebGPU storage buffers on Metal/D3D12 by @orktes in #146
  • State styles: step only the transitions under way while no input changed by @orktes in #161
  • Text: draw scaling text from a texture of its paint, exact once settled by @orktes in #165
  • Web: no more first-visit pipeline stutter (parallel pipeline warm-up, shipped + remembered lists) by @orktes in #169
  • web: stop Safari popping the on-screen keyboard when a page comes back by @orktes in #164
  • Showcase site natively: jsui-viewer on Graphite Metal, browser-like trackpad scrolling, --state by @orktes in #170
  • Godot: UI thread for the tick, damage tracking and paint recording (web: -0.15 ms/frame pipelined) by @orktes in #147
  • Site smoke test: wait for the loading splash before screenshots by @orktes in #174
  • VectorView: react-native-svg and react-native-skia Canvas (#167, #139) by @orktes in #177
  • Worklets: react-native-worklets on JSUI (#140) by @orktes in #176
  • First-class video:
  • Site: /vector page (react-native-svg, Skia Canvas, worklets demos) by @orktes in #179
  • Release 0.10.0: Video, SVG/Canvas, worklets by @orktes in #180

Full Changelog: v0.9.0...v0.10.0

JSUI 0.9.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 18:48
d45acf5

JSUI 0.9.0 makes web deploys one command with WebGPU included, brings the Godot integration to godot-aw3's threaded web export, keeps Vulkan pipelines across launches, and documents what JSUI costs a game in a new docs/PERFORMANCE.md.

Highlights

  • jsui build --web <dir> writes a deployable static site: the bundle, the host scripts, all three WASM builds (WebGPU, WebGL, CPU) and an index.html, every URL content-hashed (#136). No more copying jsui-web.js and dist*/ out of node_modules by hand, and no more silently losing WebGPU by deploying only dist-webgl/. The deployed jsui-web.js knows its module versions, so custom pages need no moduleVersions; later builds keep an edited index.html and update its URLs, and --html uses your own page. The bundle defaults to --format source there, since browsers run it on their own JS engine.
  • WebGPU warning: when the browser has WebGPU but dist-gpu isn't deployed (or isn't listed in moduleVersions), createJsui() now logs a console warning naming the fix instead of requesting a device it can't use and quietly rendering on WebGL (#136).
  • Godot on the web (godot-aw3): the Godot integration builds as a static library for the fork's threaded WebGPU export template (scripts/build-godot-web.sh, with Skia Graphite on WebGPU built with pthreads). The demo renders with Graphite on WebGPU in Chrome, with input, the JS thread and the shared HUD working (#135).
  • Vulkan pipeline cache on disk: Graphite's Vulkan context keeps the driver's VkPipelineCache in the user cache directory across launches, validated against the device and driver, so background precompiles stop being full driver compiles every launch (#131).

Performance

  • docs/PERFORMANCE.md: where JSUI runs in a game's frame, JS per frame on the demo HUD and showcase screens, native-first vs React state, spikes, memory and disk, engine frame times with and without the UI, and web numbers vs react-native-web (#128, #132).
  • Measuring the UI's cost: the raylib, sokol, Unity, Unreal and Godot examples take --no-ui and --bench (--bench-seconds in Godot) to time the same game with and without JSUI; the Godot demo's --hud runs the shared HUD scene (#129, #130).
  • sokol on Metal: on macOS the sokol example runs on Metal with Graphite drawing straight into sokol's own texture (UI cost +0.8-1.2 ms on GL down to +0.51 ms). JSUI_GL_INCREMENTAL lets a GL host's own texture be the retained frame, so only damage is repainted; raylib uses it (+0.28 to +0.19 ms) (#133).
  • The showcase can run on QuickJS for comparison with ?js=quickjs (#132).

Fixes

  • Godot demo: the self-test probes no longer draw over the UI (#134).
  • Release workflow: the npx smoke test waits for every package to appear on npm (#127).

What's Changed

  • Release: wait for every package on npm before the npx smoke test by @orktes in #127
  • Docs: PERFORMANCE.md, what JSUI costs a game by @orktes in #128
  • Engine examples: --no-ui and --bench for measuring the UI's frame cost by @orktes in #129
  • Vulkan: keep the driver's pipeline cache on disk across launches by @orktes in #131
  • Host JS engine branch caught up with main; js-bench fix, showcase on both engines, re-measured web numbers by @orktes in #132
  • Godot demo: --hud runs the shared HUD scene; PERFORMANCE.md Godot row on it by @orktes in #130
  • Engine examples: sokol on Metal (Graphite) on macOS, incremental GL texture targets for raylib by @orktes in #133
  • Godot demo: draw the self-test probes transparent by @orktes in #134
  • Godot integration: threaded web build for godot-aw3's web export by @orktes in #135
  • Web: jsui build --web deploys every WASM build; warn when dist-gpu is missing by @orktes in #136
  • Release 0.9.0: version bump and release notes by @orktes in #138

Full Changelog: v0.8.0...v0.9.0

JSUI 0.8.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 04:26
fb83f52

JSUI 0.8.0 continues the native-first work on top of 0.7.0's JS thread: input default actions no longer wait for JS, a native typewriter and pausable clocks, an overlay layer for popouts, and a much cheaper render-thread snapshot. A new guide, docs/NATIVE_FIRST.md, says when to use each native-first feature.

Highlights

  • Input without waiting on JS (#122): with JS on its own thread, Tab, Enter / Space / gamepad A, D-pad and stick navigation, text editing and wheel scrolling used to wait for JS's answer whenever a listener was on the path. Native now decides from the committed tree:
    • handlers marked fn.__passive = true never call preventDefault(), so their default action runs at once;
    • preventDefaultKeys (key or code) and preventDefaultButtons (gamepad buttons) on the focused path veto those keys at once, whatever JS answers;
    • global listeners can veto only some keys: addGlobalListener(type, fn, { passive } | { vetoes }).
      Pressable, Touchables, Text, TextInput, Modal, BackHandler and the gamepad store declare these themselves, so Enter presses, focus moves and typing never wait for JS.
  • Native typewriter (#123): <Text reveal revealMode="chars|words" revealFade revealFraction> paints only the first N graphemes or words of a paragraph laid out whole, so it never re-wraps. Animated.Text reveal={node} drives it natively. The showcase dialogue's JS time went from 245 to 1.5 µs per frame.
  • Pausable clocks (#123): Animated.clock({ start, speed, paused, running }) with pause(), resume(), reset(t) and setSpeed(x), run natively; a running node (a host-state bind, an interaction) can hold it. A paused clock no longer keeps the host rendering. Animated.clock() without options is still the shared frame clock.
  • Overlay layer for popouts (#124): <Overlay anchor placement offset flip collision boundary matchWidth hideWhenClipped> renders its children above everything and outside any clip, while staying the logical child of its React parent (hover and press chains, groups, focus order, event bubbling). The runtime places it next to its anchor every layout, flips it when it doesn't fit, keeps it inside the viewport or a boundary, and follows scrolling and transforms with no JS. <OverlayArrow> points at the anchor.

Performance

  • Render-thread snapshot (#125): with the JS thread on, every tick rebuilt the frame snapshot JS reads from (~30 µs and 300-1200 allocations per frame). Unchanged tables are now shared with the last snapshot, an unchanged tick publishes nothing, and empty overlays are skipped: 3-10x less owner-thread work per frame.

Showcase

  • Inventory popouts use the overlay layer: drawn above neighbouring slots and panels, flipped below when there is no room, kept on screen (#124).
  • The dialogue typewriter reveals natively (#123).

What's Changed

  • Input defaults without waiting on JS: declared keys, passive handlers, filtered global listeners by @orktes in #122
  • Native typewriter text reveal and pausable Animated.clock by @orktes in #123
  • Native overlay layer for popouts: placed, flipped and clipped by the runtime by @orktes in #124
  • Render thread: share unchanged frame-snapshot tables, skip empty overlays; native-first docs by @orktes in #125
  • Release 0.8.0: version bump and release notes by @orktes in #126

Full Changelog: v0.7.0...v0.8.0

JSUI 0.7.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 02:51
9034bb6

JSUI 0.7.0 runs JS on its own thread in every native host, as React Native does: frames, animations, scrolling and input keep going while JS renders, commits or collects garbage. It also removes first-launch shader stutter with a pipeline compile pool, precompiles and persistent shader caches.

Behaviour change: JS on its own thread by default in native hosts

The Godot, Unity and Unreal integrations, the native viewer and the engine examples (raylib, SDL3, sokol) now run the bundle on a JS thread (#112, #114, #115, #118, #120). jsui_tick and the renders never wait for JS; each tick applies the React commits JS finished since the last one, whole, and native Animated (host buffers included), scrolling, LayoutAnimations, hit testing, layout and paint run every frame even while JS is busy. With a 300 ms JS stall, Unity kept ticking and rendering with the longest frame under 1 ms.

What changes for a host and an app:

  • What JS does in a tick lands in a later tick, unless you wait for it: jsui_sync(rt, timeout_ms) or a jsui_tick_ex with JSUI_TICK_SYNC_JS (scene cuts, screenshots, tests). The integrations expose these as SyncJs() / SyncJsNextFrame() (Unity, Unreal) and sync_js() / sync_js_next_frame() (Godot).
  • on_message, on_state, on_call, on_audio, log and load callbacks run inside a later jsui_tick (or jsui_sync), not while JS is on the stack; jsui_post_message and jsui_call_ui only queue.
  • jsui_send_* return what native predicts, not whether a handler called preventDefault(). A key on a view with a key handler waits for JS's answer up to js_event_deadline_ms (100 ms by default).
  • React Native's callback measures (ref.measure, UIManager.measure) answer after the next layout, as in React Native; the synchronous native measure reads the last frame's layout.

To opt out (single-threaded frames as in 0.6.0): set jsThread = JsThreadMode.Off on Unity's JsuiView, JsThread = EJsuiJsThread::Off on Unreal's UJsuiWidget, js_thread = JS_THREAD_OFF on Godot's JsuiView, or pass --js-thread off to the viewer and examples. In the C API the mode is JsuiConfig.js_thread / jsui_set_js_thread, and jsui_config_init still defaults to JSUI_JS_THREAD_OFF. JSUI_JS_THREAD_LOCKSTEP runs JS on the thread but waits for it every frame, which gives single-threaded frames. The web build is unchanged (the host JS engine has no JS thread; worker mode is still opt-in).

New APIs: jsui_sync, JSUI_TICK_SYNC_JS, jsui_debug_stall_js (demos and smoke tests), on_js_ready to wake a sleeping host, and js_* perf counters (js_busy_ms, js_lag_frames, js_sync_ms, ...). The viewer switches modes with F6 and stalls JS with F7. The JS-thread suites run under ThreadSanitizer in CI.

No more first-launch shader stutter

  • Graphite compile pool: Metal, Vulkan and Dawn contexts compile pipelines on up to 4 background threads, so a frame with several new kinds of draws waits for the slowest compile instead of their sum, and preloaded shaders (precompileShaders) warm up off-frame (#113).
  • Pipeline cache by default: Graphite keeps a cache file per program in the user's cache directory, so pipelines a first launch compiles are ready from the second launch on, in every host (#113).
  • Common precompiles: the pipelines JSUI's painter draws most (fills, images, gradients, text, blurred rounded rects, for single-sampled and multisampled passes) are precompiled on the first frame of a target, and jsui_gpu_prepare_target starts them before the first frame (Godot calls it). JSUI_PRECOMPILE_COMMON=off turns it off (#116, #117).
  • Ganesh shader cache file for GL program binaries, Direct3D HLSL and iOS Metal (#119).

Rendering and showcase

  • Nine-patch shadow masks on GPU canvases: a big card's shadow is rendered at its corners plus a stretched middle instead of full size on the CPU, removing a 25 ms paint on the showcase's Home to Motion navigation (#111).
  • Native-first showcase screens: the scoreboard's match clock, the loading screen's progress and the inventory's hover popouts run on native Animated values, state styles and Visibility instead of re-rendering React; the scoreboard's idle JS dropped from 125 to 55 µs per frame (#110).

What's Changed

  • Native-first showcase screens, inventory hover popouts, format time, press styles over native animation by @orktes in #110
  • render: nine-patch shadow masks on GPU canvases by @orktes in #111
  • JS thread step 1: record native mutations in a command buffer by @orktes in #112
  • JS thread step 2: inbound message queue and late event answers by @orktes in #114
  • render: Graphite compile pool, off-frame shader warm-ups, default pipeline cache by @orktes in #113
  • JS thread step 3: thread-safe shared state, frame snapshot, host-callback queue by @orktes in #115
  • render: precompile the common Graphite pipelines on the compile pool by @orktes in #116
  • render: precompile multisampled-pass pipelines; jsui_gpu_prepare_target by @orktes in #117
  • render: persistent shader cache file for Ganesh (GL, Direct3D, iOS Metal) by @orktes in #119
  • JS thread step 4: run JS on its own thread (opt-in), jsui_sync, stall acceptance tests by @orktes in #118
  • JS thread step 5: on by default in every native host, sync/stall APIs, docs by @orktes in #120
  • Release 0.7.0: version bump and release notes by @orktes in #121

Full Changelog: v0.6.0...v0.7.0

JSUI 0.6.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 23:37
3f647b6

JSUI 0.6.0 makes the native libraries about 40% smaller, moves more of the UI off the JS thread (native expressions, composites, animated text and hover / press / focus styles), adds JS debugging in Chrome DevTools and VS Code, and makes navigation smooth with time-sliced renders, idle teardown and a faster QuickJS that collects garbage between frames.

Highlights

  • JS debugging: every dev-mode runtime (native viewer, game engines, --headless) is a Chrome DevTools / VS Code target through jsui dev, with breakpoints on JSX lines via source maps. Runtimes show up in chrome://inspect, and the debugger costs nothing while no breakpoint, step or pause is set. Build option JSUI_DEBUGGER (off on wasm) (#97, #101).
  • Animated.derive: values computed from Animated values, host data or the frame clock run as native math expressions every frame, with no JS and no frame of lag. Animated.derive([x, cam], (ux, cx) => clamp((ux - cx) * 0.1, 0, 400)), Animated.expr, Animated.clock(), GLSL-style helpers (clamp, lerp/mix, step, smoothstep, fract, wrap). jsui build keeps the function source for bytecode bundles (#103).
  • Native composites and animated text: sequence / parallel / stagger / loop / delay of native-driven steps run as one native animation, so choreography keeps going while JS is busy. The native driver animates layout keys too (width, top, flex, ...), unlike React Native. <Animated.Text text={Animated.format(node, {decimals, grouping, prefix, suffix})} /> updates numbers without re-renders (#106).
  • State styles without JS: hoveredStyle, pressedStyle, focusedStyle, focusVisibleStyle and disabledStyle on any host element, with transitions, plus group / groupHoveredStyle for descendants and useInteraction() for native 0..1 state values (#106).
  • Group state, Visibility and host-state bindings: useGroupState() gives descendants of a <Group> / <Pressable group> its hover / press / focus as native Animated values. <Visibility visible={bool | Animated node}> shows and hides natively, with fade / scale transitions. useHostStateBind(key, path) / Animated.hostState bind a native value to a field of shared host state, so styles, Animated.Text, derive and Visibility follow game data without a JS tick. Together they make hover popouts and data-driven HUD pieces with no JS (#108).
  • Smooth navigation: React's scheduler yields on the runtime's per-tick JS budget, so transitions render in slices instead of stalling frames. Set it with jsui_set_js_frame_budget, jsFrameBudget on the web or js_frame_budget_ms in Godot (default 5 ms, 0 turns it off). onLayout events reach JS in one batch per tick, and text from sliced renders is shaped in spare frame time before the commit (#98). The old page is torn down in idle slices instead of in the commit frames: frames over 16.7 ms during showcase navigation drop from 5.3 to 3.3 per run (#104).

Smaller binaries

Skia's desktop, iOS and Android builds now embed the trimmed ICU data set the web and Windows builds already used (everything text shaping and line breaking need, without collation, locales, converters and time zones), the iOS xcframework drops the unused arm64e slice, and every library is linked with dead code stripping (#99). Text renders byte-identically, including Thai, CJK, Arabic, Hebrew and emoji.

Binary (unpacked, MB) 0.5.0 0.6.0
libjsui.so linux-x64 26.5 16.8
libjsui.so linux-arm64 25.8 16.1
libjsui.dylib macOS universal 45.8 26.7
jsui.dll windows-x64 15.6 15.7
Godot linux x86_64 30.6 15.9
Godot macOS universal 47.9 28.8
Unity macOS bundle 55.7 32.5
Unity linux x86_64 28.3 16.8
iOS libjsui.a (per SDK) 129.3 56.6

Release downloads: macOS 46.6 to 27.1 MB, linux-x64 25.8 to 15.8 MB, Godot addon 58.2 to 37.3 MB, Unity 45.6 to 30.7 MB, Unreal 42.1 to 29.5 MB, iOS 97.2 to 43.7 MB. Windows was already on the trimmed ICU data.

Performance

  • QuickJS engine patches from react-native-quickjs (inline caches, object literal shape templates, fused opcodes, holey dense arrays, string caches, faster JSON and RegExp) on every build: 8-24% less JS time across jsui-bench (#100).
  • GC between frames: collections that come due while JS runs are deferred to the end of the tick, so they no longer land in the middle of a commit. The mount scenario's JS p95 drops from 24.0 to 8.4 ms. jsui_get_perf reports gc_* totals (#100).
  • Engine demo HUD: a game-state update re-renders only what changed; a tick with an FPS update goes from 1.09 to 0.40 ms median (#107).

Fixes

  • Unity smoke test and HMR test made robust on slow runners (#98, #102).

What's Changed

  • JS debugging: Chrome DevTools / VS Code for any dev-mode runtime by @orktes in #97
  • Smooth navigation: time-sliced React renders on a configurable JS frame budget by @orktes in #98
  • Debugger follow-ups: chrome://inspect discovery, no slowdown while idle by @orktes in #101
  • Fix flaky HMR test in js packages CI by @orktes in #102
  • QuickJS: react-native-quickjs engine patches + generational GC between frames by @orktes in #100
  • Navigation: tear down the old page in idle slices, not in the commit frames by @orktes in #104
  • Animated.derive: native math expressions over Animated values, host data and the clock by @orktes in #103
  • Engine demo HUD: a game-state update re-renders only what changed by @orktes in #107
  • Native composites, animated text and state styles (hover / press / focus without JS) by @orktes in #106
  • Shrink the native libraries: trimmed ICU data, no arm64e on iOS, dead code stripping by @orktes in #99
  • Group state, Visibility and native host-state bindings (hover popouts without JS) by @orktes in #108
  • Fast number parse/format (no wasm soft-float) + jsui-nav phase profiling by @orktes in #105
  • Release 0.6.0: version bump and release notes by @orktes in #109

Full Changelog: v0.5.0...v0.6.0

JSUI 0.5.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 20:35
167e472

JSUI 0.5.0 is the first release that ships prebuilt native binaries and engine plugins next to the npm packages, and it brings audio, custom fonts, GPU rendering on Windows and Linux, and a large performance round.

Install

  • npm: npm install @orktes/jsui-react @orktes/jsui-web and npm install -D @orktes/jsui-cli
  • Agent skill: npx @orktes/jsui-cli skill install
  • Unity: Package Manager → Add package from git URL → https://github.com/orktes/jsui.git#upm (or #upm/v0.5.0), or the com.orktes.jsui-0.5.0.tgz below
  • Unreal Engine 5: unzip jsui-unreal-0.5.0.zip into your project's Plugins/
  • Godot: unzip jsui-godot-0.5.0.zip into your project (addons/jsui/)
  • C/C++, Rust, Go and other hosts: jsui-0.5.0-<platform> archives (shared library, jsui.h, CMake package find_package(jsui), jsui-viewer); iOS: jsui-0.5.0-ios-xcframework.zip

Highlights

  • Prebuilt binaries on every release: libjsui for Linux x64/arm64, macOS universal and Windows x64, the Godot addon for all of them, and an iOS xcframework (#78).
  • Unity package and Unreal plugin: com.orktes.jsui (JsuiView, native plugin on Metal, Vulkan and D3D) and the Jsui UMG widget plugin, both with GPU rendering prebuilt (#75, #80, #81, #90, #92).
  • Engine examples: raylib, SDL3 (Skia straight into SDL's GPU texture) and sokol hosts of one shared game HUD, with click-to-select units and self-tests through each engine's input path (#67, #76, #77, #92).
  • GPU on Windows and Linux: Skia m157 on Windows (Ganesh D3D12/D3D11, Graphite Vulkan), Direct3D in Godot, Vulkan/D3D in Unity and Unreal (#82).
  • Audio: UI sounds and music through a host on_audio handler, with a built-in miniaudio default, Web Audio on the web and Godot audio buses; Sound, useSound, useMusic, UISounds in React (#69).
  • Custom fonts: @font-face registry, WOFF2/TTC, variable fonts, fallbacks, an expo-font compatible API and host APIs (#68).
  • Shader preloading: precompileShaders / jsui_precompile_shader warm GPU pipelines before first use (#70).
  • Rust and Go bindings over the C API, each with a GPU example app (#83).
  • Android proof of concept: NDK host on Skia Ganesh GLES (#79).

Performance

  • Native prop diffing, allocation-free native Animated, O(changed) damage walk, cached moving shadows (#84).
  • Profile-guided QuickJS in the release binaries, faster CPU paint, opt-in React Compiler (#85).
  • Precompiled QuickJS bytecode bundles by default in jsui build (with a source fallback) (#86).
  • Fast damage regions for many moving views: 300 moving markers paint in 2.5 ms instead of 33.5 ms natively (#89).
  • QuickJS hot-path patches (Object.keys, for-in, object literals, shape transitions), a React reconciler specialized for the JSUI host config, and a leaner React layer (#93).

Web

  • The browser's own JS engine is now the default for createJsui (#89, #93). Pass js: 'quickjs' to keep running the bundle on QuickJS; pages whose CSP forbids eval fall back to QuickJS on their own. The CLI still uses QuickJS by default.
  • Opt-in worker mode, createJsui({ worker: true }), renders the UI in a Worker on an OffscreenCanvas (#63), with WebKit and context-loss fixes (#71–#74).

Tools

  • Shared live sessions: jsui dev --shared and --attach let a person and agents drive the same running app, in the viewer, a game, the browser or --headless (#62, #65).
  • One-command agent skill install (#61).

Fixes

  • The "nodes live" count no longer grows: raw text instances are forgotten on delete (#87).

What's Changed

  • Web: opt-in worker mode, createJsui({ worker: true }), with UI rendering in a Worker on OffscreenCanvas by @orktes in #63
  • Site: hero feature highlights, agent skill one-liner, crawlable content, OG tags, llms.txt by @orktes in #64
  • CI: run the WebGPU showcase perf guards (install workspace packages before the browser tests) by @orktes in #66
  • Shared session for every runtime: agents drive the game, the native viewer or the browser by @orktes in #65
  • Custom fonts: @font-face registry, WOFF2/TTC, variable fonts, fallbacks, expo-font API, host APIs by @orktes in #68
  • Engine examples: raylib, SDL3 and sokol hosts of one shared HUD by @orktes in #67
  • Shader preloading: precompileShaders / jsui_precompile_shader warm GPU pipelines ahead of use by @orktes in #70
  • Worker mode follow-ups: context-loss guard, hit map only when needed, submit first in the frame by @orktes in #71
  • WebKit fixes: poll video frames after an rVFC context loss, survive WebGL loss mid-frame, cross-origin video by @orktes in #72
  • Worker mode: host textures come back after a WebKit GPU reset; cross-origin images by @orktes in #73
  • WebKit polls video frames from the start; fewer polled uploads; poster race by @orktes in #74
  • Audio: host-played UI sounds and music (on_audio handler, built-in miniaudio, Web Audio, Godot buses), Sound / useMusic / UISounds by @orktes in #69
  • Unity: com.orktes.jsui package (native plugin + JsuiView) and the example game by @orktes in #75
  • SDL3 example: the UI on the GPU (Graphite Metal / Graphite Vulkan / Ganesh GL into SDL's texture), CPU only as fallback by @orktes in #76
  • Engine examples: FPS over recent frames; raylib links with JSUI_AUDIO on macOS by @orktes in #77
  • Android: NDK example host on Skia Ganesh GLES, APK build, CI, "Runs in" entry by @orktes in #79
  • Unreal Engine 5 example: Jsui plugin (UMG widget, Skia Graphite on Unreal's Metal RHI) + the shared HUD game by @orktes in #80
  • Release binaries: prebuilt native libraries, Godot addon and iOS xcframework on every GitHub Release by @orktes in #78
  • Ship the Unity package and the Unreal plugin on GitHub Releases (Unity: tarball + git URL, GPU path prebuilt) by @orktes in #81
  • Rust and Go bindings over the C API, with a GPU quest-log example app in each by @orktes in #83
  • Perf round 1: native prop diffing, faster QuickJS, allocation-free native Animated, O(changed) damage walk, cached moving shadows by @orktes in #84
  • GPU rendering on Windows and Linux: Skia m157 for Windows (Graphite Vulkan, Ganesh D3D12), Direct3D backend, engine GPU paths by @orktes in #82
  • Perf: profile-guided QuickJS in release builds, faster CPU paint, opt-in React Compiler by @orktes in #85
  • Fix the growing "nodes live" count: forget raw text instances on delete by @orktes in #87
  • Showcase site: nebula warp intro after load by @orktes in #88
  • Precompiled QuickJS bytecode bundles by default (jsui build), with a source fallback by @orktes in #86
  • Unreal: HUD clicks work in fullscreen on macOS; the selftest clicks through Slate's platform input by @orktes in #90
  • Perf: host JS engine on web (opt-in), fast damage regions for many moving views by @orktes in #89
  • Engine examples: click a unit to select it; selftests through each engine's input path by @orktes in #92
  • CI: run Linux jobs on GitHub-hosted runners by @orktes in #91
  • Docs: bring ARCHITECTURE.md up to date with the current runtime by @orktes in #94
  • Perf: browser JS engine by default on web, faster QuickJS interpreter, leaner React layer by @orktes in #93
  • Release 0.5.0: version bump, release notes, quick follow-up release steps by @orktes in #95
  • CI: parallelize the WebGPU wasm job (critical path) by @orktes in #96

Full Changelog: v0.4.0...v0.5.0