Component
import MMD, { type MMDTemplateEntry, type MMDHandle, MMDLoadDetails, MMDUpdatePreview } from "@arclockproject/mmd-player";
For examples and live demos, see the Component guide.
MMD
Component · default export
A full MMD (MikuMikuDance) player, built on Babylon.js. Its start screen lets users pick a preset, build a scene from your files, or browse them. It then loads the characters, motions, camera, stage and music, and plays them in 3D, with controls for desktop and mobile.
Browser only. Each player has its own state obtainable with mmdRef.
Props
-
mmdRef?(Ref<MMDHandle>) — Gets this player's state and preview, e.g.mmd.current.MMDLoadDetails. -
maxWidth?(string | number) — Largest width of the player, as a CSS value. -
maxHeight?(string | number) — Largest height of the player, as a CSS value. -
rawMMDDetails(returnPromiseMaybe<rawMMDDetails>) — Returns the files the scene builder can choose from. Called once, on mount. -
presets(returnPromiseMaybe<MMDTemplateEntry[]>) — Returns the ready-made scenes shown in the presets tab. Called once, on mount. -
noDebug?(boolean) — Hide the debug panel and the scene preview button. -
getFileBrowser?((data: { fileSystemRaw: string[]; base: string; customAction?: (file: string) => void }) => ReactNode) — Renders the file browser tab, e.g. withFileBrowserfrom@arclockproject/common. Without it, that tab stays display a harmless text error message.Keep in mind that if creating a gallery browser from scratch, you will need to implement a custom handler for
customActionto parse the url and decide how to write intoMMDLoadDetailsfields such asMMDLoadDetails.stagePMXorMMDLoadDetails.entitiesCurrently, there is no documentation to help in creating a custom FileBrowser. Manual reading of source code is required. Please reference to
mmd-player/src/loadFile.tsx -
basePathMMD(string) — Base prefix path. Expecting all mmd files to sit at this location.Must not have a trailing
/ -
loadAudioMeta((value: string) => [string, string]) — Turns the text typed into the debug panel's audio field into file URLs. Called by its "Audio Fetch" button.Used primarly for assisting in manually generating presets if value is an id, and audio/thumbnails are in a format for
{id}.pngand{id}.mp3value— Input Field value from UI- Returns [
/some/path/{value}.mp3,/other/path/{value}.png]
Example
const mmd = useRef<MMDHandle>(null); // mmd.current?.MMDLoadDetails
<MMD
mmdRef={mmd}
basePathMMD="/mmd"
rawMMDDetails={() => fetch("/mmd/files.json").then((r) => r.json())}
presets={() => []}
loadAudioMeta={(id) => [`/music/${id}.mp3`, `/music/${id}.png`]}
/>
MMDTemplateEntry
Type
type MMDTemplateEntry
A ready-made scene, shown in the presets tab and passed to MMD's
presets prop. The scene preview dialog (MMDUpdatePreview) produces this
shape, so a scene built in the player can be copied in as a preset.
Properties
title(string) — Title on the preset card.subTitle(string) — Second line on the preset card.thumbnail(string) — URL of the preset card's image.music?(string) — URL of the music.musicYT?(string) — Not used yet.vmdCamera?(string) — URL of the camera motion (.vmd).stageFolder?(string) — URL of the stage's folder, ending with/.stagePMX?(string) — File name of the stage model, insidestageFolder.entities?(({ movement?: string[]; model: { folder: string; file: string } } | null)[]) — The characters, by slot.nullleaves a slot empty.entitiesOffset?((SimpleVector | null)[]) — Position of each character, by slot.entitiesAngle?((SimpleVector | null)[]) — Rotation of each character, by slot.modelPlayOffset?(number) — Frames to shift the character motion by, to line it up with the music.focusedModel?(number) — Index of the character the controls and camera follow at the start.actionMemory?(({ [key: string]: number } | null)[]) — Morph weights of each character, by slot and then morph name.
MMDHandle
Type
type MMDHandle
What MMD's mmdRef points to: that player's state, and a way to refresh its
debug preview.
Properties
MMDLoadDetails(MMDLoadDetails) — This player's live state.MMDUpdatePreview(() => void) — Writes this player's scene asMMDTemplateEntryJSON into its debug dialog, so it can be copied intopresetsmanually. The player calls this itself when its scene changes, so you only need it after changingMMDLoadDetailsyourself.
Example
const mmd = useRef<MMDHandle>(null);
// <MMD mmdRef={mmd} basePathMMD="/mmd" … />
mmd.current?.MMDLoadDetails.focusedModel; // 0
MMDLoadDetails
Class
class MMDLoadDetails
The live state of one player: what the scene builder and presets have
selected and while playing, the running scene. The player's UI reads and
writes it directly. Each MMD has its own, reachable through its mmdRef
(see MMDHandle).
Changing it before pressing play changes what loads.
Properties
music(string, default"") — Text from the debug panel's audio field, or the preset's music URL.musicRaw(string, default"") — URL of the music that plays.vmdCamera(string, default"") — URL of the camera motion (.vmd).thumbnail(string, default"") — URL of the thumbnail image.stageFolder(string, default"") — URL of the stage's folder, ending with/.stagePMX(string, default"") — File name of the stage model, insidestageFolder.offsetCharacters(boolean, defaultfalse) — Place characters side by side automatically, instead of usingentitiesOffset.entities({ movement?: string[]; model?: { folder: string; file: string } }[]) — The characters, by slot. Each has a model and its motion files.modelMorph(MmdMorphController[]) — Morph controllers of the loaded characters. Set while playing. Used for debugging only.controller(object) — The running scene and its parts. Set while playing.focusedModel(number, default0) — Index of the character the controls and camera follow. Read live by player.maxModelFocus(number, default5) — Number of character slots in the scene builder.useBulletPhysics(boolean, defaulttrue) — Use Bullet physics (Ammo.js), which behaves closer to MMD.falseuses the lighter Havok engine.useAdvanceRendering(boolean, defaulttrue) — Add screen-space reflections and other extra rendering effects.startMode("desktop" | "mobile", default"desktop") — Which controls to use, set by the start buttons.zCamOffset(SimpleVector) — Offset of the camera from the focused character.entitiesOffset(SimpleVector[]) — Position of each character, by slot.entitiesAngle(SimpleVector[]) — Rotation of each character, by slot.entitiesData([MmdAnimation | undefined, MmdMesh | undefined][]) — Loaded motion and model of each character. Set while playing.actionMemory({ [key: string]: number }[]) — Morph weights of each character, by slot and then morph name.resolutions(object) — Selected render resolutions, as indexes into the resolution list.
MMDLoadDetails.refocusModel()
MMDLoadDetails.refocusModel(): void
Points the camera at focusedModel. Does nothing until playing.
MMDUpdatePreview()
Function
MMDUpdatePreview(): never
Removed in 1.0.0. Use mmdRef.current.MMDUpdatePreview() instead.
Returns never
SimpleVector
Type · not exported, used by the API above
type SimpleVector
A 3D position or rotation. Rotations are in radians, around each axis.
Properties
x(number)y(number)z(number)
returnPromiseMaybe
Type · not exported, used by the API above
type returnPromiseMaybe<k> = (() => k) | (() => Promise<k>)
A function that returns a value, or a promise of one.
rawMMDDetails
Type · not exported, used by the API above
type rawMMDDetails
The MMD files the scene builder can choose from, as full paths.
Files only show up in the scene builder when named by role: .chara.pmx or
.chara.pmd (characters), .stage.pmx or .stage.pmd (stages),
.chara.vmd (character motion), .chara.part.vmd (partial character
motion, E.g. lip-sync) and .cam.vmd (camera motion).
In case you want non-mmd files to also show up, you will need to manually
combine the mmd file types and the remaining file types into the all property.
Properties
-
pmd(string[]) — Model files (.pmd). -
pmx(string[]) — Model files (.pmx). -
vmd(string[]) — Motion files (.vmd). -
all?(string[]) — Every file, for the file browser tab. Defaults topmd,pmxandvmdcombined if undefined.May included non-mmd file types. Those won't be handled with onclick, so manual on click event will need to be provided.
Example
const files = {
pmd: [],
pmx: ["/group/folder/Miku.chara.pmx", "/group/folder2/Room.stage.pmx"],
vmd: ["/group2/folder/Dance.chara.vmd", "/group2/folder/Dance.cam.vmd"],
}; // <MMD basePathMMD="/mmd" rawMMDDetails={() => files} … />