diff --git a/MakerPrompt.Blazor/MakerPrompt.Blazor.csproj b/MakerPrompt.Blazor/MakerPrompt.Blazor.csproj
index 73a3a9e..803b862 100644
--- a/MakerPrompt.Blazor/MakerPrompt.Blazor.csproj
+++ b/MakerPrompt.Blazor/MakerPrompt.Blazor.csproj
@@ -23,6 +23,7 @@
+
diff --git a/MakerPrompt.Blazor/Program.cs b/MakerPrompt.Blazor/Program.cs
index 5db4987..b4e02c8 100644
--- a/MakerPrompt.Blazor/Program.cs
+++ b/MakerPrompt.Blazor/Program.cs
@@ -1,6 +1,7 @@
using System.Globalization;
using MakerPrompt.Blazor;
using MakerPrompt.Blazor.Services;
+using MakerPrompt.Shared.ShapeIt;
using MakerPrompt.Shared.Utils;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
@@ -11,6 +12,10 @@
builder.RootComponents.Add("head::after");
builder.Services.RegisterMakerPromptSharedServices();
+builder.Services.AddShapeItForMakerPrompt();
+
+// Override the default NullSceneRenderer with the web-based renderer for Blazor
+builder.Services.AddScoped();
var host = builder.Build();
const string defaultCulture = "en-US";
diff --git a/MakerPrompt.Blazor/Services/WebCadSceneRenderer.cs b/MakerPrompt.Blazor/Services/WebCadSceneRenderer.cs
new file mode 100644
index 0000000..00475b7
--- /dev/null
+++ b/MakerPrompt.Blazor/Services/WebCadSceneRenderer.cs
@@ -0,0 +1,63 @@
+using MakerPrompt.Shared.ShapeIt.Rendering;
+using Microsoft.JSInterop;
+
+namespace MakerPrompt.Blazor.Services;
+
+///
+/// Web-based CAD scene renderer using a dedicated Web Worker and OffscreenCanvas.
+///
+public class WebCadSceneRenderer : ISceneRenderer
+{
+ private readonly IJSRuntime _jsRuntime;
+ private bool _initialized;
+
+ public WebCadSceneRenderer(IJSRuntime jsRuntime)
+ {
+ _jsRuntime = jsRuntime;
+ }
+
+ public async Task InitializeAsync(CancellationToken ct = default)
+ {
+ if (_initialized)
+ return;
+
+ // Initialize the CAD renderer with a canvas element
+ // The canvas ID would need to be provided by the component using this renderer
+ _initialized = true;
+ await Task.CompletedTask;
+ }
+
+ public async Task RenderAsync(SceneSnapshot snapshot, CancellationToken ct = default)
+ {
+ if (!_initialized)
+ throw new InvalidOperationException("Renderer not initialized. Call InitializeAsync first.");
+
+ // Send scene snapshot to the web worker via JS interop
+ await _jsRuntime.InvokeVoidAsync("cadRenderer.render", snapshot);
+ }
+
+ public async Task SetCameraAsync(CameraState camera, CancellationToken ct = default)
+ {
+ if (!_initialized)
+ throw new InvalidOperationException("Renderer not initialized. Call InitializeAsync first.");
+
+ // Send camera state to the web worker via JS interop
+ await _jsRuntime.InvokeVoidAsync("cadRenderer.setCamera", camera);
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ if (_initialized)
+ {
+ try
+ {
+ await _jsRuntime.InvokeVoidAsync("cadRenderer.dispose");
+ }
+ catch
+ {
+ // Ignore errors during disposal
+ }
+ _initialized = false;
+ }
+ }
+}
diff --git a/MakerPrompt.Blazor/wwwroot/cadRendererInterop.js b/MakerPrompt.Blazor/wwwroot/cadRendererInterop.js
new file mode 100644
index 0000000..66c900b
--- /dev/null
+++ b/MakerPrompt.Blazor/wwwroot/cadRendererInterop.js
@@ -0,0 +1,72 @@
+// CAD Renderer JavaScript Interop
+// Bridges Blazor C# with the CAD Web Worker
+
+window.cadRenderer = {
+ worker: null,
+ canvas: null,
+
+ initialize: async function(canvasId) {
+ console.log('Initializing CAD renderer for canvas:', canvasId);
+
+ // Get canvas element
+ this.canvas = document.getElementById(canvasId);
+ if (!this.canvas) {
+ console.error('Canvas not found:', canvasId);
+ return false;
+ }
+
+ // Create and initialize worker
+ try {
+ this.worker = new Worker('makerpromptCadWorker.js');
+
+ // Wait for initialization
+ return new Promise((resolve) => {
+ this.worker.addEventListener('message', function handler(e) {
+ if (e.data.type === 'initialized') {
+ this.removeEventListener('message', handler);
+ resolve(e.data.success);
+ }
+ });
+
+ // Send init message
+ this.worker.postMessage({ type: 'init', data: { canvasId } });
+ });
+ } catch (error) {
+ console.error('Failed to create CAD worker:', error);
+ return false;
+ }
+ },
+
+ render: function(sceneSnapshot) {
+ if (!this.worker) {
+ console.error('CAD worker not initialized');
+ return;
+ }
+
+ this.worker.postMessage({
+ type: 'render',
+ data: sceneSnapshot
+ });
+ },
+
+ setCamera: function(cameraState) {
+ if (!this.worker) {
+ console.error('CAD worker not initialized');
+ return;
+ }
+
+ this.worker.postMessage({
+ type: 'setCamera',
+ data: cameraState
+ });
+ },
+
+ dispose: function() {
+ if (this.worker) {
+ this.worker.postMessage({ type: 'dispose' });
+ this.worker.terminate();
+ this.worker = null;
+ }
+ this.canvas = null;
+ }
+};
diff --git a/MakerPrompt.Blazor/wwwroot/index.html b/MakerPrompt.Blazor/wwwroot/index.html
index 688457d..8387d0d 100644
--- a/MakerPrompt.Blazor/wwwroot/index.html
+++ b/MakerPrompt.Blazor/wwwroot/index.html
@@ -36,6 +36,7 @@
+