@leverege/tpi-viz 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
1
+ // The viewer's DOM skeleton. mountViewer() injects this into its container so
2
+ // the panel wiring (getElementById('threeCanvas'), '#layer-toggles', …) works
3
+ // whether the viewer is standalone or embedded in a host app. Previously this
4
+ // markup was inline in index.html; it lives here now so it's the single source
5
+ // for both distribution modes.
6
+ export const VIEWER_SKELETON = `
7
+ <div id="loading">Loading scene...</div>
8
+
9
+ <!-- Shown when no scene/shell is provided. -->
10
+ <div id="no-scene" class="landing hidden">
11
+ <div class="landing-card">
12
+ <header class="landing-header">
13
+ <h1>TPI Scene Viewer</h1>
14
+ <p class="landing-subtitle">Pick a scene to render, or generate a new one from the CLI.</p>
15
+ </header>
16
+
17
+ <section id="available-scenes-wrap" class="landing-scenes hidden">
18
+ <h2>Scenes <span class="landing-count" id="scenes-count"></span></h2>
19
+ <input type="search" id="scenes-filter" class="landing-filter" placeholder="Filter…" autocomplete="off" />
20
+ <div id="available-scenes" class="landing-scene-groups"></div>
21
+ </section>
22
+ </div>
23
+ </div>
24
+
25
+ <div class="container hidden" id="app">
26
+ <!-- Left sidebar: Elements + Camera Tree -->
27
+ <div class="sidebar" id="left-sidebar">
28
+ <div id="layers-panel">
29
+ <h3>Elements</h3>
30
+ <div id="layer-toggles"></div>
31
+ </div>
32
+ <div id="camera-tree-panel">
33
+ <h3>Flows</h3>
34
+ <div id="camera-tree" class="camera-tree"></div>
35
+ </div>
36
+ </div>
37
+
38
+ <!-- Main 3D area -->
39
+ <div class="main-area">
40
+ <div class="canvas-container">
41
+ <canvas id="threeCanvas"></canvas>
42
+ <div class="controls" id="pov-controls"></div>
43
+ </div>
44
+ <!-- Bottom image lightbox (opens on step-image click) -->
45
+ <div id="image-lightbox" class="hidden">
46
+ <div class="resize-handle" id="lightbox-resize-handle"></div>
47
+ <div class="lightbox-header">
48
+ <span id="lightbox-counter">1 / 1</span>
49
+ <div class="lightbox-nav">
50
+ <button class="btn-small" id="lightbox-prev">&laquo;</button>
51
+ <button class="btn-small" id="lightbox-next">&raquo;</button>
52
+ </div>
53
+ <span class="close-btn" id="close-lightbox" title="Close">&times;</span>
54
+ </div>
55
+ <div class="lightbox-body">
56
+ <canvas id="lightbox-canvas" style="display:none"></canvas>
57
+ <img id="lightbox-img" src="" alt="Full view" />
58
+ </div>
59
+ </div>
60
+ </div>
61
+
62
+ <!-- Right sidebar: Camera Inspector -->
63
+ <div class="sidebar right-sidebar hidden" id="right-sidebar">
64
+ <h3>
65
+ <span id="right-sidebar-title">Camera</span>
66
+ <span class="close-btn" id="close-right-panel" title="Close">&times;</span>
67
+ </h3>
68
+ <!-- Flow step navigation (shown when flow is active) -->
69
+ <div id="flow-nav" class="hidden">
70
+ <div class="flow-nav-title" id="flow-nav-title">Flow</div>
71
+ <div class="flow-step-nav">
72
+ <button class="btn-small" id="btn-prev-step" title="Previous step (&larr;)">&#9664;</button>
73
+ <span id="step-counter">Step 1 / 1</span>
74
+ <button class="btn-small" id="btn-next-step" title="Next step (&rarr;)">&#9654;</button>
75
+ <button class="btn-small" id="btn-play-stop" title="Play/Stop (Space)" style="margin-left:8px">&#9654; Play</button>
76
+ </div>
77
+ <div id="step-info"></div>
78
+ <!-- Image panel: shown when current step has images -->
79
+ <div id="image-panel" class="hidden">
80
+ <div class="image-nav">
81
+ <button class="btn-small" id="btn-prev-img" title="Previous image (A)">&laquo;</button>
82
+ <span id="image-counter">1 / 1</span>
83
+ <button class="btn-small" id="btn-next-img" title="Next image (D)">&raquo;</button>
84
+ <button class="btn-small" id="btn-laser-overlay" title="Toggle laser mask overlay (L)" style="margin-left:auto; opacity:0.5">&#9681; Laser</button>
85
+ <button class="btn-small" id="btn-score-overlay" title="Toggle laser score overlay (S)" style="opacity:0.5; display:none">&#9682; Score</button>
86
+ <button class="btn-small" id="btn-projected-overlay" title="Toggle projected contour (P)" style="opacity:0.5; display:none">&#9634; Proj</button>
87
+ <button class="btn-small" id="btn-aligned-overlay" title="Toggle aligned contour (;)" style="opacity:0.5; display:none">&#9635; Align</button>
88
+ </div>
89
+ <div id="image-display">
90
+ <canvas id="step-image-canvas" style="display:none"></canvas>
91
+ <img id="step-image" src="" alt="Capture" />
92
+ </div>
93
+ </div>
94
+ </div>
95
+ <!-- Camera detail: PTZ sliders + kinematic params -->
96
+ <div id="camera-detail"></div>
97
+ </div>
98
+ </div>
99
+ `;
@@ -0,0 +1,18 @@
1
+ // Standalone entry: the /viz/ static app, the Vite dev server, and the Python
2
+ // `tpi-viz serve` wheel all load this. It derives mount opts from the URL and
3
+ // mounts the viewer. The embedded (Imaginarium React) path does NOT use this —
4
+ // it imports mountViewer directly and passes opts as props.
5
+ import { mountViewer } from './main.js';
6
+
7
+ const params = new URLSearchParams( location.search );
8
+ const opts = {
9
+ shellId : params.get( 'shell' ) || undefined,
10
+ configId : params.get( 'configId' ) || undefined,
11
+ sceneUrl : params.get( 'sceneUrl' ) || undefined,
12
+ scene : params.get( 'scene' ) || undefined,
13
+ };
14
+
15
+ const root = document.getElementById( 'viewer-root' ) || document.body;
16
+ mountViewer( root, opts ).catch( ( err ) => {
17
+ console.error( 'Viewer failed to mount:', err );
18
+ } );