File size: 2,154 Bytes
0de805c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"""
3D mesh viewer for GLB/glTF. Returns HTML for use with st.components.v1.html().
Uses Google's <model-viewer> web component with base64-embedded GLB.
"""

import base64
from pathlib import Path

# Embedding very large GLBs can make the page slow; warn above this size (bytes)
MAX_EMBED_BYTES = 15 * 1024 * 1024  # 15 MB


def mesh_viewer_html(glb_path: str | Path | None = None, glb_bytes: bytes | None = None, height_px: int = 480) -> str:
    """
    Build HTML for an interactive 3D mesh viewer (model-viewer).
    Provide either glb_path (file path) or glb_bytes (raw GLB). Prefers path if both given.
    Returns HTML string. If no valid input or file too large, returns a short error HTML.
    """
    data_uri: str | None = None
    if glb_path:
        p = Path(glb_path)
        if p.is_file() and p.suffix.lower() in (".glb", ".gltf"):
            try:
                raw = p.read_bytes()
            except Exception:
                raw = b""
        else:
            raw = b""
    elif glb_bytes:
        raw = glb_bytes
    else:
        raw = b""

    if not raw or len(raw) < 4:
        return (
            "<p style='padding:1em;color:#888;'>No GLB loaded. Upload a .glb file or choose one from outputs.</p>"
        )

    if len(raw) > MAX_EMBED_BYTES:
        return (
            f"<p style='padding:1em;color:#c66;'>Mesh is too large to embed in viewer ({len(raw) / 1024 / 1024:.1f} MB). "
            "Use a local viewer or a smaller mesh.</p>"
        )

    b64 = base64.b64encode(raw).decode("utf-8")
    data_uri = f"data:model/gltf-binary;base64,{b64}"

    # model-viewer from unpkg; use module script
    return f"""<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <script type="module" src="https://unpkg.com/@google/model-viewer@3.4.0/dist/model-viewer.min.js"></script>
  <style>
    model-viewer {{ width: 100%; height: {height_px}px; background: #1a1a1a; }}
  </style>
</head>
<body>
  <model-viewer
    src="{data_uri}"
    alt="3D mesh"
    camera-controls
    auto-rotate
    shadow-intensity="0.6"
    exposure="0.8"
    style="width:100%; height:{height_px}px;"
  ></model-viewer>
</body>
</html>"""