@thatopen/services 0.1.3 → 0.3.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.
- package/README.md +59 -46
- package/dist/built-in/index.d.ts +486 -563
- package/dist/cli/lib/npmrc.d.ts +28 -0
- package/dist/cli/lib/npmrc.test.d.ts +1 -0
- package/dist/cli.js +91 -7
- package/dist/core/client.d.ts +10 -0
- package/dist/index.cjs.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +42 -32
- package/dist/types/npm.d.ts +14 -0
- package/dist/vite-env.d.ts +1 -1
- package/docs/builtin/paths.json +74 -70
- package/docs/cli/create.md +28 -28
- package/docs/cli/local-server.md +38 -38
- package/docs/cli/login.md +32 -32
- package/docs/cli/publish.md +31 -31
- package/docs/cli/run.md +26 -26
- package/docs/cli/serve.md +43 -43
- package/docs/cli/swap.md +30 -30
- package/package.json +100 -100
- package/resources/AGENTS.md +40 -40
- package/src/built-in/CDEManager/example.ts +214 -214
- package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -226
- package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -186
- package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -295
- package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -210
- package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -230
- package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -230
- package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -166
- package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -177
- package/src/built-in/UIManager/src/app/example.ts +99 -99
- package/src/built-in/UIManager/src/app/examples/AppState/example.ts +142 -142
- package/src/built-in/UIManager/src/app/examples/Banner/example.ts +161 -0
- package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +125 -125
- package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +126 -0
- package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +92 -92
- package/src/built-in/UIManager/src/app/examples/Modal/example.ts +165 -0
- package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +135 -161
- package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +104 -104
- package/src/built-in/index.ts +649 -755
- package/src/cli/templates/app/README.md +241 -241
- package/src/cli/templates/app/index.html +35 -27
- package/src/cli/templates/app/package.json +31 -27
- package/src/cli/templates/app/src/app.ts +37 -0
- package/src/cli/templates/app/src/assets/tool-placeholder.ts +50 -0
- package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -87
- package/src/cli/templates/app/src/bim-components/CloudRunner/src/index.ts +1 -1
- package/src/cli/templates/app/src/bim-components/CloudRunner/src/types.ts +5 -5
- package/src/cli/templates/app/src/bim-components/index.ts +1 -1
- package/src/cli/templates/app/src/globals.ts +1 -0
- package/src/cli/templates/app/src/main.ts +340 -56
- package/src/cli/templates/app/src/setups/active-tool-hud.ts +69 -0
- package/src/cli/templates/app/src/setups/camera-tools.ts +63 -0
- package/src/cli/templates/app/src/setups/camera-views.ts +201 -0
- package/src/cli/templates/app/src/setups/card-header.ts +35 -0
- package/src/cli/templates/app/src/setups/clipper-panel.ts +167 -0
- package/src/cli/templates/app/src/setups/clipper-tool.ts +754 -0
- package/src/cli/templates/app/src/setups/clipper.ts +75 -0
- package/src/cli/templates/app/src/setups/cloud-runner.ts +13 -9
- package/src/cli/templates/app/src/setups/commands-panel.ts +239 -0
- package/src/cli/templates/app/src/setups/data-table-panel.ts +2224 -0
- package/src/cli/templates/app/src/setups/exploded-view.ts +246 -0
- package/src/cli/templates/app/src/setups/file-format-icons.ts +95 -0
- package/src/cli/templates/app/src/setups/files-panel.ts +1503 -0
- package/src/cli/templates/app/src/setups/fps-indicator.ts +63 -0
- package/src/cli/templates/app/src/setups/graphics-panel.ts +490 -0
- package/src/cli/templates/app/src/setups/helper-panel.ts +88 -0
- package/src/cli/templates/app/src/setups/hider.ts +98 -0
- package/src/cli/templates/app/src/setups/index.ts +33 -3
- package/src/cli/templates/app/src/setups/inspection.ts +136 -0
- package/src/cli/templates/app/src/setups/measurement-panel.ts +188 -0
- package/src/cli/templates/app/src/setups/measurement-settings-panel.ts +161 -0
- package/src/cli/templates/app/src/setups/measurement-tool.ts +570 -0
- package/src/cli/templates/app/src/setups/measurements.ts +133 -0
- package/src/cli/templates/app/src/setups/model-tree.ts +797 -0
- package/src/cli/templates/app/src/setups/navigation-gizmo.ts +316 -0
- package/src/cli/templates/app/src/setups/objects-panel.ts +127 -0
- package/src/cli/templates/app/src/setups/plans-panel.ts +619 -0
- package/src/cli/templates/app/src/setups/properties-panel.ts +1048 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/hidden-tiles-plugin.ts +88 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/point-tile-plugin.ts +166 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/render-frame.ts +31 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/splat-tile-plugin.ts +51 -0
- package/src/cli/templates/app/src/setups/reality-capture-viewer.ts +1383 -0
- package/src/cli/templates/app/src/setups/right-sidebar.ts +178 -0
- package/src/cli/templates/app/src/setups/settings-panel.ts +94 -0
- package/src/cli/templates/app/src/setups/styles-panel.ts +110 -0
- package/src/cli/templates/app/src/setups/styles.ts +375 -0
- package/src/cli/templates/app/src/setups/tool-mode-manager.ts +150 -0
- package/src/cli/templates/app/src/setups/tool-mode.ts +23 -0
- package/src/cli/templates/app/src/setups/toolbar.ts +229 -0
- package/src/cli/templates/app/src/setups/ui-manager.ts +27 -0
- package/src/cli/templates/app/src/setups/visibility-toolbar.ts +498 -0
- package/src/cli/templates/app/src/setups/walkthrough.ts +528 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -0
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -0
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -0
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -0
- package/src/cli/templates/app/src/ui-components/index.ts +2 -1
- package/src/cli/templates/app/tsconfig.json +16 -17
- package/src/cli/templates/app/vite.config.js +45 -42
- package/src/cli/templates/cloud-component/README.md +205 -205
- package/src/cli/templates/cloud-component/_thatopen +5 -5
- package/src/cli/templates/cloud-component/declarations.json +4 -4
- package/src/cli/templates/cloud-component/package.json +21 -21
- package/src/cli/templates/cloud-component/src/main.ts +70 -70
- package/src/cli/templates/cloud-component/tsconfig.json +16 -16
- package/src/cli/templates/cloud-component/vite.config.js +46 -46
- package/src/cli/templates/shared/AGENTS.md +8 -8
- package/src/cli/templates/shared/CLAUDE.md +1 -1
- package/src/cli/templates/shared/_gitignore +5 -4
- package/src/built-in/AppManager/example.ts +0 -86
- package/src/built-in/FileList/example.ts +0 -107
- package/src/built-in/TabbedNavigation/example.ts +0 -115
- package/src/built-in/ViewportsManager/example.ts +0 -106
- package/src/cli/templates/app/src/setups/fragments.ts +0 -18
- package/src/cli/templates/app/src/setups/ifc-loader.ts +0 -12
- package/src/cli/templates/app/src/ui-components/AppPanel/index.ts +0 -160
|
@@ -1,241 +1,241 @@
|
|
|
1
|
-
# ThatOpen BIM App
|
|
2
|
-
|
|
3
|
-
This is a BIM (Building Information Modeling) app built for the That Open Platform.
|
|
4
|
-
It runs in the browser inside the platform's iframe and has access to a 3D viewer,
|
|
5
|
-
UI components, and the platform API.
|
|
6
|
-
|
|
7
|
-
## How this app works
|
|
8
|
-
|
|
9
|
-
- **Entry point**: `src/main.ts` — runs as an IIFE when the platform loads the app.
|
|
10
|
-
- **Build output**: `dist/bundle.js` — a single IIFE file built by Vite.
|
|
11
|
-
- **Platform context**: The platform injects `window.__THATOPEN_CONTEXT__` with:
|
|
12
|
-
- `appId` — this app's unique ID
|
|
13
|
-
- `projectId` — the project this app belongs to
|
|
14
|
-
- `accessToken` — Auth0 JWT for API calls
|
|
15
|
-
- `apiUrl` — base URL for the That Open API
|
|
16
|
-
|
|
17
|
-
## Commands
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm run dev # Start dev server (esbuild watch + serve on :4000)
|
|
21
|
-
npm run build # Build dist/bundle.js (Vite/Rollup production build)
|
|
22
|
-
npm run login # Authenticate with the platform (saves token locally)
|
|
23
|
-
npm run publish # Publish to the platform
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Local development
|
|
27
|
-
|
|
28
|
-
Apps run inside the That Open Platform (platform.thatopen.com) within a project —
|
|
29
|
-
not as standalone websites. To develop locally:
|
|
30
|
-
|
|
31
|
-
1. Run `npm run dev` — this watches source files with esbuild and serves the bundle on port 4000.
|
|
32
|
-
2. Open your project on the platform and click the debug button.
|
|
33
|
-
3. Live reload is enabled — save a file to rebuild automatically.
|
|
34
|
-
|
|
35
|
-
The dev server (`thatopen serve`) uses esbuild for near-instant incremental rebuilds.
|
|
36
|
-
**Important**: Do NOT run `vite`, `vite build --watch`, or `npx vite` directly for development.
|
|
37
|
-
Always use `npm run dev` which runs `thatopen serve` under the hood.
|
|
38
|
-
|
|
39
|
-
## Key libraries
|
|
40
|
-
|
|
41
|
-
| Package | Import | Purpose |
|
|
42
|
-
|---------|--------|---------|
|
|
43
|
-
| `@thatopen/components` | `OBC` | BIM engine — components, fragments, worlds |
|
|
44
|
-
| `@thatopen/components-front` | `OBF` | Front-end BIM components (Highlighter, measurements, etc.) |
|
|
45
|
-
| `@thatopen/fragments` | `FRAGS` | Fragment geometry format |
|
|
46
|
-
| `@thatopen/ui` | `BUI` | UI web components (`<bim-panel>`, `<bim-grid>`, etc.) |
|
|
47
|
-
| `three` | `THREE` | 3D rendering engine |
|
|
48
|
-
| `@thatopen/services` | `EngineServicesClient` | Platform API client + built-in components |
|
|
49
|
-
|
|
50
|
-
## Architecture pattern
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
1. Create EngineServicesClient from platform context
|
|
54
|
-
2. Call client.setup(globals, ...builtIns) — creates OBC.Components,
|
|
55
|
-
inits BUI, loads built-in components, calls components.init()
|
|
56
|
-
3. Create viewport(s) and UI elements
|
|
57
|
-
4. Configure AppManager with elements + layouts
|
|
58
|
-
5. Call app.init()
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Built-in components
|
|
62
|
-
|
|
63
|
-
Built-in components are platform-hosted UI modules loaded at runtime via the API client.
|
|
64
|
-
They are fetched, evaluated, and registered with the OBC component system.
|
|
65
|
-
|
|
66
|
-
| Component | Purpose |
|
|
67
|
-
|-----------|---------|
|
|
68
|
-
| **AppManager** | App shell — CSS grid layout system with sidebar for switching layouts |
|
|
69
|
-
| **ViewportsManager** | Factory for 3D viewports with pre-configured world (scene, camera, renderer) |
|
|
70
|
-
| **LoadModelButton** | Button + dropdown for loading IFC and Fragments files |
|
|
71
|
-
| **ViewerToolbar** | Toolbar with Show/Hide/Focus/Isolate actions and color palette |
|
|
72
|
-
| **ModelsPanel** | Panel listing loaded models with search bar and load button |
|
|
73
|
-
| **ModelsDropdown** | Dropdown selector listing loaded models |
|
|
74
|
-
| **ClassificationsList** | Hierarchical table of IFC classification data |
|
|
75
|
-
| **ClashesList** | Interactive clash detection results with click-to-highlight |
|
|
76
|
-
| **ClippingsList** | Panel listing clipping planes with enable/delete controls |
|
|
77
|
-
| **LengthMeasuringsList** | Panel listing length measurements with cumulative total |
|
|
78
|
-
| **AreaMeasuringsList** | Panel listing area measurements with area/perimeter totals |
|
|
79
|
-
| **ColorsPalette** | Color picker grid with custom input and Highlighter styles |
|
|
80
|
-
| **HighlightersList** | Panel listing Highlighter styles with manage/apply actions |
|
|
81
|
-
| **QtoComparisonList** | Side-by-side quantity comparison for two selected elements |
|
|
82
|
-
| **QueriesHierarchy** | Recursive multi-level query browser for IFC data |
|
|
83
|
-
| **CustomViewLegend** | Color legend overlay with colored circles and labels |
|
|
84
|
-
| **ScreenshotAnnotator** | Modal for annotating screenshots (arrows, text, freehand) via MarkerJS |
|
|
85
|
-
|
|
86
|
-
**Full API reference**: Each component has detailed JSDoc with `@example` blocks in the
|
|
87
|
-
`@thatopen/services` package source (`src/built-in/index.ts`). Read that file for config
|
|
88
|
-
interfaces, method signatures, and code examples.
|
|
89
|
-
|
|
90
|
-
### Loading pattern
|
|
91
|
-
|
|
92
|
-
Use `setup` to create the component system and load built-in components in one call:
|
|
93
|
-
|
|
94
|
-
```ts
|
|
95
|
-
import { PlatformClient, AppManager, ViewportsManager } from "@thatopen/services";
|
|
96
|
-
|
|
97
|
-
const client = PlatformClient.fromPlatformContext();
|
|
98
|
-
|
|
99
|
-
// Creates OBC.Components, inits BUI, loads built-ins, calls components.init()
|
|
100
|
-
const { components } = await client.setup(
|
|
101
|
-
{ OBC, OBF, BUI, THREE, FRAGS },
|
|
102
|
-
AppManager, ViewportsManager,
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
const app = components.get(AppManager);
|
|
106
|
-
const viewports = components.get(ViewportsManager);
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
You can also load components individually if needed:
|
|
110
|
-
|
|
111
|
-
```ts
|
|
112
|
-
// Batch load (parallel)
|
|
113
|
-
await client.initBuiltInComponents(components, AppManager, ViewportsManager);
|
|
114
|
-
|
|
115
|
-
// Or one at a time
|
|
116
|
-
await client.initBuiltInComponent(AppManager, components);
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### Required globals per component
|
|
120
|
-
|
|
121
|
-
| Component | Globals to pass | Extra npm packages needed |
|
|
122
|
-
|-----------|----------------|--------------------------|
|
|
123
|
-
| AppManager | `{ OBC, BUI }` | — |
|
|
124
|
-
| ViewportsManager | `{ OBC, BUI, THREE, FRAGS }` | — |
|
|
125
|
-
| LoadModelButton | `{ OBC, BUI }` | — |
|
|
126
|
-
| ModelsDropdown | `{ OBC, BUI }` | — |
|
|
127
|
-
| ViewerToolbar | `{ OBC, OBF, BUI, THREE }` | `@thatopen/components-front` |
|
|
128
|
-
| ColorsPalette | `{ OBC, OBF, BUI }` | `@thatopen/components-front` |
|
|
129
|
-
| ClashesList | `{ OBC, OBF, BUI, THREE }` | `@thatopen/components-front` |
|
|
130
|
-
| ClassificationsList | `{ OBC, OBF, BUI }` | `@thatopen/components-front` |
|
|
131
|
-
| ClippingsList | `{ OBC, BUI }` | — |
|
|
132
|
-
| HighlightersList | `{ OBC, OBF, BUI }` | `@thatopen/components-front` |
|
|
133
|
-
| LengthMeasuringsList | `{ OBC, OBF, BUI, THREE }` | `@thatopen/components-front` |
|
|
134
|
-
| AreaMeasuringsList | `{ OBC, OBF, BUI, THREE }` | `@thatopen/components-front` |
|
|
135
|
-
| QtoComparisonList | `{ OBC, OBF, BUI }` | `@thatopen/components-front` |
|
|
136
|
-
| QueriesHierarchy | `{ OBC, OBF, BUI }` | `@thatopen/components-front` |
|
|
137
|
-
| CustomViewLegend | `{ OBC, BUI }` | — |
|
|
138
|
-
| ScreenshotAnnotator | `{ OBC, BUI, MARKERJS }` | `@markerjs/markerjs3` |
|
|
139
|
-
|
|
140
|
-
### Global abbreviations
|
|
141
|
-
|
|
142
|
-
```ts
|
|
143
|
-
import * as OBC from "@thatopen/components";
|
|
144
|
-
import * as OBF from "@thatopen/components-front"; // needed for Toolbar, Highlighters, Clashes, etc.
|
|
145
|
-
import * as BUI from "@thatopen/ui";
|
|
146
|
-
import * as THREE from "three";
|
|
147
|
-
import * as FRAGS from "@thatopen/fragments";
|
|
148
|
-
import * as MARKERJS from "@markerjs/markerjs3"; // needed for ScreenshotAnnotator
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### AppManager — app shell with CSS grid layouts
|
|
152
|
-
|
|
153
|
-
Creates a grid-based layout system. Define named element slots and named layouts.
|
|
154
|
-
A sidebar for switching layouts appears automatically when multiple layouts exist.
|
|
155
|
-
|
|
156
|
-
```ts
|
|
157
|
-
const Layouts = ["Viewer", "Split"];
|
|
158
|
-
const Elements = ["viewer", "panel"];
|
|
159
|
-
|
|
160
|
-
await app.init({
|
|
161
|
-
client,
|
|
162
|
-
icons: undefined, // pass Record<K, string> when using typed App interface with icon keys
|
|
163
|
-
grid: (grid: BUI.Grid<Layouts, Elements>) => {
|
|
164
|
-
grid.elements = {
|
|
165
|
-
viewer: viewportElement,
|
|
166
|
-
panel: panelFunction, // Can be HTMLElement, () => BUI.TemplateResult, or { template, initialState }
|
|
167
|
-
};
|
|
168
|
-
grid.layouts = {
|
|
169
|
-
Viewer: { template: `"viewer" 1fr / 1fr` },
|
|
170
|
-
Split: {
|
|
171
|
-
template: `"panel viewer" 1fr / 20rem 1fr`,
|
|
172
|
-
icon: "solar:settings-bold",
|
|
173
|
-
},
|
|
174
|
-
};
|
|
175
|
-
},
|
|
176
|
-
});
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
The `template` string uses CSS `grid-template` shorthand: `"areas" rows / columns`.
|
|
180
|
-
|
|
181
|
-
### ViewportsManager — 3D viewport factory
|
|
182
|
-
|
|
183
|
-
Creates viewports with pre-configured world (scene, camera, renderer) and auto-initialized fragments.
|
|
184
|
-
|
|
185
|
-
```ts
|
|
186
|
-
const viewports = components.get(ViewportsManager);
|
|
187
|
-
const { element, world } = await viewports.create();
|
|
188
|
-
// element is an HTMLElement to place in a layout slot
|
|
189
|
-
// world has world.scene, world.camera, world.renderer
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
## Loading a BIM model
|
|
193
|
-
|
|
194
|
-
```ts
|
|
195
|
-
const fragments = components.get(OBC.FragmentsManager);
|
|
196
|
-
|
|
197
|
-
// From URL
|
|
198
|
-
const response = await fetch("https://example.com/model.frag");
|
|
199
|
-
const buffer = await response.arrayBuffer();
|
|
200
|
-
await fragments.core.load(buffer, { modelId: "my-model" });
|
|
201
|
-
|
|
202
|
-
// From platform storage
|
|
203
|
-
const fileResponse = await client.downloadFile(fileId);
|
|
204
|
-
const fileBuffer = await fileResponse.arrayBuffer();
|
|
205
|
-
await fragments.core.load(fileBuffer, { modelId: "my-model" });
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
## EngineServicesClient API (commonly used in apps)
|
|
209
|
-
|
|
210
|
-
```ts
|
|
211
|
-
// Recommended: auto-reads window.__THATOPEN_CONTEXT__ and sets useBearer: true
|
|
212
|
-
const client = PlatformClient.fromPlatformContext();
|
|
213
|
-
console.log(client.context.projectId); // access the platform context
|
|
214
|
-
|
|
215
|
-
// Files
|
|
216
|
-
const files = await client.listFiles();
|
|
217
|
-
const file = await client.getFile(fileId);
|
|
218
|
-
const response = await client.downloadFile(fileId);
|
|
219
|
-
await client.createFile({ file: blob, name: "model.ifc", versionTag: "v1" });
|
|
220
|
-
|
|
221
|
-
// Folders
|
|
222
|
-
const folders = await client.listFolders();
|
|
223
|
-
await client.createFolder("My Folder");
|
|
224
|
-
|
|
225
|
-
// Execute cloud components
|
|
226
|
-
const { executionId } = await client.executeComponent(componentId, { param: "value" });
|
|
227
|
-
client.onExecutionProgress(executionId, (data) => {
|
|
228
|
-
// data.progressUpdate — progress percentage
|
|
229
|
-
// data.messageUpdate — status messages
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
// Test against a local cloud component (requires thatopen local-server running in the component project)
|
|
233
|
-
client.localServerUrl = "http://localhost:4001";
|
|
234
|
-
const local = await client.executeComponent("any-id", { param: "value" });
|
|
235
|
-
client.localServerUrl = null; // reset to use the cloud API
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
## Configuration
|
|
239
|
-
|
|
240
|
-
- `.thatopen` — local config (gitignored). Created by `npm run login`. Contains `accessToken`, `apiUrl`, and `appId` after first publish.
|
|
241
|
-
- `vite.config.js` — builds to IIFE format as `dist/bundle.js`. All dependencies are bundled.
|
|
1
|
+
# ThatOpen BIM App
|
|
2
|
+
|
|
3
|
+
This is a BIM (Building Information Modeling) app built for the That Open Platform.
|
|
4
|
+
It runs in the browser inside the platform's iframe and has access to a 3D viewer,
|
|
5
|
+
UI components, and the platform API.
|
|
6
|
+
|
|
7
|
+
## How this app works
|
|
8
|
+
|
|
9
|
+
- **Entry point**: `src/main.ts` — runs as an IIFE when the platform loads the app.
|
|
10
|
+
- **Build output**: `dist/bundle.js` — a single IIFE file built by Vite.
|
|
11
|
+
- **Platform context**: The platform injects `window.__THATOPEN_CONTEXT__` with:
|
|
12
|
+
- `appId` — this app's unique ID
|
|
13
|
+
- `projectId` — the project this app belongs to
|
|
14
|
+
- `accessToken` — Auth0 JWT for API calls
|
|
15
|
+
- `apiUrl` — base URL for the That Open API
|
|
16
|
+
|
|
17
|
+
## Commands
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm run dev # Start dev server (esbuild watch + serve on :4000)
|
|
21
|
+
npm run build # Build dist/bundle.js (Vite/Rollup production build)
|
|
22
|
+
npm run login # Authenticate with the platform (saves token locally)
|
|
23
|
+
npm run publish # Publish to the platform
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Local development
|
|
27
|
+
|
|
28
|
+
Apps run inside the That Open Platform (platform.thatopen.com) within a project —
|
|
29
|
+
not as standalone websites. To develop locally:
|
|
30
|
+
|
|
31
|
+
1. Run `npm run dev` — this watches source files with esbuild and serves the bundle on port 4000.
|
|
32
|
+
2. Open your project on the platform and click the debug button.
|
|
33
|
+
3. Live reload is enabled — save a file to rebuild automatically.
|
|
34
|
+
|
|
35
|
+
The dev server (`thatopen serve`) uses esbuild for near-instant incremental rebuilds.
|
|
36
|
+
**Important**: Do NOT run `vite`, `vite build --watch`, or `npx vite` directly for development.
|
|
37
|
+
Always use `npm run dev` which runs `thatopen serve` under the hood.
|
|
38
|
+
|
|
39
|
+
## Key libraries
|
|
40
|
+
|
|
41
|
+
| Package | Import | Purpose |
|
|
42
|
+
|---------|--------|---------|
|
|
43
|
+
| `@thatopen/components` | `OBC` | BIM engine — components, fragments, worlds |
|
|
44
|
+
| `@thatopen/components-front` | `OBF` | Front-end BIM components (Highlighter, measurements, etc.) |
|
|
45
|
+
| `@thatopen/fragments` | `FRAGS` | Fragment geometry format |
|
|
46
|
+
| `@thatopen/ui` | `BUI` | UI web components (`<bim-panel>`, `<bim-grid>`, etc.) |
|
|
47
|
+
| `three` | `THREE` | 3D rendering engine |
|
|
48
|
+
| `@thatopen/services` | `EngineServicesClient` | Platform API client + built-in components |
|
|
49
|
+
|
|
50
|
+
## Architecture pattern
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
1. Create EngineServicesClient from platform context
|
|
54
|
+
2. Call client.setup(globals, ...builtIns) — creates OBC.Components,
|
|
55
|
+
inits BUI, loads built-in components, calls components.init()
|
|
56
|
+
3. Create viewport(s) and UI elements
|
|
57
|
+
4. Configure AppManager with elements + layouts
|
|
58
|
+
5. Call app.init()
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Built-in components
|
|
62
|
+
|
|
63
|
+
Built-in components are platform-hosted UI modules loaded at runtime via the API client.
|
|
64
|
+
They are fetched, evaluated, and registered with the OBC component system.
|
|
65
|
+
|
|
66
|
+
| Component | Purpose |
|
|
67
|
+
|-----------|---------|
|
|
68
|
+
| **AppManager** | App shell — CSS grid layout system with sidebar for switching layouts |
|
|
69
|
+
| **ViewportsManager** | Factory for 3D viewports with pre-configured world (scene, camera, renderer) |
|
|
70
|
+
| **LoadModelButton** | Button + dropdown for loading IFC and Fragments files |
|
|
71
|
+
| **ViewerToolbar** | Toolbar with Show/Hide/Focus/Isolate actions and color palette |
|
|
72
|
+
| **ModelsPanel** | Panel listing loaded models with search bar and load button |
|
|
73
|
+
| **ModelsDropdown** | Dropdown selector listing loaded models |
|
|
74
|
+
| **ClassificationsList** | Hierarchical table of IFC classification data |
|
|
75
|
+
| **ClashesList** | Interactive clash detection results with click-to-highlight |
|
|
76
|
+
| **ClippingsList** | Panel listing clipping planes with enable/delete controls |
|
|
77
|
+
| **LengthMeasuringsList** | Panel listing length measurements with cumulative total |
|
|
78
|
+
| **AreaMeasuringsList** | Panel listing area measurements with area/perimeter totals |
|
|
79
|
+
| **ColorsPalette** | Color picker grid with custom input and Highlighter styles |
|
|
80
|
+
| **HighlightersList** | Panel listing Highlighter styles with manage/apply actions |
|
|
81
|
+
| **QtoComparisonList** | Side-by-side quantity comparison for two selected elements |
|
|
82
|
+
| **QueriesHierarchy** | Recursive multi-level query browser for IFC data |
|
|
83
|
+
| **CustomViewLegend** | Color legend overlay with colored circles and labels |
|
|
84
|
+
| **ScreenshotAnnotator** | Modal for annotating screenshots (arrows, text, freehand) via MarkerJS |
|
|
85
|
+
|
|
86
|
+
**Full API reference**: Each component has detailed JSDoc with `@example` blocks in the
|
|
87
|
+
`@thatopen/services` package source (`src/built-in/index.ts`). Read that file for config
|
|
88
|
+
interfaces, method signatures, and code examples.
|
|
89
|
+
|
|
90
|
+
### Loading pattern
|
|
91
|
+
|
|
92
|
+
Use `setup` to create the component system and load built-in components in one call:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { PlatformClient, AppManager, ViewportsManager } from "@thatopen/services";
|
|
96
|
+
|
|
97
|
+
const client = PlatformClient.fromPlatformContext();
|
|
98
|
+
|
|
99
|
+
// Creates OBC.Components, inits BUI, loads built-ins, calls components.init()
|
|
100
|
+
const { components } = await client.setup(
|
|
101
|
+
{ OBC, OBF, BUI, THREE, FRAGS },
|
|
102
|
+
AppManager, ViewportsManager,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const app = components.get(AppManager);
|
|
106
|
+
const viewports = components.get(ViewportsManager);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
You can also load components individually if needed:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
// Batch load (parallel)
|
|
113
|
+
await client.initBuiltInComponents(components, AppManager, ViewportsManager);
|
|
114
|
+
|
|
115
|
+
// Or one at a time
|
|
116
|
+
await client.initBuiltInComponent(AppManager, components);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Required globals per component
|
|
120
|
+
|
|
121
|
+
| Component | Globals to pass | Extra npm packages needed |
|
|
122
|
+
|-----------|----------------|--------------------------|
|
|
123
|
+
| AppManager | `{ OBC, BUI }` | — |
|
|
124
|
+
| ViewportsManager | `{ OBC, BUI, THREE, FRAGS }` | — |
|
|
125
|
+
| LoadModelButton | `{ OBC, BUI }` | — |
|
|
126
|
+
| ModelsDropdown | `{ OBC, BUI }` | — |
|
|
127
|
+
| ViewerToolbar | `{ OBC, OBF, BUI, THREE }` | `@thatopen/components-front` |
|
|
128
|
+
| ColorsPalette | `{ OBC, OBF, BUI }` | `@thatopen/components-front` |
|
|
129
|
+
| ClashesList | `{ OBC, OBF, BUI, THREE }` | `@thatopen/components-front` |
|
|
130
|
+
| ClassificationsList | `{ OBC, OBF, BUI }` | `@thatopen/components-front` |
|
|
131
|
+
| ClippingsList | `{ OBC, BUI }` | — |
|
|
132
|
+
| HighlightersList | `{ OBC, OBF, BUI }` | `@thatopen/components-front` |
|
|
133
|
+
| LengthMeasuringsList | `{ OBC, OBF, BUI, THREE }` | `@thatopen/components-front` |
|
|
134
|
+
| AreaMeasuringsList | `{ OBC, OBF, BUI, THREE }` | `@thatopen/components-front` |
|
|
135
|
+
| QtoComparisonList | `{ OBC, OBF, BUI }` | `@thatopen/components-front` |
|
|
136
|
+
| QueriesHierarchy | `{ OBC, OBF, BUI }` | `@thatopen/components-front` |
|
|
137
|
+
| CustomViewLegend | `{ OBC, BUI }` | — |
|
|
138
|
+
| ScreenshotAnnotator | `{ OBC, BUI, MARKERJS }` | `@markerjs/markerjs3` |
|
|
139
|
+
|
|
140
|
+
### Global abbreviations
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import * as OBC from "@thatopen/components";
|
|
144
|
+
import * as OBF from "@thatopen/components-front"; // needed for Toolbar, Highlighters, Clashes, etc.
|
|
145
|
+
import * as BUI from "@thatopen/ui";
|
|
146
|
+
import * as THREE from "three";
|
|
147
|
+
import * as FRAGS from "@thatopen/fragments";
|
|
148
|
+
import * as MARKERJS from "@markerjs/markerjs3"; // needed for ScreenshotAnnotator
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### AppManager — app shell with CSS grid layouts
|
|
152
|
+
|
|
153
|
+
Creates a grid-based layout system. Define named element slots and named layouts.
|
|
154
|
+
A sidebar for switching layouts appears automatically when multiple layouts exist.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
const Layouts = ["Viewer", "Split"];
|
|
158
|
+
const Elements = ["viewer", "panel"];
|
|
159
|
+
|
|
160
|
+
await app.init({
|
|
161
|
+
client,
|
|
162
|
+
icons: undefined, // pass Record<K, string> when using typed App interface with icon keys
|
|
163
|
+
grid: (grid: BUI.Grid<Layouts, Elements>) => {
|
|
164
|
+
grid.elements = {
|
|
165
|
+
viewer: viewportElement,
|
|
166
|
+
panel: panelFunction, // Can be HTMLElement, () => BUI.TemplateResult, or { template, initialState }
|
|
167
|
+
};
|
|
168
|
+
grid.layouts = {
|
|
169
|
+
Viewer: { template: `"viewer" 1fr / 1fr` },
|
|
170
|
+
Split: {
|
|
171
|
+
template: `"panel viewer" 1fr / 20rem 1fr`,
|
|
172
|
+
icon: "solar:settings-bold",
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The `template` string uses CSS `grid-template` shorthand: `"areas" rows / columns`.
|
|
180
|
+
|
|
181
|
+
### ViewportsManager — 3D viewport factory
|
|
182
|
+
|
|
183
|
+
Creates viewports with pre-configured world (scene, camera, renderer) and auto-initialized fragments.
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
const viewports = components.get(ViewportsManager);
|
|
187
|
+
const { element, world } = await viewports.create();
|
|
188
|
+
// element is an HTMLElement to place in a layout slot
|
|
189
|
+
// world has world.scene, world.camera, world.renderer
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Loading a BIM model
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
const fragments = components.get(OBC.FragmentsManager);
|
|
196
|
+
|
|
197
|
+
// From URL
|
|
198
|
+
const response = await fetch("https://example.com/model.frag");
|
|
199
|
+
const buffer = await response.arrayBuffer();
|
|
200
|
+
await fragments.core.load(buffer, { modelId: "my-model" });
|
|
201
|
+
|
|
202
|
+
// From platform storage
|
|
203
|
+
const fileResponse = await client.downloadFile(fileId);
|
|
204
|
+
const fileBuffer = await fileResponse.arrayBuffer();
|
|
205
|
+
await fragments.core.load(fileBuffer, { modelId: "my-model" });
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## EngineServicesClient API (commonly used in apps)
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
// Recommended: auto-reads window.__THATOPEN_CONTEXT__ and sets useBearer: true
|
|
212
|
+
const client = PlatformClient.fromPlatformContext();
|
|
213
|
+
console.log(client.context.projectId); // access the platform context
|
|
214
|
+
|
|
215
|
+
// Files
|
|
216
|
+
const files = await client.listFiles();
|
|
217
|
+
const file = await client.getFile(fileId);
|
|
218
|
+
const response = await client.downloadFile(fileId);
|
|
219
|
+
await client.createFile({ file: blob, name: "model.ifc", versionTag: "v1" });
|
|
220
|
+
|
|
221
|
+
// Folders
|
|
222
|
+
const folders = await client.listFolders();
|
|
223
|
+
await client.createFolder("My Folder");
|
|
224
|
+
|
|
225
|
+
// Execute cloud components
|
|
226
|
+
const { executionId } = await client.executeComponent(componentId, { param: "value" });
|
|
227
|
+
client.onExecutionProgress(executionId, (data) => {
|
|
228
|
+
// data.progressUpdate — progress percentage
|
|
229
|
+
// data.messageUpdate — status messages
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Test against a local cloud component (requires thatopen local-server running in the component project)
|
|
233
|
+
client.localServerUrl = "http://localhost:4001";
|
|
234
|
+
const local = await client.executeComponent("any-id", { param: "value" });
|
|
235
|
+
client.localServerUrl = null; // reset to use the cloud API
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Configuration
|
|
239
|
+
|
|
240
|
+
- `.thatopen` — local config (gitignored). Created by `npm run login`. Contains `accessToken`, `apiUrl`, and `appId` after first publish.
|
|
241
|
+
- `vite.config.js` — builds to IIFE format as `dist/bundle.js`. All dependencies are bundled.
|
|
@@ -1,27 +1,35 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>ThatOpen App</title>
|
|
7
|
-
<style>
|
|
8
|
-
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
-
html, body { width: 100%; height: 100%; overflow: hidden; font-family: system-ui, -apple-system, sans-serif; }
|
|
10
|
-
#that-open-app { width: 100%; height: 100%; }
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>ThatOpen App</title>
|
|
7
|
+
<style>
|
|
8
|
+
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
html, body { width: 100%; height: 100%; overflow: hidden; font-family: system-ui, -apple-system, sans-serif; }
|
|
10
|
+
#that-open-app { width: 100%; height: 100%; }
|
|
11
|
+
/* Scrollbar rail = the panel surface (#262629). Every panel (app .xxx-vp
|
|
12
|
+
tracks) and every bim-* shadow-DOM scrollbar reads var(--bim-scrollbar--bgc,
|
|
13
|
+
…), so defining it once here makes all rails match the surface instead of
|
|
14
|
+
falling back to the lighter bg-contrast-40 (#5F5F64).
|
|
15
|
+
NOTE: must use --bim-ui_gray-1 (defined UNCONDITIONALLY at :root = #262629),
|
|
16
|
+
not --bim-ui_bg-contrast-* (only defined under @media/theme-class scopes, so
|
|
17
|
+
it doesn't resolve at <html>:root and left --bim-scrollbar--bgc unset). */
|
|
18
|
+
:root { --bim-scrollbar--bgc: var(--bim-ui_gray-1, #262629); }
|
|
19
|
+
</style>
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<div id="that-open-app"></div>
|
|
23
|
+
<script>
|
|
24
|
+
// Simulates the context that the platform provides in production.
|
|
25
|
+
// When running inside the platform iframe, these values come from query params.
|
|
26
|
+
window.__THATOPEN_CONTEXT__ = {
|
|
27
|
+
appId: 'local-dev',
|
|
28
|
+
projectId: 'local-project',
|
|
29
|
+
accessToken: '',
|
|
30
|
+
apiUrl: 'http://localhost:3000',
|
|
31
|
+
};
|
|
32
|
+
</script>
|
|
33
|
+
<script type="module" src="/src/main.ts"></script>
|
|
34
|
+
</body>
|
|
35
|
+
</html>
|
|
@@ -1,27 +1,31 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "{{PROJECT_NAME}}",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"dev": "thatopen serve",
|
|
7
|
-
"build": "vite build",
|
|
8
|
-
"login": "thatopen login --local",
|
|
9
|
-
"publish": "thatopen publish"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"@lit/context": "^1.1.6",
|
|
13
|
-
"lit": "^3.0.0",
|
|
14
|
-
"@markerjs/markerjs3": "^3.9.0",
|
|
15
|
-
"@thatopen/components": "~3.4.0",
|
|
16
|
-
"@thatopen/components-front": "~3.4.0",
|
|
17
|
-
"@thatopen/fragments": "~3.4.0",
|
|
18
|
-
"@thatopen/services": "file:../../../..",
|
|
19
|
-
"@thatopen/ui": "~3.4.0",
|
|
20
|
-
"three": "^0.182.0"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "thatopen serve",
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"login": "thatopen login --local",
|
|
9
|
+
"publish": "thatopen publish"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@lit/context": "^1.1.6",
|
|
13
|
+
"lit": "^3.0.0",
|
|
14
|
+
"@markerjs/markerjs3": "^3.9.0",
|
|
15
|
+
"@thatopen/components": "~3.4.0",
|
|
16
|
+
"@thatopen/components-front": "~3.4.0",
|
|
17
|
+
"@thatopen/fragments": "~3.4.0",
|
|
18
|
+
"@thatopen/services": "file:../../../..",
|
|
19
|
+
"@thatopen/ui": "~3.4.0",
|
|
20
|
+
"three": "^0.182.0",
|
|
21
|
+
"@sparkjsdev/spark": "^0.1.10",
|
|
22
|
+
"3d-tiles-renderer": "^0.4.28",
|
|
23
|
+
"camera-controls": "^3.1.2",
|
|
24
|
+
"web-ifc": "^0.0.77"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/three": "^0.182.0",
|
|
28
|
+
"typescript": "^5.2.0",
|
|
29
|
+
"vite": "^5.2.0"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { PlatformClient, ProjectData } from "@thatopen/services";
|
|
2
|
+
|
|
3
|
+
// ─── A2 migration shim ───────────────────────────────────────────────────────
|
|
4
|
+
// Pre-A2 the platform `AppManager` built-in held the platform `client` +
|
|
5
|
+
// `projectData`, reached via `components.get(AppManager)`. Juan removed
|
|
6
|
+
// AppManager (consolidated into UIManager / top-app). top-app now owns that
|
|
7
|
+
// state and exposes it via lit contexts — but a few non-lit call sites
|
|
8
|
+
// (CloudRunner, data-table-panel, app-info-section) just need `.client` /
|
|
9
|
+
// `.projectData` synchronously. This tiny module holds them, set once from
|
|
10
|
+
// main.ts, and keeps `getAppManager(...)` returning the same `{ client,
|
|
11
|
+
// projectData }` shape those call sites expect.
|
|
12
|
+
|
|
13
|
+
let _client: PlatformClient | undefined;
|
|
14
|
+
let _projectData: ProjectData | undefined;
|
|
15
|
+
|
|
16
|
+
/** Called once from main.ts after the platform client (and projectData) exist. */
|
|
17
|
+
export const setAppContext = (
|
|
18
|
+
client: PlatformClient,
|
|
19
|
+
projectData?: ProjectData,
|
|
20
|
+
) => {
|
|
21
|
+
_client = client;
|
|
22
|
+
_projectData = projectData;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Back-compat accessor mirroring the old `components.get(AppManager)` surface
|
|
27
|
+
* the remaining call sites use (`.client` / `.projectData`). The `components`
|
|
28
|
+
* arg is ignored — kept only for signature compatibility with existing callers.
|
|
29
|
+
*/
|
|
30
|
+
export const getAppManager = (_components?: unknown) => ({
|
|
31
|
+
get client() {
|
|
32
|
+
return _client;
|
|
33
|
+
},
|
|
34
|
+
get projectData() {
|
|
35
|
+
return _projectData;
|
|
36
|
+
},
|
|
37
|
+
});
|