Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c3c56a1
feat: Add web view component (WIP)
AlejandroFernandezLuces May 20, 2026
7f34c88
chore: adding changelog file 75.added.md [dependabot-skip]
pyansys-ci-bot May 20, 2026
626a661
feat: Add web view component (WIP)
AlejandroFernandezLuces May 25, 2026
fbe90d4
Merge branch 'feat/webview' of https://github.com/ansys/python-usd-vi…
AlejandroFernandezLuces May 25, 2026
3b0a133
chore: adding changelog file 75.added.md [dependabot-skip]
pyansys-ci-bot May 25, 2026
40513cd
fix: Split code into modules
AlejandroFernandezLuces May 25, 2026
ab224ab
Merge branch 'feat/webview' of https://github.com/ansys/python-usd-vi…
AlejandroFernandezLuces May 25, 2026
ddf3457
fix: Code cleanup
AlejandroFernandezLuces May 25, 2026
6a14283
Merge branch 'main' into feat/webview
AlejandroFernandezLuces May 26, 2026
4cf7059
Merge branch 'feat/webview' of https://github.com/ansys/python-usd-vi…
AlejandroFernandezLuces May 26, 2026
c844658
fix: Remove imports from init
AlejandroFernandezLuces May 26, 2026
7dc7a68
fix: Rename param
AlejandroFernandezLuces May 26, 2026
8f90747
fix: Tests
AlejandroFernandezLuces May 26, 2026
869b461
chore: adding changelog file 75.added.md [dependabot-skip]
pyansys-ci-bot May 26, 2026
0d11827
fix: Docstring
AlejandroFernandezLuces May 26, 2026
3f04b87
Merge branch 'feat/webview' of https://github.com/ansys/python-usd-vi…
AlejandroFernandezLuces May 26, 2026
8c8fbff
Merge branch 'main' into feat/webview
AlejandroFernandezLuces May 28, 2026
2b336ce
Merge branch 'main' into feat/webview
AlejandroFernandezLuces May 29, 2026
c2705a1
fix: License header
AlejandroFernandezLuces May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,16 @@ not_a_dir
*usd_build/
*OpenUSD/
*install_dir/
*oneTBB/
*tbb_wasm/
*tbb_wasm_build/
*usd_wasm/
*openusd_wasm_build/
*emsdk/
examples/sphere.usda
examples/*_viewer.html
examples/*_page.html
examples/*_webprep.usda

/ALL_BUILD*
/CMakeCache.txt
Expand All @@ -201,4 +210,6 @@ examples/sphere.usda
/resources/
/source/
/cmake.*
temp.usda
temp.usda

examples/assets/complex_scene/*
1 change: 1 addition & 0 deletions doc/changelog.d/75.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add web view component
2 changes: 1 addition & 1 deletion examples/00-view-usd.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from ansys.tools.usdviewer.viewer import USDViewer

# Load USD file
path = r"display_color.usda"
path = r"assets/display_color_vertex.usda"
viewer = USDViewer(title="USD Viewer", size=(800, 800))
viewer.load_usd(path)
viewer.show()
2 changes: 1 addition & 1 deletion examples/01-vtk-asset-resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from ansys.tools.usdviewer.viewer import USDViewer


vtk_asset_path = r"display_color_vtk.usda"
vtk_asset_path = r"assets/display_color_vtk.usda"
# Initialize the USD Viewer.
viewer = USDViewer(title="USD Viewer", size=(800, 800))
# Load USD file with VTK asset.
Expand Down
4 changes: 2 additions & 2 deletions examples/02-convert-types.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@
import pyvista

# Read a simple VTK file
sphere = pyvista.read("sphere.vtk")
sphere = pyvista.read("assets/sphere.vtk")

# Create a new USD stage
stage = Usd.Stage.CreateNew("sphere.usda")

# Convert VTK to USD and add to stage
stage = VTKConverter.convert_vtk_file_to_usd("sphere.vtk", stage)
stage = VTKConverter.convert_vtk_file_to_usd("assets/sphere.vtk", stage)

# View the USD file in the USD Viewer
viewer = USDViewer(title="USD Viewer", size=(800, 800))
Expand Down
41 changes: 41 additions & 0 deletions examples/03-web-view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright (C) 2025 - 2026 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""
.. _ref_usd_web_viewer:

==============
USD Web Viewer
==============

This example shows how to generate a web-based USD viewer component.
"""
import webbrowser

from ansys.tools.usdviewer.web.html_export import export_viewer_html


if __name__ == "__main__":
html_path = export_viewer_html("assets/display_color_vtk.usda")
print(f"Viewer page generated at: {html_path}")
print("Controls: left-drag orbit, right-drag pan, mouse wheel zoom.")
webbrowser.open(html_path.resolve().as_uri())

77 changes: 77 additions & 0 deletions examples/04-export-viewer-html.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Copyright (C) 2025 - 2026 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
.. _ref_usd_web_viewer_integration:

==========================
USD Web Viewer integration
==========================

Example on how to export a USD viewer and embed it inside a standalone webpage via iframe.

Running this script produces two files in the same directory as the source
asset:

* ``display_color_vtk_viewer.html`` - the self-contained Three.js viewer
* ``display_color_vtk_page.html`` - a demo webpage that hosts the viewer
inside an ``<iframe>``

Open ``display_color_vtk_page.html`` in any browser to see the result.
"""

import webbrowser
from pathlib import Path

from ansys.tools.usdviewer.web.html_export import export_viewer_html

# Use external template for parent HTML page to avoid cluttering the code.
_PAGE_TEMPLATE = (Path(__file__).parent / "assets" / "page_template.html").read_text(encoding="utf-8")


if __name__ == "__main__":


source = Path("assets/display_color_vtk.usda")

# Name of the component to be integrated.
output_path = source.parent / f"{source.stem}_viewer.html"

# Export the viewer HTML file for the given USD source.
viewer_path = export_viewer_html(source, output_path=output_path)

print(f"Viewer HTML : {viewer_path}")

# Generate a simple wrapper page that embeds the viewer via iframe.
page_path = source.parent / f"{source.stem}_page.html"
page_path.write_text(
_PAGE_TEMPLATE.format(
title=f"{source.name} - USD Viewer",
model_name=source.name,
viewer_filename=viewer_path.name,
),
encoding="utf-8",
)
print(f"Wrapper page : {page_path}")

# Open the wrapper page in the default web browser.
webbrowser.open(page_path.resolve().as_uri())
File renamed without changes.
23 changes: 23 additions & 0 deletions examples/assets/display_color_vertex.usda
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#usda 1.0
(
defaultPrim = "root"
endTimeCode = 300
framesPerSecond = 30
startTimeCode = 0
)

def Xform "root"
{
def Mesh "mesh"
{
int[] faceVertexCounts = [4]
int[] faceVertexIndices = [0, 2, 3, 1]
normal3f[] normals = [(0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0)]
point3f[] points = [(-5, 0, 5), (-5, 0, -5), (5, 0, 5), (5, 0, -5)]
color3f[] primvars:displayColor = [(1, 0, 1), (1, 0, 0), (0, 1, 0), (0, 0, 1)] (
interpolation = "faceVarying"
)
uniform token subdivisionScheme = "none"
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ def Xform "root"
int[] faceVertexIndices = [0, 2, 3, 1]
normal3f[] normals = [(0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0)]
point3f[] points = [(-5, 0, 5), (-5, 0, -5), (5, 0, 5), (5, 0, -5)]
color3f[] primvars:displayColor = [(1, 0, 0)]
color3f[] primvars:displayColor = [(0, 1, 0)]
uniform token subdivisionScheme = "none"
}

def "sphere_vtk"
{
custom asset Asset = @sphere.vtk@
custom asset Asset = @stress.vtk@
}
}

123 changes: 123 additions & 0 deletions examples/assets/page_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{title}</title>
<style>
*, *::before, *::after {{ box-sizing: border-box; margin: 0; padding: 0; }}

body {{
font-family: "Segoe UI", system-ui, sans-serif;
background: #f0f2f5;
color: #1a1d23;
}}

header {{
background: #1e2127;
color: #f3f4f6;
padding: 18px 32px;
display: flex;
align-items: center;
gap: 14px;
box-shadow: 0 2px 8px rgba(0,0,0,.35);
}}

header h1 {{
font-size: 1.25rem;
font-weight: 600;
letter-spacing: .02em;
}}

header span.badge {{
font-size: .7rem;
background: #7cd7ff22;
border: 1px solid #7cd7ff55;
color: #7cd7ff;
border-radius: 4px;
padding: 2px 7px;
}}

main {{
max-width: 1100px;
margin: 40px auto;
padding: 0 24px;
}}

.card {{
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,.08);
overflow: hidden;
}}

.card-header {{
padding: 16px 20px;
border-bottom: 1px solid #e5e7eb;
display: flex;
justify-content: space-between;
align-items: center;
}}

.card-header h2 {{
font-size: 1rem;
font-weight: 600;
}}

.card-header .hint {{
font-size: .8rem;
color: #6b7280;
}}

iframe {{
display: block;
width: 100%;
height: 520px;
border: none;
}}

.info {{
margin-top: 28px;
font-size: .875rem;
color: #374151;
line-height: 1.7;
}}

.info code {{
background: #f3f4f6;
border: 1px solid #e5e7eb;
border-radius: 4px;
padding: 1px 5px;
font-family: "Cascadia Code", "Fira Code", monospace;
font-size: .8rem;
}}
</style>
</head>
<body>
<header>
<h1>USD Viewer</h1>
<span class="badge">Three.js · iframe embed</span>
</header>

<main>
<div class="card">
<div class="card-header">
<h2>{model_name}</h2>
<span class="hint">Left-drag orbit &nbsp;·&nbsp; right-drag pan &nbsp;·&nbsp; scroll zoom</span>
</div>
<iframe src="{viewer_filename}" title="3-D model viewer"
allowfullscreen loading="lazy"></iframe>
</div>

<p class="info">
The viewer above is a self-contained <code>{viewer_filename}</code>
file generated by
<code>export_viewer_html()</code> and embedded here with a single
<code>&lt;iframe&gt;</code> tag. Replace the
<code>src</code> attribute with any
<code>*_viewer.html</code> file produced by the same function to
display a different model.
</p>
</main>
</body>
</html>
File renamed without changes.
Binary file added examples/assets/stress.vtk
Binary file not shown.
File renamed without changes.
Binary file removed examples/robot_walk_idle.usdz
Binary file not shown.
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies = [
"pyopengl", # OpenUSD build dep
"pyside6", # OpenUSD build dep
"vtk",
"pygltflib",
]
scripts.usd-setup = "ansys.tools.usdviewer.autosetup:main"

Expand Down Expand Up @@ -69,6 +70,7 @@ tests = [

[tool.hatch.build.targets.wheel]
packages = [ "src/ansys" ]
include = [ "src/ansys/tools/usdviewer/web/*.html" ]

[tool.ruff]
line-length = 120
Expand Down
Loading
Loading