Gradio custom component: 3D MMD model viewer powered by Babylon.js + babylon-mmd
Project description
gradio_mmd_widget
[!WARNING] Unewviewed AI code Unewviewed AI code still remains.
A Gradio custom component for rendering MMD motion data in the browser with Babylon.js and babylon-mmd.
Why this component?
- Play VMD motion files with a built-in MMD character
- Use it directly as a Gradio input or output component
- Great for demos, interactive storytelling, and lightweight 3D previews
Installation
pip install gradio_mmd_viewer
Quick start
import gradio as gr
from gradio_mmd_viewer import MMDViewer
with gr.Blocks() as demo:
gr.Markdown("## MMD Viewer")
viewer = MMDViewer(
value="asset/demo.vmd",
label="MMD Viewer",
scale=2,
min_width=800,
)
if __name__ == "__main__":
demo.launch()
User guide
Component parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
value |
str | None |
None |
VMD motion file path or URL |
model_url |
str | None |
None |
PMX/BPMX model file path or URL. If None, uses the built-in model |
pmx_zip |
str | None |
None |
Path to a ZIP containing a PMX model. Extracted automatically → model_url |
physics_enabled |
bool |
False |
Enable physics simulation for the model |
grey_mode |
bool |
False |
Render in flat grey (no textures) |
camera_position |
tuple[float, float, float] |
(0, 38, -25) |
Initial camera position (x, y, z) |
camera_rotation |
tuple[float, float] |
(0, 0) |
Initial camera rotation (alpha, beta) in radians |
audio_url |
str | None |
None |
Audio file path for animation sync |
1. Built-in model + VMD motion
The simplest usage — uses the built-in MMD model and plays a VMD motion:
import gradio as gr
from gradio_mmd_viewer import MMDViewer
with gr.Blocks() as demo:
viewer = MMDViewer(
value="asset/demo.vmd",
label="MMD Viewer",
scale=2,
min_width=800,
)
demo.launch()
2. Upload VMD motion dynamically
Use gr.File to let users upload .vmd files, then update the viewer via callback:
import gradio as gr
from gradio_mmd_viewer import MMDViewer
def load_motion(vmd_file):
if vmd_file is None:
return gr.update()
return gr.update(value=vmd_file)
with gr.Blocks() as demo:
vmd_input = gr.File(label="Upload VMD", file_types=[".vmd"])
viewer = MMDViewer(label="MMD Viewer", scale=2, min_width=800)
vmd_input.change(fn=load_motion, inputs=vmd_input, outputs=viewer)
demo.launch()
3. Upload PMX model via ZIP
Users can upload a ZIP containing a PMX model (with textures). The component extracts it and serves the model + textures automatically:
import gradio as gr
from gradio_mmd_viewer import MMDViewer, extract_pmx_zip
def load_model(pmx_zip):
if pmx_zip is None:
return gr.update()
model_url = extract_pmx_zip(pmx_zip)
return gr.update(model_url=model_url)
with gr.Blocks() as demo:
zip_input = gr.File(label="Upload PMX ZIP", file_types=[".zip"])
viewer = MMDViewer(label="MMD Viewer", scale=2, min_width=800)
zip_input.change(fn=load_model, inputs=zip_input, outputs=viewer)
demo.launch()
ZIP structure: The ZIP should contain a
.pmxfile and its texture directory (typicallyTex/). The extractor searches recursively for the first.pmxfile.
4. Full example: VMD + PMX ZIP + audio + camera control
import gradio as gr
from gradio_mmd_viewer import MMDViewer, extract_pmx_zip
def update_viewer(vmd_file, pmx_zip, audio_file, physics, grey, cam_x, cam_y, cam_z):
updates = {
"physics_enabled": physics,
"grey_mode": grey,
"camera_position": (cam_x, cam_y, cam_z),
}
if vmd_file is not None:
updates["value"] = vmd_file
if pmx_zip is not None:
updates["model_url"] = extract_pmx_zip(pmx_zip)
if audio_file is not None:
updates["audio_url"] = audio_file
return gr.update(**updates)
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=1):
vmd_input = gr.File(label="VMD Motion", file_types=[".vmd"])
pmx_input = gr.File(label="PMX Model (ZIP)", file_types=[".zip"])
audio_input = gr.File(label="Audio", file_types=[".mp3", ".wav", ".ogg"])
physics = gr.Checkbox(label="Physics", value=False)
grey = gr.Checkbox(label="Grey Mode", value=False)
cam_x = gr.Number(label="Camera X", value=0)
cam_y = gr.Number(label="Camera Y", value=38)
cam_z = gr.Number(label="Camera Z", value=-25)
btn = gr.Button("Load", variant="primary")
with gr.Column(scale=2):
viewer = MMDViewer(
label="3D Viewport",
scale=1,
min_width=600,
camera_position=(0, 38, -25),
)
btn.click(
fn=update_viewer,
inputs=[vmd_input, pmx_input, audio_input, physics, grey, cam_x, cam_y, cam_z],
outputs=viewer,
)
demo.launch()
Path handling
The component handles file paths automatically:
- Relative paths (e.g.
"asset/demo.vmd"): passed through as-is, served by Gradio's asset system - Absolute paths (e.g.
"C:/models/demo.vmd"): auto-converted to/gradio_api/file=...URLs viapostprocess() - ZIP extraction:
extract_pmx_zip()extracts to a temp cache directory, registers it viagr.set_static_paths(), and returns a servable/gradio_api/file=...URL
Note: When using
gr.update()in callbacks, absolute paths inmodel_urloraudio_urlare not auto-converted. Useextract_pmx_zip()for ZIP files — it returns the correct URL. For plain file paths, thepostprocess()hook handles conversion onvalue, but formodel_urlandaudio_urlyou should convert manually or pass them through the constructor.
Demo
Run the bundled demo with:
python demo/app.py
Development notes
Technical implementation details, architecture notes, build steps, and troubleshooting guidance are maintained in AGENTS.md.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gradio_mmd_viewer-0.0.21.tar.gz.
File metadata
- Download URL: gradio_mmd_viewer-0.0.21.tar.gz
- Upload date:
- Size: 5.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2f8f25ab46fb2ddd8a9ff39c43ae5dd03599cec5cb7cb2fc31c1402fe7cf06c
|
|
| MD5 |
99a9ee4e2eabddd4034b8b0af7f8d854
|
|
| BLAKE2b-256 |
b530ab291a81b607afed50a41565702a0056ab28cdf18bb5cf93339b0a59ea5d
|
File details
Details for the file gradio_mmd_viewer-0.0.21-py3-none-any.whl.
File metadata
- Download URL: gradio_mmd_viewer-0.0.21-py3-none-any.whl
- Upload date:
- Size: 3.6 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f6f8b8bbf19c575215c64b7218802e5a4e485cdb521f0ded161c6a92da407902
|
|
| MD5 |
7d06a3d10c751d5dbf66cafe15ef1c1e
|
|
| BLAKE2b-256 |
08d0f23874d5c99edab93fd5d962356ac08042147c6b9bd577ba6e9fecadbe71
|