Devtools panel
useDevtoolsPanel(schema) declares a panel for the entity a component renders. The debugger draws it at the top of the inspector while the entity is selected, and over the entity in the world once the entity is pinned. The game styles nothing: the devtools draw every declared panel in the same card, in their own dark glass.
Call it in the component that renders the Entity, before the return, as Leva’s useControls is called:
import { useState } from "react";import { button, Entity, Spin, useDevtoolsPanel, type EntityProps,} from "@spawnite/engine";
const startSpeed = 1;
export function Crate({ position = [0, 0, 0] }: Pick<EntityProps, "position">) { const [speed, setSpeed] = useState(startSpeed); useDevtoolsPanel({ spinSpeed: { value: speed, onChange: setSpeed, min: 0, max: 10 }, position, reset: button(() => setSpeed(startSpeed)), });
return ( <Entity name="Crate" position={position}> <Spin speed={speed} /> </Entity> );}The schema
Section titled “The schema”Each key is one row, in the order written. The label is the key split from camelCase, so spinSpeed reads as Spin speed. Each value is one of the following:
- A plain value reads out and takes no edit: a number, a word, a flag, or a list or a record of them, such as a position. A whole number reads as it is, and any other number and a list of numbers read to one decimal, as the inspector reads a position.
{ value, onChange }is a field. A number withminandmaxis a slider with a box beside it, andstepsets its step; a number without them is a box. A flag is a switch. A word is a text field that commits on Enter. A number or a word withoptionsis a select of those options.button(fn)is a button that callsfnwhen pressed.custom(element)draws the element in a row of its own inside the panel’s card, for a widget the schema cannot draw, such as a small chart.
The component passes the schema on every render, so a readout is as live as the component: a value the component renders with shows as it changes. useInspect exposes state a tool reads without drawing it; the devtools page says how.
Where it shows
Section titled “Where it shows”- The inspector draws the panel’s card above the entity’s behaviour cards, whether or not the world panels are on.
- The world panel stands over a pinned entity while the World panels switch is on. The debugger page says how a pin works.
- Send to agent carries the readouts’ and the fields’ values under
panelin the bundle, anddescribe(id)returns them, so the agent reads what the creator saw.
Headless, the hook does nothing, since nothing draws a panel there.
What the other engines do
Section titled “What the other engines do”Unreal marks a property VisibleAnywhere for a readout, gives a number ClampMin and ClampMax for a slider, and a function CallInEditor for a button. Leva writes the same three as a plain value, { value, min, max } and button(fn), and the schema here takes Leva’s shape, which every React Three Fiber agent has read. The devtools draw the panel rather than Leva, so it matches the rest of the debugger.