@thatopen/services 0.3.1 → 0.3.2

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.
Files changed (42) hide show
  1. package/README.md +3 -0
  2. package/dist/built-in/index.d.ts +22 -2
  3. package/dist/cli.js +3 -3
  4. package/docs/ai-quickstart.md +86 -0
  5. package/docs/builtin/paths.json +74 -74
  6. package/docs/cli/create.md +4 -3
  7. package/package.json +1 -1
  8. package/src/built-in/index.ts +22 -2
  9. package/src/cli/templates/app/src/app.ts +37 -37
  10. package/src/cli/templates/app/src/assets/tool-placeholder.ts +50 -50
  11. package/src/cli/templates/app/src/main.ts +223 -340
  12. package/src/cli/templates/app/src/setups/camera-tools.ts +63 -63
  13. package/src/cli/templates/app/src/setups/clipper-tool.ts +20 -1
  14. package/src/cli/templates/app/src/setups/clipper.ts +75 -75
  15. package/src/cli/templates/app/src/setups/index.ts +23 -33
  16. package/src/cli/templates/app/src/setups/inspection.ts +136 -136
  17. package/src/cli/templates/app/src/setups/measurement-tool.ts +19 -1
  18. package/src/cli/templates/app/src/setups/measurements.ts +133 -133
  19. package/src/cli/templates/app/src/setups/reality-capture/lib/hidden-tiles-plugin.ts +88 -88
  20. package/src/cli/templates/app/src/setups/reality-capture/lib/point-tile-plugin.ts +166 -166
  21. package/src/cli/templates/app/src/setups/reality-capture/lib/render-frame.ts +31 -31
  22. package/src/cli/templates/app/src/setups/reality-capture/lib/splat-tile-plugin.ts +51 -51
  23. package/src/cli/templates/app/src/setups/reality-capture-viewer.ts +1383 -1383
  24. package/src/cli/templates/app/src/setups/right-sidebar.ts +178 -178
  25. package/src/cli/templates/app/src/setups/styles-panel.ts +110 -110
  26. package/src/cli/templates/app/src/setups/tool-mode-manager.ts +15 -9
  27. package/src/cli/templates/app/src/setups/tool-mode.ts +23 -23
  28. package/src/cli/templates/app/src/setups/active-tool-hud.ts +0 -69
  29. package/src/cli/templates/app/src/setups/clipper-panel.ts +0 -167
  30. package/src/cli/templates/app/src/setups/commands-panel.ts +0 -239
  31. package/src/cli/templates/app/src/setups/data-table-panel.ts +0 -2224
  32. package/src/cli/templates/app/src/setups/file-format-icons.ts +0 -95
  33. package/src/cli/templates/app/src/setups/files-panel.ts +0 -1503
  34. package/src/cli/templates/app/src/setups/fps-indicator.ts +0 -63
  35. package/src/cli/templates/app/src/setups/graphics-panel.ts +0 -490
  36. package/src/cli/templates/app/src/setups/measurement-settings-panel.ts +0 -161
  37. package/src/cli/templates/app/src/setups/model-tree.ts +0 -797
  38. package/src/cli/templates/app/src/setups/objects-panel.ts +0 -127
  39. package/src/cli/templates/app/src/setups/properties-panel.ts +0 -1048
  40. package/src/cli/templates/app/src/setups/settings-panel.ts +0 -94
  41. package/src/cli/templates/app/src/setups/visibility-toolbar.ts +0 -498
  42. package/src/cli/templates/app/src/setups/walkthrough.ts +0 -528
