URL.pathname yields /C:/... on Windows, which Bun.build rejects as a root directory. fileURLToPath returns a native path on every platform.
Session: ses_f330c012affeeWEt6hY3uyjEvQ
Build the real Wasm browser package before native browser-bundle tests so CI validates the same files that publishing includes. The test job checks out the GPUI submodule and installs the same nightly toolchain and wasm-bindgen version used by the publish job.
Allow the end-to-end tarball consumer test enough time to pack, install, and compile the Solid fixture on Windows without Bun terminating the process at its five-second default.
Session: ses_f330c012affeeWEt6hY3uyjEvQ
Point the temporary consumer override at the locally packed native tarball. Bun otherwise tries to download the Solid tarball transitive native dependency from npm, which fails while validating a not-yet-published release. Continue exercising the real packaged native and Solid code in both the preload and build-plugin checks.
Session: ses_f330c012affeeWEt6hY3uyjEvQ
The Linux binary exports a constructor-only TestGpuixRenderer stub, while macOS and Windows expose the full implementation. Narrow the constructor through hasTestGpuixRenderer before assigning it to the shared test-renderer API so Linux can build the shared JavaScript package without claiming an unavailable renderer.
Session: ses_f330c012affeeWEt6hY3uyjEvQ
Set CARGO_BUILD_TARGET on the build matrix step so both napi builds select the configured platform while the trailing build:js command runs tsc without a Rust target. This unblocks the previously prepared 0.10.0 release for native, React, and Solid; no package versions or changelog changes are needed because 0.10.0 has never been published.
Session: ses_f330c012affeeWEt6hY3uyjEvQ
The dark sky pixel disappears on the video. The dots now use #a1cef8,
a light sky pixel from the left edge of the hero image.
Session: ses_f354b12f6ffecM3jsw9hX59RHp
#6490bc was an average of bright sky pixels, so it looked pale. The open
sky at the top left of the hero is one flat color, #234e9d. Use that for
the docs primary color and the hero dots.
Session: ses_f354b12f6ffecM3jsw9hX59RHp
The site accent was orange. The new README image is a light blue sky, so
the Holocron primary color is now #6490bc, the average of the bright
saturated sky pixels.
Session: ses_f354b12f6ffecM3jsw9hX59RHp
The top image was the mail.tax screenshot. Swap in the painted-sky
dashboard and match the caption to the glass window, cards, and schedule.
Session: ses_f354b12f6ffecM3jsw9hX59RHp
Consume the pending changesets into a minor release. Users get the official Solid 1 renderer, AnimatePresence exit animations, live image uploads and scrollIntoView on host refs, native window controls, and an OS file picker.
Bump the native Cargo crate, native npm package, React package, Solid package, generated napi loader version checks, and Bun workspace lock to 0.10.0. Keep published adapter dependencies on @gpuix/native as workspace:^. CI is the only publish path for native platform binaries.
Fixes#68
Session: ses_f3b7fae0dffeZjEBH48TZSQVBq
Drop the previous GPU image when src or a live upload replaces it, and when the img node is pruned. Without drop_image, every setImagePixels frame leaked a RenderImage.
scrollIntoView now uses the virtual-list logical index, not the windowed child index. A windowStart of 50 plus child 5 now scrolls to item 55.
Attach setImage, setImagePixels, and scrollIntoView in getPublicInstance instead of createInstance, so concurrent React can abandon a host node before the methods exist. Pass the original buffer through instead of copying it with Buffer.from.
The waveform test compares two live phases. Encoded setImage and windowed scrollIntoView have screenshot and list tests.
Session: ses_f3c07efdbffeHwbaQhsE7fIz5z
When every exiting child reported complete, the map still held those
keys as true. A later exit of the same keyed child then hit the
early return and never called onExitComplete or swapped rendered
children back to the present set.
Clear the map after a completed batch so the next exit can run.
Session: ses_f3d2f1310ffeo5K8hcRmsuYLWO
Add website/src/guides/solid.mdx covering install, preload, render,
primitives, motion, Select, testing, and automation. Link it from
the Guides nav and from the README Solid section.
The Solid AnimatePresence test now wraps the exiting motion.div in
Show. A boolean && child is not a tracked hole, so the previous
test never actually unmounted.
Session: ses_f3c074549ffe2jtrJMYbbLhqMx
Port the chat example to @gpuix/solid under examples/solid with jsx
preserve, the Solid bunfig preload, and a matching automation driver.
examples/package.json now depends on @gpuix/solid and solid-js and
adds chat-solid. bun.lock follows that.
mem-mount.tsx (React) and examples/solid/mem-mount.tsx print mount
time plus RSS/heap for the same ChatApp so the two adapters can be
compared.
Session: ses_f3c65bfd5ffegJLklT8domWQ7B
GPUI reserved a full line for an empty string. Solid's universal
renderer emits an empty placeholder text node for every dynamic hole
(Show, For, conditional). Those placeholders painted as 26px rows and
stretched Select menu items in the Solid chat example.
The native fix already landed. This changeset documents it for the
next changelog.
Session: ses_f3c65bfd5ffegJLklT8domWQ7B
The README live-image example encoded PNG via canvas.toBuffer.
node-canvas already exposes packed RGBA through getImageData().data,
which is what setImagePixels wants.
Switch the example to a 2x bitmap (1600x160 into an 800x80 box) and
push ImageData instead of PNG. Call out that toBuffer('raw') is not
RGBA: it is BGRA or ARGB, native endian, and may include stride
padding.
The waveform example still writes the same RGBA layout by hand.
Session: ses_f3b99a94affe1b6zCIvuV8WoPt
`<img>` refs can push image bytes without a data URL or JSON mutation.
`setImage` takes encoded PNG, JPEG, WebP, GIF, SVG, BMP, TIFF, ICO, or
Netpbm. `setImagePixels` takes packed RGBA. Prefer pixels for a live
waveform. There is no density argument. Upload a 2x bitmap into a 1x
layout box on retina.
Every host ref now has `scrollIntoView()`, which scrolls the nearest
overflow parent or `<virtual-list>` until that node is visible.
The waveform example paints a generated 2x RGBA buffer through
`setImagePixels`.
Session: ses_f3c07efdbffeHwbaQhsE7fIz5z
Stop copying napi wire types in `@gpuix/native/host`. Re-export
ElementBounds, HighlightMatch, PathPromptOptions, EdgeInsets, and
overlay stats from the generated addon types.
Helpers now ask only for the methods they use:
- createMutationQueue takes MutationHost (applyBatch)
- window observers take WindowSizeHost / WindowInsetsHost
- selection observation takes SelectionHost
NativeRenderer stays the adapter-facing type: required applyBatch,
plus live renderer methods as Partial<Pick<GpuixRenderer, ...>>.
Fakes can still implement applyBatch alone. Do not subclass the
napi GpuixRenderer.
Session: ses_f3c88f82affeXgsQdmQW4wpizp
Resolve the native renderer through the package browser condition and expose CPU throttling from a browser-safe subpath so both public adapters bundle for WebGPU without importing node:module.
Add browser bundle coverage to the native package suite and run those package checks in CI after both adapters are built.
Make Solid motion completions generation-aware, reject stale targets, and keep presence removal idempotent. Replace the native motion invariant panic with a safe target fallback.
Session: ses_f4102f732ffesSfYYRRHlXA2j9
Add the Solid quick start, shared native runtime architecture, package build instructions, and framework parity rules to the public contract and contributor guide.
Build and test Solid in the platform matrix, then publish it after @gpuix/native beside the React adapter.
Session: ses_f4102f732ffesSfYYRRHlXA2j9
Introduce @gpuix/solid for stable Solid 1 with a small universal host tree, shared native mutation and event infrastructure, native-backed testing and automation, motion, AnimatePresence, Select, Combobox, and Tooltip.
Compile reactive JSX through an OpenTUI-style Bun preload and exported Bun.build plugin, with no Vite or wrapper CLI. Add direct workspace, real native renderer, imported TSX, and installed-tarball end-to-end coverage.
Automatically flush signal mutations outside event boundaries while keeping failed native batches available for retry.
Session: ses_f4102f732ffesSfYYRRHlXA2j9
Co-authored-by: juan <47119916+jhomra21@users.noreply.github.com>
Tie motion completion to the generation that started each target so queued events cannot complete a replacement animation. Preserve partial target values and finish no-op, invalid, and offscreen exits.
Harden AnimatePresence participant registration, cancellation, and keyed sibling handling with focused native-backed regressions.
Session: ses_f3d2f1310ffeo5K8hcRmsuYLWO
Replace React-owned copies of host types, atomic mutation transport, renderer state, automation, testing, frame-loop helpers, and CPU throttling with @gpuix/native subpaths.
Keep the existing React testing and automation entry points as thin adapters, and preserve the public React API by re-exporting the new imperative window, selection, and text-search primitives.
Session: ses_f4102f732ffesSfYYRRHlXA2j9
Publish the framework-neutral host contract, mutation batching, renderer ownership, native testing, automation, observers, text search, and frame-loop helpers from @gpuix/native subpaths.
Generate an ESM-first napi-rs loader, retain the documented Hermes CommonJS loader, and update napi-rs to the latest supported CLI and crate releases. Add installed-package resolution tests for the loader and shared subpaths.
Make motion completion generation-aware so stale targets cannot remove current elements, partial targets preserve existing animated values, invalid or no-op exits settle, and offscreen virtual-list motion advances independently of paint.
Session: ses_f4102f732ffesSfYYRRHlXA2j9
Keep leaving motion nodes mounted until native motion reaches the exit target, matching Motion for React. AnimatePresence holds the child, motion.div swaps animate to exit while isPresent is false, and motionComplete then unmounts it. Without AnimatePresence, unmount stays immediate.
Native MotionState now reports just_settled once when a track reaches its current target, including zero-duration retargets. GpuixView emits motionComplete after the build, the same way highlight events flush, so a setState in the handler cannot re-enter the frame.
Wire onMotionComplete through host types and the reconciler. Export AnimatePresence, usePresence, and useIsPresent. Document the API, add GPU-backed unmount coverage, and add a minor changeset.
Session: ses_f40bbeaeeffebG77zwP6ZNd8m0
Move visibility and opacity, including hover and active refinements, onto the outer anchored FloatingLayer surface. Nested opacity no longer multiplies against the deferred fallback fill.
pointerEvents none now disables the anchored occluder so a hidden or non-interactive overlay does not steal hits. Background, border, shadow, overflow, and layout stay on the inner content.
Extend the retained-tree snapshot so hover and active surface styles, content opacity stripping, and occlude false are covered. Document the overlay contract in the README and the pending changeset.
Session: ses_f4fec2f63ffeX4htZahVSoX5f6
Expose minimizeWindow, zoomWindow, and toggleFullscreen through the native renderer and React renderer contract.
Dispatch macOS operations directly through the embedded window and route Windows, Linux, and FreeBSD operations through the GPUI UI command channel.
Document the desktop-only API, regenerate the N-API declarations, and add a production binding regression test plus a minor changeset for issue #68.
Session: ses_f41046982ffe9HBet3NGzDDJXd
Copy uniform and per-corner border radii from FloatingLayer content to the outer anchored surface. This prevents the deferred fallback background from showing square corners behind Select, Combobox, and Tooltip popups.
Add retained-tree snapshot coverage for every supported radius property and document the overlay behavior.
Session: ses_f4fec2f63ffeX4htZahVSoX5f6
Expose promptForPaths through the desktop renderer and React renderer contract. The promise resolves selected absolute paths, returns null for cancellation, validates unsupported option combinations, and rejects on browser builds.
Route Windows and Linux requests through the GPUI UI command channel. Settle all desktop results through napi-rs JsDeferred without holding a libuv worker for the lifetime of the operating-system dialog.
Keep the capability optional for injected mutation-only renderers. Add native option tests, a production deferred rejection test, test-renderer cancellation coverage, generated declarations, public docs, and the Windows GPUI cancellation caveat.
Session: ses_f4fec2f63ffeX4htZahVSoX5f6
Draw input and textarea carets at the full line height so the bar matches the painted editor row.
Propagate paste shortcuts when the clipboard is empty, contains only an image, contains external paths, or belongs to a read-only editor. Keep ordinary text and mixed text-plus-image clipboard content on the native text insertion path.
Add Rust and React regression coverage for clipboard classification, element and window event propagation, and caret geometry.
Session: ses_f4fec2f63ffeX4htZahVSoX5f6
The count is two words, so without nowrap it wraps at the space when the
title takes the remaining width. whiteSpace nowrap plus flexShrink 0
keeps 1,000 messages together. The title still shrinks.
Session: ses_f5601bbdaffevYnfCmDhYOddPC
The caret used to be 75% of fontSize so it matched approximate cap height.
That bar looked too short next to the glyphs. Size it to the em square
instead, still capped by lineHeight so extra leading does not stretch it
past the line box.
Chat composer at fontSize 14 / lineHeight 20 now paints a 14px caret
instead of 10.5px. Chrome uses the full line height; Firefox uses font
size after you type. This matches Firefox.
Session: ses_f5601bbdaffevYnfCmDhYOddPC
Consume the pending changesets into a minor release. Users get a window-level onSelectionChange callback for text selection, a live-window click panic fix, and docs to pin @gpuix/react and @gpuix/native to the same exact version.
Bump the native Cargo crate, native npm package, React package, generated napi loader version checks, and Bun workspace lock to 0.9.0. Keep the published React dependency on @gpuix/native as workspace:^. CI is the only publish path for native platform binaries.
Fixes#38
Session: ses_f56207a65ffeFBg1JxfiwGIPqH
React apps can now react when the selected text ranges change, which is the
gap that blocked porting termcast onto gpuix. Selection is app-wide and
rebuilt at paint, so this is a root callback on render() / createRoot(),
the same attachment as onKeyDown, not a per-element prop.
Native emit reads the same SelectionState as getSelectedText and keys on a
span identity hash, so an unchanged frame does not fire. Empty on mount is
not a change. A later clear fires once with value omitted. The payload is
a normal EventPayload; value is the joined selected text.
```
drag / clear ► SelectionState.identity() ► emit selectionChange
► handleGpuixEvent
► onSelectionChange(event)
```
Session: ses_f59f89012ffecnPBB1A40P5don
A physical left click still aborted 0.8.0 with
`cannot update GpuixView while it is already being updated`.
0.8.0 already dispatched automation mouse through AnyWindowHandle,
so that path no longer leased the root view. AppKit still does.
The text-selection mouse-up listener then nested-updated the same
GpuixView while GPUI held the lease.
A tap never started a drag, so skip drag-end cleanup there.
Real selection-drag move and end work now run through App::defer,
after the current GPUI effect cycle returns the root lease.
The test renderer now leases GpuixView the same way AppKit does
for mouse down, move, up, and click. The old AnyWindowHandle path
hid this panic. Cover it with a click that must not abort.
Fixes#38
Session: ses_f5bf1a57bffekyaF7gpwuhWzPr
Drop the keyword dump that told people to search for GPUI React. Lead with
what GPUIX is, then send users to bunx @gpuix/cli new instead of a local
examples/ command that needs a native build.
Repo example commands stay later, with a note that they need a clone.
Session: ses_f5eb2b952ffeq1yIyyzc0zuYur
Bun on Windows cannot load `/D:/...` paths. fileURLToPath produces a real Windows path so the uncaught-exception and unhandled-rejection subprocess tests can import the renderer.
Session: ses_f5effe0ccffeXHPxxwP7cFDI4h
Consume the pending changesets into a minor release. Users get GPUI accessibility through role and aria-* props, Base UI Select wrapping with asChild, Finder file drops, GitHub Releases auto-update, Wayland layer-shell windows, http(s) img sources, textDecoration, textarea newlines, font-sized input rows, a runtime error overlay that keeps the macOS window alive, and several desktop and browser reliability fixes.
Bump the native Cargo crate, native npm package, React package, generated napi loader version checks, and Bun workspace lock to 0.8.0. Keep the published React dependency on @gpuix/native as workspace:^. CI is the only publish path for native platform binaries.
Fixes#37Fixes#38Fixes#39Fixes#41Fixes#46Fixes#47Fixes#59Fixes#63
Session: ses_f5effe0ccffeXHPxxwP7cFDI4h
GPUI uses a flat painted hit list and does not bubble clicks. A custom row
with its own background can therefore cover SelectItem or ComboboxItem and
prevent selection, hover state, and popup close behavior.
Add asChild to both item primitives through the existing renderSlot path.
The custom row becomes the host item itself, so it owns one native hit target,
one event id, the item ref, composed handlers, state styles, and disabled
selection behavior.
Migrate every chat picker to asChild. MenuRow now forwards its ref and host
props, while keeping its own row padding. Add end-to-end tests for filled
Select and Combobox rows and a chat regression assertion for menu row height.
Document when to use asChild, including the ref and host-prop forwarding
contract. Add a React patch changeset with the new public API.
Session: ses_f61007e8fffe0tRyMx0uRPPeCZ
Browser WebGPU creates its public window handle before the internal GPUI window can accept updates. Calling focusElement from a React mount effect therefore threw GPUIX web window is not ready even though WEB_WINDOW was already present.
Store the latest browser focus target outside the window update path. Consume it during GpuixView render, after the window is active, and apply it after focus handles are synchronized. Explicit focus keeps precedence over autoFocus.
Use the same deferred focus state on desktop when a requested host element does not have a focus handle yet. Clear an older pending request whenever a newer request focuses an existing handle, so stale state cannot steal focus on a later render.
Document startup queuing and the latest-request-wins rule. Add a native patch changeset for the browser API behavior.
Session: ses_f61007e8fffe0tRyMx0uRPPeCZ
Select rows stole the click. GPUI has no bubbling, so a filled MenuRow
sat on top of SelectItem and the pick never ran. The fill now lives on
the item. Inner icons and labels set pointerEvents none.
Search stayed at 420px and closed on an outside press. The dim layer
used to take the hit, so onMouseDownOutside never fired. The listener
is on the card. Opening search autoFocuses the filter field.
The composer stays mounted across threads, so autoFocus only ran once.
New Task, a thread switch, and history now call focusElement.
The demo reply no longer bolds the last word, so markdown cannot put a
period on the next line.
Session: ses_f61007e8fffe0tRyMx0uRPPeCZ
Each sidebar row now owns its own transcript. Clicking a thread paints
that conversation. New Task prepends a blank Today thread and clears
the composer. Sends append the user turn, then a demo assistant reply
that says this is the GPUIX chat demo. Retry rebuilds that last reply.
History arrows walk a stack of thread ids. Search filters titles.
Settings shows a short note and can cycle the frame overlay. The
inspector lists the current thread, model, reasoning, access, and
mode. The list filter keeps only threads for the selected project.
Tests cover thread switch, new task, demo reply, inspector, and
history. The live launch wait looks for GPUIX chat demo so the quoted
user text cannot match twice.
Session: ses_f61007e8fffe0tRyMx0uRPPeCZ
https://gpuix.dev/chat-example/ stayed on the loader for two reasons.
The error overlay read process.platform at module load. A browser has
no process, so that threw before Wasm started. OVERLAY_MONO is now a
CSS font stack. readMacCpuThrottle() treats a missing process as no
THROTTLE. render() only calls process.exit when process exists.
createRoot() also called setWindowKeyEvents before GPUI finished
opening the web window, which threw GPUIX web window is not ready.
The wasm renderer now queues those listeners the same way it already
queues the debug overlay, then applies them when start_web_app builds
GpuixView.
The production chat bundle copies examples/web.css, and the website
serves it as /chat-example/web.css so the loader styles load.
Session: ses_f64d18bc8ffeysXOZPWSnfTQWv
The Holocron title, docs.json description, and README lead now say GPUI
and React for native apps, not only native React on the GPU. The hero
tagline is GPUI and React / for native apps. Keywords on the homepage
frontmatter are GPUI, GPUI React, GPUI TypeScript, and native GPUI app.
The shader overlay uses a 0.7 alpha multiplier instead of a dark/light
opacity class, so the flare stays visible behind the new copy.
Session: ses_f64f287b1ffeD0rCw6d52oXfHk
That file is a 500kb CJS dump from a hermes/idle experiment. It is not source.
Leave it untracked so it cannot land in a commit by accident.
Session: ses_f61007e8fffe0tRyMx0uRPPeCZ
The docs index used to open on the README heading. Put an Above
block on the homepage like Holocron: one H1, GitHub and browser
buttons, and VideoBackgroundShader behind it.
Tagline is native React on the GPU. That is the product: React
and TypeScript paint through GPUI to Metal, DirectX, or Vulkan.
No Electron. No web view.
The heading uses Arizona Flare from mintlify.com/data. The shader
uses Holocron's hero-bg.mp4, cropped into the ring so the dots
fill the page-width banner. Color is a light orange at low
opacity. The canvas stays inside --grid-max-width; w-screen was
what spilled past the page.
Session: ses_f64f287b1ffeD0rCw6d52oXfHk
The GPUI fork in zed/ already implements layer-shell at the Rust level
(WindowKind::LayerShell, layer_shell::LayerShellOptions), but nothing
reached JS: WindowOptions had no way to ask for it, so @gpuix/react
could only open normal floating windows. A panel, dock, notification
shade or wallpaper needs an edge-anchored surface with an exclusive
zone, which is exactly what layer-shell is for.
Add to the napi WindowOptions:
- layerShell?: LayerShellOptions - namespace, layer (background |
bottom | top | overlay), anchor (top / bottom / left / right, two
opposite edges stretch that axis), exclusiveZone, exclusiveEdge,
margin ([top, right, bottom, left]), keyboardInteractivity (none |
on-demand | exclusive). All optional; the default anchor is a top
bar (top | left | right) and the default layer is top.
- appId?: string - Wayland app_id / X11 WM_CLASS, useful on its own
and needed for a compositor to target a layer surface by rule.
to_gpui_window_options maps layerShell onto WindowKind::LayerShell and
drops the titlebar. The WindowKind variant only exists on a
wayland-enabled Linux gpui build, so the mapping is
cfg(target_os = "linux"); on macOS and Windows layerShell is ignored
and appId still applies. init_threaded opens a layer surface at the
origin instead of Bounds::centered, since the compositor places it
from its anchor.
index.d.ts is hand-edited rather than regenerated: the @napi-rs/cli
in node_modules emits a much smaller index.d.ts than the committed
one (it drops every doc comment and all of TestGpuixRenderer's
methods), so a full `napi build` regen here would be a large
destructive diff unrelated to this change. The added block matches
the shape napi produces for these structs.
Tests in renderer.rs cover the mapping (anchor union, exclusive zone
and edge, margin, keyboard interactivity, titlebar dropped) and that a
window with no layerShell stays Normal with a titlebar.
Verified on Hyprland (3 monitors): a @gpuix/react app calling
render(<Bar/>, { layerShell: { anchor: ['top','left','right'],
exclusiveZone: 34 } }) opens a 34px top bar, hyprctl reports the
kite-panel layer surface and reserved: [0, 34, 0, 0], and a React
setInterval clock re-renders live on the surface.