BugViewer 0.8.0
See the version list below for details.
dotnet add package BugViewer --version 0.8.0
NuGet\Install-Package BugViewer -Version 0.8.0
<PackageReference Include="BugViewer" Version="0.8.0" />
<PackageVersion Include="BugViewer" Version="0.8.0" />
<PackageReference Include="BugViewer" />
paket add BugViewer --version 0.8.0
#r "nuget: BugViewer, 0.8.0"
#:package BugViewer@0.8.0
#addin nuget:?package=BugViewer&version=0.8.0
#tool nuget:?package=BugViewer&version=0.8.0
BugViewer

Why Bug?
The most appropriate name would be Blazor WebGPU Viewer. This could be abbreviated as BWG Viewer, which is fine - but awkward to say and type. So, we simply change the double-U to a single-U → thus BugViewer.
Description
BugViewer is a Blazor component that renders a 3D file with the new WebGPU. It includes controls to view a single part (as opposed to being a game engine). The goal is to provide a clear method to view 3D parts with minimal Javascript.
The main things that are visualized are:
- triangles/meshes
- polylines
- text billboards
Installation
BugViewer can be installed as Nuget package: https://www.nuget.org/packages/BugViewer/
Usage
Simple scenario
Just add the BugViewer Component to your Razor page.:
<BugViewer @ref="viewer" Height="80%" Width="80%" />
The ./samples folder contains some examples of how to setup the canvas.
Saving and loading scenes
BugViewer.SceneRequest is the portable presentation contract. It stores 3D geometry,
colors, labels, complete steps or lazy step groups, transforms, and 2D plots in versioned
UTF-8 JSON. Optional viewer settings, camera, and InitialStep restore the saved view.
Saving a stepped request retains the whole timeline, including history limits and null
transform barriers, rather than just the displayed frame.
Use SceneViewer to display either kind of request:
@using BugViewer
<SceneViewer @ref="viewer" Scene="request" />
@code {
private SceneViewer? viewer;
private SceneRequest request = new();
}
// Save or replace the contents of a SceneViewer.
await viewer.SaveSceneAsync("part.bugscene.json");
await viewer.LoadSceneAsync("part.bugscene.json");
// Persist a request directly, without creating a viewer.
request.Save("part.bugscene.json");
var restored = SceneRequest.Load("part.bugscene.json");
await viewer.LoadSceneAsync(restored);
// Keep the source request with the current step, camera, and display settings.
var current = await viewer.GetSceneAsync();
SceneRequest.Load, Save, LoadAsync, and SaveAsync accept either a file path
or a Stream. Component LoadSceneAsync and SaveSceneAsync also accept streams. Stream
overloads leave the caller's stream open and operate at its current position; asynchronous
I/O overloads accept a cancellation token. File saves replace the destination only after
serialization succeeds. Invalid scene files are rejected before changing the viewer. The
serializer uses generated metadata and works in trimmed WebAssembly builds.
SceneMesh, ScenePath, ScenePointSet, PlotRequest, and PlotTrace hold the portable
data. SceneStepGroup stores source meshes and/or a SceneStepPathSource plus an optional
indexed transform list. ScenePoint and SceneTransform retain double precision until
the visible frame is converted for rendering. Use Steps for complete frames and
StepGroups for shared source data; a request cannot use both. Treat published source
collections as immutable so cached step resolution stays valid.
The low-level BugViewer component still accepts renderer-native meshes and lines.
SceneViewer displays 3D playback or 2D plots and provides the component persistence API, Open/Save As buttons, and
Ctrl+Alt+O / Ctrl+Alt+S shortcuts. Plain Ctrl+O / Ctrl+S remain available to the browser;
AltGr input is ignored. The 3D viewer also has Open and Save As icons in Settings, below
the Camera accordion, visible even when the accordion is collapsed. In 2D, the icons appear above the plot.
The viewer header displays ViewerId, an active indicator when IsActive is true, and the
scene title and heading (also the subtitle for 3D). Supplying OnClose shows a close button
that passes ViewerId to the host; OnReady is forwarded for both 3D and 2D rendering.
Save As prompts for a filename before downloading; Cancel or Escape leaves the scene unchanged.
Names without a .json or .bugscene extension receive .bugscene.json automatically.
For a stepped scene, Save As also accepts a 1-based inclusive start and end and a positive stride.
The default selects all steps with stride 1. Each saved 3D step combines the elements visible or
introduced in its consecutive stride-sized group, retaining the latest version of an object; visible
history at the start of the selected range is included. The final group may contain fewer steps.
For 2D, each saved step uses the last plot in its group. The saved presentation opens at its first step.
Full-range stride-1 saves preserve source steps and transforms. Other 3D selections materialize grouped
frames using renderer-precision coordinates, so files and memory use may increase and original source
transforms and double-precision coordinates may not be retained. Programmatic SaveSceneAsync still
saves the complete request.
Opening a request with steps
automatically shows playback controls; opening a single scene removes them. Saving keeps
the selected timeline and current view. The keyboard commands target the focused or last
clicked request viewer (or the only one on the page), and leave editors outside it alone.
Set EnableFileShortcuts="false" to let the host own those keys. Set EnableOpenScene="false"
for a save-only viewer, or call ShowSaveAsAsync() from a host control. Use MaxSceneFileSize to
adjust the 1 GiB input allowance and FileName to suggest names for programmatically supplied
requests. These file controls belong to SceneViewer; applications using only the
low-level BugViewer renderer should use this presentation component for scene files.
Opening and saving display progress in the same nonmodal viewer overlay. Opening reports bytes read
and can be canceled without replacing the current scene; saving shows its current stage and can be
canceled during preparation or serialization. Once the download is handed to the browser it cannot be
canceled from the viewer. Some synchronous work may delay cancellation. Saving buffers the exported
scene and JSON in memory, and the browser may make additional copies; the input allowance is configurable,
but available browser memory still determines the practical scene size.
Stepped playback reuses prepared geometry and a bounded GPU resource cache, prefetches the next two stride positions, and transfers missing geometry in binary chunks. A frame becomes visible only after its resources are ready. Playback uses elapsed-time deadlines and does not skip steps to conceal missed deadlines. Source collections must remain immutable after publication; publish a new request when changing source geometry. Existing JSON files and the public Load/Save methods retain the version-1 format.
SceneViewer exposes OnStepRendered with timings, transferred bytes, cache hits, and the browser submission timestamp.
For large saved scenes, use its Performance publish profile; setup instructions
and measured results are in docs/performance.md.
Plotly ships with the
library and loads only when displaying a 2D request.
Opaque fragments write depth before translucent objects are drawn. Translucent meshes, paths (including faded edges), labels, grid, and axes use weighted blended order-independent transparency, so crossing geometry no longer depends on object-center draw order. This method approximates rather than exactly reproduces depth-sorted blending; overlapping colors can differ from exact results, and very deep stacks can exceed the precision or range of the accumulation buffers. It requires the WebGPU accumulation and revealage render targets; there is currently no sorted-rendering fallback if those resources cannot be created. The viewer reports WebGPU failures rather than silently switching modes.
TVGL's WebGPUPresenter now produces this shared contract. Its derived PresenterRequest
keeps blocking/hold settings and callbacks in the presenter, and source-face references
stay in a presenter-side table. Those runtime details are excluded from the file. Reloaded
requests retain geometry and playback, but do not recreate live TVGL objects or callbacks.
Browser applications use streams from InputFile and browser downloads instead of local file paths.
The LoadAndShowScene sample is a viewing-only
app for previously saved scenes:
dotnet run --project samples/LoadAndShowScene
For VS Code debugging, select LoadAndShowScene (Blazor WebAssembly) in Run and Debug. The standalone WebAssembly app runs in a browser via its development server; do not launch its output DLL as a .NET console application. Stop any existing sample server before debugging if it is already using port 5220.
Open the displayed localhost URL in a WebGPU-capable browser. Use the Settings gear's
Open scene control or Ctrl+Alt+O to browse for a .bugscene.json file. In a 2D scene,
the Open control appears above the plot. Scenes with no saved camera are automatically framed.
Loading replaces the current request.
Host the standalone viewer
The sample is a static Blazor WebAssembly site: it loads scene files selected by the user into the browser and saves through a browser download. The sample does not need a server API for scene processing. The site assets must still be downloaded, and there is currently no service worker or offline-install support. A WebGPU-capable browser and a secure context (HTTPS, or localhost for development) are required. Browser memory can limit the practical file size below the configured 1 GiB limit.
To prepare a GitHub Pages deployment:
- In the repository's Settings > Pages, choose GitHub Actions as the build and deployment source. Check the visibility and availability of Pages for your repository before publishing; do not put private scene files in the website.
- Push the workflow and app changes to the default branch. In Actions, select Deploy scene viewer to GitHub Pages and run it manually. The workflow does not deploy automatically on push.
- Open the URL reported by the deployment. The workflow uses the Pages base path, so both a repository subpath and a root/custom-domain site are supported.
The deployed page provides Open scene in Settings and the Ctrl+Alt+O shortcut. Treat the deployed site and browser extensions as trusted code when viewing sensitive files; the local-file design is not a guarantee against a compromised host or browser.
Run the persistence and viewer-integration checks with:
dotnet run --project tests/BugViewer.SceneTests
Performance comparison
See the reproducible scene-loading benchmark and validation guide.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.AspNetCore.Components (>= 10.0.14)
- Microsoft.AspNetCore.Components.Web (>= 10.0.14)
- Microsoft.FluentUI.AspNetCore.Components (>= 5.0.1)
- Microsoft.FluentUI.AspNetCore.Components.Icons (>= 5.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.8.1 | 0 | 11/3/2026 |
| 0.8.0 | 52 | 10/30/2026 |
| 0.7.8 | 63 | 10/28/2026 |
| 0.7.7 | 78 | 10/27/2026 |
| 0.7.6 | 78 | 10/27/2026 |
| 0.7.5 | 83 | 10/27/2026 |
| 0.7.0 | 112 | 10/5/2026 |
| 0.6.9 | 98 | 9/20/2026 |
| 0.6.8 | 79 | 9/12/2026 |
| 0.6.7 | 161 | 9/7/2026 |
| 0.6.5 | 116 | 9/1/2026 |
| 0.6.4 | 120 | 8/31/2026 |
| 0.6.0 | 123 | 8/27/2026 |
| 0.5.2 | 175 | 1/22/2026 |
| 0.5.1 | 158 | 1/13/2026 |
| 0.5.0 | 147 | 1/13/2026 |