Mimo: Interactive UI inside Wallpapers

Wallpaper windows are click-through and never become the OS key window. As a result, the browser inside them never sees real pointermove, click, or keydown events — your <button> does not click, your <input> does not focus, and dnd-kit cannot start a drag. Mimo is the layer bundled with the Fluxlay SDK that turns Fluxlay's OS input streams (useMousePosition, useMouseEvents, useKeyboard) into synthetic DOM events so that ordinary React UI works inside a wallpaper.

Wrap your wallpaper root once with <MimoProvider> and forget about the wiring.

When you need it

Add <MimoProvider> whenever your wallpaper renders interactive UI:

  • buttons, links, accordions, tabs
  • text inputs (with useImeInput handling IME)
  • dnd-kit, react-dnd Pointer backend, Framer Motion drag
  • focus rings via useIsFocused
  • anything that relies on onPointerDown, onClick, onKeyDown, etc.

If your wallpaper is purely visual (a particle effect, a clock face, animated art with no UI), you do not need Mimo.

Quick start

MimoProvider lives on a separate subpath:

import { MimoProvider } from "@fluxlay/react/mimo";
 
export function Root() {
  return (
    <MimoProvider cursor>
      <App />
    </MimoProvider>
  );
}

That is the entire setup. Inside <App /> you can write ordinary React:

function App() {
  return (
    <div>
      <button onClick={() => alert("clicked")}>Click me</button>
      <input placeholder="日本語入力もできます" />
    </div>
  );
}

The button fires real click events, the input gets focused on click, and IME composition routes into the input automatically — all without extra wiring.

The cursor prop renders a virtual cursor element following the synthetic pointer. It is recommended because the OS cursor is invisible inside wallpaper windows, leaving users without a visual reference.

How it works

  1. The Fluxlay desktop app captures OS-level mouse and keyboard input and pushes them to the wallpaper as event streams.
  2. MimoProvider subscribes to those streams via useMousePosition, useMouseEvents, and useKeyboard.
  3. Each event is fed into the underlying MimoForwarder.
  4. The forwarder hit-tests the DOM (descending into open shadow roots) and dispatches a synthetic PointerEvent / MouseEvent / WheelEvent / KeyboardEvent on the target.
  5. React's event system sees those events as if a real user produced them and runs your handlers.

Mimo covers the full set of expected behaviors: click / dblclick / contextmenu / auxclick, ancestor chain semantics for pointerover / pointerleave, pointer capture (setPointerCapture & friends), modifier propagation across pointer + keyboard, movement deltas, and pointer cancel.

Limitations

Some behaviors cannot be triggered from synthetic events because of the browser's isTrusted gate. Most have Fluxlay-side workarounds:

LimitationWorkaround
<input> / <textarea> raw text entry (synthetic KeyboardEvent does not mutate value)IME route handles Japanese / Chinese / Korean automatically. Use useImeInput for direct control.
OS-level CSS :hover (the OS cursor never enters the window)Pass cursor to MimoProvider for a virtual cursor; toggle hover state imperatively if needed.
OS context menus, browser shortcuts, autoplay unlockBuild them in-app instead of relying on the OS chrome.
HTML5 native drag-and-drop (draggable attribute, dataTransfer, file drops)Use dnd-kit / react-dnd Pointer backend / Framer Motion drag — these go through pointer capture and work.

Customization

Most knobs (pointer, keyboard, cursor, autoFocus, keyboardTarget, pointerCapture, click thresholds) are props on <MimoProvider>. See the MimoProvider reference for the full list.

If you need to provide your own input source — for tests, replay, or running the wallpaper outside the Fluxlay desktop app — use the lower-level MimoForwarderProvider exported from @fluxlay/react/mimo.