Skip to content

๐ŸŽฎย ย Three.js 3D Viewer

Submitted by Lukas Masuch

Summary

Display 3D models (GLTF, GLB, OBJ, STL, PLY, FBX) with interactive orbit controls using Three.js.

Functions

three_viewer

Display a 3D model using Three.js with interactive orbit controls.

Supports common 3D formats including GLTF/GLB (recommended), OBJ, STL, PLY, and FBX.

Parameters:

Name Type Description Default
source str | Path | bytes | BytesIO | RawIOBase | BufferedReader

The 3D model to display. Can be: - A URL (http:// or https://) - A local file path (str or Path) - Binary data (bytes) - A BytesIO or file-like object

required
file_format str | None

Explicit format override (e.g., ".glb", ".stl", ".obj"). Required for bytes/BytesIO inputs with non-GLB formats. If not provided, the format is inferred from the source.

None
height int

Height of the viewer in pixels.

400
key str | None

Unique key for this component instance.

None

Returns:

Type Description
DeltaGenerator

The Streamlit DeltaGenerator for this component.

Example:

```python
three_viewer("model.glb")
three_viewer("https://example.com/model.gltf", height=600)
three_viewer(stl_bytes, file_format=".stl")
```
Source code in src/streamlit_extras/three_viewer/__init__.py
@extra
def three_viewer(
    source: str | Path | bytes | BytesIO | RawIOBase | BufferedReader,
    *,
    file_format: str | None = None,
    height: int = 400,
    key: str | None = None,
) -> DeltaGenerator:
    """Display a 3D model using Three.js with interactive orbit controls.

    Supports common 3D formats including GLTF/GLB (recommended), OBJ, STL, PLY, and FBX.

    Args:
        source: The 3D model to display. Can be:
            - A URL (http:// or https://)
            - A local file path (str or Path)
            - Binary data (bytes)
            - A BytesIO or file-like object
        file_format: Explicit format override (e.g., ".glb", ".stl", ".obj").
            Required for bytes/BytesIO inputs with non-GLB formats.
            If not provided, the format is inferred from the source.
        height: Height of the viewer in pixels.
        key: Unique key for this component instance.

    Returns:
        The Streamlit DeltaGenerator for this component.

    Example:

        ```python
        three_viewer("model.glb")
        three_viewer("https://example.com/model.gltf", height=600)
        three_viewer(stl_bytes, file_format=".stl")
        ```
    """
    # Normalize format if provided
    normalized_format = None
    if file_format is not None:
        normalized_format = file_format.lower()
        if not normalized_format.startswith("."):
            normalized_format = "." + normalized_format

    url, detected_format = _process_source(source, normalized_format)

    # Use normalized format if provided, otherwise use detected format
    final_format = normalized_format or detected_format

    # Validate the format
    if final_format and final_format not in _SUPPORTED_FORMATS:
        supported = ", ".join(sorted(_SUPPORTED_FORMATS))
        st.exception(ValueError(f"Unsupported 3D model format: '{final_format}'. Supported formats are: {supported}"))
        # Return empty component to avoid frontend crash
        return st.empty()

    component = _get_component()
    return component(
        key=key,
        data={
            "url": url,
            "format": final_format,
            "height": height,
        },
    )

Import:

from streamlit_extras.three_viewer import three_viewer # (1)!
  1. You should add this to the top of your .py file ๐Ÿ› 

Examples

example_basic

def example_basic() -> None:
    """Basic 3D viewer demo with a sample model."""
    st.write("### Basic 3D Viewer")
    st.write("Display a 3D model from a URL with orbit controls.")

    # Using a public GLB model from the Khronos glTF sample models
    model_url = (
        "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Duck/glTF-Binary/Duck.glb"
    )

    three_viewer(model_url, height=400, key="basic_demo")

    st.caption("Drag to rotate, scroll to zoom, right-click drag to pan.")

example_with_options

def example_with_options() -> None:
    """Interactive demo with configurable height."""
    st.write("### Configurable Height")

    height = st.slider("Viewer height", min_value=200, max_value=800, value=400, step=50)

    model_url = "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/BoxAnimated/glTF-Binary/BoxAnimated.glb"
    three_viewer(model_url, height=height, key="options_demo")