Placement overlay
Drag the model into place and read the fit value back.
When you need it
fit: 'upper-body' assumes a full-body rig that fills its canvas. A rig drawn from the waist up overflows at twice the size, and one drawn off center in its canvas leans to one side. model3.json records the canvas size but not where the character sits inside it, so no default can correct for that.
The overlay is the answer: drag the model where you want it and copy the value back into your code.
Turn it on
<Live2DModel src="/models/model.model3.json" debug fit="upper-body" />That is the whole setup. The overlay owns the placement while it is up, and a fit prop that has not actually changed is not reapplied over it.
Add onFitChange only when your app wants the value too, to store it or show it in your own UI:
const [fit, setFit] = useState<ModelFit>('upper-body')
<Live2DModel src="/models/model.model3.json" debug fit={fit} onFitChange={setFit} />Vanilla takes the same flag:
const live2d = await createLive2D({
container: document.querySelector('#avatar')!,
coreUrl: '/live2dcubismcore.min.js',
src: '/models/model.model3.json',
debug: true,
})
live2d.setDebug(false)The overlay entry loads on demand, so leaving debug off costs nothing in the root bundle. Mount it yourself with mountLive2DDebugOverlay() from live2d-web/debug if you want it somewhere else.
One model at a time
The overlay covers the canvas to take the pointer, so two of them cannot share
it. Turning debug on for a model moves the overlay to that model, and it
goes when that model does.
Put debug on whichever model you are adjusting. Your app already knows which
one that is, so it is a prop to move rather than something the library has to
pick for you.
Drag, scroll, nudge
Drag to move, scroll to zoom around the cursor, arrow keys to nudge (hold Shift for finer steps), + and - to zoom from the anchor. Full and Upper body jump to the presets, and the one the placement is currently on is marked. Reset returns to where the placement stood when the overlay opened, or to the last one the app applied, and is disabled when there is nothing to undo.
The bar shows the scale, not the value. That value is the output, needed once, and Copy delivers it. If the clipboard refuses, as it can outside a secure context, the literal appears above the bar so it can be selected by hand.
Pointer events stop at the overlay, including the click a press makes. Without it, onTap would fire on release, and followPointer would chase the cursor while the model slid under it.
The value it gives you
fit={{ scale: 1.4, offsetX: -0.12, offsetY: -0.24, units: 'stage' }}units: 'stage' reads the offsets as a fraction of the stage width and height, so the placement holds when the canvas resizes. Offsets default to units: 'px', which is fixed to the size they were measured at: fine for an overlay of a known size, wrong for a page that reflows.
scale multiplies the upper-body fit either way, so it needs no unit.