From 2888a1a0be64ff2db86733b2f15490c3b9f84b46 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 10 Sep 2026 14:59:25 +0200 Subject: [PATCH 1/3] feat(viewer): add configurable browser tab and toolbar title createViewer() now accepts a title option that sets document.title when provided, and is also injected as the toolbar's heading text (previously hardcoded "COMPAS ThreeJs") via a new toolbarTitleKey/ useToolbarTitle(), following the same provide/inject pattern as toolbarPlacement/openbarPlacement/objectActionsPlacement. The standalone websocket entry point (main.ts) reads the title from a `title` URL query param, matching how ws_host/ws_port are already passed through, so a Python App can set both per instance without any frontend-side wiring. Co-Authored-By: Claude Sonnet 5 --- src/components/layout/Toolbar.vue | 4 +++- src/library/index.ts | 8 ++++++++ src/library/public.d.ts | 2 ++ src/library/types.ts | 2 ++ src/main.ts | 3 +++ src/viewer/viewer_context.ts | 8 ++++++++ 6 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/components/layout/Toolbar.vue b/src/components/layout/Toolbar.vue index bfcc0e0..59ed388 100644 --- a/src/components/layout/Toolbar.vue +++ b/src/components/layout/Toolbar.vue @@ -6,7 +6,7 @@ id="toolbar" >

- COMPAS ThreeJs + {{ toolbarTitle }}

@@ -29,6 +29,7 @@ import DisplayGroup from "@/components/tools/display/DisplayGroup.vue"; import { isHorizontalPlacement, useToolbarPlacement, + useToolbarTitle, useViewerRuntime, } from "@/viewer/viewer_context"; import { useHover } from "@/composables/useHover"; @@ -43,6 +44,7 @@ const { isHovered } = useHover(toolbarElement); const { theme, blockPicker } = useViewerRuntime().store; const placement = useToolbarPlacement(); const isHorizontal = isHorizontalPlacement(placement); +const toolbarTitle = useToolbarTitle(); watchEffect(() => { blockPicker.value = isHovered.value; diff --git a/src/library/index.ts b/src/library/index.ts index e59a794..f764548 100644 --- a/src/library/index.ts +++ b/src/library/index.ts @@ -7,6 +7,7 @@ import { objectActionsPlacementKey, openbarPlacementKey, toolbarPlacementKey, + toolbarTitleKey, useViewerRuntime, viewerRuntimeKey, } from "../viewer/viewer_context"; @@ -48,6 +49,10 @@ export function createViewer( ); } + if (options.title) { + document.title = options.title; + } + const runtime = markRaw(new ViewerRuntime(container, options)); const app = createApp(App, { runtime, @@ -58,6 +63,9 @@ export function createViewer( app.provide(toolbarPlacementKey, options.toolbarPlacement ?? "left"); app.provide(openbarPlacementKey, options.openbarPlacement ?? "left"); app.provide(metadataPlacementKey, options.metadataPlacement ?? "right"); + if (options.title) { + app.provide(toolbarTitleKey, options.title); + } app.provide( objectActionsPlacementKey, options.objectActionsPlacement ?? "right", diff --git a/src/library/public.d.ts b/src/library/public.d.ts index 30b8939..d6ff600 100644 --- a/src/library/public.d.ts +++ b/src/library/public.d.ts @@ -43,6 +43,8 @@ export interface CompasViewerOptions { websocket?: ViewerWebSocketOptions; defaultLighting?: boolean; showToolbar?: boolean; + /** Browser tab title to apply for this viewer instance. Leaves `document.title` untouched if omitted. */ + title?: string; /** * Extra toolbar modules mounted after the built-in groups - e.g. a component * installed from an npm package. Each module owns its own icons/behavior/ids the diff --git a/src/library/types.ts b/src/library/types.ts index 1c5da84..70045c7 100644 --- a/src/library/types.ts +++ b/src/library/types.ts @@ -18,6 +18,8 @@ export interface CompasViewerOptions { websocket?: ViewerWebSocketOptions; defaultLighting?: boolean; showToolbar?: boolean; + /** Browser tab title to apply for this viewer instance. Leaves `document.title` untouched if omitted. */ + title?: string; /** * Extra toolbar modules to mount after the built-in groups - e.g. a `.vue` group * installed from an npm package. Each module owns its own icons/behavior/ids the diff --git a/src/main.ts b/src/main.ts index 2c05801..e7f6e3a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,7 +3,10 @@ import { createViewer } from "./library"; const container = document.querySelector("#app"); if (!container) throw new Error("Standalone viewer requires an #app container"); +const title = new URLSearchParams(window.location.search).get("title") ?? undefined; + createViewer(container, { mode: "websocket", showToolbar: true, + title, }); diff --git a/src/viewer/viewer_context.ts b/src/viewer/viewer_context.ts index 0928c4e..4b9fadf 100644 --- a/src/viewer/viewer_context.ts +++ b/src/viewer/viewer_context.ts @@ -7,6 +7,10 @@ export const viewerRuntimeKey: InjectionKey = Symbol( "compas-viewer-runtime", ); +export const toolbarTitleKey: InjectionKey = Symbol( + "compas-viewer-toolbar-title", +); + export function useViewerRuntime(): ViewerRuntime { const runtime = inject(viewerRuntimeKey); if (!runtime) { @@ -15,6 +19,10 @@ export function useViewerRuntime(): ViewerRuntime { return runtime; } +export function useToolbarTitle(): string { + return inject(toolbarTitleKey, "COMPAS ThreeJs"); +} + /** * Which edge of the viewer a panel docks to. Panels sharing an edge stack along it, in * a fixed priority order (toolbar, openbar, metadata, objectActions) - see App.vue. From e4ef9af0ac60c660053e0ae9abdd6c271c41c62b Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 21 Sep 2026 14:54:16 +0200 Subject: [PATCH 2/3] docs(examples): add a configurable tab title example Interactive demo of createViewer's title option: retyping it recreates the viewer, showing the browser tab title and the toolbar heading (normally hardcoded "COMPAS ThreeJs") both update. Verified in a real browser via Playwright. Co-Authored-By: Claude Sonnet 5 --- examples/embedded_tab_title.html | 145 +++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 examples/embedded_tab_title.html diff --git a/examples/embedded_tab_title.html b/examples/embedded_tab_title.html new file mode 100644 index 0000000..4d77a84 --- /dev/null +++ b/examples/embedded_tab_title.html @@ -0,0 +1,145 @@ + + + + + + Configurable tab title + + + + + + + +
+ + + + + Sets both the browser tab title and the toolbar heading (normally + "COMPAS ThreeJs"). + +
+ +
+ + + + From 953dd968f18ad0042a1c78f1a153409b5a7e091c Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 23 Sep 2026 08:00:48 +0200 Subject: [PATCH 3/3] style: apply Prettier formatting to src/main.ts Co-Authored-By: Claude Opus 5.5 --- src/main.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index e7f6e3a..6573345 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,7 +3,8 @@ import { createViewer } from "./library"; const container = document.querySelector("#app"); if (!container) throw new Error("Standalone viewer requires an #app container"); -const title = new URLSearchParams(window.location.search).get("title") ?? undefined; +const title = + new URLSearchParams(window.location.search).get("title") ?? undefined; createViewer(container, { mode: "websocket",