package/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  Client library and CLI for building BIM apps and cloud components on [That Open Platform](https://platform.thatopen.com). Apps run inside the platform's browser environment; cloud components run server-side and can be triggered from any app.
4
4
 
5
+ > **Using an AI assistant?** Point it at this single file and it can take you from nothing to a running app:
6
+ > → [`docs/ai-quickstart.md`](https://raw.githubusercontent.com/ThatOpen/engine_services/main/docs/ai-quickstart.md)
7
+
5
8
  ## Quick Start
6
9
 
7
10
  ### 1. Install the CLI
@@ -80,8 +80,6 @@ export type CDEMachineState = {
80
80
  kind: "idle";
81
81
  } | {
82
82
  kind: "loading";
83
- } | {
84
- kind: "uploading";
85
83
  } | {
86
84
  kind: "preparing";
87
85
  files: CDEFile[];
@@ -356,6 +354,22 @@ declare class _CDEManager extends OBC.Component implements OBC.Transitionable<CD
356
354
  files?: CDEFile[];
357
355
  folder?: ItemFolder;
358
356
  }>;
357
+ readonly onUploadStarted: OBC.Event<{
358
+ count: number;
359
+ }>;
360
+ readonly onIfcConversionStarted: OBC.Event<{
361
+ file: CDEFile;
362
+ }>;
363
+ readonly onIfcConversionProgress: OBC.Event<{
364
+ file: CDEFile;
365
+ progress: number;
366
+ }>;
367
+ readonly onIfcConversionCompleted: OBC.Event<{
368
+ file: CDEFile;
369
+ success: boolean;
370
+ error?: string;
371
+ }>;
372
+ readonly conversionProgress: Map<string, number>;
359
373
  enabled: boolean;
360
374
  projectName: string;
361
375
  missingMetadataPlaceholder: string;
@@ -363,6 +377,7 @@ declare class _CDEManager extends OBC.Component implements OBC.Transitionable<CD
363
377
  visibleColumns: Set<string>;
364
378
  ctx?: CDEContext;
365
379
  private _machineState;
380
+ private _activeUploads;
366
381
  private _showArchived;
367
382
  private _preArchivedViewMode;
368
383
  private _archivedFiles;
@@ -465,6 +480,11 @@ declare class _CDEManager extends OBC.Component implements OBC.Transitionable<CD
465
480
  file: CDEFile;
466
481
  existing: CDEFile;
467
482
  }[];
483
+ resolveViewFile(file: CDEFile): CDEFile;
484
+ private _saveConversionIndex;
485
+ private _loadConversionIndex;
486
+ private _resumePendingConversions;
487
+ private _triggerIfcConversions;
468
488
  uploadFiles(files: File[], folderId?: string | null, options?: {
469
489
  forceNew?: boolean;
470
490
  }): Promise<void>;
package/dist/cli.js CHANGED
@@ -8099,13 +8099,13 @@ const createCommand = new Command2("create").argument("<project-name>", 'Name of
8099
8099
  console.error(`Unknown template "${opts.template}". Available: ${TEMPLATES.join(", ")}`);
8100
8100
  process.exit(1);
8101
8101
  }
8102
- if (template === "app" && !opts.beta) {
8102
+ if (!opts.beta) {
8103
8103
  console.error(
8104
- `The "app" template currently requires the beta engine libraries.
8104
+ `Non-beta projects are not available yet.
8105
8105
 
8106
8106
  thatopen create ${projectName} --beta
8107
8107
 
8108
- Public (non-beta) engine support is coming with the October release.`
8108
+ The templates currently require the beta engine libraries. Public (non-beta) engine support is coming with the October release.`
8109
8109
  );
8110
8110
  process.exit(1);
8111
8111
  }
@@ -0,0 +1,86 @@
1
+ # That Open Platform — AI Quick Start (zero to a running app)
2
+
3
+ You are an AI assistant. A user pointed you at this URL so you can scaffold and run a
4
+ **BIM app** on the [That Open Platform](https://platform.thatopen.com) from scratch, using
5
+ `@thatopen/services` (the `thatopen` CLI + client library). Follow the steps below in order.
6
+
7
+ > The only secret you need is a **platform API token** — **not** an npm token. The CLI
8
+ > derives private beta-registry access from the platform token automatically.
9
+
10
+ ---
11
+
12
+ ## 0. Prerequisites (check, don't assume)
13
+
14
+ - **Node.js ≥ 18** and **npm** — verify with `node -v`.
15
+ - A **That Open Platform API token**. The user creates it themselves:
16
+ → **https://platform.thatopen.com/dashboard/data → API Tokens → create → copy.**
17
+ Ask the user to paste it. **Never print it back, never write it into a file, never commit it.**
18
+
19
+ ## 1. Install the CLI
20
+
21
+ ```bash
22
+ npm install -g @thatopen/services@latest
23
+ ```
24
+
25
+ ## 2. Log in (do this BEFORE creating the project)
26
+
27
+ ```bash
28
+ thatopen login --token <platform-token>
29
+ ```
30
+
31
+ This validates the token and stores it in `~/.thatopen/config.json`. Login **must** come
32
+ first: the next step's install pulls the private `@thatopen-platform/*-beta` packages, and
33
+ `create` uses your logged-in token to write an authenticated `.npmrc` so that install can
34
+ resolve them. No npm account or manual npm token is involved.
35
+
36
+ ## 3. Scaffold a beta app
37
+
38
+ ```bash
39
+ thatopen create my-app --beta
40
+ cd my-app
41
+ ```
42
+
43
+ `--beta` is required for now: the bundled viewer uses engine APIs that currently live only
44
+ in the beta libraries (public engine support lands with the October release). `create`
45
+ configures private beta access from your platform token and runs `npm install` for you.
46
+
47
+ ## 4. Run it
48
+
49
+ ```bash
50
+ npm run dev
51
+ ```
52
+
53
+ This serves the app and opens it inside the platform. **You now have a complete, working
54
+ viewer** — model loading, spatial tree, properties, measurement, sectioning, and more.
55
+
56
+ ## 5. Then build — read the in-project agent guide
57
+
58
+ The scaffold is a real app, not a blank page. **Before changing anything**, open and follow:
59
+
60
+ ```
61
+ node_modules/@thatopen/services/resources/AGENTS.md
62
+ ```
63
+
64
+ (The scaffolded project's own `AGENTS.md` points here too.) It is the canonical guide: it
65
+ indexes every platform built-in, the client API, the CLI, and the engine / UI example sets.
66
+ Load those indexes before writing code. **All UI must be built with Lit + `@thatopen/ui`
67
+ (`BUI`)** — consult the design system before writing any UI. Run the app first, then extend
68
+ it; don't rebuild a viewer from scratch.
69
+
70
+ ## 6. Publish (when ready)
71
+
72
+ ```bash
73
+ npm run publish
74
+ ```
75
+
76
+ Builds the app, zips it (`dist/bundle.zip`), and uploads a new version to the platform.
77
+
78
+ ---
79
+
80
+ ## Rules for you, the assistant
81
+
82
+ - **Platform token only.** Never introduce, request, or store an npm token.
83
+ - **Never echo or persist the user's token.** It belongs only in `~/.thatopen/config.json` /
84
+ `.npmrc`, both of which the CLI manages and git-ignores.
85
+ - **Propose a short plan and get the user's OK** before changing files.
86
+ - The scaffold already works — **extend it, don't replace it.**
@@ -1,74 +1,74 @@
1
- [
2
- {
3
- "path": "src/built-in/CDEManager/example.ts",
4
- "description": "CDEManager — CDEManager is the central state machine for a Common Data Environment. It holds files, folders, metadata schemas, viewer groups, and user permissions, and exposes a typed state machine that all file operations — selecting, editing, uploading, viewing — route through. It has no DOM or Three.js dependencies and can run in Node, a browser, or a server-side worker wherever `@thatopen/components` is available."
5
- },
6
- {
7
- "path": "src/built-in/CDEManager/examples/FileEditing/example.ts",
8
- "description": "Bulk file editing — stage, preview, revert, and commit — A project manager preparing a deliverable handoff needs to update discipline tags across fifteen IFC files after a scope change, rename each to match the new naming convention, and archive three superseded models — all before anything is sent to the backend. Doing the changes one file at a time risks leaving the file list in a half-updated state if the session is interrupted, and there is no way to review exactly what will change before committing."
9
- },
10
- {
11
- "path": "src/built-in/CDEManager/examples/FileMoves/example.ts",
12
- "description": "Drag-and-drop file and folder moves — A coordinator restructures the project after a scope change: structural files move from the root into a dedicated discipline folder, a MEP sub-folder needs to be promoted to the top level, and a few documents need to come back to root to appear in the general view. Drag-and-drop is the natural gesture for all of this, but each drag session has intermediate stages — the file is \"in the air\", hovering over a candidate target — and every panel watching the file table should see the right state without coordinating directly with the drag component."
13
- },
14
- {
15
- "path": "src/built-in/CDEManager/examples/FileOperations/example.ts",
16
- "description": "File operations — inline edit, rename, view, download, archive — BIM coordinators reviewing a model drop repeat the same small actions throughout their session: correcting a discipline tag that changed after a scope revision, renaming a file to match the agreed convention, opening it alongside the structural model to check for clashes, handing it off to a sub-consultant, or removing a superseded version from the live set. If every panel in the platform handles these separately, two panels looking at the same file at the same time can show contradictory states — one says \"uploading\", another still shows the old name."
17
- },
18
- {
19
- "path": "src/built-in/CDEManager/examples/FileTransfers/example.ts",
20
- "description": "File uploads, versioning, and the download cache — A site coordinator drops a batch of files onto the CDE every Monday after the weekend review: some are entirely new models, some are revised versions of files already in the project, and sometimes the metadata group they upload into should be stamped automatically onto the new files. If the platform makes the coordinator sort this out manually, it slows the handoff and introduces naming errors. And if an upload fails halfway through a batch, the file table should land in a safe state rather than freeze at a loading spinner."
21
- },
22
- {
23
- "path": "src/built-in/CDEManager/examples/FolderManagement/example.ts",
24
- "description": "Folder management — create, rename, archive, and commit — A project reaches the construction phase and the coordination team needs to restructure the folder hierarchy: add a \"Facades\" discipline folder, rename \"Structural\" to its official abbreviation, and archive two superseded folders that have been merged. Doing these one at a time through separate API calls means the folder tree flickers between invalid states as each change lands — a freshly created folder appears before its sibling is renamed, and the archived folders briefly disappear before the new one is visible."
25
- },
26
- {
27
- "path": "src/built-in/CDEManager/examples/MetadataSchema/example.ts",
28
- "description": "Metadata schema — define, stage, and publish field definitions — Every project has its own vocabulary for describing files: discipline codes, revision phases, area zones, review statuses. A metadata schema defines which fields exist, what values they accept, and whether they are mandatory. Without a structured schema, each user invents their own labels and the file list becomes impossible to filter or report on consistently."
29
- },
30
- {
31
- "path": "src/built-in/CDEManager/examples/MetadataViews/example.ts",
32
- "description": "Metadata views — organize fields into named table layouts — A structural engineer and an MEP coordinator look at the same file list but care about completely different metadata. Showing every field to everyone produces a wide table that is hard to navigate. Metadata views let each role define which fields appear in which order — saving the layout so the table opens correctly next time without requiring a manual setup every session."
33
- },
34
- {
35
- "path": "src/built-in/CDEManager/examples/ProjectConfig/example.ts",
36
- "description": "Project configuration — read, write, and reload persistent data — A CDE application needs to store two kinds of configuration: project-wide settings that all team members share (the metadata schema, custom naming rules) and personal settings that belong to one user (which columns are visible, which metadata views are pinned). Both live inside the project's file storage under a reserved system folder, so they travel with the project and don't rely on a separate configuration service."
37
- },
38
- {
39
- "path": "src/built-in/UIManager/src/app/example.ts",
40
- "description": "top-app — Front-end developers building BIM web apps need to coordinate several async initialization steps before the UI can be shown — loading the engine, preparing fragment workers, registering loaders — and users need visible feedback on what is happening during that wait, rather than a blank screen."
41
- },
42
- {
43
- "path": "src/built-in/UIManager/src/app/examples/AppState/example.ts",
44
- "description": "Shared reactive state with AppState — Developers building interactive BIM panels often need sibling components — a filter selector and a results table, for example — to stay in sync without a shared parent. Lifting state to a common ancestor and threading it down as props works for shallow trees but becomes unwieldy as the component tree grows."
45
- },
46
- {
47
- "path": "src/built-in/UIManager/src/app/examples/Banner/example.ts",
48
- "description": "Persistent banners with top:banner — Some application states need a persistent, visible indicator that stays on screen until the state is explicitly cleared — an archived-files mode, a read-only permission warning, a degraded-connectivity notice. A toast auto-dismisses after a few seconds, which is wrong for these cases. A modal blocks interaction entirely, which is too heavy."
49
- },
50
- {
51
- "path": "src/built-in/UIManager/src/app/examples/Contexts/example.ts",
52
- "description": "Consuming platform contexts in child components — Developers building custom BIM panels need access to the 3D engine, the platform API, and the current project's metadata — but threading these objects down through props across multiple component layers forces every intermediate element to know about data it doesn't use, making trees brittle and hard to refactor."
53
- },
54
- {
55
- "path": "src/built-in/UIManager/src/app/examples/FileDrop/example.ts",
56
- "description": "File drag-and-drop with top:files-dropped — Desktop BIM workflows often rely on dragging files straight from the OS file manager onto the browser window — but wiring a document-level dragenter, dragover, dragleave, and drop handler that correctly tracks nested enter/leave counts, shows a visual overlay, and forwards the files to the right component is tedious boilerplate to repeat for every app."
57
- },
58
- {
59
- "path": "src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts",
60
- "description": "Floating layout — Developers building BIM coordination tools often want the 3D model to fill the entire window while control panels float above it — but standard grid layouts give every area equal standing, shrinking the viewer into one cell and leaving visible seams between it and the panels."
61
- },
62
- {
63
- "path": "src/built-in/UIManager/src/app/examples/Modal/example.ts",
64
- "description": "Confirmation modals with top:modal — Destructive or irreversible actions — deleting records, overwriting files, leaving unsaved changes — should ask the user to confirm before proceeding. Opening a custom dialog element from a deeply nested component means threading a reference to a controller up through every layer of the tree."
65
- },
66
- {
67
- "path": "src/built-in/UIManager/src/app/examples/Notifications/example.ts",
68
- "description": "Toasts and cross-component notifications — Developers building BIM processing UIs need to surface status updates, errors, and async feedback to users from different points in the component tree — but reaching back to the app root to trigger a notification from a deeply nested component requires threading a reference through every layer in between."
69
- },
70
- {
71
- "path": "src/built-in/UIManager/src/app/examples/Sidebar/example.ts",
72
- "description": "Sidebar navigation — Product teams building BIM apps often need multiple distinct views — a 3D model viewer, a data browser, a settings screen — but wiring a custom nav bar and managing view transitions from scratch adds complexity before any real feature work begins."
73
- }
74
- ]
1
+ [
2
+ {
3
+ "path": "src/built-in/CDEManager/example.ts",
4
+ "description": "CDEManager — CDEManager is the central state machine for a Common Data Environment. It holds files, folders, metadata schemas, viewer groups, and user permissions, and exposes a typed state machine that all file operations — selecting, editing, uploading, viewing — route through. It has no DOM or Three.js dependencies and can run in Node, a browser, or a server-side worker wherever `@thatopen/components` is available."
5
+ },
6
+ {
7
+ "path": "src/built-in/CDEManager/examples/FileEditing/example.ts",
8
+ "description": "Bulk file editing — stage, preview, revert, and commit — A project manager preparing a deliverable handoff needs to update discipline tags across fifteen IFC files after a scope change, rename each to match the new naming convention, and archive three superseded models — all before anything is sent to the backend. Doing the changes one file at a time risks leaving the file list in a half-updated state if the session is interrupted, and there is no way to review exactly what will change before committing."
9
+ },
10
+ {
11
+ "path": "src/built-in/CDEManager/examples/FileMoves/example.ts",
12
+ "description": "Drag-and-drop file and folder moves — A coordinator restructures the project after a scope change: structural files move from the root into a dedicated discipline folder, a MEP sub-folder needs to be promoted to the top level, and a few documents need to come back to root to appear in the general view. Drag-and-drop is the natural gesture for all of this, but each drag session has intermediate stages — the file is \"in the air\", hovering over a candidate target — and every panel watching the file table should see the right state without coordinating directly with the drag component."
13
+ },
14
+ {
15
+ "path": "src/built-in/CDEManager/examples/FileOperations/example.ts",
16
+ "description": "File operations — inline edit, rename, view, download, archive — BIM coordinators reviewing a model drop repeat the same small actions throughout their session: correcting a discipline tag that changed after a scope revision, renaming a file to match the agreed convention, opening it alongside the structural model to check for clashes, handing it off to a sub-consultant, or removing a superseded version from the live set. If every panel in the platform handles these separately, two panels looking at the same file at the same time can show contradictory states — one says \"uploading\", another still shows the old name."
17
+ },
18
+ {
19
+ "path": "src/built-in/CDEManager/examples/FileTransfers/example.ts",
20
+ "description": "File uploads, versioning, and the download cache — A site coordinator drops a batch of files onto the CDE every Monday after the weekend review: some are entirely new models, some are revised versions of files already in the project, and sometimes the metadata group they upload into should be stamped automatically onto the new files. If the platform makes the coordinator sort this out manually, it slows the handoff and introduces naming errors. And if an upload fails halfway through a batch, the file table should land in a safe state rather than freeze at a loading spinner."
21
+ },
22
+ {
23
+ "path": "src/built-in/CDEManager/examples/FolderManagement/example.ts",
24
+ "description": "Folder management — create, rename, archive, and commit — A project reaches the construction phase and the coordination team needs to restructure the folder hierarchy: add a \"Facades\" discipline folder, rename \"Structural\" to its official abbreviation, and archive two superseded folders that have been merged. Doing these one at a time through separate API calls means the folder tree flickers between invalid states as each change lands — a freshly created folder appears before its sibling is renamed, and the archived folders briefly disappear before the new one is visible."
25
+ },
26
+ {
27
+ "path": "src/built-in/CDEManager/examples/MetadataSchema/example.ts",
28
+ "description": "Metadata schema — define, stage, and publish field definitions — Every project has its own vocabulary for describing files: discipline codes, revision phases, area zones, review statuses. A metadata schema defines which fields exist, what values they accept, and whether they are mandatory. Without a structured schema, each user invents their own labels and the file list becomes impossible to filter or report on consistently."
29
+ },
30
+ {
31
+ "path": "src/built-in/CDEManager/examples/MetadataViews/example.ts",
32
+ "description": "Metadata views — organize fields into named table layouts — A structural engineer and an MEP coordinator look at the same file list but care about completely different metadata. Showing every field to everyone produces a wide table that is hard to navigate. Metadata views let each role define which fields appear in which order — saving the layout so the table opens correctly next time without requiring a manual setup every session."
33
+ },
34
+ {
35
+ "path": "src/built-in/CDEManager/examples/ProjectConfig/example.ts",
36
+ "description": "Project configuration — read, write, and reload persistent data — A CDE application needs to store two kinds of configuration: project-wide settings that all team members share (the metadata schema, custom naming rules) and personal settings that belong to one user (which columns are visible, which metadata views are pinned). Both live inside the project's file storage under a reserved system folder, so they travel with the project and don't rely on a separate configuration service."
37
+ },
38
+ {
39
+ "path": "src/built-in/UIManager/src/app/example.ts",
40
+ "description": "top-app — Front-end developers building BIM web apps need to coordinate several async initialization steps before the UI can be shown — loading the engine, preparing fragment workers, registering loaders — and users need visible feedback on what is happening during that wait, rather than a blank screen."
41
+ },
42
+ {
43
+ "path": "src/built-in/UIManager/src/app/examples/AppState/example.ts",
44
+ "description": "Shared reactive state with AppState — Developers building interactive BIM panels often need sibling components — a filter selector and a results table, for example — to stay in sync without a shared parent. Lifting state to a common ancestor and threading it down as props works for shallow trees but becomes unwieldy as the component tree grows."
45
+ },
46
+ {
47
+ "path": "src/built-in/UIManager/src/app/examples/Banner/example.ts",
48
+ "description": "Persistent banners with top:banner — Some application states need a persistent, visible indicator that stays on screen until the state is explicitly cleared — an archived-files mode, a read-only permission warning, a degraded-connectivity notice. A toast auto-dismisses after a few seconds, which is wrong for these cases. A modal blocks interaction entirely, which is too heavy."
49
+ },
50
+ {
51
+ "path": "src/built-in/UIManager/src/app/examples/Contexts/example.ts",
52
+ "description": "Consuming platform contexts in child components — Developers building custom BIM panels need access to the 3D engine, the platform API, and the current project's metadata — but threading these objects down through props across multiple component layers forces every intermediate element to know about data it doesn't use, making trees brittle and hard to refactor."
53
+ },
54
+ {
55
+ "path": "src/built-in/UIManager/src/app/examples/FileDrop/example.ts",
56
+ "description": "File drag-and-drop with top:files-dropped — Desktop BIM workflows often rely on dragging files straight from the OS file manager onto the browser window — but wiring a document-level dragenter, dragover, dragleave, and drop handler that correctly tracks nested enter/leave counts, shows a visual overlay, and forwards the files to the right component is tedious boilerplate to repeat for every app."
57
+ },
58
+ {
59
+ "path": "src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts",
60
+ "description": "Floating layout — Developers building BIM coordination tools often want the 3D model to fill the entire window while control panels float above it — but standard grid layouts give every area equal standing, shrinking the viewer into one cell and leaving visible seams between it and the panels."
61
+ },
62
+ {
63
+ "path": "src/built-in/UIManager/src/app/examples/Modal/example.ts",
64
+ "description": "Confirmation modals with top:modal — Destructive or irreversible actions — deleting records, overwriting files, leaving unsaved changes — should ask the user to confirm before proceeding. Opening a custom dialog element from a deeply nested component means threading a reference to a controller up through every layer of the tree."
65
+ },
66
+ {
67
+ "path": "src/built-in/UIManager/src/app/examples/Notifications/example.ts",
68
+ "description": "Toasts and cross-component notifications — Developers building BIM processing UIs need to surface status updates, errors, and async feedback to users from different points in the component tree — but reaching back to the app root to trigger a notification from a deeply nested component requires threading a reference through every layer in between."
69
+ },
70
+ {
71
+ "path": "src/built-in/UIManager/src/app/examples/Sidebar/example.ts",
72
+ "description": "Sidebar navigation — Product teams building BIM apps often need multiple distinct views — a 3D model viewer, a data browser, a settings screen — but wiring a custom nav bar and managing view transitions from scratch adds complexity before any real feature work begins."
73
+ }
74
+ ]
@@ -17,12 +17,13 @@ thatopen create . # scaffold into the current directory
17
17
  - `--template <template>`, `-t` — Template to use. Default: `app`.
18
18
  - `app` — Browser BIM app running inside the platform iframe.
19
19
  - `cloud-component` — Server-side component executed by the platform's cloud engine and consumed in apps and/or automations.
20
- - `--beta` — Use private beta engine libraries (`@thatopen-platform/*-beta`) instead of the public ones. Sets `beta: true` in `.thatopen` so `serve`, `local-server`, and `vite build` all resolve to beta packages automatically. Requires beta npm access configured.
20
+ - `--beta` — Use private beta engine libraries (`@thatopen-platform/*-beta`) instead of the public ones. Sets `beta: true` in `.thatopen` so `serve`, `local-server`, and `vite build` all resolve to beta packages automatically. Requires beta npm access configured (handled automatically once you `thatopen login`).
21
+
22
+ > **`--beta` is currently required.** The templates depend on engine APIs that only exist in the beta libraries, so scaffolding without `--beta` errors out for now. Public (non-beta) support is coming with the October release.
21
23
 
22
24
  **Examples:**
23
25
  ```bash
24
- thatopen create my-app
25
- thatopen create my-app -t cloud-component
26
26
  thatopen create my-app --beta
27
+ thatopen create my-app -t cloud-component --beta
27
28
  thatopen create . --beta
28
29
  ```
package/package.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "access": "public"
16
16
  },
17
17
  "private": false,
18
- "version": "0.3.1",
18
+ "version": "0.3.2",
19
19
  "main": "dist/index.cjs.js",
20
20
  "module": "dist/index.es.js",
21
21
  "types": "dist/index.d.ts",
@@ -83,8 +83,6 @@ export type CDEMachineState = {
83
83
  kind: "idle";
84
84
  } | {
85
85
  kind: "loading";
86
- } | {
87
- kind: "uploading";
88
86
  } | {
89
87
  kind: "preparing";
90
88
  files: CDEFile[];
@@ -360,6 +358,22 @@ declare class _CDEManager extends OBC.Component implements OBC.Transitionable<CD
360
358
  files?: CDEFile[];
361
359
  folder?: ItemFolder;
362
360
  }>;
361
+ readonly onUploadStarted: OBC.Event<{
362
+ count: number;
363
+ }>;
364
+ readonly onIfcConversionStarted: OBC.Event<{
365
+ file: CDEFile;
366
+ }>;
367
+ readonly onIfcConversionProgress: OBC.Event<{
368
+ file: CDEFile;
369
+ progress: number;
370
+ }>;
371
+ readonly onIfcConversionCompleted: OBC.Event<{
372
+ file: CDEFile;
373
+ success: boolean;
374
+ error?: string;
375
+ }>;
376
+ readonly conversionProgress: Map<string, number>;
363
377
  enabled: boolean;
364
378
  projectName: string;
365
379
  missingMetadataPlaceholder: string;
@@ -367,6 +381,7 @@ declare class _CDEManager extends OBC.Component implements OBC.Transitionable<CD
367
381
  visibleColumns: Set<string>;
368
382
  ctx?: CDEContext;
369
383
  private _machineState;
384
+ private _activeUploads;
370
385
  private _showArchived;
371
386
  private _preArchivedViewMode;
372
387
  private _archivedFiles;
@@ -469,6 +484,11 @@ declare class _CDEManager extends OBC.Component implements OBC.Transitionable<CD
469
484
  file: CDEFile;
470
485
  existing: CDEFile;
471
486
  }[];
487
+ resolveViewFile(file: CDEFile): CDEFile;
488
+ private _saveConversionIndex;
489
+ private _loadConversionIndex;
490
+ private _resumePendingConversions;
491
+ private _triggerIfcConversions;
472
492
  uploadFiles(files: File[], folderId?: string | null, options?: {
473
493
  forceNew?: boolean;
474
494
  }): Promise<void>;
@@ -1,37 +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
- });
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
+ });
@@ -1,50 +1,50 @@
1
- /**
2
- * Empty-state illustration for the helper panel (from
3
- * "Frame 691314571.svg" — a translucent stacked-cards glyph with a check badge).
4
- * Stored as a string and served as a data URI so it needs no import/build
5
- * config. Theme-safe: all fills are translucent white/#F8F8F8 over transparent,
6
- * so it reads correctly on the dark bg-base card.
7
- */
8
- export const toolPlaceholderSvg = `<svg width="157" height="156" viewBox="0 0 157 156" fill="none" xmlns="http://www.w3.org/2000/svg">
9
- <g clip-path="url(#clip0_12378_11440)">
10
- <mask id="mask0_12378_11440" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="157" height="156">
11
- <ellipse cx="78.5" cy="78" rx="78.5" ry="78" fill="url(#paint0_radial_12378_11440)"/>
12
- </mask>
13
- <g mask="url(#mask0_12378_11440)">
14
- <path d="M2.33321 94.9001H34.2999C38.7803 94.9001 41.0205 94.9001 42.7318 94.0281C44.2371 93.2611 45.4609 92.0373 46.2279 90.532C47.0999 88.8207 47.0999 86.5805 47.0999 82.1V50.4353C47.0999 48.1467 47.0999 47.0024 46.8058 45.948C46.5453 45.0139 46.1172 44.135 45.5423 43.3541C44.8933 42.4726 43.9922 41.7672 42.1902 40.3565L28.9883 30.0212C27.6995 29.0123 27.0551 28.5078 26.3403 28.1493C25.7061 27.8311 25.0324 27.5988 24.3369 27.4583C23.5531 27.3 22.7347 27.3 21.098 27.3H2.33321C-2.14722 27.3 -4.38743 27.3 -6.09872 28.172C-7.60402 28.939 -8.82786 30.1628 -9.59485 31.6681C-10.4668 33.3794 -10.4668 35.6196 -10.4668 40.1V82.1001C-10.4668 86.5805 -10.4668 88.8207 -9.59485 90.532C-8.82786 92.0373 -7.60402 93.2611 -6.09872 94.0281C-4.38743 94.9001 -2.14722 94.9001 2.33321 94.9001Z" fill="#F8F8F8" fill-opacity="0.08" style="mix-blend-mode:luminosity"/>
15
- <path d="M2.33321 94.9001H34.2999C38.7803 94.9001 41.0205 94.9001 42.7318 94.0281C44.2371 93.2611 45.4609 92.0373 46.2279 90.532C47.0999 88.8207 47.0999 86.5805 47.0999 82.1V50.4353C47.0999 48.1467 47.0999 47.0024 46.8058 45.948C46.5453 45.0139 46.1172 44.135 45.5423 43.3541C44.8933 42.4726 43.9922 41.7672 42.1902 40.3565L28.9883 30.0212C27.6995 29.0123 27.0551 28.5078 26.3403 28.1493C25.7061 27.8311 25.0324 27.5988 24.3369 27.4583C23.5531 27.3 22.7347 27.3 21.098 27.3H2.33321C-2.14722 27.3 -4.38743 27.3 -6.09872 28.172C-7.60402 28.939 -8.82786 30.1628 -9.59485 31.6681C-10.4668 33.3794 -10.4668 35.6196 -10.4668 40.1V82.1001C-10.4668 86.5805 -10.4668 88.8207 -9.59485 90.532C-8.82786 92.0373 -7.60402 93.2611 -6.09872 94.0281C-4.38743 94.9001 -2.14722 94.9001 2.33321 94.9001Z" stroke="white" stroke-opacity="0.15" stroke-width="1.5"/>
16
- <path d="M154.667 61.0999H122.7C118.22 61.0999 115.98 61.0999 114.268 61.9719C112.763 62.7389 111.539 63.9627 110.772 65.468C109.9 67.1793 109.9 69.4195 109.9 73.9V105.565C109.9 107.853 109.9 108.998 110.194 110.052C110.455 110.986 110.883 111.865 111.458 112.646C112.107 113.527 113.008 114.233 114.81 115.644L128.012 125.979C129.3 126.988 129.945 127.492 130.66 127.851C131.294 128.169 131.968 128.401 132.663 128.542C133.447 128.7 134.265 128.7 135.902 128.7H154.667C159.147 128.7 161.387 128.7 163.099 127.828C164.604 127.061 165.828 125.837 166.595 124.332C167.467 122.621 167.467 120.38 167.467 115.9V73.8999C167.467 69.4195 167.467 67.1793 166.595 65.468C165.828 63.9627 164.604 62.7389 163.099 61.9719C161.387 61.0999 159.147 61.0999 154.667 61.0999Z" fill="#F8F8F8" fill-opacity="0.08" style="mix-blend-mode:luminosity"/>
17
- <path d="M84.758 182H116.725C121.205 182 123.445 182 125.157 181.128C126.662 180.361 127.886 179.137 128.653 177.632C129.525 175.921 129.525 173.68 129.525 169.2V137.535C129.525 135.247 129.525 134.102 129.231 133.048C128.97 132.114 128.542 131.235 127.967 130.454C127.318 129.573 126.417 128.867 124.615 127.456L111.413 117.121C110.124 116.112 109.48 115.608 108.765 115.249C108.131 114.931 107.457 114.699 106.762 114.558C105.978 114.4 105.16 114.4 103.523 114.4H84.758C80.2776 114.4 78.0374 114.4 76.3261 115.272C74.8208 116.039 73.5969 117.263 72.83 118.768C71.958 120.479 71.958 122.72 71.958 127.2V169.2C71.958 173.68 71.958 175.921 72.83 177.632C73.5969 179.137 74.8208 180.361 76.3261 181.128C78.0374 182 80.2776 182 84.758 182Z" fill="#F8F8F8" fill-opacity="0.08" style="mix-blend-mode:luminosity"/>
18
- </g>
19
- <path d="M63.2502 111.583H93.7502C98.2306 111.583 100.471 111.583 102.182 110.711C103.687 109.944 104.911 108.721 105.678 107.215C106.55 105.504 106.55 103.264 106.55 98.7833V67.3691C106.55 65.1068 106.55 63.9756 106.262 62.9315C106.007 62.0065 105.588 61.1349 105.024 60.3584C104.387 59.482 103.503 58.7763 101.735 57.3651L89.0157 47.2126C87.7173 46.1763 87.0681 45.6581 86.3455 45.2897C85.7044 44.9628 85.0221 44.7239 84.3172 44.5794C83.5226 44.4166 82.6919 44.4166 81.0307 44.4166H63.2502C58.7698 44.4166 56.5296 44.4166 54.8183 45.2886C53.313 46.0556 52.0891 47.2794 51.3221 48.7847C50.4502 50.496 50.4502 52.7362 50.4502 57.2166V98.7833C50.4502 103.264 50.4502 105.504 51.3221 107.215C52.0891 108.721 53.313 109.944 54.8183 110.711C56.5296 111.583 58.7698 111.583 63.2502 111.583Z" fill="#F8F8F8" fill-opacity="0.05" style="mix-blend-mode:luminosity"/>
20
- <g filter="url(#filter0_d_12378_11440)">
21
- <path d="M62.6 109H94.4C97.7603 109 99.4405 109 100.724 108.346C101.853 107.771 102.771 106.853 103.346 105.724C104 104.44 104 102.76 104 99.4V67.0766C104 65.3954 104 64.5548 103.788 63.7778C103.599 63.0894 103.29 62.4402 102.873 61.8605C102.404 61.2062 101.751 60.677 100.445 59.6184L87.5178 49.1419C86.5385 48.3482 86.0489 47.9514 85.5023 47.6691C85.0175 47.4187 84.5007 47.2355 83.9664 47.1248C83.364 47 82.7338 47 81.4733 47H62.6C59.2397 47 57.5595 47 56.2761 47.654C55.1471 48.2292 54.2292 49.1471 53.654 50.2761C53 51.5595 53 53.2397 53 56.6V99.4C53 102.76 53 104.44 53.654 105.724C54.2292 106.853 55.1471 107.771 56.2761 108.346C57.5595 109 59.2397 109 62.6 109Z" fill="#F8F8F8" fill-opacity="0.08" style="mix-blend-mode:luminosity"/>
22
- <path d="M62.6 109H94.4C97.7603 109 99.4405 109 100.724 108.346C101.853 107.771 102.771 106.853 103.346 105.724C104 104.44 104 102.76 104 99.4V67.0766C104 65.3954 104 64.5548 103.788 63.7778C103.599 63.0894 103.29 62.4402 102.873 61.8605C102.404 61.2062 101.751 60.677 100.445 59.6184L87.5178 49.1419C86.5385 48.3482 86.0489 47.9514 85.5023 47.6691C85.0175 47.4187 84.5007 47.2355 83.9664 47.1248C83.364 47 82.7338 47 81.4733 47H62.6C59.2397 47 57.5595 47 56.2761 47.654C55.1471 48.2292 54.2292 49.1471 53.654 50.2761C53 51.5595 53 53.2397 53 56.6V99.4C53 102.76 53 104.44 53.654 105.724C54.2292 106.853 55.1471 107.771 56.2761 108.346C57.5595 109 59.2397 109 62.6 109Z" stroke="white" stroke-opacity="0.18" stroke-width="1.5"/>
23
- </g>
24
- <path d="M75.9031 85.0833C74.6481 85.0833 73.5803 84.6373 72.6998 83.7452C71.8192 82.8531 71.3789 81.7713 71.3789 80.5V75.5C71.3789 74.2286 71.8192 73.1468 72.6998 72.2548C73.5803 71.3627 74.6481 70.9166 75.9031 70.9166H80.8386C82.0936 70.9166 83.1613 71.3627 84.0419 72.2548C84.9225 73.1468 85.3628 74.2286 85.3628 75.5V80.5C85.3628 81.7713 84.9225 82.8531 84.0419 83.7452C83.1613 84.6373 82.0936 85.0833 80.8386 85.0833H75.9031ZM77.5483 79.2885L76.1721 77.8941C76.0582 77.7788 75.915 77.7198 75.7425 77.717C75.5702 77.7144 75.4244 77.7734 75.3051 77.8941C75.1859 78.015 75.1264 78.1613 75.1264 78.3333C75.1264 78.5052 75.1859 78.6516 75.3051 78.7725L77.0278 80.5177C77.1765 80.6682 77.35 80.7435 77.5483 80.7435C77.7465 80.7435 77.92 80.6682 78.0688 80.5177L81.7656 76.7725C81.8794 76.657 81.9377 76.512 81.9404 76.3373C81.943 76.1627 81.8848 76.015 81.7656 75.8941C81.6464 75.7734 81.5019 75.7131 81.3321 75.7131C81.1624 75.7131 81.0179 75.7734 80.8986 75.8941L77.5483 79.2885Z" fill="#F8F8F8" fill-opacity="0.85"/>
25
- </g>
26
- <defs>
27
- <filter id="filter0_d_12378_11440" x="20.25" y="14.25" width="116.5" height="143.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
28
- <feFlood flood-opacity="0" result="BackgroundImageFix"/>
29
- <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
30
- <feOffset dy="24"/>
31
- <feGaussianBlur stdDeviation="12"/>
32
- <feComposite in2="hardAlpha" operator="out"/>
33
- <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
34
- <feBlend mode="multiply" in2="BackgroundImageFix" result="effect1_dropShadow_12378_11440"/>
35
- <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_12378_11440" result="shape"/>
36
- </filter>
37
- <radialGradient id="paint0_radial_12378_11440" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(78.5 78) rotate(90) scale(78 78.5)">
38
- <stop stop-color="#D9D9D9"/>
39
- <stop offset="1" stop-color="#737373" stop-opacity="0"/>
40
- </radialGradient>
41
- <clipPath id="clip0_12378_11440">
42
- <rect width="157" height="156" fill="white"/>
43
- </clipPath>
44
- </defs>
45
- </svg>`;
46
-
47
- /** The illustration as a data URI, ready for an `<img src>`. */
48
- export const toolPlaceholderUri = `data:image/svg+xml;utf8,${encodeURIComponent(
49
- toolPlaceholderSvg,
50
- )}`;
1
+ /**
2
+ * Empty-state illustration for the helper panel (from
3
+ * "Frame 691314571.svg" — a translucent stacked-cards glyph with a check badge).
4
+ * Stored as a string and served as a data URI so it needs no import/build
5
+ * config. Theme-safe: all fills are translucent white/#F8F8F8 over transparent,
6
+ * so it reads correctly on the dark bg-base card.
7
+ */
8
+ export const toolPlaceholderSvg = `<svg width="157" height="156" viewBox="0 0 157 156" fill="none" xmlns="http://www.w3.org/2000/svg">
9
+ <g clip-path="url(#clip0_12378_11440)">
10
+ <mask id="mask0_12378_11440" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="157" height="156">
11
+ <ellipse cx="78.5" cy="78" rx="78.5" ry="78" fill="url(#paint0_radial_12378_11440)"/>
12
+ </mask>
13
+ <g mask="url(#mask0_12378_11440)">
14
+ <path d="M2.33321 94.9001H34.2999C38.7803 94.9001 41.0205 94.9001 42.7318 94.0281C44.2371 93.2611 45.4609 92.0373 46.2279 90.532C47.0999 88.8207 47.0999 86.5805 47.0999 82.1V50.4353C47.0999 48.1467 47.0999 47.0024 46.8058 45.948C46.5453 45.0139 46.1172 44.135 45.5423 43.3541C44.8933 42.4726 43.9922 41.7672 42.1902 40.3565L28.9883 30.0212C27.6995 29.0123 27.0551 28.5078 26.3403 28.1493C25.7061 27.8311 25.0324 27.5988 24.3369 27.4583C23.5531 27.3 22.7347 27.3 21.098 27.3H2.33321C-2.14722 27.3 -4.38743 27.3 -6.09872 28.172C-7.60402 28.939 -8.82786 30.1628 -9.59485 31.6681C-10.4668 33.3794 -10.4668 35.6196 -10.4668 40.1V82.1001C-10.4668 86.5805 -10.4668 88.8207 -9.59485 90.532C-8.82786 92.0373 -7.60402 93.2611 -6.09872 94.0281C-4.38743 94.9001 -2.14722 94.9001 2.33321 94.9001Z" fill="#F8F8F8" fill-opacity="0.08" style="mix-blend-mode:luminosity"/>
15
+ <path d="M2.33321 94.9001H34.2999C38.7803 94.9001 41.0205 94.9001 42.7318 94.0281C44.2371 93.2611 45.4609 92.0373 46.2279 90.532C47.0999 88.8207 47.0999 86.5805 47.0999 82.1V50.4353C47.0999 48.1467 47.0999 47.0024 46.8058 45.948C46.5453 45.0139 46.1172 44.135 45.5423 43.3541C44.8933 42.4726 43.9922 41.7672 42.1902 40.3565L28.9883 30.0212C27.6995 29.0123 27.0551 28.5078 26.3403 28.1493C25.7061 27.8311 25.0324 27.5988 24.3369 27.4583C23.5531 27.3 22.7347 27.3 21.098 27.3H2.33321C-2.14722 27.3 -4.38743 27.3 -6.09872 28.172C-7.60402 28.939 -8.82786 30.1628 -9.59485 31.6681C-10.4668 33.3794 -10.4668 35.6196 -10.4668 40.1V82.1001C-10.4668 86.5805 -10.4668 88.8207 -9.59485 90.532C-8.82786 92.0373 -7.60402 93.2611 -6.09872 94.0281C-4.38743 94.9001 -2.14722 94.9001 2.33321 94.9001Z" stroke="white" stroke-opacity="0.15" stroke-width="1.5"/>
16
+ <path d="M154.667 61.0999H122.7C118.22 61.0999 115.98 61.0999 114.268 61.9719C112.763 62.7389 111.539 63.9627 110.772 65.468C109.9 67.1793 109.9 69.4195 109.9 73.9V105.565C109.9 107.853 109.9 108.998 110.194 110.052C110.455 110.986 110.883 111.865 111.458 112.646C112.107 113.527 113.008 114.233 114.81 115.644L128.012 125.979C129.3 126.988 129.945 127.492 130.66 127.851C131.294 128.169 131.968 128.401 132.663 128.542C133.447 128.7 134.265 128.7 135.902 128.7H154.667C159.147 128.7 161.387 128.7 163.099 127.828C164.604 127.061 165.828 125.837 166.595 124.332C167.467 122.621 167.467 120.38 167.467 115.9V73.8999C167.467 69.4195 167.467 67.1793 166.595 65.468C165.828 63.9627 164.604 62.7389 163.099 61.9719C161.387 61.0999 159.147 61.0999 154.667 61.0999Z" fill="#F8F8F8" fill-opacity="0.08" style="mix-blend-mode:luminosity"/>
17
+ <path d="M84.758 182H116.725C121.205 182 123.445 182 125.157 181.128C126.662 180.361 127.886 179.137 128.653 177.632C129.525 175.921 129.525 173.68 129.525 169.2V137.535C129.525 135.247 129.525 134.102 129.231 133.048C128.97 132.114 128.542 131.235 127.967 130.454C127.318 129.573 126.417 128.867 124.615 127.456L111.413 117.121C110.124 116.112 109.48 115.608 108.765 115.249C108.131 114.931 107.457 114.699 106.762 114.558C105.978 114.4 105.16 114.4 103.523 114.4H84.758C80.2776 114.4 78.0374 114.4 76.3261 115.272C74.8208 116.039 73.5969 117.263 72.83 118.768C71.958 120.479 71.958 122.72 71.958 127.2V169.2C71.958 173.68 71.958 175.921 72.83 177.632C73.5969 179.137 74.8208 180.361 76.3261 181.128C78.0374 182 80.2776 182 84.758 182Z" fill="#F8F8F8" fill-opacity="0.08" style="mix-blend-mode:luminosity"/>
18
+ </g>
19
+ <path d="M63.2502 111.583H93.7502C98.2306 111.583 100.471 111.583 102.182 110.711C103.687 109.944 104.911 108.721 105.678 107.215C106.55 105.504 106.55 103.264 106.55 98.7833V67.3691C106.55 65.1068 106.55 63.9756 106.262 62.9315C106.007 62.0065 105.588 61.1349 105.024 60.3584C104.387 59.482 103.503 58.7763 101.735 57.3651L89.0157 47.2126C87.7173 46.1763 87.0681 45.6581 86.3455 45.2897C85.7044 44.9628 85.0221 44.7239 84.3172 44.5794C83.5226 44.4166 82.6919 44.4166 81.0307 44.4166H63.2502C58.7698 44.4166 56.5296 44.4166 54.8183 45.2886C53.313 46.0556 52.0891 47.2794 51.3221 48.7847C50.4502 50.496 50.4502 52.7362 50.4502 57.2166V98.7833C50.4502 103.264 50.4502 105.504 51.3221 107.215C52.0891 108.721 53.313 109.944 54.8183 110.711C56.5296 111.583 58.7698 111.583 63.2502 111.583Z" fill="#F8F8F8" fill-opacity="0.05" style="mix-blend-mode:luminosity"/>
20
+ <g filter="url(#filter0_d_12378_11440)">
21
+ <path d="M62.6 109H94.4C97.7603 109 99.4405 109 100.724 108.346C101.853 107.771 102.771 106.853 103.346 105.724C104 104.44 104 102.76 104 99.4V67.0766C104 65.3954 104 64.5548 103.788 63.7778C103.599 63.0894 103.29 62.4402 102.873 61.8605C102.404 61.2062 101.751 60.677 100.445 59.6184L87.5178 49.1419C86.5385 48.3482 86.0489 47.9514 85.5023 47.6691C85.0175 47.4187 84.5007 47.2355 83.9664 47.1248C83.364 47 82.7338 47 81.4733 47H62.6C59.2397 47 57.5595 47 56.2761 47.654C55.1471 48.2292 54.2292 49.1471 53.654 50.2761C53 51.5595 53 53.2397 53 56.6V99.4C53 102.76 53 104.44 53.654 105.724C54.2292 106.853 55.1471 107.771 56.2761 108.346C57.5595 109 59.2397 109 62.6 109Z" fill="#F8F8F8" fill-opacity="0.08" style="mix-blend-mode:luminosity"/>
22
+ <path d="M62.6 109H94.4C97.7603 109 99.4405 109 100.724 108.346C101.853 107.771 102.771 106.853 103.346 105.724C104 104.44 104 102.76 104 99.4V67.0766C104 65.3954 104 64.5548 103.788 63.7778C103.599 63.0894 103.29 62.4402 102.873 61.8605C102.404 61.2062 101.751 60.677 100.445 59.6184L87.5178 49.1419C86.5385 48.3482 86.0489 47.9514 85.5023 47.6691C85.0175 47.4187 84.5007 47.2355 83.9664 47.1248C83.364 47 82.7338 47 81.4733 47H62.6C59.2397 47 57.5595 47 56.2761 47.654C55.1471 48.2292 54.2292 49.1471 53.654 50.2761C53 51.5595 53 53.2397 53 56.6V99.4C53 102.76 53 104.44 53.654 105.724C54.2292 106.853 55.1471 107.771 56.2761 108.346C57.5595 109 59.2397 109 62.6 109Z" stroke="white" stroke-opacity="0.18" stroke-width="1.5"/>
23
+ </g>
24
+ <path d="M75.9031 85.0833C74.6481 85.0833 73.5803 84.6373 72.6998 83.7452C71.8192 82.8531 71.3789 81.7713 71.3789 80.5V75.5C71.3789 74.2286 71.8192 73.1468 72.6998 72.2548C73.5803 71.3627 74.6481 70.9166 75.9031 70.9166H80.8386C82.0936 70.9166 83.1613 71.3627 84.0419 72.2548C84.9225 73.1468 85.3628 74.2286 85.3628 75.5V80.5C85.3628 81.7713 84.9225 82.8531 84.0419 83.7452C83.1613 84.6373 82.0936 85.0833 80.8386 85.0833H75.9031ZM77.5483 79.2885L76.1721 77.8941C76.0582 77.7788 75.915 77.7198 75.7425 77.717C75.5702 77.7144 75.4244 77.7734 75.3051 77.8941C75.1859 78.015 75.1264 78.1613 75.1264 78.3333C75.1264 78.5052 75.1859 78.6516 75.3051 78.7725L77.0278 80.5177C77.1765 80.6682 77.35 80.7435 77.5483 80.7435C77.7465 80.7435 77.92 80.6682 78.0688 80.5177L81.7656 76.7725C81.8794 76.657 81.9377 76.512 81.9404 76.3373C81.943 76.1627 81.8848 76.015 81.7656 75.8941C81.6464 75.7734 81.5019 75.7131 81.3321 75.7131C81.1624 75.7131 81.0179 75.7734 80.8986 75.8941L77.5483 79.2885Z" fill="#F8F8F8" fill-opacity="0.85"/>
25
+ </g>
26
+ <defs>
27
+ <filter id="filter0_d_12378_11440" x="20.25" y="14.25" width="116.5" height="143.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
28
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
29
+ <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
30
+ <feOffset dy="24"/>
31
+ <feGaussianBlur stdDeviation="12"/>
32
+ <feComposite in2="hardAlpha" operator="out"/>
33
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
34
+ <feBlend mode="multiply" in2="BackgroundImageFix" result="effect1_dropShadow_12378_11440"/>
35
+ <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_12378_11440" result="shape"/>
36
+ </filter>
37
+ <radialGradient id="paint0_radial_12378_11440" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(78.5 78) rotate(90) scale(78 78.5)">
38
+ <stop stop-color="#D9D9D9"/>
39
+ <stop offset="1" stop-color="#737373" stop-opacity="0"/>
40
+ </radialGradient>
41
+ <clipPath id="clip0_12378_11440">
42
+ <rect width="157" height="156" fill="white"/>
43
+ </clipPath>
44
+ </defs>
45
+ </svg>`;
46
+
47
+ /** The illustration as a data URI, ready for an `<img src>`. */
48
+ export const toolPlaceholderUri = `data:image/svg+xml;utf8,${encodeURIComponent(
49
+ toolPlaceholderSvg,
50
+ )}`;