@thatopen/services 0.7.0 → 0.9.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 +62 -62
- package/dist/built-in/index.d.ts +66 -41
- package/dist/cli/lib/revit-addin.d.ts +8 -0
- package/dist/cli.js +154 -13
- package/dist/core/client.d.ts +6 -0
- package/dist/core/platform-client.d.ts +139 -0
- package/dist/core/platform-client.live.test.d.ts +1 -0
- package/dist/core/platform-client.notifications.test.d.ts +1 -0
- package/dist/index.cjs.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +635 -445
- package/dist/types/notifications.d.ts +54 -0
- package/dist/vite-env.d.ts +1 -1
- package/docs/ai-quickstart.md +120 -1
- package/docs/cli/create.md +29 -29
- 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/docs/flow-plugin-guide.md +26 -0
- package/docs/revit-collab-quickstart.md +26 -17
- package/docs/rhino-interop-quickstart.md +74 -7
- package/package.json +1 -1
- 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 +97 -97
- package/src/built-in/UIManager/src/app/examples/AppState/example.ts +140 -140
- package/src/built-in/UIManager/src/app/examples/Banner/example.ts +159 -159
- package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +123 -123
- package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +124 -124
- package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +90 -90
- package/src/built-in/UIManager/src/app/examples/Modal/example.ts +163 -163
- package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +133 -133
- package/src/built-in/UIManager/src/app/examples/ProjectFileStorage/example.ts +150 -150
- package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +102 -102
- package/src/built-in/UIManager/src/clashes-panel/example.ts +183 -183
- package/src/built-in/UIManager/src/git-history-panel/example.ts +70 -70
- package/src/built-in/UIManager/src/models-list/example.ts +122 -122
- package/src/built-in/UIManager/src/topics-panel/example.ts +170 -170
- package/src/built-in/index.ts +66 -41
- package/src/cli/templates/app/index.html +35 -35
- package/src/cli/templates/app/package.json +32 -32
- package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -95
- 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 -1
- package/src/cli/templates/app/src/main.history.ts +191 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -26
- package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -1
- package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -15
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -37
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -1
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -14
- package/src/cli/templates/app/src/ui-components/index.ts +2 -2
- package/src/cli/templates/app/tsconfig.json +16 -16
- package/src/cli/templates/app/vite.config.js +57 -57
- 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 -5
package/docs/cli/swap.md
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Toggle or explicitly set the engine library mode between stable public packages (@thatopen/*) and private beta packages (@thatopen-platform/*-beta). Updates package.json and .thatopen, then runs npm install. Source code never changes — aliases handle resolution."
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## thatopen swap
|
|
6
|
-
|
|
7
|
-
Switches the project between stable and beta engine libraries. Without flags, it toggles from the current state. Updates `package.json` dependencies and sets `beta` in `.thatopen` so `thatopen serve`, `thatopen local-server`, and `vite build` all pick up the change automatically.
|
|
8
|
-
|
|
9
|
-
Source code stays unchanged — `@thatopen/components` imports resolve to the correct package via esbuild/vite aliases based on the `beta` flag in `.thatopen`.
|
|
10
|
-
|
|
11
|
-
**Usage:**
|
|
12
|
-
```bash
|
|
13
|
-
thatopen swap # toggle: stable → beta or beta → stable
|
|
14
|
-
thatopen swap --beta # force beta
|
|
15
|
-
thatopen swap --stable # force stable
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
**Flags:**
|
|
19
|
-
|
|
20
|
-
- `--beta` — Switch to beta libraries (`@thatopen-platform/*-beta`).
|
|
21
|
-
- `--stable` — Switch back to stable public libraries (`@thatopen/*`).
|
|
22
|
-
|
|
23
|
-
**Examples:**
|
|
24
|
-
```bash
|
|
25
|
-
thatopen swap
|
|
26
|
-
thatopen swap --beta
|
|
27
|
-
thatopen swap --stable
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
> Beta packages are private and the access must be explicitly granted by That Open Company.
|
|
1
|
+
---
|
|
2
|
+
description: "Toggle or explicitly set the engine library mode between stable public packages (@thatopen/*) and private beta packages (@thatopen-platform/*-beta). Updates package.json and .thatopen, then runs npm install. Source code never changes — aliases handle resolution."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## thatopen swap
|
|
6
|
+
|
|
7
|
+
Switches the project between stable and beta engine libraries. Without flags, it toggles from the current state. Updates `package.json` dependencies and sets `beta` in `.thatopen` so `thatopen serve`, `thatopen local-server`, and `vite build` all pick up the change automatically.
|
|
8
|
+
|
|
9
|
+
Source code stays unchanged — `@thatopen/components` imports resolve to the correct package via esbuild/vite aliases based on the `beta` flag in `.thatopen`.
|
|
10
|
+
|
|
11
|
+
**Usage:**
|
|
12
|
+
```bash
|
|
13
|
+
thatopen swap # toggle: stable → beta or beta → stable
|
|
14
|
+
thatopen swap --beta # force beta
|
|
15
|
+
thatopen swap --stable # force stable
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Flags:**
|
|
19
|
+
|
|
20
|
+
- `--beta` — Switch to beta libraries (`@thatopen-platform/*-beta`).
|
|
21
|
+
- `--stable` — Switch back to stable public libraries (`@thatopen/*`).
|
|
22
|
+
|
|
23
|
+
**Examples:**
|
|
24
|
+
```bash
|
|
25
|
+
thatopen swap
|
|
26
|
+
thatopen swap --beta
|
|
27
|
+
thatopen swap --stable
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
> Beta packages are private and the access must be explicitly granted by That Open Company.
|
|
@@ -152,6 +152,32 @@ made every proposal declare its units, which looked careful and was a bug waitin
|
|
|
152
152
|
an author state a unit while writing coordinates in an axis convention the target does not use, a
|
|
153
153
|
mistake no declared unit can catch.
|
|
154
154
|
|
|
155
|
+
### Who wrote it
|
|
156
|
+
|
|
157
|
+
`author` is free text for a timeline to print. `userId` is the one that has to be right: it is what
|
|
158
|
+
the platform's own member component resolves into a real name and face. Get it wrong and the
|
|
159
|
+
proposal shows up under somebody else's avatar, which is worse than showing none.
|
|
160
|
+
|
|
161
|
+
**In a browser app, take it from `getProjectData`.** It answers with `currentUser` already resolved
|
|
162
|
+
server-side, and the members it lists are keyed by exactly the id the history panel indexes:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const { currentUser } = await client.getProjectData(projectId);
|
|
166
|
+
const userId = currentUser?.user._id; // what the avatar resolves against
|
|
167
|
+
const author = currentUser?.user.fullName; // what the timeline prints
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Do not look for it on the client's context.** `client.context` is the four fields the platform
|
|
171
|
+
injects into the iframe: `appId`, `projectId`, `accessToken`, `apiUrl`. Reading `context.userId` or
|
|
172
|
+
`context.user.name` yields `undefined`, and both failures are silent: the envelope simply ships
|
|
173
|
+
without a `userId`, and the panel falls back to passing `author` as the email, so the member
|
|
174
|
+
component renders whatever it makes of a string that names nobody. A converter did exactly this, and
|
|
175
|
+
it looked fine until somebody noticed the proposal was wearing another person's face.
|
|
176
|
+
|
|
177
|
+
**In a native plug-in there is no such call**, so read the `u` claim out of the API key's JWT payload
|
|
178
|
+
(base64url, no signature check, since this only decides which name to display). That is what the
|
|
179
|
+
Revit add-in does.
|
|
180
|
+
|
|
155
181
|
### The verbs
|
|
156
182
|
|
|
157
183
|
One per item, in the attribute `flow:op`:
|
|
@@ -46,6 +46,12 @@ the point.
|
|
|
46
46
|
|
|
47
47
|
## Step 0 — Ask what the user wants to do
|
|
48
48
|
|
|
49
|
+
**Only if they have not already told you.** "I want to start a new collaborative project in Revit
|
|
50
|
+
and here is my file" is (A), said plainly. Reading it back as a four-way menu costs the user a
|
|
51
|
+
whole turn to answer something they just said, and that is the single most common way this guide
|
|
52
|
+
wastes somebody's time. Work out which one it is, say which one you took it to be in one line, and
|
|
53
|
+
carry on. Ask only for what is genuinely missing.
|
|
54
|
+
|
|
49
55
|
> "What would you like to do?
|
|
50
56
|
> (A) **Share** a Revit model with my team for the first time.
|
|
51
57
|
> (B) **Connect** to a shared central a teammate already uploaded.
|
|
@@ -164,27 +170,30 @@ Re-run `thatopen revit status` every ten seconds or so until `"loaded": true`.
|
|
|
164
170
|
|
|
165
171
|
## Step 3 — Do the action
|
|
166
172
|
|
|
167
|
-
### (A) Share a model —
|
|
173
|
+
### (A) Share a model — one command
|
|
168
174
|
|
|
169
175
|
```
|
|
170
|
-
thatopen revit
|
|
176
|
+
thatopen revit share --file "<FILE>" --project <PROJECT>
|
|
171
177
|
```
|
|
172
178
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
179
|
+
That is the whole of it. `share` installs the add-in if nothing is listening, starts Revit and
|
|
180
|
+
waits for it, checks whether the file is already a central, publishes it, and opens the user's own
|
|
181
|
+
local. It prints each of the five steps as it reaches them, so a long silence is always a step you
|
|
182
|
+
can name.
|
|
183
|
+
|
|
184
|
+
- **`--doc <name>`** is optional. Left out, it comes from the file name, kebab-cased.
|
|
185
|
+
- **`--project`** takes the dashboard URL as happily as the id.
|
|
186
|
+
- **The original file is never modified.** Everything happens on a copy, which is why `share` does
|
|
187
|
+
not need to ask before converting: there is nothing to lose. Say so rather than asking.
|
|
188
|
+
- **It joins at the end on purpose.** Sharing a model and then carrying on in the original file is
|
|
189
|
+
the one reliable way to end up outside your own team.
|
|
190
|
+
|
|
191
|
+
Steps 1 and 2 (CLI, login, add-in) still have to have happened: `share` installs the add-in but it
|
|
192
|
+
cannot log in for somebody.
|
|
193
|
+
|
|
194
|
+
If you need the pieces separately — a central that already exists, a different convert decision,
|
|
195
|
+
scripting around it — they are still there: `thatopen revit inspect --file`, then
|
|
196
|
+
`thatopen revit publish-central --project --doc --file [--convert]`, then `thatopen revit join`.
|
|
188
197
|
|
|
189
198
|
### (B) Connect to a central — `join`
|
|
190
199
|
|
|
@@ -258,8 +258,25 @@ to `row.data(j)`.
|
|
|
258
258
|
|
|
259
259
|
### Units, and why the envelope has no units field
|
|
260
260
|
|
|
261
|
-
|
|
262
|
-
and it
|
|
261
|
+
**Print both files' metadata BEFORE you write a line of the converter.** This is an ordering
|
|
262
|
+
instruction, not advice. The whole conversion rests on what those two files declare, and it takes
|
|
263
|
+
thirty seconds to find out:
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
for (const id of [rhinoFileId, revitFileId]) {
|
|
267
|
+
const res = await client.downloadFile(id);
|
|
268
|
+
const m = FRAGS.EditUtils.getModelFromBuffer(new Uint8Array(await res.arrayBuffer()), false);
|
|
269
|
+
console.log(id, m.metadata());
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Measured on a live demo, 2026-08-05: a converter was written the other way round, four hundred lines
|
|
274
|
+
first and the check afterwards, and the target's metadata turned out to be `{}`. Everything above the
|
|
275
|
+
units gate was correct and none of it could run. Read the two files, then write the converter around
|
|
276
|
+
what is actually in them.
|
|
277
|
+
|
|
278
|
+
A proposal's numbers are in the terms of **what the target published**. When Revit's export declares
|
|
279
|
+
anything, it says so itself:
|
|
263
280
|
|
|
264
281
|
```json
|
|
265
282
|
"data": { "units": "ft", "axes": "z-up", "note": "Revit's own terms, untouched. Operations are written in these." }
|
|
@@ -269,12 +286,21 @@ Rhino publishes its document units in the same place, `model.metadata()`, under
|
|
|
269
286
|
sample project that is `Millimeters`. So the converter divides by **304.8**, and it is the converter's
|
|
270
287
|
job precisely because it is the only piece that knows both sides.
|
|
271
288
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
289
|
+
**When the target declares nothing.** Models published by add-in versions before 1.2.27 carry empty
|
|
290
|
+
metadata on their first commit, so `{}` is a state you will meet on any project created before then.
|
|
291
|
+
Revit's internal length unit is always decimal feet, so the factor is not actually in doubt; what is
|
|
292
|
+
missing is the file saying so. Take feet, say out loud that you are taking it, and then **prove it
|
|
293
|
+
from the data** rather than leaving it as an assumption:
|
|
294
|
+
|
|
295
|
+
- Read one existing column's `Position` out of the target, and compare it against the same column
|
|
296
|
+
measured in the source. On the sample project: `-30.19028688187479` ft times 304.8 is **-9202 mm**,
|
|
297
|
+
which is exactly the bay edge measured in Rhino.
|
|
298
|
+
- Keep a sanity check on every converted point: refuse anything landing more than about ten metres
|
|
299
|
+
from an existing element of the same category. That is what catches a factor-of-1000 error, and it
|
|
300
|
+
works whether or not the file declared anything.
|
|
275
301
|
|
|
276
|
-
**
|
|
277
|
-
nothing about the result says why.
|
|
302
|
+
**What you must never do is guess silently.** A wrong factor puts the columns a thousand times too
|
|
303
|
+
far away, and nothing about the result says why. Refusing is a worse demo and a better outcome.
|
|
278
304
|
|
|
279
305
|
### Building the payload
|
|
280
306
|
|
|
@@ -335,6 +361,38 @@ would have built a converter against a layer name nobody was using any more.
|
|
|
335
361
|
The tables above are here so nobody has to do that. If you still want to see real bytes, publish
|
|
336
362
|
something small and read it back inside the app.
|
|
337
363
|
|
|
364
|
+
### What "it builds" does not tell you
|
|
365
|
+
|
|
366
|
+
The dev build does not typecheck. `npm run build` said **111 modules, built clean** on a converter
|
|
367
|
+
whose `tsc --noEmit` was red in four places, and the run that produced this guide read that line as
|
|
368
|
+
proof and moved on. Run the typechecker separately, and read what it says.
|
|
369
|
+
|
|
370
|
+
Its complaint was worth having. A file that does not exist yet is read with a fallback, and the
|
|
371
|
+
fallback's shape becomes the type:
|
|
372
|
+
|
|
373
|
+
```ts
|
|
374
|
+
const history = await this._readJson(id, { commits: [] }); // commits: never[]
|
|
375
|
+
const head = history.commits.at(-1); // head: never
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Every field read off `head` is then an error, which is the typechecker pointing out that the empty
|
|
379
|
+
case was never really thought about. Type the fallback, and decide what an empty history means.
|
|
380
|
+
|
|
381
|
+
Three more that only fail once somebody presses the button:
|
|
382
|
+
|
|
383
|
+
- **The published file name is a parameter, not a constant.** `/publish` takes `name`. A converter
|
|
384
|
+
that hardcodes `rhino-columns.frag` answers "publish from Rhino first" when the file is right
|
|
385
|
+
there under another name. If you cannot find it, list what the folder actually holds and say so.
|
|
386
|
+
- **A loose folder match picks silently.** Falling back from an exact name to "any folder ending in
|
|
387
|
+
this" is fine with one project and wrong the first time there are two, with nothing on screen to
|
|
388
|
+
say which one it chose.
|
|
389
|
+
- **The platform round trip is not exercised by anything above.** The two failures this cost were
|
|
390
|
+
`parentFolderId` and the version tag, and both compiled, read fine, and only spoke on the first
|
|
391
|
+
real click. Press it once yourself, on something small, before showing it to anybody.
|
|
392
|
+
|
|
393
|
+
Not clicking it in front of the user is still the right call. Queuing a proposal writes into a
|
|
394
|
+
shared project, and that is theirs to trigger. Press it in a scratch document instead.
|
|
395
|
+
|
|
338
396
|
## 6. Accept it in Revit
|
|
339
397
|
|
|
340
398
|
The Revit add-in's local API, `%APPDATA%\ThatOpen\revit-addin.json`, header `X-RevitFlow-Token`.
|
|
@@ -389,3 +447,12 @@ lands in the history, with the new columns in it, viewable in the app like any o
|
|
|
389
447
|
- **Version tags are timestamps, not counts.** Numbering by how many entries there are collides on
|
|
390
448
|
the very first update.
|
|
391
449
|
- **Stray `.frag` files on the machine are not the current format.** They are an earlier session.
|
|
450
|
+
- **Read the two files' metadata before writing the converter, not after.** Everything the
|
|
451
|
+
conversion rests on is declared in them, or is not, and finding out costs thirty seconds at the
|
|
452
|
+
start and four hundred lines at the end.
|
|
453
|
+
- **Build only what was asked for.** An extra button and an extra layout are minutes each, and they
|
|
454
|
+
come out of the same hour as the thing that has to work.
|
|
455
|
+
- **A clean build is not a typecheck.** Vite does not run `tsc`. "Built clean" and "correct" are two
|
|
456
|
+
different sentences.
|
|
457
|
+
- **Read these guides verbatim.** A fetch that summarises gives you the shape of the thing and none
|
|
458
|
+
of the numbers, and every number here was paid for. Use the raw URL.
|
package/package.json
CHANGED
package/resources/AGENTS.md
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
# Building on the That Open Platform — Agent Guide
|
|
2
|
-
|
|
3
|
-
You are an AI assistant helping a user build a **BIM app** or **cloud component** on the
|
|
4
|
-
That Open Platform using **`@thatopen/services`** (the `thatopen` CLI + client library).
|
|
5
|
-
|
|
6
|
-
**Read this file first, then immediately load all indexes listed below before doing anything else.**
|
|
7
|
-
|
|
8
|
-
> This guide is tool-agnostic: it works with any AI (Claude, Codex, your own). All local docs it
|
|
9
|
-
> references ship inside the `@thatopen/services` package under `docs/`.
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Session start — load all indexes in parallel
|
|
14
|
-
|
|
15
|
-
Do this before answering any question or writing any code. These are compact description indexes:
|
|
16
|
-
|
|
17
|
-
| What | Where |
|
|
18
|
-
|---|---|
|
|
19
|
-
| Platform built-ins | `node_modules/@thatopen/services/docs/builtin/paths.json` |
|
|
20
|
-
| Platform client API | `node_modules/@thatopen/services/docs/client/paths.json` |
|
|
21
|
-
| CLI commands | `node_modules/@thatopen/services/docs/cli/paths.json` |
|
|
22
|
-
| Engine components (`OBC`, `OBF`) | `https://raw.githubusercontent.com/ThatOpen/engine_components/refs/heads/main/examples/paths.json` |
|
|
23
|
-
| Fragments (`FRAGS`) | `https://raw.githubusercontent.com/ThatOpen/engine_fragment/refs/heads/main/examples/paths.json` |
|
|
24
|
-
| UI components (`BUI`) | `https://raw.githubusercontent.com/ThatOpen/engine_ui-components/refs/heads/main/examples/paths.json` — **skip** entries whose path contains `packages/obc` or `bim-grid` |
|
|
25
|
-
|
|
26
|
-
Once you have these, you know everything available on the platform. Only then fetch a specific example file when you need implementation details.
|
|
27
|
-
|
|
28
|
-
> **Path resolution:** all `path` entries inside the local indexes (`docs/`, `src/`) are relative to the `@thatopen/services` package root — prepend `node_modules/@thatopen/services/` when reading any of those files.
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## How to work
|
|
33
|
-
|
|
34
|
-
- **The scaffold is already a complete, working viewer** (model loading, spatial tree, properties).
|
|
35
|
-
**Run it first** (`npm run dev`) to see it work, *then* extend it — don't rebuild a viewer from scratch.
|
|
36
|
-
- **
|
|
37
|
-
- If something already exists in the indexes, use it — don't reimplement it.
|
|
38
|
-
|
|
39
|
-
## Hard rules (always apply)
|
|
40
|
-
|
|
1
|
+
# Building on the That Open Platform — Agent Guide
|
|
2
|
+
|
|
3
|
+
You are an AI assistant helping a user build a **BIM app** or **cloud component** on the
|
|
4
|
+
That Open Platform using **`@thatopen/services`** (the `thatopen` CLI + client library).
|
|
5
|
+
|
|
6
|
+
**Read this file first, then immediately load all indexes listed below before doing anything else.**
|
|
7
|
+
|
|
8
|
+
> This guide is tool-agnostic: it works with any AI (Claude, Codex, your own). All local docs it
|
|
9
|
+
> references ship inside the `@thatopen/services` package under `docs/`.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Session start — load all indexes in parallel
|
|
14
|
+
|
|
15
|
+
Do this before answering any question or writing any code. These are compact description indexes:
|
|
16
|
+
|
|
17
|
+
| What | Where |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Platform built-ins | `node_modules/@thatopen/services/docs/builtin/paths.json` |
|
|
20
|
+
| Platform client API | `node_modules/@thatopen/services/docs/client/paths.json` |
|
|
21
|
+
| CLI commands | `node_modules/@thatopen/services/docs/cli/paths.json` |
|
|
22
|
+
| Engine components (`OBC`, `OBF`) | `https://raw.githubusercontent.com/ThatOpen/engine_components/refs/heads/main/examples/paths.json` |
|
|
23
|
+
| Fragments (`FRAGS`) | `https://raw.githubusercontent.com/ThatOpen/engine_fragment/refs/heads/main/examples/paths.json` |
|
|
24
|
+
| UI components (`BUI`) | `https://raw.githubusercontent.com/ThatOpen/engine_ui-components/refs/heads/main/examples/paths.json` — **skip** entries whose path contains `packages/obc` or `bim-grid` |
|
|
25
|
+
|
|
26
|
+
Once you have these, you know everything available on the platform. Only then fetch a specific example file when you need implementation details.
|
|
27
|
+
|
|
28
|
+
> **Path resolution:** all `path` entries inside the local indexes (`docs/`, `src/`) are relative to the `@thatopen/services` package root — prepend `node_modules/@thatopen/services/` when reading any of those files.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## How to work
|
|
33
|
+
|
|
34
|
+
- **The scaffold is already a complete, working viewer** (model loading, spatial tree, properties).
|
|
35
|
+
**Run it first** (`npm run dev`) to see it work, *then* extend it — don't rebuild a viewer from scratch.
|
|
36
|
+
- **Do the thing they asked for.** If the request already says what to build, build it. Stop and ask only when you are about to change files you did not create, when the request can be read two ways that mean different work, or when the next step is destructive.
|
|
37
|
+
- If something already exists in the indexes, use it — don't reimplement it.
|
|
38
|
+
|
|
39
|
+
## Hard rules (always apply)
|
|
40
|
+
|
|
41
41
|
1. **All UI must be built with Lit**, using the web components from `@thatopen/ui` (`BUI`) — `bim-button`, `bim-panel`, `bim-panel-section`, `bim-toolbar`, `bim-dropdown`, `bim-input`, and the rest of `packages/core`. Always consult the design system before writing any UI: `https://raw.githubusercontent.com/ThatOpen/engine_ui-components/refs/heads/main/DESIGN.md`.
|