@ikaros-arch/react-3dhop-iiif 0.1.0 → 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/LICENSE +674 -674
- package/README.md +381 -381
- package/dist/index.d.mts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +71 -71
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/IIIFViewer.tsx","../src/context.tsx","../src/iiif/mat4.ts","../src/iiif/camera.ts","../src/iiif/language.ts","../src/iiif/parser.ts","../src/iiif/transforms.ts","../src/iiif/units.ts","../src/iiif/toModels.ts","../src/IIIFMultiManifestViewer.tsx","../src/multiManifestContext.tsx","../src/iiif/toMultiModels.ts","../src/collectionContext.tsx","../src/iiif/collection.ts","../src/panels/IIIFCollectionPicker.tsx","../src/panels/IIIFCollectionCarousel.tsx","../src/panels/IIIFSummary.tsx","../src/panels/IIIFMetadataPanel.tsx","../src/panels/IIIFModelsPanel.tsx","../src/panels/IIIFMultiManifestModelsPanel.tsx","../src/panels/IIIFSavedViewsPanel.tsx","../src/panels/IIIFLanguageSwitcher.tsx"],"sourcesContent":["export { IIIFViewer } from './IIIFViewer.js';\r\nexport type { IIIFViewerProps } from './IIIFViewer.js';\r\n\r\nexport { IIIFMultiManifestViewer } from './IIIFMultiManifestViewer.js';\r\nexport type { IIIFMultiManifestViewerProps } from './IIIFMultiManifestViewer.js';\r\n\r\nexport { IIIFProvider, useIIIFManifest } from './context.js';\r\nexport type { IIIFContextValue, IIIFProviderProps, IIIFStatus } from './context.js';\r\n\r\nexport { IIIFMultiManifestProvider, useIIIFMultiManifest } from './multiManifestContext.js';\r\nexport type {\r\n IIIFMultiManifestContextValue,\r\n IIIFMultiManifestProviderProps,\r\n IIIFMultiManifestStatus,\r\n ManifestGroup\r\n} from './multiManifestContext.js';\r\n\r\nexport { IIIFCollectionProvider, useIIIFCollection } from './collectionContext.js';\r\nexport type {\r\n IIIFCollectionContextValue,\r\n IIIFCollectionProviderProps,\r\n IIIFCollectionStatus\r\n} from './collectionContext.js';\r\n\r\nexport { IIIFCollectionPicker } from './panels/IIIFCollectionPicker.js';\r\nexport type { IIIFCollectionPickerProps } from './panels/IIIFCollectionPicker.js';\r\nexport { IIIFCollectionCarousel } from './panels/IIIFCollectionCarousel.js';\r\nexport type { IIIFCollectionCarouselProps } from './panels/IIIFCollectionCarousel.js';\r\n\r\nexport { IIIFSummary } from './panels/IIIFSummary.js';\r\nexport type { IIIFSummaryProps } from './panels/IIIFSummary.js';\r\nexport { IIIFMetadataPanel } from './panels/IIIFMetadataPanel.js';\r\nexport type { IIIFMetadataPanelProps } from './panels/IIIFMetadataPanel.js';\r\nexport { IIIFModelsPanel } from './panels/IIIFModelsPanel.js';\r\nexport type { IIIFModelsPanelProps } from './panels/IIIFModelsPanel.js';\r\nexport { IIIFMultiManifestModelsPanel } from './panels/IIIFMultiManifestModelsPanel.js';\r\nexport type { IIIFMultiManifestModelsPanelProps } from './panels/IIIFMultiManifestModelsPanel.js';\r\nexport { IIIFSavedViewsPanel } from './panels/IIIFSavedViewsPanel.js';\r\nexport type { IIIFSavedViewsPanelProps } from './panels/IIIFSavedViewsPanel.js';\r\nexport { IIIFLanguageSwitcher, LANGUAGE_NAMES } from './panels/IIIFLanguageSwitcher.js';\r\nexport type { IIIFLanguageSwitcherProps } from './panels/IIIFLanguageSwitcher.js';\r\n\r\n// Pure helpers, usable without React.\r\nexport { loadManifest, parseManifest, selectBestSource, FORMAT_PREFERENCE } from './iiif/parser.js';\r\nexport type { LoadManifestOptions, ParseOptions } from './iiif/parser.js';\r\n\r\nexport { loadCollection, parseCollection } from './iiif/collection.js';\r\nexport type { LoadCollectionOptions, ParseCollectionOptions } from './iiif/collection.js';\r\n\r\nexport { sceneFromManifest, DEFAULT_MEASURE_UNIT } from './iiif/toModels.js';\r\nexport type { SceneFromManifest, ToModelsOptions } from './iiif/toModels.js';\r\n\r\nexport { sceneFromManifests, layoutManifests } from './iiif/toMultiModels.js';\r\nexport type { SceneFromManifests, ToMultiModelsOptions, ManifestSceneEntry } from './iiif/toMultiModels.js';\r\n\r\nexport { getUnitScaleFactor, isKnownUnit, UNITS_IN_METRES } from './iiif/units.js';\r\nexport type { UnitName } from './iiif/units.js';\r\n\r\nexport { buildModelMatrix, composeTransforms, transformToMatrix } from './iiif/transforms.js';\r\nexport type { ModelMatrixOptions } from './iiif/transforms.js';\r\n\r\nexport { cameraToView, track2view, view2track, viewToCameraAnnotation } from './iiif/camera.js';\r\nexport type { CameraAnnotationOptions, SceneFraming, TrackballState } from './iiif/camera.js';\r\n\r\nexport { collectLanguages, resolveLanguageMap, DEFAULT_FALLBACK_LANGUAGES } from './iiif/language.js';\r\n\r\nexport type {\r\n Diagnostic,\r\n DiagnosticHandler,\r\n IIIFAnnotation,\r\n IIIFAnnotationBody,\r\n IIIFAnnotationPage,\r\n IIIFAnnotationTarget,\r\n IIIFCollection,\r\n IIIFCollectionItem,\r\n IIIFManifest,\r\n IIIFMetadataEntry,\r\n IIIFModelSource,\r\n IIIFPointSelector,\r\n IIIFScene,\r\n IIIFThumbnail,\r\n IIIFTransform,\r\n LanguageMap,\r\n LocalizableValue,\r\n ParsedCamera,\r\n ParsedCollection,\r\n ParsedCollectionItem,\r\n ParsedManifest,\r\n ParsedMetadata,\r\n ParsedModel,\r\n Vector3,\r\n View\r\n} from './iiif/types.js';\r\n","import React, { useEffect, useMemo, useState } from 'react';\r\nimport { ThreeDHopViewer, type ThreeDHopViewerProps } from '@ikaros-arch/react-3dhop';\r\nimport { IIIFProvider, useIIIFManifest, type IIIFStatus } from './context.js';\r\nimport { loadManifest, parseManifest } from './iiif/parser.js';\r\nimport { sceneFromManifest, type SceneFromManifest, type ToModelsOptions } from './iiif/toModels.js';\r\nimport type { Diagnostic, IIIFManifest, ParsedManifest } from './iiif/types.js';\r\n\r\nexport type IIIFViewerProps = Omit<ThreeDHopViewerProps, 'models' | 'modelUrl'> & {\r\n /** A manifest URL to fetch, or an already-fetched manifest object. */\r\n manifest: string | IIIFManifest;\r\n /** Language used for labels and metadata. Defaults to the browser's, falling back to `'en'`. */\r\n language?: string;\r\n /** Overrides the manifest's `display unit`, changing the scale the scene is rendered at. */\r\n displayUnit?: string;\r\n /** Applies the manifest's first camera as the initial view once the scene is ready. */\r\n applyInitialCamera?: boolean;\r\n onLoad?: (parsed: ParsedManifest, scene: SceneFromManifest) => void;\r\n onError?: (error: Error) => void;\r\n onDiagnostic?: (diagnostic: Diagnostic) => void;\r\n /** Rendered instead of the viewer while the manifest is being fetched. */\r\n loadingFallback?: React.ReactNode;\r\n /** Rendered instead of the viewer when the manifest cannot be loaded or parsed. */\r\n errorFallback?: React.ReactNode | ((error: Error) => React.ReactNode);\r\n};\r\n\r\nfunction defaultLanguage(): string {\r\n if (typeof navigator !== 'undefined' && navigator.language) {\r\n return navigator.language.split('-')[0];\r\n }\r\n return 'en';\r\n}\r\n\r\n/**\r\n * Renders a IIIF 3D manifest with 3DHOP.\r\n *\r\n * Fetches and parses the manifest, derives the scene, and makes the result available to any\r\n * descendant through `useIIIFManifest()`. Everything `<ThreeDHopViewer>` accepts can be passed\r\n * through, except the model props this component supplies itself.\r\n */\r\nexport const IIIFViewer: React.FC<IIIFViewerProps> = ({\r\n manifest,\r\n language: languageProp,\r\n displayUnit,\r\n applyInitialCamera = true,\r\n onLoad,\r\n onError,\r\n onDiagnostic,\r\n loadingFallback = null,\r\n errorFallback = null,\r\n space,\r\n config,\r\n trackball,\r\n children,\r\n ...viewerProps\r\n}) => {\r\n const [language, setLanguage] = useState(() => languageProp ?? defaultLanguage());\r\n const [status, setStatus] = useState<IIIFStatus>('idle');\r\n const [error, setError] = useState<Error | null>(null);\r\n const [parsed, setParsed] = useState<ParsedManifest | null>(null);\r\n const [diagnostics, setDiagnostics] = useState<Diagnostic[]>([]);\r\n\r\n useEffect(() => {\r\n if (languageProp) {\r\n setLanguage(languageProp);\r\n }\r\n }, [languageProp]);\r\n\r\n useEffect(() => {\r\n const controller = new AbortController();\r\n const collected: Diagnostic[] = [];\r\n const handleDiagnostic = (diagnostic: Diagnostic) => {\r\n collected.push(diagnostic);\r\n onDiagnostic?.(diagnostic);\r\n };\r\n\r\n const finish = (result: ParsedManifest) => {\r\n if (controller.signal.aborted) {\r\n return;\r\n }\r\n setParsed(result);\r\n setDiagnostics(collected);\r\n setStatus('ready');\r\n setError(null);\r\n };\r\n\r\n const fail = (cause: unknown) => {\r\n if (controller.signal.aborted) {\r\n return;\r\n }\r\n const normalized = cause instanceof Error ? cause : new Error(String(cause));\r\n setParsed(null);\r\n setDiagnostics(collected);\r\n setStatus('error');\r\n setError(normalized);\r\n onError?.(normalized);\r\n };\r\n\r\n setStatus('loading');\r\n\r\n if (typeof manifest === 'string') {\r\n loadManifest(manifest, { language, signal: controller.signal, onDiagnostic: handleDiagnostic })\r\n .then(finish)\r\n .catch((cause) => {\r\n if (cause instanceof DOMException && cause.name === 'AbortError') {\r\n return;\r\n }\r\n fail(cause);\r\n });\r\n } else {\r\n try {\r\n finish(parseManifest(manifest, { language, onDiagnostic: handleDiagnostic }));\r\n } catch (cause) {\r\n fail(cause);\r\n }\r\n }\r\n\r\n return () => controller.abort();\r\n // `language` is deliberately excluded: switching language re-resolves labels below rather than\r\n // re-fetching the manifest.\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [manifest, onDiagnostic, onError]);\r\n\r\n // Re-resolving is cheap and keeps a single source of truth for language handling.\r\n const localized = useMemo(() => {\r\n if (!parsed) {\r\n return null;\r\n }\r\n return parseManifest(parsed.manifest, { language });\r\n }, [parsed, language]);\r\n\r\n const scene = useMemo(() => {\r\n if (!localized) {\r\n return null;\r\n }\r\n return sceneFromManifest(localized, { displayUnit, space, config, trackball } satisfies ToModelsOptions);\r\n }, [localized, displayUnit, space, config, trackball]);\r\n\r\n useEffect(() => {\r\n if (status === 'ready' && localized && scene) {\r\n onLoad?.(localized, scene);\r\n }\r\n // Firing only when the parsed result changes; `onLoad` identity is the caller's concern.\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [status, localized, scene]);\r\n\r\n if (status === 'error' && error) {\r\n return <>{typeof errorFallback === 'function' ? errorFallback(error) : errorFallback}</>;\r\n }\r\n\r\n if (!scene || !localized) {\r\n return <>{loadingFallback}</>;\r\n }\r\n\r\n return (\r\n <ThreeDHopViewer\r\n {...viewerProps}\r\n models={scene.models}\r\n space={scene.space}\r\n config={scene.config}\r\n trackball={scene.trackball}\r\n measurementUnits={viewerProps.measurementUnits ?? scene.displayUnit}\r\n >\r\n <IIIFProvider\r\n status={status}\r\n error={error}\r\n diagnostics={diagnostics}\r\n parsed={localized}\r\n scene={scene}\r\n language={language}\r\n setLanguage={setLanguage}\r\n >\r\n {applyInitialCamera && localized.cameras.length > 0 ? <InitialCamera /> : null}\r\n {children}\r\n </IIIFProvider>\r\n </ThreeDHopViewer>\r\n );\r\n};\r\n\r\n/**\r\n * Applies the manifest's first camera as the opening view.\r\n *\r\n * This waits for the scene framing rather than running on mount: the presenter only knows the\r\n * scene's centre and radius after the scene has been set, and `goToCamera` is a no-op until then.\r\n */\r\nconst InitialCamera: React.FC = () => {\r\n const [applied, setApplied] = useState(false);\r\n const { goToCamera, cameras, isSceneReady } = useIIIFManifest();\r\n\r\n useEffect(() => {\r\n if (applied || !isSceneReady || cameras.length === 0) {\r\n return;\r\n }\r\n goToCamera(0, 0);\r\n setApplied(true);\r\n }, [applied, cameras.length, goToCamera, isSceneReady]);\r\n\r\n return null;\r\n};\r\n","import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\r\nimport { useThreeDHopViewer } from '@ikaros-arch/react-3dhop';\r\nimport { cameraToView, track2view, view2track, viewToCameraAnnotation, type SceneFraming, type TrackballState } from './iiif/camera.js';\r\nimport { resolveLanguageMap } from './iiif/language.js';\r\nimport type { Diagnostic, LocalizableValue, ParsedCamera, ParsedManifest, ParsedMetadata, ParsedModel } from './iiif/types.js';\r\nimport type { SceneFromManifest } from './iiif/toModels.js';\r\n\r\nexport type IIIFStatus = 'idle' | 'loading' | 'ready' | 'error';\r\n\r\nexport type IIIFContextValue = {\r\n status: IIIFStatus;\r\n error: Error | null;\r\n /** Non-fatal notes collected while parsing, in the order they were emitted. */\r\n diagnostics: Diagnostic[];\r\n parsed: ParsedManifest | null;\r\n metadata: ParsedMetadata | null;\r\n models: ParsedModel[];\r\n cameras: ParsedCamera[];\r\n languages: string[];\r\n language: string;\r\n setLanguage: (language: string) => void;\r\n /** Resolves any language map from the manifest into the active language. */\r\n localize: (value: LocalizableValue | undefined) => string;\r\n measureUnit: string;\r\n displayUnit: string;\r\n /**\r\n * Whether the presenter has established the scene's centre and radius. Camera operations are\r\n * no-ops until this is true, because there is nothing to convert against yet.\r\n */\r\n isSceneReady: boolean;\r\n /** Animates the camera to the manifest camera at `index`. */\r\n goToCamera: (index: number, durationSeconds?: number) => void;\r\n /** Captures the current camera as an IIIF annotation, or `null` if the scene is not ready. */\r\n saveCurrentView: (label?: string) => Record<string, unknown> | null;\r\n /** Shows or hides one model. Pass the IIIF annotation id. */\r\n setModelVisible: (modelId: string, visible: boolean) => void;\r\n isModelVisible: (modelId: string) => boolean;\r\n toggleModelTransparency: (modelId: string) => void;\r\n isModelTransparent: (modelId: string) => boolean;\r\n};\r\n\r\nconst IIIFContext = createContext<IIIFContextValue | null>(null);\r\n\r\n/** Access the IIIF manifest state. Must be called from inside an `<IIIFViewer>`. */\r\nexport function useIIIFManifest(): IIIFContextValue {\r\n const value = useContext(IIIFContext);\r\n if (!value) {\r\n throw new Error('useIIIFManifest must be used within an <IIIFViewer>.');\r\n }\r\n return value;\r\n}\r\n\r\nexport type IIIFProviderProps = {\r\n status: IIIFStatus;\r\n error: Error | null;\r\n diagnostics: Diagnostic[];\r\n parsed: ParsedManifest | null;\r\n scene: SceneFromManifest | null;\r\n language: string;\r\n setLanguage: (language: string) => void;\r\n children?: React.ReactNode;\r\n};\r\n\r\n/**\r\n * Supplies IIIF state to descendants and bridges it to the live presenter.\r\n *\r\n * Rendered inside `<ThreeDHopViewer>` so it can reach the viewer context, which is the only place\r\n * the presenter — and with it the scene framing that camera conversion needs — is available.\r\n */\r\nexport const IIIFProvider: React.FC<IIIFProviderProps> = ({\r\n status,\r\n error,\r\n diagnostics,\r\n parsed,\r\n scene,\r\n language,\r\n setLanguage,\r\n children\r\n}) => {\r\n const { presenter, registerSceneObserver } = useThreeDHopViewer();\r\n const [framing, setFraming] = useState<SceneFraming | null>(null);\r\n // Held as state, not refs: the panels render these as controlled inputs, so a toggle has to\r\n // produce a new context value or the consumers never re-render and React reverts the checkbox.\r\n const [visibility, setVisibility] = useState<Record<string, boolean>>({});\r\n const [transparency, setTransparency] = useState<Record<string, boolean>>({});\r\n\r\n // The presenter only derives sceneCenter/sceneRadiusInv once a scene has been set, so read them\r\n // when the viewer tells us the scene changed rather than on mount.\r\n useEffect(() => {\r\n return registerSceneObserver((instance) => {\r\n const center = instance.sceneCenter;\r\n const radiusInv = instance.sceneRadiusInv;\r\n if (Array.isArray(center) && center.length >= 3 && typeof radiusInv === 'number') {\r\n setFraming({ sceneCenter: [center[0], center[1], center[2]], sceneRadiusInv: radiusInv });\r\n }\r\n // A new scene resets every instance to its declared state.\r\n setVisibility({});\r\n setTransparency({});\r\n });\r\n }, [registerSceneObserver]);\r\n\r\n const localize = useCallback(\r\n (value: LocalizableValue | undefined) => resolveLanguageMap(value, language),\r\n [language]\r\n );\r\n\r\n const goToCamera = useCallback(\r\n (index: number, durationSeconds = 0.5) => {\r\n if (!parsed || !framing || !presenter) {\r\n return;\r\n }\r\n const camera = parsed.cameras[index];\r\n if (!camera) {\r\n return;\r\n }\r\n\r\n const view = cameraToView(camera, framing, parsed.models);\r\n const trackState = view2track(view, framing);\r\n\r\n // The presenter treats a zero duration as \"unspecified\" and animates over its own default,\r\n // so jumping straight to the view has to bypass the animation entirely.\r\n if (durationSeconds > 0 && typeof presenter.animateToTrackballPosition === 'function') {\r\n presenter.animateToTrackballPosition(trackState, durationSeconds);\r\n } else {\r\n presenter.setTrackballPosition?.(trackState);\r\n presenter.repaint?.();\r\n }\r\n\r\n if (camera.type === 'OrthographicCamera') {\r\n presenter.setCameraOrthographic?.();\r\n } else {\r\n presenter.setCameraPerspective?.();\r\n }\r\n },\r\n [framing, parsed, presenter]\r\n );\r\n\r\n const saveCurrentView = useCallback(\r\n (label?: string) => {\r\n if (!presenter || !framing) {\r\n return null;\r\n }\r\n\r\n const trackState = presenter.getTrackballPosition?.();\r\n if (!Array.isArray(trackState) || trackState.length < 6) {\r\n return null;\r\n }\r\n\r\n const isOrthographic = presenter.getCameraType?.() === 'orthographic';\r\n const fov = isOrthographic ? 0 : presenter._scene?.space?.cameraFOV ?? 60;\r\n\r\n const view = track2view(trackState as TrackballState, framing, fov);\r\n return viewToCameraAnnotation(view, { label, sceneId: parsed?.manifest.items?.[0]?.id });\r\n },\r\n [framing, parsed, presenter]\r\n );\r\n\r\n const instanceKeyFor = useCallback(\r\n (modelId: string) => scene?.instanceIdsByModelId[modelId],\r\n [scene]\r\n );\r\n\r\n const isModelVisible = useCallback(\r\n (modelId: string) => visibility[modelId] ?? true,\r\n [visibility]\r\n );\r\n\r\n const setModelVisible = useCallback(\r\n (modelId: string, visible: boolean) => {\r\n const key = instanceKeyFor(modelId);\r\n if (!key || !presenter) {\r\n return;\r\n }\r\n // The presenter only offers a toggle, so state is tracked here to make this idempotent.\r\n if ((visibility[modelId] ?? true) === visible) {\r\n return;\r\n }\r\n presenter.toggleInstanceVisibilityByName?.(key, true);\r\n setVisibility((current) => ({ ...current, [modelId]: visible }));\r\n },\r\n [instanceKeyFor, presenter, visibility]\r\n );\r\n\r\n const isModelTransparent = useCallback(\r\n (modelId: string) => transparency[modelId] ?? false,\r\n [transparency]\r\n );\r\n\r\n const toggleModelTransparency = useCallback(\r\n (modelId: string) => {\r\n const key = instanceKeyFor(modelId);\r\n if (!key || !presenter) {\r\n return;\r\n }\r\n presenter.toggleInstanceTransparencyByName?.(key, true);\r\n setTransparency((current) => ({ ...current, [modelId]: !(current[modelId] ?? false) }));\r\n },\r\n [instanceKeyFor, presenter]\r\n );\r\n\r\n const value = useMemo<IIIFContextValue>(\r\n () => ({\r\n status,\r\n error,\r\n diagnostics,\r\n parsed,\r\n metadata: parsed?.metadata ?? null,\r\n models: parsed?.models ?? [],\r\n cameras: parsed?.cameras ?? [],\r\n languages: parsed?.languages ?? [],\r\n language,\r\n setLanguage,\r\n localize,\r\n measureUnit: scene?.measureUnit ?? 'mm',\r\n displayUnit: scene?.displayUnit ?? 'mm',\r\n isSceneReady: framing !== null,\r\n goToCamera,\r\n saveCurrentView,\r\n setModelVisible,\r\n isModelVisible,\r\n toggleModelTransparency,\r\n isModelTransparent\r\n }),\r\n [\r\n diagnostics,\r\n error,\r\n framing,\r\n goToCamera,\r\n isModelTransparent,\r\n isModelVisible,\r\n language,\r\n localize,\r\n parsed,\r\n saveCurrentView,\r\n scene,\r\n setLanguage,\r\n setModelVisible,\r\n status,\r\n toggleModelTransparency\r\n ]\r\n );\r\n\r\n return <IIIFContext.Provider value={value}>{children}</IIIFContext.Provider>;\r\n};\r\n","import type { Vector3 } from './types.js';\r\n\r\n/**\r\n * A minimal 4x4 matrix implementation matching SpiderGL's conventions, so the matrices produced\r\n * here can be handed straight to 3DHOP.\r\n *\r\n * Layout is **column-major**: `m[column * 4 + row]`, the same order WebGL expects. A translation\r\n * therefore lives in elements 12, 13 and 14. `multiply(a, b)` returns `a · b`, so the rightmost\r\n * factor is applied to a point first.\r\n *\r\n * This is reimplemented rather than delegated to the `SglMat4` global so it can be unit-tested in\r\n * Node and does not depend on 3DHOP's scripts having loaded.\r\n */\r\nexport type Mat4 = number[];\r\n\r\nexport function identity(): Mat4 {\r\n return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];\r\n}\r\n\r\nexport function translation([x, y, z]: Vector3): Mat4 {\r\n return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1];\r\n}\r\n\r\nexport function scaling([x, y, z]: Vector3): Mat4 {\r\n return [x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1];\r\n}\r\n\r\nexport function degToRad(degrees: number): number {\r\n return (degrees * Math.PI) / 180;\r\n}\r\n\r\nexport function radToDeg(radians: number): number {\r\n return (radians * 180) / Math.PI;\r\n}\r\n\r\n/** Rotation of `angle` radians about `axis`, via Rodrigues' formula. */\r\nexport function rotationAngleAxis(angle: number, axis: Vector3): Mat4 {\r\n const length = Math.hypot(axis[0], axis[1], axis[2]);\r\n if (length === 0) {\r\n return identity();\r\n }\r\n\r\n const x = axis[0] / length;\r\n const y = axis[1] / length;\r\n const z = axis[2] / length;\r\n\r\n const s = Math.sin(angle);\r\n const c = Math.cos(angle);\r\n const t = 1 - c;\r\n\r\n return [\r\n t * x * x + c,\r\n t * x * y + z * s,\r\n t * z * x - y * s,\r\n 0,\r\n t * x * y - z * s,\r\n t * y * y + c,\r\n t * y * z + x * s,\r\n 0,\r\n t * z * x + y * s,\r\n t * y * z - x * s,\r\n t * z * z + c,\r\n 0,\r\n 0,\r\n 0,\r\n 0,\r\n 1\r\n ];\r\n}\r\n\r\n/** Returns `a · b`. */\r\nexport function multiply(a: Mat4, b: Mat4): Mat4 {\r\n const out: Mat4 = new Array(16);\r\n\r\n for (let column = 0; column < 4; column += 1) {\r\n for (let row = 0; row < 4; row += 1) {\r\n let sum = 0;\r\n for (let k = 0; k < 4; k += 1) {\r\n sum += a[k * 4 + row] * b[column * 4 + k];\r\n }\r\n out[column * 4 + row] = sum;\r\n }\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/** Returns `a · b · c · …`, i.e. the rightmost matrix is applied to a point first. */\r\nexport function multiplyAll(...matrices: Mat4[]): Mat4 {\r\n return matrices.reduce<Mat4>((accumulator, matrix) => multiply(accumulator, matrix), identity());\r\n}\r\n\r\n/** Transforms a point (implicit w = 1) and performs the perspective divide. */\r\nexport function transformPoint(m: Mat4, [x, y, z]: Vector3): Vector3 {\r\n const w = m[3] * x + m[7] * y + m[11] * z + m[15];\r\n const divisor = w === 0 ? 1 : w;\r\n\r\n return [\r\n (m[0] * x + m[4] * y + m[8] * z + m[12]) / divisor,\r\n (m[1] * x + m[5] * y + m[9] * z + m[13]) / divisor,\r\n (m[2] * x + m[6] * y + m[10] * z + m[14]) / divisor\r\n ];\r\n}\r\n","import { degToRad, radToDeg, multiply, rotationAngleAxis, transformPoint } from './mat4.js';\r\nimport type { ParsedCamera, ParsedModel, Vector3, View } from './types.js';\r\n\r\n/**\r\n * 3DHOP's turntable trackball state: `[phi, theta, panX, panY, panZ, distance]`.\r\n *\r\n * `phi` (heading) and `theta` (elevation) are degrees; the pan and distance components are in\r\n * scene-radius units, i.e. already divided by the scene radius.\r\n */\r\nexport type TrackballState = [number, number, number, number, number, number];\r\n\r\n/**\r\n * The scene framing the presenter derives once a scene is loaded. Both values are needed to move\r\n * between world coordinates and the normalised space the trackball operates in.\r\n */\r\nexport type SceneFraming = {\r\n sceneCenter: Vector3;\r\n /** Reciprocal of the scene radius, as the presenter stores it. */\r\n sceneRadiusInv: number;\r\n};\r\n\r\nconst Y_AXIS: Vector3 = [0, 1, 0];\r\nconst NEGATIVE_X_AXIS: Vector3 = [-1, 0, 0];\r\n\r\n/** Below this, a vector's horizontal component carries no reliable heading. */\r\nconst DEGENERATE = 1e-9;\r\n\r\n/**\r\n * Converts a world-space camera to a trackball state. The exact inverse of {@link track2view}.\r\n *\r\n * Heading is recovered from the view direction, falling back to the up vector only when the camera\r\n * looks straight up or straight down and the direction has no horizontal component left to read.\r\n * The fallback is deliberately narrow: a camera parsed out of a manifest has no authored up vector\r\n * — {@link cameraToView} synthesises world up — so leaning on it for any merely steep view would\r\n * lose the heading entirely.\r\n *\r\n * Both branches use `atan2` rather than `asin`. An `asin` only spans a half-turn and needs a\r\n * quadrant correction, which is easy to get wrong below the horizon, and it divides by a cosine\r\n * that vanishes exactly where the input is already ill-conditioned.\r\n */\r\nexport function view2track(view: View, framing: SceneFraming): TrackballState {\r\n const { sceneCenter, sceneRadiusInv } = framing;\r\n\r\n const panX = (view.target[0] - sceneCenter[0]) * sceneRadiusInv;\r\n const panY = (view.target[1] - sceneCenter[1]) * sceneRadiusInv;\r\n const panZ = (view.target[2] - sceneCenter[2]) * sceneRadiusInv;\r\n\r\n const direction: Vector3 = [\r\n view.target[0] - view.position[0],\r\n view.target[1] - view.position[1],\r\n view.target[2] - view.position[2]\r\n ];\r\n const length = Math.hypot(direction[0], direction[1], direction[2]);\r\n\r\n if (length === 0) {\r\n return [0, 0, panX, panY, panZ, 0];\r\n }\r\n\r\n const unit: Vector3 = [direction[0] / length, direction[1] / length, direction[2] / length];\r\n const distance = length * sceneRadiusInv;\r\n\r\n const theta = radToDeg(-Math.asin(clamp(unit[1], -1, 1)));\r\n\r\n // `theta` comes from an `asin`, so it is always within [-90, 90] and `cos(theta)` is never\r\n // negative — the view-direction branch needs no sign correction. The up vector's horizontal part\r\n // is scaled by `sin(theta)` instead, which is negative below the horizon and would otherwise\r\n // mirror the heading.\r\n let phi: number;\r\n if (Math.hypot(unit[0], unit[2]) > DEGENERATE) {\r\n phi = radToDeg(Math.atan2(-unit[0], -unit[2]));\r\n } else if (view.up && Math.hypot(view.up[0], view.up[2]) > DEGENERATE) {\r\n const sign = theta >= 0 ? 1 : -1;\r\n phi = radToDeg(Math.atan2(sign * -view.up[0], sign * -view.up[2]));\r\n } else {\r\n // Looking straight down the Y axis with no usable up vector: every heading is equivalent.\r\n phi = 0;\r\n }\r\n\r\n return [phi, theta, panX, panY, panZ, distance];\r\n}\r\n\r\n/** Inverse of {@link view2track}. */\r\nexport function track2view(trackState: TrackballState, framing: SceneFraming, fov = 60): View {\r\n const { sceneCenter, sceneRadiusInv } = framing;\r\n const [phi, theta, panX, panY, panZ, normalizedDistance] = trackState;\r\n\r\n const target: Vector3 = [\r\n panX / sceneRadiusInv + sceneCenter[0],\r\n panY / sceneRadiusInv + sceneCenter[1],\r\n panZ / sceneRadiusInv + sceneCenter[2]\r\n ];\r\n\r\n // The camera sits at [0, 0, distance] tilted about -X and then swung about Y, relative to target.\r\n const orientation = multiply(\r\n rotationAngleAxis(degToRad(phi), Y_AXIS),\r\n rotationAngleAxis(degToRad(theta), NEGATIVE_X_AXIS)\r\n );\r\n\r\n const distance = normalizedDistance / sceneRadiusInv;\r\n const offset = transformPoint(orientation, [0, 0, distance]);\r\n const up = transformPoint(orientation, [0, 1, 0]);\r\n\r\n return {\r\n position: [offset[0] + target[0], offset[1] + target[1], offset[2] + target[2]],\r\n target,\r\n up,\r\n fov\r\n };\r\n}\r\n\r\n/**\r\n * Builds the world-space view a manifest camera describes.\r\n *\r\n * The look-at point is resolved in priority order: an explicit `lookAt` point, then the position of\r\n * the model the camera's `lookAt` refers to, then the scene centre.\r\n */\r\nexport function cameraToView(camera: ParsedCamera, framing: SceneFraming, models: readonly ParsedModel[] = []): View {\r\n let target: Vector3 = [...framing.sceneCenter];\r\n\r\n if (camera.target) {\r\n target = camera.target;\r\n } else if (camera.lookAtId) {\r\n const referenced = models.find((model) => model.id === camera.lookAtId);\r\n if (referenced) {\r\n target = referenced.position;\r\n }\r\n }\r\n\r\n return {\r\n position: camera.position,\r\n target,\r\n up: [0, 1, 0],\r\n // An orthographic camera has no field of view; 0 is the sentinel 3DHOP's own tooling uses.\r\n fov: camera.type === 'OrthographicCamera' ? 0 : camera.fov ?? 60\r\n };\r\n}\r\n\r\nexport type CameraAnnotationOptions = {\r\n /** Base for the generated `@id`s. */\r\n idBase?: string;\r\n label?: string;\r\n /** Id of the `Scene` the camera annotation targets. */\r\n sceneId?: string;\r\n};\r\n\r\nfunction round(value: number, decimals: number): number {\r\n const factor = 10 ** decimals;\r\n return Math.round(value * factor) / factor;\r\n}\r\n\r\n/**\r\n * Serialises a view as an IIIF camera annotation, ready to be pasted into a manifest's\r\n * `AnnotationPage`. The inverse of what {@link cameraToView} consumes.\r\n */\r\nexport function viewToCameraAnnotation(\r\n view: View,\r\n { idBase = 'https://example.org/iiif/3d', label, sceneId = 'https://example.org/iiif/scene/1' }: CameraAnnotationOptions = {}\r\n): Record<string, unknown> {\r\n const timestamp = Date.now();\r\n const isOrthographic = view.fov === 0;\r\n\r\n return {\r\n id: `${idBase}/camera_${timestamp}`,\r\n type: 'Annotation',\r\n motivation: ['painting'],\r\n body: [\r\n {\r\n id: `${idBase}/cameras/${timestamp}`,\r\n type: isOrthographic ? 'OrthographicCamera' : 'PerspectiveCamera',\r\n label: { en: [label ?? `Saved View ${new Date().toLocaleString()}`] },\r\n lookAt: {\r\n type: 'PointSelector',\r\n x: round(view.target[0], 3),\r\n y: round(view.target[1], 3),\r\n z: round(view.target[2], 3)\r\n },\r\n ...(isOrthographic ? {} : { fieldOfView: round(view.fov, 1) })\r\n }\r\n ],\r\n target: [\r\n {\r\n type: 'SpecificResource',\r\n source: { id: sceneId, type: 'Scene' },\r\n selector: [\r\n {\r\n type: 'PointSelector',\r\n x: round(view.position[0], 3),\r\n y: round(view.position[1], 3),\r\n z: round(view.position[2], 3)\r\n }\r\n ]\r\n }\r\n ]\r\n };\r\n}\r\n\r\nfunction clamp(value: number, min: number, max: number): number {\r\n return Math.min(max, Math.max(min, value));\r\n}\r\n","import type { LanguageMap, LocalizableValue } from './types.js';\r\n\r\n/**\r\n * Languages tried, in order, when the requested one is absent. Mirrors the behaviour of the\r\n * original viewer, which was authored for a Norwegian institution publishing in English.\r\n */\r\nexport const DEFAULT_FALLBACK_LANGUAGES = ['en', 'no', 'nb', 'nn'];\r\n\r\n/**\r\n * Resolves an IIIF language map to a single string.\r\n *\r\n * Tries `language`, then each of `fallbacks`, then any remaining language in the map. Returns an\r\n * empty string when nothing is available, so callers can render without null checks.\r\n *\r\n * Unlike the original implementation this takes the language as an argument rather than reading a\r\n * module-level global, so two viewers on one page can show different languages.\r\n */\r\nexport function resolveLanguageMap(\r\n value: LocalizableValue | undefined | null,\r\n language: string,\r\n fallbacks: readonly string[] = DEFAULT_FALLBACK_LANGUAGES\r\n): string {\r\n if (value == null) {\r\n return '';\r\n }\r\n\r\n if (typeof value === 'string') {\r\n return value;\r\n }\r\n\r\n if (typeof value !== 'object') {\r\n return '';\r\n }\r\n\r\n const pick = (tag: string): string | undefined => {\r\n const entry = (value as LanguageMap)[tag];\r\n if (entry == null) {\r\n return undefined;\r\n }\r\n if (Array.isArray(entry)) {\r\n return entry.length > 0 ? entry[0] : undefined;\r\n }\r\n return entry.length > 0 ? entry : undefined;\r\n };\r\n\r\n const direct = pick(language);\r\n if (direct !== undefined) {\r\n return direct;\r\n }\r\n\r\n for (const fallback of fallbacks) {\r\n if (fallback === language) {\r\n continue;\r\n }\r\n const candidate = pick(fallback);\r\n if (candidate !== undefined) {\r\n return candidate;\r\n }\r\n }\r\n\r\n for (const tag of Object.keys(value)) {\r\n const candidate = pick(tag);\r\n if (candidate !== undefined) {\r\n return candidate;\r\n }\r\n }\r\n\r\n return '';\r\n}\r\n\r\n/**\r\n * The properties IIIF defines as language maps. Only these are inspected for language tags.\r\n *\r\n * Recognising a language map by shape alone does not work: `{ \"id\": \"…\", \"type\": \"Model\",\r\n * \"format\": \"Nexus\" }` is also an object whose every value is a string, and treating it as one\r\n * offers \"id\", \"type\" and \"format\" to the user as languages.\r\n */\r\nconst LANGUAGE_MAP_KEYS = new Set(['label', 'value', 'summary']);\r\n\r\nfunction isLanguageMap(value: unknown): value is LanguageMap {\r\n if (value == null || typeof value !== 'object' || Array.isArray(value)) {\r\n return false;\r\n }\r\n\r\n const entries = Object.entries(value);\r\n return (\r\n entries.length > 0 &&\r\n entries.every(\r\n ([, entry]) =>\r\n typeof entry === 'string' || (Array.isArray(entry) && entry.every((item) => typeof item === 'string'))\r\n )\r\n );\r\n}\r\n\r\n/**\r\n * Collects every language tag used by the language maps reachable from `value`.\r\n *\r\n * IIIF uses the tag `none` for values that carry no language; it is a valid key but not a language\r\n * a user would ever choose, so it is excluded.\r\n */\r\nexport function collectLanguages(value: unknown, into: Set<string> = new Set()): Set<string> {\r\n if (value == null || typeof value !== 'object') {\r\n return into;\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n value.forEach((item) => collectLanguages(item, into));\r\n return into;\r\n }\r\n\r\n Object.entries(value as Record<string, unknown>).forEach(([key, entry]) => {\r\n if (LANGUAGE_MAP_KEYS.has(key) && isLanguageMap(entry)) {\r\n Object.keys(entry).forEach((tag) => {\r\n if (tag !== 'none') {\r\n into.add(tag);\r\n }\r\n });\r\n return;\r\n }\r\n\r\n collectLanguages(entry, into);\r\n });\r\n\r\n return into;\r\n}\r\n","import { collectLanguages, resolveLanguageMap } from './language.js';\r\nimport type {\r\n DiagnosticHandler,\r\n IIIFAnnotation,\r\n IIIFAnnotationBody,\r\n IIIFAnnotationTarget,\r\n IIIFManifest,\r\n IIIFModelSource,\r\n IIIFPointSelector,\r\n LocalizableValue,\r\n ParsedCamera,\r\n ParsedManifest,\r\n ParsedMetadata,\r\n ParsedModel,\r\n Vector3\r\n} from './types.js';\r\n\r\n/**\r\n * Ranking used when an annotation offers the same model in several formats. Nexus wins because it\r\n * is the only one 3DHOP streams progressively; glTF ranks last because 3DHOP cannot load it at all\r\n * and it is only ever a fallback worth reporting.\r\n */\r\nexport const FORMAT_PREFERENCE: Record<string, number> = {\r\n glb: 1,\r\n gltf: 1,\r\n 'model/gltf-binary': 1,\r\n 'model/gltf+json': 1,\r\n obj: 2,\r\n 'model/obj': 2,\r\n ply: 3,\r\n 'application/ply': 3,\r\n nexus: 4,\r\n nxz: 4,\r\n nxs: 4,\r\n 'application/octet-stream+nexus': 4\r\n};\r\n\r\nfunction first<T>(value: T | T[] | undefined | null): T | undefined {\r\n if (Array.isArray(value)) {\r\n return value.length > 0 ? value[0] : undefined;\r\n }\r\n return value ?? undefined;\r\n}\r\n\r\nfunction toVector3(selector: IIIFPointSelector | undefined): Vector3 {\r\n return [selector?.x ?? 0, selector?.y ?? 0, selector?.z ?? 0];\r\n}\r\n\r\n/** Reads the first `PointSelector` reachable from an annotation target. */\r\nfunction readPointSelector(target: IIIFAnnotation['target']): IIIFPointSelector | undefined {\r\n if (!target || typeof target === 'string') {\r\n return undefined;\r\n }\r\n\r\n const entry = first<IIIFAnnotationTarget>(target as IIIFAnnotationTarget | IIIFAnnotationTarget[]);\r\n const selector = first(entry?.selector);\r\n\r\n return selector?.type === 'PointSelector' || selector?.x !== undefined ? selector : undefined;\r\n}\r\n\r\n/**\r\n * A `SpecificResource` body always counts as a model here: in the IIIF 3D subset this package\r\n * supports it exists only to wrap a model with a transform list. Claiming it even when its `source`\r\n * is missing or empty means the annotation is reported as an unusable model rather than as an\r\n * unrecognised body type, which is the more useful message for what is really an authoring slip.\r\n */\r\nfunction isModelBody(body: IIIFAnnotationBody | undefined): boolean {\r\n return body?.type === 'Model' || body?.type === 'SpecificResource';\r\n}\r\n\r\nfunction isCameraBody(body: IIIFAnnotationBody | undefined): boolean {\r\n return body?.type === 'PerspectiveCamera' || body?.type === 'OrthographicCamera';\r\n}\r\n\r\n/** Picks the source this viewer can make the best use of. See {@link FORMAT_PREFERENCE}. */\r\nexport function selectBestSource(\r\n source: IIIFModelSource | IIIFModelSource[] | undefined\r\n): IIIFModelSource | undefined {\r\n if (!source) {\r\n return undefined;\r\n }\r\n if (!Array.isArray(source)) {\r\n return source;\r\n }\r\n if (source.length <= 1) {\r\n return source[0];\r\n }\r\n\r\n const rank = (candidate: IIIFModelSource) => FORMAT_PREFERENCE[(candidate.format ?? '').toLowerCase()] ?? 0;\r\n\r\n return [...source].sort((a, b) => rank(b) - rank(a))[0];\r\n}\r\n\r\n/**\r\n * Metadata labels lifted into dedicated fields, keyed by their lowercased English or Norwegian\r\n * label. Everything else stays in `metadata.fields` untouched.\r\n */\r\nconst KNOWN_FIELDS: Record<string, keyof ParsedMetadata> = {\r\n museum: 'museum',\r\n 'inventory number': 'inventory',\r\n inventarnummer: 'inventory',\r\n 'object id': 'objectId',\r\n 'objekt-id': 'objectId',\r\n 'measure unit': 'measureUnit',\r\n 'måleenhet': 'measureUnit',\r\n 'display unit': 'displayUnit',\r\n visningsenhet: 'displayUnit'\r\n};\r\n\r\nexport type ParseOptions = {\r\n /** Language used to resolve labels and values. Defaults to `'en'`. */\r\n language?: string;\r\n onDiagnostic?: DiagnosticHandler;\r\n};\r\n\r\nfunction parseMetadata(manifest: IIIFManifest, language: string): ParsedMetadata {\r\n const resolve = (value: LocalizableValue | undefined) => resolveLanguageMap(value, language);\r\n\r\n const metadata: ParsedMetadata = {\r\n label: resolve(manifest.label),\r\n fields: []\r\n };\r\n\r\n const summary = resolve(manifest.summary);\r\n if (summary) {\r\n metadata.summary = summary;\r\n }\r\n\r\n const attribution = resolve(manifest.requiredStatement?.value);\r\n if (attribution) {\r\n metadata.attribution = attribution;\r\n }\r\n\r\n (manifest.metadata ?? []).forEach((entry) => {\r\n const localizedLabel = resolve(entry.label);\r\n const value = resolve(entry.value);\r\n\r\n metadata.fields.push({ label: localizedLabel, value });\r\n\r\n // Recognised fields are matched on the English label so the mapping survives a language switch.\r\n const canonicalKey = resolveLanguageMap(entry.label, 'en').trim().toLowerCase();\r\n const known = KNOWN_FIELDS[canonicalKey];\r\n if (known) {\r\n (metadata as Record<string, unknown>)[known] = value;\r\n }\r\n });\r\n\r\n return metadata;\r\n}\r\n\r\nfunction parseModelAnnotation(\r\n annotation: IIIFAnnotation,\r\n body: IIIFAnnotationBody,\r\n onDiagnostic?: DiagnosticHandler\r\n): ParsedModel | undefined {\r\n let url: string | undefined;\r\n let format: string | undefined;\r\n let measureUnit: string | undefined;\r\n let transforms: ParsedModel['transforms'] = [];\r\n\r\n if (body.type === 'Model') {\r\n url = body.id;\r\n format = body.format;\r\n measureUnit = body.measureUnit;\r\n } else {\r\n const source = selectBestSource(body.source);\r\n if (!source) {\r\n onDiagnostic?.({\r\n level: 'warning',\r\n message: `Model annotation ${annotation.id ?? '(no id)'} has no usable source; skipping.`\r\n });\r\n return undefined;\r\n }\r\n url = source.id;\r\n format = source.format;\r\n measureUnit = source.measureUnit ?? body.measureUnit;\r\n\r\n if (Array.isArray(body.transform)) {\r\n transforms = body.transform;\r\n }\r\n }\r\n\r\n if (!url) {\r\n onDiagnostic?.({\r\n level: 'warning',\r\n message: `Model annotation ${annotation.id ?? '(no id)'} has no source URL; skipping.`\r\n });\r\n return undefined;\r\n }\r\n\r\n // 3DHOP only has loaders for Nexus and PLY. Anything else is reported here rather than failing\r\n // silently at load time with nothing on screen to explain it.\r\n const normalizedFormat = (format ?? '').toLowerCase();\r\n const unrenderable = normalizedFormat.includes('gltf')\r\n ? 'glTF'\r\n : normalizedFormat === 'glb' || normalizedFormat === 'model/gltf-binary'\r\n ? 'glTF'\r\n : normalizedFormat === 'obj' || normalizedFormat === 'model/obj'\r\n ? 'OBJ'\r\n : undefined;\r\n\r\n if (unrenderable) {\r\n onDiagnostic?.({\r\n level: 'warning',\r\n message: `Model ${url} is ${unrenderable}, which 3DHOP cannot render. Convert it to Nexus (.nxz) or PLY.`\r\n });\r\n }\r\n\r\n return {\r\n id: annotation.id ?? url,\r\n rawLabel: annotation.label,\r\n url,\r\n format,\r\n measureUnit,\r\n position: toVector3(readPointSelector(annotation.target)),\r\n transforms\r\n };\r\n}\r\n\r\nfunction parseCameraAnnotation(annotation: IIIFAnnotation, body: IIIFAnnotationBody): ParsedCamera {\r\n const camera: ParsedCamera = {\r\n id: body.id,\r\n type: body.type === 'OrthographicCamera' ? 'OrthographicCamera' : 'PerspectiveCamera',\r\n rawLabel: body.label ?? annotation.label,\r\n position: toVector3(readPointSelector(annotation.target))\r\n };\r\n\r\n const fov = body.fieldOfView ?? body.fov;\r\n if (typeof fov === 'number') {\r\n camera.fov = fov;\r\n }\r\n\r\n if (body.lookAt) {\r\n // `lookAt` is either a point in space or a reference to another annotation.\r\n if (body.lookAt.type === 'PointSelector' || body.lookAt.x !== undefined) {\r\n camera.target = toVector3(body.lookAt);\r\n }\r\n if (body.lookAt.id) {\r\n camera.lookAtId = body.lookAt.id;\r\n }\r\n }\r\n\r\n return camera;\r\n}\r\n\r\n/**\r\n * Parses an already-fetched IIIF manifest into the viewer-ready shape.\r\n *\r\n * Unrecognised annotations are reported through `onDiagnostic` and skipped rather than aborting\r\n * the parse, so a manifest with one bad entry still renders the rest.\r\n */\r\nexport function parseManifest(manifest: IIIFManifest, options: ParseOptions = {}): ParsedManifest {\r\n const { language = 'en', onDiagnostic } = options;\r\n\r\n const models: ParsedModel[] = [];\r\n const cameras: ParsedCamera[] = [];\r\n\r\n const scenes = (manifest.items ?? []).filter((item) => item?.type === 'Scene');\r\n\r\n if (scenes.length === 0) {\r\n onDiagnostic?.({\r\n level: 'warning',\r\n message: 'Manifest contains no Scene; there is nothing to render.'\r\n });\r\n }\r\n\r\n if (scenes.length > 1) {\r\n onDiagnostic?.({\r\n level: 'info',\r\n message: `Manifest contains ${scenes.length} scenes; all of them are merged into one view.`\r\n });\r\n }\r\n\r\n scenes.forEach((scene) => {\r\n (scene.items ?? []).forEach((page) => {\r\n if (page?.type !== 'AnnotationPage') {\r\n return;\r\n }\r\n\r\n (page.items ?? []).forEach((annotation) => {\r\n const body = first(annotation?.body);\r\n\r\n if (isModelBody(body)) {\r\n const model = parseModelAnnotation(annotation, body as IIIFAnnotationBody, onDiagnostic);\r\n if (model) {\r\n models.push(model);\r\n }\r\n return;\r\n }\r\n\r\n if (isCameraBody(body)) {\r\n cameras.push(parseCameraAnnotation(annotation, body as IIIFAnnotationBody));\r\n return;\r\n }\r\n\r\n onDiagnostic?.({\r\n level: 'info',\r\n message: `Skipping annotation ${annotation?.id ?? '(no id)'} of unsupported body type \"${\r\n body?.type ?? 'undefined'\r\n }\".`\r\n });\r\n });\r\n });\r\n });\r\n\r\n return {\r\n manifest,\r\n metadata: parseMetadata(manifest, language),\r\n models,\r\n cameras,\r\n languages: Array.from(collectLanguages(manifest)).sort()\r\n };\r\n}\r\n\r\nexport type LoadManifestOptions = ParseOptions & {\r\n signal?: AbortSignal;\r\n /** Injectable for testing and for consumers with their own HTTP stack. */\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\n/** Fetches a manifest by URL and parses it. Rejects on network, JSON, or HTTP-status failures. */\r\nexport async function loadManifest(url: string, options: LoadManifestOptions = {}): Promise<ParsedManifest> {\r\n const { signal, fetchImpl = fetch, ...parseOptions } = options;\r\n\r\n const response = await fetchImpl(url, { signal });\r\n if (!response.ok) {\r\n throw new Error(`Failed to load IIIF manifest (${response.status} ${response.statusText}): ${url}`);\r\n }\r\n\r\n let json: unknown;\r\n try {\r\n json = await response.json();\r\n } catch (cause) {\r\n const detail = cause instanceof Error ? cause.message : String(cause);\r\n throw new Error(`IIIF manifest at ${url} is not valid JSON: ${detail}`);\r\n }\r\n\r\n if (!json || typeof json !== 'object') {\r\n throw new Error(`IIIF manifest at ${url} is not a JSON object.`);\r\n }\r\n\r\n return parseManifest(json as IIIFManifest, parseOptions);\r\n}\r\n","import {\r\n degToRad,\r\n identity,\r\n multiply,\r\n rotationAngleAxis,\r\n scaling,\r\n translation,\r\n type Mat4\r\n} from './mat4.js';\r\nimport type { IIIFTransform, Vector3 } from './types.js';\r\n\r\n/**\r\n * Converts a single IIIF transform to a matrix.\r\n *\r\n * `RotateTransform` has two authored forms: per-axis Euler angles (`{ x, y, z }`, degrees) and a\r\n * single axis-angle (`{ axis: 'y', angle: 45 }`). The Euler form is composed Z, then Y, then X,\r\n * matching how 3DHOP's presenter interprets its own `rotation` triple.\r\n */\r\nexport function transformToMatrix(transform: IIIFTransform): Mat4 {\r\n switch (transform.type) {\r\n case 'ScaleTransform':\r\n return scaling([transform.x ?? 1, transform.y ?? 1, transform.z ?? 1]);\r\n\r\n case 'TranslateTransform':\r\n return translation([transform.x ?? 0, transform.y ?? 0, transform.z ?? 0]);\r\n\r\n case 'RotateTransform': {\r\n if (transform.axis !== undefined || transform.angle !== undefined) {\r\n const angle = degToRad(transform.angle ?? 0);\r\n switch (transform.axis) {\r\n case 'x':\r\n return rotationAngleAxis(angle, [1, 0, 0]);\r\n case 'y':\r\n return rotationAngleAxis(angle, [0, 1, 0]);\r\n case 'z':\r\n default:\r\n return rotationAngleAxis(angle, [0, 0, 1]);\r\n }\r\n }\r\n\r\n const rx = rotationAngleAxis(degToRad(transform.x ?? 0), [1, 0, 0]);\r\n const ry = rotationAngleAxis(degToRad(transform.y ?? 0), [0, 1, 0]);\r\n const rz = rotationAngleAxis(degToRad(transform.z ?? 0), [0, 0, 1]);\r\n return multiply(multiply(rz, ry), rx);\r\n }\r\n\r\n default:\r\n return identity();\r\n }\r\n}\r\n\r\n/**\r\n * Composes an ordered IIIF transform list into a single matrix.\r\n *\r\n * IIIF applies the transforms in the order they are listed, so the first entry acts on the model\r\n * first. In matrix terms that makes it the rightmost factor: `Tn · … · T2 · T1`.\r\n *\r\n * This is why the list must be composed rather than flattened into a single translation/rotation/\r\n * scale triple: with a flattened triple, `translate` then `rotate` and `rotate` then `translate`\r\n * produce the same result, when they should not.\r\n */\r\nexport function composeTransforms(transforms: readonly IIIFTransform[] | undefined): Mat4 {\r\n if (!transforms || transforms.length === 0) {\r\n return identity();\r\n }\r\n\r\n return transforms.reduce<Mat4>(\r\n (accumulated, transform) => multiply(transformToMatrix(transform), accumulated),\r\n identity()\r\n );\r\n}\r\n\r\nexport type ModelMatrixOptions = {\r\n /** Placement of the model in scene coordinates, from the annotation's `PointSelector`. */\r\n position?: Vector3;\r\n /** The annotation's `transform` list, in authored order. */\r\n transforms?: readonly IIIFTransform[];\r\n /**\r\n * Converts scene-level coordinates — the `PointSelector` and any `TranslateTransform` — from the\r\n * manifest's measure unit to the display unit.\r\n */\r\n sceneScale?: number;\r\n /**\r\n * Converts the mesh's own vertex coordinates from the unit that model is authored in to the\r\n * display unit. Differs from `sceneScale` only when the annotation overrides `measureUnit`.\r\n */\r\n geometryScale?: number;\r\n};\r\n\r\n/**\r\n * Builds the full model matrix for one IIIF model annotation.\r\n *\r\n * ```text\r\n * M = S(sceneScale) · T(position) · L · S(geometryScale / sceneScale)\r\n * ```\r\n *\r\n * Read right to left, that is: bring the mesh's vertices from their own unit into the manifest's\r\n * unit, apply the manifest's ordered transform list, place the result at the `PointSelector`\r\n * position, then convert the whole scene from the manifest's unit to the display unit. Keeping the\r\n * unit conversions on the outside and inside — rather than folding them into the instance scale —\r\n * is what makes positions and translations scale correctly alongside the geometry.\r\n *\r\n * When the model does not override `measureUnit`, `geometryScale / sceneScale` is 1 and the\r\n * innermost factor drops out.\r\n */\r\nexport function buildModelMatrix({\r\n position = [0, 0, 0],\r\n transforms,\r\n sceneScale = 1,\r\n geometryScale = sceneScale\r\n}: ModelMatrixOptions): Mat4 {\r\n const relativeGeometryScale = sceneScale === 0 ? 1 : geometryScale / sceneScale;\r\n\r\n let matrix = composeTransforms(transforms);\r\n\r\n if (relativeGeometryScale !== 1) {\r\n matrix = multiply(matrix, scaling([relativeGeometryScale, relativeGeometryScale, relativeGeometryScale]));\r\n }\r\n\r\n if (position[0] !== 0 || position[1] !== 0 || position[2] !== 0) {\r\n matrix = multiply(translation(position), matrix);\r\n }\r\n\r\n if (sceneScale !== 1) {\r\n matrix = multiply(scaling([sceneScale, sceneScale, sceneScale]), matrix);\r\n }\r\n\r\n return matrix;\r\n}\r\n","/**\r\n * Length units the viewer understands, expressed as their size in metres.\r\n *\r\n * `um` and `µm` are both accepted because manifests are hand-authored and the micro sign is\r\n * awkward to type.\r\n */\r\nexport const UNITS_IN_METRES: Record<string, number> = {\r\n km: 1000,\r\n m: 1,\r\n cm: 0.01,\r\n mm: 0.001,\r\n um: 0.000001,\r\n 'µm': 0.000001,\r\n nm: 0.000000001\r\n};\r\n\r\nexport type UnitName = keyof typeof UNITS_IN_METRES;\r\n\r\nexport function isKnownUnit(unit: string | undefined | null): boolean {\r\n return typeof unit === 'string' && Object.prototype.hasOwnProperty.call(UNITS_IN_METRES, unit.trim());\r\n}\r\n\r\n/**\r\n * Multiplier that converts a length in `fromUnit` to the same length in `toUnit`.\r\n *\r\n * Unknown units are treated as a factor of 1 rather than raising, matching the original viewer:\r\n * a manifest with a typo'd unit still renders, just unscaled.\r\n */\r\nexport function getUnitScaleFactor(fromUnit: string | undefined | null, toUnit: string | undefined | null): number {\r\n const from = typeof fromUnit === 'string' ? fromUnit.trim() : '';\r\n const to = typeof toUnit === 'string' ? toUnit.trim() : '';\r\n\r\n if (from === to) {\r\n return 1;\r\n }\r\n\r\n const fromFactor = UNITS_IN_METRES[from] ?? 1;\r\n const toFactor = UNITS_IN_METRES[to] ?? 1;\r\n\r\n return fromFactor / toFactor;\r\n}\r\n","import type { ModelDefinition, SceneRenderConfig, SceneSpaceConfig, TrackballConfig } from '@ikaros-arch/react-3dhop';\r\nimport { buildModelMatrix } from './transforms.js';\r\nimport { getUnitScaleFactor } from './units.js';\r\nimport type { ParsedManifest, ParsedModel } from './types.js';\r\n\r\n/** Unit assumed when a manifest declares none. Matches the original viewer's behaviour. */\r\nexport const DEFAULT_MEASURE_UNIT = 'mm';\r\n\r\nexport type SceneFromManifest = {\r\n models: Record<string, ModelDefinition>;\r\n space: SceneSpaceConfig;\r\n config: SceneRenderConfig;\r\n trackball: TrackballConfig;\r\n /** The unit the scene's coordinates are now in — what measurements should be labelled with. */\r\n displayUnit: string;\r\n measureUnit: string;\r\n /** Maps each generated instance key back to the IIIF annotation it came from. */\r\n instanceIdsByModelId: Record<string, string>;\r\n};\r\n\r\nexport type ToModelsOptions = {\r\n /** Overrides the manifest's `display unit` metadata. */\r\n displayUnit?: string;\r\n /** Merged over the defaults derived from the manifest. */\r\n space?: SceneSpaceConfig;\r\n config?: SceneRenderConfig;\r\n trackball?: TrackballConfig;\r\n};\r\n\r\nfunction sanitizeKey(value: string, fallback: string): string {\r\n const cleaned = value.replace(/[^A-Za-z0-9_-]/g, '_').replace(/_+/g, '_').replace(/^_+|_+$/g, '');\r\n return cleaned.length > 0 ? cleaned : fallback;\r\n}\r\n\r\n/**\r\n * Translates a parsed manifest into the props `<ThreeDHopViewer>` needs.\r\n *\r\n * Models sharing a source URL are collapsed onto a single mesh, so a manifest that places the same\r\n * object several times downloads it once.\r\n */\r\nexport function sceneFromManifest(parsed: ParsedManifest, options: ToModelsOptions = {}): SceneFromManifest {\r\n const measureUnit = parsed.metadata.measureUnit?.trim() || DEFAULT_MEASURE_UNIT;\r\n const displayUnit = options.displayUnit?.trim() || parsed.metadata.displayUnit?.trim() || measureUnit;\r\n\r\n const sceneScale = getUnitScaleFactor(measureUnit, displayUnit);\r\n\r\n const models: Record<string, ModelDefinition> = {};\r\n const instanceIdsByModelId: Record<string, string> = {};\r\n const meshIdByUrl = new Map<string, string>();\r\n const usedKeys = new Set<string>();\r\n\r\n parsed.models.forEach((model: ParsedModel, index: number) => {\r\n let meshId = meshIdByUrl.get(model.url);\r\n if (!meshId) {\r\n meshId = `iiif_mesh_${meshIdByUrl.size}`;\r\n meshIdByUrl.set(model.url, meshId);\r\n }\r\n\r\n let key = sanitizeKey(model.id, `iiif_model_${index}`);\r\n while (usedKeys.has(key)) {\r\n key = `${key}_${index}`;\r\n }\r\n usedKeys.add(key);\r\n\r\n const geometryScale = model.measureUnit\r\n ? getUnitScaleFactor(model.measureUnit, displayUnit)\r\n : sceneScale;\r\n\r\n models[key] = {\r\n url: model.url,\r\n meshId,\r\n // Pinned, because the scene builder otherwise derives the instance name from the entry key\r\n // (`model_<key>`) and the panels address instances by the name recorded below.\r\n instanceId: key,\r\n transform: {\r\n matrix: buildModelMatrix({\r\n position: model.position,\r\n transforms: model.transforms,\r\n sceneScale,\r\n geometryScale\r\n })\r\n },\r\n tags: ['SPECIMEN'],\r\n color: [0.5, 0.5, 0.5],\r\n backfaceColor: [0.5, 0.5, 0.5, 3.0],\r\n specularColor: [0.0, 0.0, 0.0, 256.0]\r\n };\r\n\r\n instanceIdsByModelId[model.id] = key;\r\n });\r\n\r\n const space: SceneSpaceConfig = {\r\n centerMode: 'scene',\r\n radiusMode: 'scene',\r\n cameraNearFar: [0.01, 5.0],\r\n ...options.space\r\n };\r\n\r\n const config: SceneRenderConfig = {\r\n pickedpointColor: [1.0, 0.0, 1.0],\r\n measurementColor: [0.5, 1.0, 0.5],\r\n showClippingPlanes: true,\r\n showClippingBorder: true,\r\n // A half-unit clipping border is invisible on a millimetre-scale object and enormous on a\r\n // metre-scale one, so the metre case gets its own value.\r\n clippingBorderSize: displayUnit === 'm' ? 0.002 : 0.5,\r\n clippingBorderColor: [0.0, 1.0, 1.0],\r\n ...options.config\r\n };\r\n\r\n const trackball: TrackballConfig = {\r\n type: 'TurntablePanTrackball',\r\n ...options.trackball,\r\n trackOptions: {\r\n startPhi: 15.0,\r\n startTheta: 15.0,\r\n startDistance: 2.0,\r\n minMaxPhi: [-180, 180],\r\n minMaxTheta: [-90.0, 90.0],\r\n minMaxDist: [0.1, 3.0],\r\n ...options.trackball?.trackOptions\r\n }\r\n };\r\n\r\n return { models, space, config, trackball, displayUnit, measureUnit, instanceIdsByModelId };\r\n}\r\n","import React, { useEffect, useMemo, useState } from 'react';\r\nimport { ThreeDHopViewer, type ThreeDHopViewerProps } from '@ikaros-arch/react-3dhop';\r\nimport { IIIFMultiManifestProvider, type IIIFMultiManifestStatus } from './multiManifestContext.js';\r\nimport { loadManifest, parseManifest } from './iiif/parser.js';\r\nimport { sceneFromManifests, type SceneFromManifests, type ToMultiModelsOptions } from './iiif/toMultiModels.js';\r\nimport type { Diagnostic, IIIFManifest, ParsedManifest, Vector3 } from './iiif/types.js';\r\n\r\nexport type IIIFMultiManifestViewerProps = Omit<ThreeDHopViewerProps, 'models' | 'modelUrl'> & {\r\n /** Manifest URLs to fetch, or already-fetched manifest objects, in display order. */\r\n manifests: Array<string | IIIFManifest>;\r\n /** Language used for labels. Defaults to the browser's, falling back to `'en'`. */\r\n language?: string;\r\n /** Overrides every manifest's `display unit`, converting them all onto one shared scale. */\r\n displayUnit?: string;\r\n /** Gap kept between adjacent manifests' layout circles, in the shared displayUnit. */\r\n gap?: number;\r\n /** Floor applied to every manifest's placement-spread radius. See `ToMultiModelsOptions.minRadius`. */\r\n minRadius?: number;\r\n /** Manifests per row before wrapping onto a new row. */\r\n columns?: number;\r\n /** Escape hatch: an explicit offset per manifest key, skipping automatic layout for that manifest. */\r\n layoutOverrides?: Record<string, Vector3>;\r\n onLoad?: (scene: SceneFromManifests) => void;\r\n /** Fired once per manifest that fails to load or parse. */\r\n onError?: (error: Error, sourceId: string) => void;\r\n onDiagnostic?: (diagnostic: Diagnostic) => void;\r\n /** Rendered instead of the viewer while the manifests are being fetched. */\r\n loadingFallback?: React.ReactNode;\r\n /** Rendered instead of the viewer when any manifest cannot be loaded or parsed. */\r\n errorFallback?: React.ReactNode | ((errors: Array<{ sourceId: string; error: Error }>) => React.ReactNode);\r\n};\r\n\r\nfunction defaultLanguage(): string {\r\n if (typeof navigator !== 'undefined' && navigator.language) {\r\n return navigator.language.split('-')[0];\r\n }\r\n return 'en';\r\n}\r\n\r\nfunction sourceIdFor(manifest: string | IIIFManifest, index: number): string {\r\n if (typeof manifest === 'string') {\r\n return manifest;\r\n }\r\n return manifest.id ?? `manifest_${index}`;\r\n}\r\n\r\n/**\r\n * Renders several IIIF 3D manifests together in one 3DHOP viewer, laid out side by side.\r\n *\r\n * A parallel component to `<IIIFViewer>` rather than an extension of it: this scene is a merge of\r\n * N independently-fetched manifests, and fails fast if any one of them can't be loaded — a mix of\r\n * \"some succeeded, some didn't\" isn't a state a shared scene can represent cleanly for v1.\r\n */\r\nexport const IIIFMultiManifestViewer: React.FC<IIIFMultiManifestViewerProps> = ({\r\n manifests,\r\n language: languageProp,\r\n displayUnit,\r\n gap,\r\n minRadius,\r\n columns,\r\n layoutOverrides,\r\n onLoad,\r\n onError,\r\n onDiagnostic,\r\n loadingFallback = null,\r\n errorFallback = null,\r\n space,\r\n config,\r\n trackball,\r\n children,\r\n ...viewerProps\r\n}) => {\r\n const [language, setLanguage] = useState(() => languageProp ?? defaultLanguage());\r\n const [status, setStatus] = useState<IIIFMultiManifestStatus>('idle');\r\n const [error, setError] = useState<Error | null>(null);\r\n const [parsedList, setParsedList] = useState<ParsedManifest[] | null>(null);\r\n const [diagnostics, setDiagnostics] = useState<Diagnostic[]>([]);\r\n\r\n useEffect(() => {\r\n if (languageProp) {\r\n setLanguage(languageProp);\r\n }\r\n }, [languageProp]);\r\n\r\n useEffect(() => {\r\n const controller = new AbortController();\r\n const collected: Diagnostic[] = [];\r\n const handleDiagnostic = (diagnostic: Diagnostic) => {\r\n collected.push(diagnostic);\r\n onDiagnostic?.(diagnostic);\r\n };\r\n\r\n setStatus('loading');\r\n\r\n Promise.all(\r\n manifests.map((manifest, index) => {\r\n if (typeof manifest === 'string') {\r\n return loadManifest(manifest, { language, signal: controller.signal, onDiagnostic: handleDiagnostic });\r\n }\r\n return Promise.resolve().then(() => parseManifest(manifest, { language, onDiagnostic: handleDiagnostic }));\r\n })\r\n )\r\n .then((results) => {\r\n if (controller.signal.aborted) {\r\n return;\r\n }\r\n setParsedList(results);\r\n setDiagnostics(collected);\r\n setStatus('ready');\r\n setError(null);\r\n })\r\n .catch((cause) => {\r\n if (controller.signal.aborted || (cause instanceof DOMException && cause.name === 'AbortError')) {\r\n return;\r\n }\r\n const normalized = cause instanceof Error ? cause : new Error(String(cause));\r\n setParsedList(null);\r\n setDiagnostics(collected);\r\n setStatus('error');\r\n setError(normalized);\r\n onError?.(normalized, 'unknown');\r\n });\r\n\r\n return () => controller.abort();\r\n // `language` is deliberately excluded: switching language re-resolves labels below rather than\r\n // re-fetching every manifest.\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [manifests, onDiagnostic, onError]);\r\n\r\n const sourceIds = useMemo(() => manifests.map(sourceIdFor), [manifests]);\r\n\r\n // Re-resolving is cheap and keeps a single source of truth for language handling.\r\n const localizedList = useMemo(() => {\r\n if (!parsedList) {\r\n return null;\r\n }\r\n return parsedList.map((parsed) => parseManifest(parsed.manifest, { language }));\r\n }, [parsedList, language]);\r\n\r\n const scene = useMemo(() => {\r\n if (!localizedList || localizedList.length === 0) {\r\n return null;\r\n }\r\n return sceneFromManifests(localizedList, sourceIds, {\r\n displayUnit,\r\n space,\r\n config,\r\n trackball,\r\n gap,\r\n minRadius,\r\n columns,\r\n layoutOverrides\r\n } satisfies ToMultiModelsOptions);\r\n }, [localizedList, sourceIds, displayUnit, space, config, trackball, gap, minRadius, columns, layoutOverrides]);\r\n\r\n useEffect(() => {\r\n if (status === 'ready' && scene) {\r\n onLoad?.(scene);\r\n }\r\n // Firing only when the merged scene changes; `onLoad` identity is the caller's concern.\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [status, scene]);\r\n\r\n if (status === 'error' && error) {\r\n return <>{typeof errorFallback === 'function' ? errorFallback([{ sourceId: 'unknown', error }]) : errorFallback}</>;\r\n }\r\n\r\n if (!scene) {\r\n return <>{loadingFallback}</>;\r\n }\r\n\r\n return (\r\n <ThreeDHopViewer\r\n {...viewerProps}\r\n models={scene.models}\r\n space={scene.space}\r\n config={scene.config}\r\n trackball={scene.trackball}\r\n measurementUnits={viewerProps.measurementUnits ?? scene.displayUnit}\r\n >\r\n <IIIFMultiManifestProvider status={status} error={error} diagnostics={diagnostics} scene={scene}>\r\n {children}\r\n </IIIFMultiManifestProvider>\r\n </ThreeDHopViewer>\r\n );\r\n};\r\n","import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\r\nimport { useThreeDHopViewer } from '@ikaros-arch/react-3dhop';\r\nimport type { Diagnostic, ParsedModel } from './iiif/types.js';\r\nimport type { SceneFromManifests } from './iiif/toMultiModels.js';\r\n\r\nexport type IIIFMultiManifestStatus = 'idle' | 'loading' | 'ready' | 'error';\r\n\r\nexport type ManifestGroup = {\r\n /** Unique within this scene. Pass to the `manifestKey` argument of the accessors below. */\r\n key: string;\r\n sourceId: string;\r\n label: string;\r\n models: ParsedModel[];\r\n};\r\n\r\nexport type IIIFMultiManifestContextValue = {\r\n status: IIIFMultiManifestStatus;\r\n error: Error | null;\r\n diagnostics: Diagnostic[];\r\n manifests: ManifestGroup[];\r\n measureUnit: string;\r\n displayUnit: string;\r\n /** Whether the presenter has established the scene, so instance toggles have something to act on. */\r\n isSceneReady: boolean;\r\n /** Shows or hides one model. `modelId` is the IIIF annotation id, scoped to `manifestKey`. */\r\n setModelVisible: (manifestKey: string, modelId: string, visible: boolean) => void;\r\n isModelVisible: (manifestKey: string, modelId: string) => boolean;\r\n toggleModelTransparency: (manifestKey: string, modelId: string) => void;\r\n isModelTransparent: (manifestKey: string, modelId: string) => boolean;\r\n};\r\n\r\nconst IIIFMultiManifestContext = createContext<IIIFMultiManifestContextValue | null>(null);\r\n\r\n/** Access the multi-manifest scene state. Must be called from inside an `<IIIFMultiManifestViewer>`. */\r\nexport function useIIIFMultiManifest(): IIIFMultiManifestContextValue {\r\n const value = useContext(IIIFMultiManifestContext);\r\n if (!value) {\r\n throw new Error('useIIIFMultiManifest must be used within an <IIIFMultiManifestViewer>.');\r\n }\r\n return value;\r\n}\r\n\r\nexport type IIIFMultiManifestProviderProps = {\r\n status: IIIFMultiManifestStatus;\r\n error: Error | null;\r\n diagnostics: Diagnostic[];\r\n scene: SceneFromManifests | null;\r\n children?: React.ReactNode;\r\n};\r\n\r\nfunction compositeKey(manifestKey: string, modelId: string): string {\r\n return `${manifestKey}::${modelId}`;\r\n}\r\n\r\n/**\r\n * Supplies multi-manifest scene state to descendants and bridges it to the live presenter.\r\n *\r\n * A deliberately smaller sibling of `<IIIFProvider>`: cameras, saved views, metadata and language\r\n * are per-manifest concepts that don't yet have a defined multi-manifest behaviour, so this only\r\n * covers per-model visibility/transparency, each scoped by the manifest it came from.\r\n */\r\nexport const IIIFMultiManifestProvider: React.FC<IIIFMultiManifestProviderProps> = ({\r\n status,\r\n error,\r\n diagnostics,\r\n scene,\r\n children\r\n}) => {\r\n const { presenter, registerSceneObserver } = useThreeDHopViewer();\r\n const [isSceneReady, setIsSceneReady] = useState(false);\r\n const [visibility, setVisibility] = useState<Record<string, boolean>>({});\r\n const [transparency, setTransparency] = useState<Record<string, boolean>>({});\r\n\r\n useEffect(() => {\r\n return registerSceneObserver(() => {\r\n setIsSceneReady(true);\r\n // A new scene resets every instance to its declared state.\r\n setVisibility({});\r\n setTransparency({});\r\n });\r\n }, [registerSceneObserver]);\r\n\r\n const instanceKeyFor = useCallback(\r\n (manifestKey: string, modelId: string) =>\r\n scene?.manifests.find((manifest) => manifest.key === manifestKey)?.instanceIdsByModelId[modelId],\r\n [scene]\r\n );\r\n\r\n const isModelVisible = useCallback(\r\n (manifestKey: string, modelId: string) => visibility[compositeKey(manifestKey, modelId)] ?? true,\r\n [visibility]\r\n );\r\n\r\n const setModelVisible = useCallback(\r\n (manifestKey: string, modelId: string, visible: boolean) => {\r\n const key = instanceKeyFor(manifestKey, modelId);\r\n const stateKey = compositeKey(manifestKey, modelId);\r\n if (!key || !presenter) {\r\n return;\r\n }\r\n if ((visibility[stateKey] ?? true) === visible) {\r\n return;\r\n }\r\n presenter.toggleInstanceVisibilityByName?.(key, true);\r\n setVisibility((current) => ({ ...current, [stateKey]: visible }));\r\n },\r\n [instanceKeyFor, presenter, visibility]\r\n );\r\n\r\n const isModelTransparent = useCallback(\r\n (manifestKey: string, modelId: string) => transparency[compositeKey(manifestKey, modelId)] ?? false,\r\n [transparency]\r\n );\r\n\r\n const toggleModelTransparency = useCallback(\r\n (manifestKey: string, modelId: string) => {\r\n const key = instanceKeyFor(manifestKey, modelId);\r\n const stateKey = compositeKey(manifestKey, modelId);\r\n if (!key || !presenter) {\r\n return;\r\n }\r\n presenter.toggleInstanceTransparencyByName?.(key, true);\r\n setTransparency((current) => ({ ...current, [stateKey]: !(current[stateKey] ?? false) }));\r\n },\r\n [instanceKeyFor, presenter]\r\n );\r\n\r\n const manifests = useMemo<ManifestGroup[]>(\r\n () =>\r\n scene?.manifests.map((manifest) => ({\r\n key: manifest.key,\r\n sourceId: manifest.sourceId,\r\n label: manifest.parsed.metadata.label,\r\n models: manifest.models\r\n })) ?? [],\r\n [scene]\r\n );\r\n\r\n const value = useMemo<IIIFMultiManifestContextValue>(\r\n () => ({\r\n status,\r\n error,\r\n diagnostics,\r\n manifests,\r\n measureUnit: scene?.measureUnit ?? 'mm',\r\n displayUnit: scene?.displayUnit ?? 'mm',\r\n isSceneReady,\r\n setModelVisible,\r\n isModelVisible,\r\n toggleModelTransparency,\r\n isModelTransparent\r\n }),\r\n [\r\n diagnostics,\r\n error,\r\n isModelTransparent,\r\n isModelVisible,\r\n isSceneReady,\r\n manifests,\r\n scene,\r\n setModelVisible,\r\n status,\r\n toggleModelTransparency\r\n ]\r\n );\r\n\r\n return <IIIFMultiManifestContext.Provider value={value}>{children}</IIIFMultiManifestContext.Provider>;\r\n};\r\n","import type { ModelDefinition, SceneRenderConfig, SceneSpaceConfig, TrackballConfig } from '@ikaros-arch/react-3dhop';\r\nimport { multiply, translation } from './mat4.js';\r\nimport { sceneFromManifest } from './toModels.js';\r\nimport type { ParsedManifest, ParsedModel, Vector3 } from './types.js';\r\n\r\nexport type ManifestSceneEntry = {\r\n /** Sanitized id for this manifest, unique within the merged scene. Used to namespace model keys\r\n * and to disambiguate per-manifest visibility/transparency state. */\r\n key: string;\r\n /** The manifest's own id/URL, kept for display/debugging. */\r\n sourceId: string;\r\n parsed: ParsedManifest;\r\n /** `parsed.models`, unmodified — for panels that need per-model metadata/labels. */\r\n models: ParsedModel[];\r\n /** IIIF annotation id -> globally-unique instance key in the merged `models` record. */\r\n instanceIdsByModelId: Record<string, string>;\r\n /** World-space offset applied to every model belonging to this manifest, in the shared displayUnit. */\r\n offset: Vector3;\r\n /** Placement-spread radius used to compute `offset`. Exposed for debugging/tests. */\r\n layoutRadius: number;\r\n};\r\n\r\nexport type SceneFromManifests = {\r\n models: Record<string, ModelDefinition>;\r\n space: SceneSpaceConfig;\r\n config: SceneRenderConfig;\r\n trackball: TrackballConfig;\r\n displayUnit: string;\r\n measureUnit: string;\r\n manifests: ManifestSceneEntry[];\r\n};\r\n\r\nexport type ToMultiModelsOptions = {\r\n /** Shared display unit every manifest is converted into. Defaults to the first manifest's. */\r\n displayUnit?: string;\r\n space?: SceneSpaceConfig;\r\n config?: SceneRenderConfig;\r\n trackball?: TrackballConfig;\r\n /** Gap kept between adjacent manifests' layout circles, in the shared displayUnit. Default 50. */\r\n gap?: number;\r\n /**\r\n * Floor applied to every manifest's placement-spread radius.\r\n *\r\n * There is no real mesh geometry size available at this point — meshes stream in later, and the\r\n * manifest only tells us where each annotation is *placed*, not how big it is. Most manifests\r\n * place a single model at the origin, which has a spread of 0; without this floor every such\r\n * manifest would land on top of the others. Tune this per dataset. Default 100.\r\n */\r\n minRadius?: number;\r\n /** Manifests per row before wrapping onto a new row. Default: unlimited (single row). */\r\n columns?: number;\r\n /** Escape hatch: an explicit offset per manifest key, skipping automatic layout for that manifest. */\r\n layoutOverrides?: Record<string, Vector3>;\r\n};\r\n\r\nfunction sanitizeKey(value: string, fallback: string): string {\r\n const cleaned = value.replace(/[^A-Za-z0-9_-]/g, '_').replace(/_+/g, '_').replace(/^_+|_+$/g, '');\r\n return cleaned.length > 0 ? cleaned : fallback;\r\n}\r\n\r\n/** Radius of the smallest circle centred on the centroid that covers every model's placement. */\r\nfunction placementSpreadRadius(models: ParsedModel[]): number {\r\n if (models.length <= 1) {\r\n return 0;\r\n }\r\n\r\n const centroid = models.reduce<Vector3>(\r\n (sum, model) => [sum[0] + model.position[0], sum[1] + model.position[1], sum[2] + model.position[2]],\r\n [0, 0, 0]\r\n );\r\n centroid[0] /= models.length;\r\n centroid[1] /= models.length;\r\n centroid[2] /= models.length;\r\n\r\n return models.reduce((max, model) => Math.max(max, Math.hypot(\r\n model.position[0] - centroid[0],\r\n model.position[1] - centroid[1],\r\n model.position[2] - centroid[2]\r\n )), 0);\r\n}\r\n\r\n/**\r\n * Arranges circles of the given radii on the X/Z plane, packed left-to-right and wrapped every\r\n * `columns` entries, each separated by `gap`. Returns one offset per input radius, re-centred so\r\n * the layout's bounding box sits on the origin (cosmetic only — `centerMode: 'scene'` reframes the\r\n * camera around the actual rendered geometry regardless).\r\n */\r\nexport function layoutManifests(radii: number[], options: { gap: number; columns: number }): Vector3[] {\r\n const { gap, columns } = options;\r\n const offsets: Vector3[] = [];\r\n\r\n let cursorX = 0;\r\n let cursorZ = 0;\r\n let rowMaxRadius = 0;\r\n let previousRadius = 0;\r\n\r\n radii.forEach((radius, index) => {\r\n const column = columns > 0 ? index % columns : index;\r\n if (column === 0 && index > 0) {\r\n cursorZ += rowMaxRadius + gap + radius;\r\n cursorX = 0;\r\n rowMaxRadius = 0;\r\n previousRadius = 0;\r\n } else if (index > 0) {\r\n cursorX += previousRadius + gap + radius;\r\n }\r\n\r\n offsets.push([cursorX, 0, cursorZ]);\r\n rowMaxRadius = Math.max(rowMaxRadius, radius);\r\n previousRadius = radius;\r\n });\r\n\r\n if (offsets.length === 0) {\r\n return offsets;\r\n }\r\n\r\n const minX = Math.min(...offsets.map((offset) => offset[0]));\r\n const maxX = Math.max(...offsets.map((offset) => offset[0]));\r\n const minZ = Math.min(...offsets.map((offset) => offset[2]));\r\n const maxZ = Math.max(...offsets.map((offset) => offset[2]));\r\n const centerX = (minX + maxX) / 2;\r\n const centerZ = (minZ + maxZ) / 2;\r\n\r\n return offsets.map(([x, y, z]) => [x - centerX, y, z - centerZ]);\r\n}\r\n\r\n/**\r\n * Translates several parsed manifests into the props `<ThreeDHopViewer>` needs for a single,\r\n * combined scene — one manifest per `ParsedManifest`, laid out side by side so their models don't\r\n * overlap even when their native coordinates coincide (see {@link ToMultiModelsOptions.minRadius}).\r\n *\r\n * Delegates all per-manifest unit conversion and matrix building to {@link sceneFromManifest}, then\r\n * re-keys and offsets the result so it can be merged into one flat model dictionary.\r\n */\r\nexport function sceneFromManifests(\r\n parsedList: ParsedManifest[],\r\n sourceIds: string[],\r\n options: ToMultiModelsOptions = {}\r\n): SceneFromManifests {\r\n const gap = options.gap ?? 50;\r\n const minRadius = options.minRadius ?? 100;\r\n const columns = options.columns ?? parsedList.length;\r\n const displayUnit =\r\n options.displayUnit?.trim() || parsedList[0]?.metadata.displayUnit?.trim() || parsedList[0]?.metadata.measureUnit?.trim() || 'mm';\r\n\r\n const perManifestScenes = parsedList.map((parsed) => sceneFromManifest(parsed, { displayUnit }));\r\n const radii = perManifestScenes.map((_, index) =>\r\n Math.max(minRadius, placementSpreadRadius(parsedList[index].models))\r\n );\r\n const autoOffsets = layoutManifests(radii, { gap, columns });\r\n\r\n const models: Record<string, ModelDefinition> = {};\r\n const usedManifestKeys = new Set<string>();\r\n const manifests: ManifestSceneEntry[] = [];\r\n\r\n parsedList.forEach((parsed, index) => {\r\n const sourceId = sourceIds[index] ?? `manifest_${index}`;\r\n let manifestKey = sanitizeKey(parsed.manifest.id ?? sourceId, `manifest_${index}`);\r\n while (usedManifestKeys.has(manifestKey)) {\r\n manifestKey = `${manifestKey}_${index}`;\r\n }\r\n usedManifestKeys.add(manifestKey);\r\n\r\n const offset = options.layoutOverrides?.[manifestKey] ?? autoOffsets[index] ?? [0, 0, 0];\r\n const offsetMatrix = translation(offset);\r\n\r\n const manifestScene = perManifestScenes[index];\r\n const instanceIdsByModelId: Record<string, string> = {};\r\n\r\n Object.entries(manifestScene.models).forEach(([localKey, modelDef]) => {\r\n const globalKey = `${manifestKey}__${localKey}`;\r\n models[globalKey] = {\r\n ...modelDef,\r\n meshId: `${manifestKey}__${modelDef.meshId}`,\r\n instanceId: globalKey,\r\n transform: {\r\n matrix: multiply(offsetMatrix, modelDef.transform!.matrix!)\r\n }\r\n };\r\n });\r\n\r\n Object.entries(manifestScene.instanceIdsByModelId).forEach(([modelId, localKey]) => {\r\n instanceIdsByModelId[modelId] = `${manifestKey}__${localKey}`;\r\n });\r\n\r\n manifests.push({\r\n key: manifestKey,\r\n sourceId,\r\n parsed,\r\n models: parsed.models,\r\n instanceIdsByModelId,\r\n offset,\r\n layoutRadius: radii[index]\r\n });\r\n });\r\n\r\n const space: SceneSpaceConfig = {\r\n centerMode: 'scene',\r\n radiusMode: 'scene',\r\n cameraNearFar: [0.01, 5.0],\r\n ...options.space\r\n };\r\n\r\n const config: SceneRenderConfig = {\r\n pickedpointColor: [1.0, 0.0, 1.0],\r\n measurementColor: [0.5, 1.0, 0.5],\r\n showClippingPlanes: true,\r\n showClippingBorder: true,\r\n clippingBorderSize: displayUnit === 'm' ? 0.002 : 0.5,\r\n clippingBorderColor: [0.0, 1.0, 1.0],\r\n ...options.config\r\n };\r\n\r\n const trackball: TrackballConfig = {\r\n type: 'TurntablePanTrackball',\r\n ...options.trackball,\r\n trackOptions: {\r\n startPhi: 15.0,\r\n startTheta: 15.0,\r\n startDistance: 2.0,\r\n minMaxPhi: [-180, 180],\r\n minMaxTheta: [-90.0, 90.0],\r\n minMaxDist: [0.1, 3.0],\r\n ...options.trackball?.trackOptions\r\n }\r\n };\r\n\r\n return { models, space, config, trackball, displayUnit, measureUnit: displayUnit, manifests };\r\n}\r\n","import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\r\nimport { loadCollection, parseCollection } from './iiif/collection.js';\r\nimport type { Diagnostic, IIIFCollection, ParsedCollectionItem } from './iiif/types.js';\r\n\r\nexport type IIIFCollectionStatus = 'idle' | 'loading' | 'ready' | 'error';\r\n\r\nexport type IIIFCollectionContextValue = {\r\n status: IIIFCollectionStatus;\r\n error: Error | null;\r\n diagnostics: Diagnostic[];\r\n label: string;\r\n summary: string | null;\r\n items: ParsedCollectionItem[];\r\n /** id of the manifest currently selected, e.g. to pass straight into `<IIIFViewer manifest={...}>`. */\r\n selectedId: string | null;\r\n selectedIndex: number;\r\n selectedItem: ParsedCollectionItem | null;\r\n selectManifest: (id: string) => void;\r\n next: () => void;\r\n previous: () => void;\r\n};\r\n\r\nconst IIIFCollectionContext = createContext<IIIFCollectionContextValue | null>(null);\r\n\r\n/** Access the IIIF collection state. Must be called from inside an `<IIIFCollectionProvider>`. */\r\nexport function useIIIFCollection(): IIIFCollectionContextValue {\r\n const value = useContext(IIIFCollectionContext);\r\n if (!value) {\r\n throw new Error('useIIIFCollection must be used within an <IIIFCollectionProvider>.');\r\n }\r\n return value;\r\n}\r\n\r\nexport type IIIFCollectionProviderProps = {\r\n /** A collection URL to fetch, or an already-fetched collection object. */\r\n collection: string | IIIFCollection;\r\n /** Language used for item labels. Defaults to `'en'`. */\r\n language?: string;\r\n /** Selects this manifest id once the collection loads, instead of the first item. */\r\n initialManifestId?: string;\r\n onLoad?: (items: ParsedCollectionItem[]) => void;\r\n onError?: (error: Error) => void;\r\n onDiagnostic?: (diagnostic: Diagnostic) => void;\r\n children?: React.ReactNode;\r\n};\r\n\r\n/**\r\n * Fetches and parses a IIIF Collection, and tracks which of its manifests is selected.\r\n *\r\n * Unlike `<IIIFViewer>`, this renders nothing itself — it only supplies `useIIIFCollection()` to\r\n * descendants, such as `<IIIFCollectionPicker>`, `<IIIFCollectionCarousel>`, and the `<IIIFViewer>`\r\n * that should render `selectedId`. Keeping it separate lets the collection state outlive remounts\r\n * of the viewer (e.g. `key={selectedId}`) that discard camera and visibility state per manifest.\r\n */\r\nexport const IIIFCollectionProvider: React.FC<IIIFCollectionProviderProps> = ({\r\n collection,\r\n language = 'en',\r\n initialManifestId,\r\n onLoad,\r\n onError,\r\n onDiagnostic,\r\n children\r\n}) => {\r\n const [status, setStatus] = useState<IIIFCollectionStatus>('idle');\r\n const [error, setError] = useState<Error | null>(null);\r\n const [label, setLabel] = useState('');\r\n const [summary, setSummary] = useState<string | null>(null);\r\n const [items, setItems] = useState<ParsedCollectionItem[]>([]);\r\n const [diagnostics, setDiagnostics] = useState<Diagnostic[]>([]);\r\n const [selectedId, setSelectedId] = useState<string | null>(initialManifestId ?? null);\r\n\r\n useEffect(() => {\r\n const controller = new AbortController();\r\n const collected: Diagnostic[] = [];\r\n const handleDiagnostic = (diagnostic: Diagnostic) => {\r\n collected.push(diagnostic);\r\n onDiagnostic?.(diagnostic);\r\n };\r\n\r\n const finish = (parsed: { label: string; summary?: string; items: ParsedCollectionItem[] }) => {\r\n if (controller.signal.aborted) {\r\n return;\r\n }\r\n setLabel(parsed.label);\r\n setSummary(parsed.summary ?? null);\r\n setItems(parsed.items);\r\n setDiagnostics(collected);\r\n setStatus('ready');\r\n setError(null);\r\n // Only defaults to the first item on the initial load; later reloads keep whatever the caller\r\n // (or the user, via selectManifest) already picked.\r\n setSelectedId((current) => current ?? parsed.items[0]?.id ?? null);\r\n onLoad?.(parsed.items);\r\n };\r\n\r\n const fail = (cause: unknown) => {\r\n if (controller.signal.aborted) {\r\n return;\r\n }\r\n const normalized = cause instanceof Error ? cause : new Error(String(cause));\r\n setStatus('error');\r\n setError(normalized);\r\n setDiagnostics(collected);\r\n onError?.(normalized);\r\n };\r\n\r\n setStatus('loading');\r\n\r\n if (typeof collection === 'string') {\r\n loadCollection(collection, { language, signal: controller.signal, onDiagnostic: handleDiagnostic })\r\n .then(finish)\r\n .catch((cause) => {\r\n if (cause instanceof DOMException && cause.name === 'AbortError') {\r\n return;\r\n }\r\n fail(cause);\r\n });\r\n } else {\r\n try {\r\n finish(parseCollection(collection, { language, onDiagnostic: handleDiagnostic }));\r\n } catch (cause) {\r\n fail(cause);\r\n }\r\n }\r\n\r\n return () => controller.abort();\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [collection, language, onLoad, onError]);\r\n\r\n const selectedIndex = useMemo(() => items.findIndex((item) => item.id === selectedId), [items, selectedId]);\r\n const selectedItem = selectedIndex >= 0 ? items[selectedIndex] : null;\r\n\r\n const selectManifest = useCallback((id: string) => {\r\n setSelectedId(id);\r\n }, []);\r\n\r\n const step = useCallback(\r\n (delta: number) => {\r\n if (items.length === 0) {\r\n return;\r\n }\r\n const base = selectedIndex >= 0 ? selectedIndex : 0;\r\n const nextIndex = (base + delta + items.length) % items.length;\r\n setSelectedId(items[nextIndex].id);\r\n },\r\n [items, selectedIndex]\r\n );\r\n\r\n const next = useCallback(() => step(1), [step]);\r\n const previous = useCallback(() => step(-1), [step]);\r\n\r\n const value = useMemo<IIIFCollectionContextValue>(\r\n () => ({\r\n status,\r\n error,\r\n diagnostics,\r\n label,\r\n summary,\r\n items,\r\n selectedId,\r\n selectedIndex,\r\n selectedItem,\r\n selectManifest,\r\n next,\r\n previous\r\n }),\r\n [status, error, diagnostics, label, summary, items, selectedId, selectedIndex, selectedItem, selectManifest, next, previous]\r\n );\r\n\r\n return <IIIFCollectionContext.Provider value={value}>{children}</IIIFCollectionContext.Provider>;\r\n};\r\n","import { resolveLanguageMap } from './language.js';\r\nimport type {\r\n DiagnosticHandler,\r\n IIIFCollection,\r\n IIIFCollectionItem,\r\n ParsedCollection,\r\n ParsedCollectionItem\r\n} from './types.js';\r\n\r\nexport type ParseCollectionOptions = {\r\n /** Language used to resolve labels and summaries. Defaults to `'en'`. */\r\n language?: string;\r\n onDiagnostic?: DiagnosticHandler;\r\n};\r\n\r\n/** The collection format only ever needs the first thumbnail; a carousel has no use for the rest. */\r\nfunction firstThumbnail(item: IIIFCollectionItem): string | undefined {\r\n const thumbnail = Array.isArray(item.thumbnail) ? item.thumbnail[0] : item.thumbnail;\r\n return thumbnail?.id;\r\n}\r\n\r\n/**\r\n * Parses an already-fetched IIIF Collection into the listing a picker or carousel needs.\r\n *\r\n * Items are expected to be `Manifest` references; anything else (e.g. a nested `Collection`) is\r\n * reported through `onDiagnostic` and skipped rather than aborting the parse.\r\n */\r\nexport function parseCollection(collection: IIIFCollection, options: ParseCollectionOptions = {}): ParsedCollection {\r\n const { language = 'en', onDiagnostic } = options;\r\n const resolve = (value: IIIFCollectionItem['label']) => resolveLanguageMap(value, language);\r\n\r\n const rawItems = collection.items ?? [];\r\n if (rawItems.length === 0) {\r\n onDiagnostic?.({ level: 'warning', message: 'Collection contains no items.' });\r\n }\r\n\r\n const items: ParsedCollectionItem[] = [];\r\n\r\n rawItems.forEach((item) => {\r\n if (item?.type && item.type !== 'Manifest') {\r\n onDiagnostic?.({\r\n level: 'info',\r\n message: `Skipping collection item ${item.id ?? '(no id)'} of unsupported type \"${item.type}\".`\r\n });\r\n return;\r\n }\r\n\r\n if (!item?.id) {\r\n onDiagnostic?.({ level: 'warning', message: 'Collection item has no id; skipping.' });\r\n return;\r\n }\r\n\r\n items.push({\r\n id: item.id,\r\n label: resolve(item.label) || item.id,\r\n summary: resolve(item.summary) || undefined,\r\n thumbnail: firstThumbnail(item)\r\n });\r\n });\r\n\r\n return {\r\n collection,\r\n label: resolve(collection.label) || 'Untitled Collection',\r\n summary: resolve(collection.summary) || undefined,\r\n items\r\n };\r\n}\r\n\r\nexport type LoadCollectionOptions = ParseCollectionOptions & {\r\n signal?: AbortSignal;\r\n /** Injectable for testing and for consumers with their own HTTP stack. */\r\n fetchImpl?: typeof fetch;\r\n};\r\n\r\n/** Fetches a collection by URL and parses it. Rejects on network, JSON, or HTTP-status failures. */\r\nexport async function loadCollection(url: string, options: LoadCollectionOptions = {}): Promise<ParsedCollection> {\r\n const { signal, fetchImpl = fetch, ...parseOptions } = options;\r\n\r\n const response = await fetchImpl(url, { signal });\r\n if (!response.ok) {\r\n throw new Error(`Failed to load IIIF collection (${response.status} ${response.statusText}): ${url}`);\r\n }\r\n\r\n let json: unknown;\r\n try {\r\n json = await response.json();\r\n } catch (cause) {\r\n const detail = cause instanceof Error ? cause.message : String(cause);\r\n throw new Error(`IIIF collection at ${url} is not valid JSON: ${detail}`);\r\n }\r\n\r\n if (!json || typeof json !== 'object') {\r\n throw new Error(`IIIF collection at ${url} is not a JSON object.`);\r\n }\r\n\r\n return parseCollection(json as IIIFCollection, parseOptions);\r\n}\r\n","import React from 'react';\r\nimport { useIIIFCollection } from '../collectionContext.js';\r\n\r\nexport type IIIFCollectionPickerProps = {\r\n label?: React.ReactNode;\r\n emptyMessage?: React.ReactNode;\r\n className?: string;\r\n labelClassName?: string;\r\n selectClassName?: string;\r\n};\r\n\r\n/** A `<select>` of every manifest in the collection. Pass the selected id straight to `<IIIFViewer>`. */\r\nexport const IIIFCollectionPicker: React.FC<IIIFCollectionPickerProps> = ({\r\n label = 'Object',\r\n emptyMessage = 'No objects in this collection.',\r\n className = 'iiif-collection-picker',\r\n labelClassName = 'iiif-collection-picker__label',\r\n selectClassName = 'iiif-collection-picker__select'\r\n}) => {\r\n const { items, selectedId, selectManifest, status } = useIIIFCollection();\r\n\r\n if (status === 'ready' && items.length === 0) {\r\n return <p className={`${className}__empty`}>{emptyMessage}</p>;\r\n }\r\n\r\n return (\r\n <div className={className}>\r\n {label ? (\r\n <label className={labelClassName} htmlFor=\"iiif-collection-select\">\r\n {label}\r\n </label>\r\n ) : null}\r\n <select\r\n id=\"iiif-collection-select\"\r\n className={selectClassName}\r\n value={selectedId ?? ''}\r\n onChange={(event) => selectManifest(event.target.value)}\r\n >\r\n {items.map((item) => (\r\n <option key={item.id} value={item.id}>\r\n {item.label}\r\n </option>\r\n ))}\r\n </select>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport { useIIIFCollection } from '../collectionContext.js';\r\n\r\nexport type IIIFCollectionCarouselProps = {\r\n previousLabel?: string;\r\n nextLabel?: string;\r\n emptyMessage?: React.ReactNode;\r\n className?: string;\r\n trackClassName?: string;\r\n itemClassName?: string;\r\n activeItemClassName?: string;\r\n thumbnailClassName?: string;\r\n labelClassName?: string;\r\n controlClassName?: string;\r\n};\r\n\r\n/** A scrollable strip of thumbnails, one per manifest in the collection, with prev/next controls. */\r\nexport const IIIFCollectionCarousel: React.FC<IIIFCollectionCarouselProps> = ({\r\n previousLabel = 'Previous object',\r\n nextLabel = 'Next object',\r\n emptyMessage = 'No objects in this collection.',\r\n className = 'iiif-carousel',\r\n trackClassName = 'iiif-carousel__track',\r\n itemClassName = 'iiif-carousel__item',\r\n activeItemClassName = 'iiif-carousel__item--active',\r\n thumbnailClassName = 'iiif-carousel__thumbnail',\r\n labelClassName = 'iiif-carousel__label',\r\n controlClassName = 'iiif-carousel__control'\r\n}) => {\r\n const { items, selectedId, selectManifest, next, previous, status } = useIIIFCollection();\r\n\r\n if (status === 'ready' && items.length === 0) {\r\n return <p className={`${className}__empty`}>{emptyMessage}</p>;\r\n }\r\n\r\n return (\r\n <div className={className}>\r\n <button\r\n type=\"button\"\r\n className={controlClassName}\r\n onClick={previous}\r\n disabled={items.length < 2}\r\n aria-label={previousLabel}\r\n >\r\n ‹\r\n </button>\r\n <ul className={trackClassName}>\r\n {items.map((item) => {\r\n const active = item.id === selectedId;\r\n return (\r\n <li key={item.id} className={active ? `${itemClassName} ${activeItemClassName}` : itemClassName}>\r\n <button type=\"button\" onClick={() => selectManifest(item.id)} aria-current={active || undefined}>\r\n {item.thumbnail ? (\r\n <img className={thumbnailClassName} src={item.thumbnail} alt=\"\" loading=\"lazy\" />\r\n ) : (\r\n <span className={thumbnailClassName} aria-hidden=\"true\" />\r\n )}\r\n <span className={labelClassName}>{item.label}</span>\r\n </button>\r\n </li>\r\n );\r\n })}\r\n </ul>\r\n <button\r\n type=\"button\"\r\n className={controlClassName}\r\n onClick={next}\r\n disabled={items.length < 2}\r\n aria-label={nextLabel}\r\n >\r\n ›\r\n </button>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport { useIIIFManifest } from '../context.js';\r\n\r\nexport type IIIFSummaryProps = {\r\n className?: string;\r\n summaryClassName?: string;\r\n attributionClassName?: string;\r\n};\r\n\r\n/**\r\n * The manifest's `summary` and the attribution from its `requiredStatement`.\r\n *\r\n * Renders nothing when the manifest supplies neither.\r\n */\r\nexport const IIIFSummary: React.FC<IIIFSummaryProps> = ({\r\n className = 'iiif-summary',\r\n summaryClassName = 'iiif-summary__text',\r\n attributionClassName = 'iiif-summary__attribution'\r\n}) => {\r\n const { metadata } = useIIIFManifest();\r\n\r\n const summary = metadata?.summary;\r\n const attribution = metadata?.attribution;\r\n\r\n if (!summary && !attribution) {\r\n return null;\r\n }\r\n\r\n return (\r\n <div className={className}>\r\n {summary ? <p className={summaryClassName}>{summary}</p> : null}\r\n {attribution ? (\r\n <p className={attributionClassName}>\r\n <small>{attribution}</small>\r\n </p>\r\n ) : null}\r\n </div>\r\n );\r\n};\r\n","import React, { useMemo } from 'react';\r\nimport { useIIIFManifest } from '../context.js';\r\nimport type { ParsedMetadata } from '../iiif/types.js';\r\n\r\n/**\r\n * Fields shown first, in this order, when the manifest provides them. Anything else the manifest\r\n * carries follows underneath, in manifest order.\r\n */\r\nconst PRIORITY_FIELDS: Array<{ key: keyof ParsedMetadata; label: string }> = [\r\n { key: 'label', label: 'Title' },\r\n { key: 'museum', label: 'Museum' },\r\n { key: 'inventory', label: 'Inventory' },\r\n { key: 'objectId', label: 'Object ID' },\r\n { key: 'measureUnit', label: 'Measure unit' },\r\n { key: 'displayUnit', label: 'Display unit' },\r\n { key: 'summary', label: 'Description' },\r\n { key: 'attribution', label: 'Attribution' }\r\n];\r\n\r\nexport type IIIFMetadataPanelProps = {\r\n heading?: React.ReactNode;\r\n /** Shown when the manifest carries no metadata at all. */\r\n emptyMessage?: React.ReactNode;\r\n /** Hides the metadata entries that are already shown as priority fields. */\r\n hideDuplicateFields?: boolean;\r\n className?: string;\r\n headingClassName?: string;\r\n tableClassName?: string;\r\n labelClassName?: string;\r\n valueClassName?: string;\r\n};\r\n\r\n/** The manifest's descriptive metadata as a definition table. */\r\nexport const IIIFMetadataPanel: React.FC<IIIFMetadataPanelProps> = ({\r\n heading = 'Metadata',\r\n emptyMessage = 'No metadata available',\r\n hideDuplicateFields = true,\r\n className = 'iiif-metadata',\r\n headingClassName = 'iiif-metadata__heading',\r\n tableClassName = 'iiif-metadata__table',\r\n labelClassName = 'iiif-metadata__label',\r\n valueClassName = 'iiif-metadata__value'\r\n}) => {\r\n const { metadata } = useIIIFManifest();\r\n\r\n const rows = useMemo(() => {\r\n if (!metadata) {\r\n return [];\r\n }\r\n\r\n const entries: Array<{ label: string; value: string }> = [];\r\n const shown = new Set<string>();\r\n\r\n PRIORITY_FIELDS.forEach(({ key, label }) => {\r\n const value = metadata[key];\r\n if (typeof value === 'string' && value.length > 0) {\r\n entries.push({ label, value });\r\n shown.add(value);\r\n }\r\n });\r\n\r\n metadata.fields.forEach((field) => {\r\n if (!field.value) {\r\n return;\r\n }\r\n if (hideDuplicateFields && shown.has(field.value)) {\r\n return;\r\n }\r\n entries.push(field);\r\n });\r\n\r\n return entries;\r\n }, [hideDuplicateFields, metadata]);\r\n\r\n return (\r\n <section className={className}>\r\n {heading ? <h2 className={headingClassName}>{heading}</h2> : null}\r\n {rows.length === 0 ? (\r\n <p className=\"iiif-metadata__empty\">{emptyMessage}</p>\r\n ) : (\r\n <table className={tableClassName}>\r\n <tbody>\r\n {rows.map((row, index) => (\r\n <tr key={`${row.label}-${index}`}>\r\n <th scope=\"row\" className={labelClassName}>\r\n {row.label}\r\n </th>\r\n <td className={valueClassName}>{row.value}</td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n )}\r\n </section>\r\n );\r\n};\r\n","import React from 'react';\r\nimport { useIIIFManifest } from '../context.js';\r\nimport type { ParsedModel } from '../iiif/types.js';\r\n\r\n/** Falls back to the source filename when an annotation carries no label. */\r\nfunction fallbackName(model: ParsedModel, index: number): string {\r\n const filename = model.url.split('/').pop() ?? '';\r\n const stem = filename.split('?')[0].split('#')[0].split('.')[0];\r\n return stem || `Model ${index + 1}`;\r\n}\r\n\r\nexport type IIIFModelsPanelProps = {\r\n heading?: React.ReactNode;\r\n emptyMessage?: React.ReactNode;\r\n visibilityLabel?: string;\r\n transparencyLabel?: string;\r\n className?: string;\r\n headingClassName?: string;\r\n listClassName?: string;\r\n itemClassName?: string;\r\n};\r\n\r\n/** Per-model visibility and transparency toggles, one row per model annotation. */\r\nexport const IIIFModelsPanel: React.FC<IIIFModelsPanelProps> = ({\r\n heading = 'Models',\r\n emptyMessage = 'No models in manifest',\r\n visibilityLabel = 'Show model',\r\n transparencyLabel = 'Toggle transparency',\r\n className = 'iiif-models',\r\n headingClassName = 'iiif-models__heading',\r\n listClassName = 'iiif-models__list',\r\n itemClassName = 'iiif-models__item'\r\n}) => {\r\n const { models, localize, isModelVisible, setModelVisible, isModelTransparent, toggleModelTransparency } =\r\n useIIIFManifest();\r\n\r\n return (\r\n <section className={className}>\r\n {heading ? <h2 className={headingClassName}>{heading}</h2> : null}\r\n {models.length === 0 ? (\r\n <p className=\"iiif-models__empty\">{emptyMessage}</p>\r\n ) : (\r\n <ul className={listClassName}>\r\n {models.map((model, index) => {\r\n const name = localize(model.rawLabel) || fallbackName(model, index);\r\n const visible = isModelVisible(model.id);\r\n const transparent = isModelTransparent(model.id);\r\n\r\n return (\r\n <li key={model.id} className={itemClassName}>\r\n <label className=\"iiif-models__visibility\">\r\n <input\r\n type=\"checkbox\"\r\n checked={visible}\r\n onChange={(event) => setModelVisible(model.id, event.target.checked)}\r\n aria-label={`${visibilityLabel}: ${name}`}\r\n />\r\n <span className=\"iiif-models__name\">{name}</span>\r\n </label>\r\n <label className=\"iiif-models__transparency\">\r\n <input\r\n type=\"checkbox\"\r\n checked={transparent}\r\n onChange={() => toggleModelTransparency(model.id)}\r\n aria-label={`${transparencyLabel}: ${name}`}\r\n />\r\n <span className=\"iiif-models__transparency-text\">{transparencyLabel}</span>\r\n </label>\r\n </li>\r\n );\r\n })}\r\n </ul>\r\n )}\r\n </section>\r\n );\r\n};\r\n","import React from 'react';\r\nimport { useIIIFMultiManifest } from '../multiManifestContext.js';\r\nimport type { ParsedModel } from '../iiif/types.js';\r\n\r\n/** Falls back to the source filename when an annotation carries no label. */\r\nfunction fallbackName(model: ParsedModel, index: number): string {\r\n const filename = model.url.split('/').pop() ?? '';\r\n const stem = filename.split('?')[0].split('#')[0].split('.')[0];\r\n return stem || `Model ${index + 1}`;\r\n}\r\n\r\nexport type IIIFMultiManifestModelsPanelProps = {\r\n heading?: React.ReactNode;\r\n emptyMessage?: React.ReactNode;\r\n visibilityLabel?: string;\r\n transparencyLabel?: string;\r\n className?: string;\r\n headingClassName?: string;\r\n groupClassName?: string;\r\n groupHeadingClassName?: string;\r\n listClassName?: string;\r\n itemClassName?: string;\r\n};\r\n\r\n/** Per-model visibility and transparency toggles, grouped under a heading per source manifest. */\r\nexport const IIIFMultiManifestModelsPanel: React.FC<IIIFMultiManifestModelsPanelProps> = ({\r\n heading = 'Models',\r\n emptyMessage = 'No manifests selected',\r\n visibilityLabel = 'Show model',\r\n transparencyLabel = 'Toggle transparency',\r\n className = 'iiif-multi-models',\r\n headingClassName = 'iiif-multi-models__heading',\r\n groupClassName = 'iiif-multi-models__group',\r\n groupHeadingClassName = 'iiif-multi-models__group-heading',\r\n listClassName = 'iiif-multi-models__list',\r\n itemClassName = 'iiif-multi-models__item'\r\n}) => {\r\n const { manifests, isModelVisible, setModelVisible, isModelTransparent, toggleModelTransparency } =\r\n useIIIFMultiManifest();\r\n\r\n return (\r\n <section className={className}>\r\n {heading ? <h2 className={headingClassName}>{heading}</h2> : null}\r\n {manifests.length === 0 ? (\r\n <p className=\"iiif-multi-models__empty\">{emptyMessage}</p>\r\n ) : (\r\n manifests.map((manifest) => (\r\n <div key={manifest.key} className={groupClassName}>\r\n <h3 className={groupHeadingClassName}>{manifest.label}</h3>\r\n <ul className={listClassName}>\r\n {manifest.models.map((model, index) => {\r\n const name = model.rawLabel && typeof model.rawLabel === 'string' ? model.rawLabel : fallbackName(model, index);\r\n const visible = isModelVisible(manifest.key, model.id);\r\n const transparent = isModelTransparent(manifest.key, model.id);\r\n\r\n return (\r\n <li key={model.id} className={itemClassName}>\r\n <label className=\"iiif-multi-models__visibility\">\r\n <input\r\n type=\"checkbox\"\r\n checked={visible}\r\n onChange={(event) => setModelVisible(manifest.key, model.id, event.target.checked)}\r\n aria-label={`${visibilityLabel}: ${name}`}\r\n />\r\n <span className=\"iiif-multi-models__name\">{name}</span>\r\n </label>\r\n <label className=\"iiif-multi-models__transparency\">\r\n <input\r\n type=\"checkbox\"\r\n checked={transparent}\r\n onChange={() => toggleModelTransparency(manifest.key, model.id)}\r\n aria-label={`${transparencyLabel}: ${name}`}\r\n />\r\n <span className=\"iiif-multi-models__transparency-text\">{transparencyLabel}</span>\r\n </label>\r\n </li>\r\n );\r\n })}\r\n </ul>\r\n </div>\r\n ))\r\n )}\r\n </section>\r\n );\r\n};\r\n","import React, { useState } from 'react';\r\nimport { useIIIFManifest } from '../context.js';\r\n\r\nexport type IIIFSavedViewsPanelProps = {\r\n heading?: React.ReactNode;\r\n emptyMessage?: React.ReactNode;\r\n /** Hides the \"save current view\" control, leaving only the manifest's own cameras. */\r\n hideSaveControl?: boolean;\r\n saveLabel?: string;\r\n /**\r\n * Called with the IIIF camera annotation for the current view. When omitted, the annotation is\r\n * shown in the panel so it can be copied into a manifest.\r\n */\r\n onSaveView?: (annotation: Record<string, unknown>) => void;\r\n className?: string;\r\n headingClassName?: string;\r\n listClassName?: string;\r\n buttonClassName?: string;\r\n};\r\n\r\n/** Buttons for the manifest's camera annotations, plus a way to capture the current view. */\r\nexport const IIIFSavedViewsPanel: React.FC<IIIFSavedViewsPanelProps> = ({\r\n heading = 'Saved views',\r\n emptyMessage = 'No saved views in manifest',\r\n hideSaveControl = false,\r\n saveLabel = 'Save current view',\r\n onSaveView,\r\n className = 'iiif-views',\r\n headingClassName = 'iiif-views__heading',\r\n listClassName = 'iiif-views__list',\r\n buttonClassName = 'iiif-views__button'\r\n}) => {\r\n const { cameras, localize, goToCamera, saveCurrentView, isSceneReady } = useIIIFManifest();\r\n const [captured, setCaptured] = useState<string | null>(null);\r\n\r\n const handleSave = () => {\r\n const annotation = saveCurrentView();\r\n if (!annotation) {\r\n return;\r\n }\r\n if (onSaveView) {\r\n onSaveView(annotation);\r\n return;\r\n }\r\n setCaptured(JSON.stringify(annotation, null, 2));\r\n };\r\n\r\n return (\r\n <section className={className}>\r\n {heading ? <h2 className={headingClassName}>{heading}</h2> : null}\r\n\r\n {cameras.length === 0 ? (\r\n <p className=\"iiif-views__empty\">{emptyMessage}</p>\r\n ) : (\r\n <ul className={listClassName}>\r\n {cameras.map((camera, index) => (\r\n <li key={camera.id ?? index}>\r\n <button\r\n type=\"button\"\r\n className={buttonClassName}\r\n onClick={() => goToCamera(index)}\r\n disabled={!isSceneReady}\r\n >\r\n {localize(camera.rawLabel) || `View ${index + 1}`}\r\n </button>\r\n </li>\r\n ))}\r\n </ul>\r\n )}\r\n\r\n {hideSaveControl ? null : (\r\n <button\r\n type=\"button\"\r\n className=\"iiif-views__save\"\r\n onClick={handleSave}\r\n disabled={!isSceneReady}\r\n >\r\n {saveLabel}\r\n </button>\r\n )}\r\n\r\n {captured ? (\r\n <pre className=\"iiif-views__output\">\r\n <code>{captured}</code>\r\n </pre>\r\n ) : null}\r\n </section>\r\n );\r\n};\r\n","import React from 'react';\r\nimport { useIIIFManifest } from '../context.js';\r\n\r\n/** Endonyms for the languages this collection publishes in; anything else falls back to the tag. */\r\nexport const LANGUAGE_NAMES: Record<string, string> = {\r\n en: 'English',\r\n no: 'Norsk',\r\n nn: 'Nynorsk',\r\n nb: 'Bokmål',\r\n de: 'Deutsch',\r\n fr: 'Français',\r\n es: 'Español',\r\n it: 'Italiano',\r\n se: 'Davvisámegiella'\r\n};\r\n\r\nexport type IIIFLanguageSwitcherProps = {\r\n label?: React.ReactNode;\r\n /** Merged over {@link LANGUAGE_NAMES} to name additional languages. */\r\n languageNames?: Record<string, string>;\r\n /** Renders the switcher even when the manifest offers only one language. */\r\n alwaysShow?: boolean;\r\n className?: string;\r\n labelClassName?: string;\r\n selectClassName?: string;\r\n};\r\n\r\n/**\r\n * Switches the language used for labels and metadata.\r\n *\r\n * Hidden when the manifest has one language or fewer, since there is nothing to choose between.\r\n */\r\nexport const IIIFLanguageSwitcher: React.FC<IIIFLanguageSwitcherProps> = ({\r\n label = 'Language',\r\n languageNames,\r\n alwaysShow = false,\r\n className = 'iiif-language',\r\n labelClassName = 'iiif-language__label',\r\n selectClassName = 'iiif-language__select'\r\n}) => {\r\n const { languages, language, setLanguage } = useIIIFManifest();\r\n\r\n if (!alwaysShow && languages.length <= 1) {\r\n return null;\r\n }\r\n\r\n const names = languageNames ? { ...LANGUAGE_NAMES, ...languageNames } : LANGUAGE_NAMES;\r\n\r\n // The active language may not be one the manifest advertises, e.g. when it came from the browser\r\n // and the manifest fell back. Showing it keeps the control from silently misreporting.\r\n const options = languages.includes(language) ? languages : [language, ...languages];\r\n\r\n return (\r\n <div className={className}>\r\n {label ? (\r\n <label className={labelClassName} htmlFor=\"iiif-language-select\">\r\n {label}\r\n </label>\r\n ) : null}\r\n <select\r\n id=\"iiif-language-select\"\r\n className={selectClassName}\r\n value={language}\r\n onChange={(event) => setLanguage(event.target.value)}\r\n >\r\n {options.map((tag) => (\r\n <option key={tag} value={tag}>\r\n {names[tag] ?? tag.toUpperCase()}\r\n </option>\r\n ))}\r\n </select>\r\n </div>\r\n );\r\n};\r\n"],"mappings":"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","names":["import_react","import_react_3dhop","value","import_jsx_runtime","import_react","import_react_3dhop","import_react","import_react_3dhop","import_jsx_runtime","sanitizeKey","import_jsx_runtime","defaultLanguage","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","fallbackName","import_react","import_jsx_runtime","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/IIIFViewer.tsx","../src/context.tsx","../src/iiif/mat4.ts","../src/iiif/camera.ts","../src/iiif/language.ts","../src/iiif/parser.ts","../src/iiif/transforms.ts","../src/iiif/units.ts","../src/iiif/toModels.ts","../src/IIIFMultiManifestViewer.tsx","../src/multiManifestContext.tsx","../src/iiif/toMultiModels.ts","../src/collectionContext.tsx","../src/iiif/collection.ts","../src/panels/IIIFCollectionPicker.tsx","../src/panels/IIIFCollectionCarousel.tsx","../src/panels/IIIFSummary.tsx","../src/panels/IIIFMetadataPanel.tsx","../src/panels/IIIFModelsPanel.tsx","../src/panels/IIIFMultiManifestModelsPanel.tsx","../src/panels/IIIFSavedViewsPanel.tsx","../src/panels/IIIFLanguageSwitcher.tsx"],"sourcesContent":["export { IIIFViewer } from './IIIFViewer.js';\nexport type { IIIFViewerProps } from './IIIFViewer.js';\n\nexport { IIIFMultiManifestViewer } from './IIIFMultiManifestViewer.js';\nexport type { IIIFMultiManifestViewerProps } from './IIIFMultiManifestViewer.js';\n\nexport { IIIFProvider, useIIIFManifest } from './context.js';\nexport type { IIIFContextValue, IIIFProviderProps, IIIFStatus } from './context.js';\n\nexport { IIIFMultiManifestProvider, useIIIFMultiManifest } from './multiManifestContext.js';\nexport type {\n IIIFMultiManifestContextValue,\n IIIFMultiManifestProviderProps,\n IIIFMultiManifestStatus,\n ManifestGroup\n} from './multiManifestContext.js';\n\nexport { IIIFCollectionProvider, useIIIFCollection } from './collectionContext.js';\nexport type {\n IIIFCollectionContextValue,\n IIIFCollectionProviderProps,\n IIIFCollectionStatus\n} from './collectionContext.js';\n\nexport { IIIFCollectionPicker } from './panels/IIIFCollectionPicker.js';\nexport type { IIIFCollectionPickerProps } from './panels/IIIFCollectionPicker.js';\nexport { IIIFCollectionCarousel } from './panels/IIIFCollectionCarousel.js';\nexport type { IIIFCollectionCarouselProps } from './panels/IIIFCollectionCarousel.js';\n\nexport { IIIFSummary } from './panels/IIIFSummary.js';\nexport type { IIIFSummaryProps } from './panels/IIIFSummary.js';\nexport { IIIFMetadataPanel } from './panels/IIIFMetadataPanel.js';\nexport type { IIIFMetadataPanelProps } from './panels/IIIFMetadataPanel.js';\nexport { IIIFModelsPanel } from './panels/IIIFModelsPanel.js';\nexport type { IIIFModelsPanelProps } from './panels/IIIFModelsPanel.js';\nexport { IIIFMultiManifestModelsPanel } from './panels/IIIFMultiManifestModelsPanel.js';\nexport type { IIIFMultiManifestModelsPanelProps } from './panels/IIIFMultiManifestModelsPanel.js';\nexport { IIIFSavedViewsPanel } from './panels/IIIFSavedViewsPanel.js';\nexport type { IIIFSavedViewsPanelProps } from './panels/IIIFSavedViewsPanel.js';\nexport { IIIFLanguageSwitcher, LANGUAGE_NAMES } from './panels/IIIFLanguageSwitcher.js';\nexport type { IIIFLanguageSwitcherProps } from './panels/IIIFLanguageSwitcher.js';\n\n// Pure helpers, usable without React.\nexport { loadManifest, parseManifest, selectBestSource, FORMAT_PREFERENCE } from './iiif/parser.js';\nexport type { LoadManifestOptions, ParseOptions } from './iiif/parser.js';\n\nexport { loadCollection, parseCollection } from './iiif/collection.js';\nexport type { LoadCollectionOptions, ParseCollectionOptions } from './iiif/collection.js';\n\nexport { sceneFromManifest, DEFAULT_MEASURE_UNIT } from './iiif/toModels.js';\nexport type { SceneFromManifest, ToModelsOptions } from './iiif/toModels.js';\n\nexport { sceneFromManifests, layoutManifests } from './iiif/toMultiModels.js';\nexport type { SceneFromManifests, ToMultiModelsOptions, ManifestSceneEntry } from './iiif/toMultiModels.js';\n\nexport { getUnitScaleFactor, isKnownUnit, UNITS_IN_METRES } from './iiif/units.js';\nexport type { UnitName } from './iiif/units.js';\n\nexport { buildModelMatrix, composeTransforms, transformToMatrix } from './iiif/transforms.js';\nexport type { ModelMatrixOptions } from './iiif/transforms.js';\n\nexport { cameraToView, track2view, view2track, viewToCameraAnnotation } from './iiif/camera.js';\nexport type { CameraAnnotationOptions, SceneFraming, TrackballState } from './iiif/camera.js';\n\nexport { collectLanguages, resolveLanguageMap, DEFAULT_FALLBACK_LANGUAGES } from './iiif/language.js';\n\nexport type {\n Diagnostic,\n DiagnosticHandler,\n IIIFAnnotation,\n IIIFAnnotationBody,\n IIIFAnnotationPage,\n IIIFAnnotationTarget,\n IIIFCollection,\n IIIFCollectionItem,\n IIIFManifest,\n IIIFMetadataEntry,\n IIIFModelSource,\n IIIFPointSelector,\n IIIFScene,\n IIIFThumbnail,\n IIIFTransform,\n LanguageMap,\n LocalizableValue,\n ParsedCamera,\n ParsedCollection,\n ParsedCollectionItem,\n ParsedManifest,\n ParsedMetadata,\n ParsedModel,\n Vector3,\n View\n} from './iiif/types.js';\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { ThreeDHopViewer, type ThreeDHopViewerProps } from '@ikaros-arch/react-3dhop';\nimport { IIIFProvider, useIIIFManifest, type IIIFStatus } from './context.js';\nimport { loadManifest, parseManifest } from './iiif/parser.js';\nimport { sceneFromManifest, type SceneFromManifest, type ToModelsOptions } from './iiif/toModels.js';\nimport type { Diagnostic, IIIFManifest, ParsedManifest } from './iiif/types.js';\n\nexport type IIIFViewerProps = Omit<ThreeDHopViewerProps, 'models' | 'modelUrl'> & {\n /** A manifest URL to fetch, or an already-fetched manifest object. */\n manifest: string | IIIFManifest;\n /** Language used for labels and metadata. Defaults to the browser's, falling back to `'en'`. */\n language?: string;\n /** Overrides the manifest's `display unit`, changing the scale the scene is rendered at. */\n displayUnit?: string;\n /** Applies the manifest's first camera as the initial view once the scene is ready. */\n applyInitialCamera?: boolean;\n onLoad?: (parsed: ParsedManifest, scene: SceneFromManifest) => void;\n onError?: (error: Error) => void;\n onDiagnostic?: (diagnostic: Diagnostic) => void;\n /** Rendered instead of the viewer while the manifest is being fetched. */\n loadingFallback?: React.ReactNode;\n /** Rendered instead of the viewer when the manifest cannot be loaded or parsed. */\n errorFallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n};\n\nfunction defaultLanguage(): string {\n if (typeof navigator !== 'undefined' && navigator.language) {\n return navigator.language.split('-')[0];\n }\n return 'en';\n}\n\n/**\n * Renders a IIIF 3D manifest with 3DHOP.\n *\n * Fetches and parses the manifest, derives the scene, and makes the result available to any\n * descendant through `useIIIFManifest()`. Everything `<ThreeDHopViewer>` accepts can be passed\n * through, except the model props this component supplies itself.\n */\nexport const IIIFViewer: React.FC<IIIFViewerProps> = ({\n manifest,\n language: languageProp,\n displayUnit,\n applyInitialCamera = true,\n onLoad,\n onError,\n onDiagnostic,\n loadingFallback = null,\n errorFallback = null,\n space,\n config,\n trackball,\n children,\n ...viewerProps\n}) => {\n const [language, setLanguage] = useState(() => languageProp ?? defaultLanguage());\n const [status, setStatus] = useState<IIIFStatus>('idle');\n const [error, setError] = useState<Error | null>(null);\n const [parsed, setParsed] = useState<ParsedManifest | null>(null);\n const [diagnostics, setDiagnostics] = useState<Diagnostic[]>([]);\n\n useEffect(() => {\n if (languageProp) {\n setLanguage(languageProp);\n }\n }, [languageProp]);\n\n useEffect(() => {\n const controller = new AbortController();\n const collected: Diagnostic[] = [];\n const handleDiagnostic = (diagnostic: Diagnostic) => {\n collected.push(diagnostic);\n onDiagnostic?.(diagnostic);\n };\n\n const finish = (result: ParsedManifest) => {\n if (controller.signal.aborted) {\n return;\n }\n setParsed(result);\n setDiagnostics(collected);\n setStatus('ready');\n setError(null);\n };\n\n const fail = (cause: unknown) => {\n if (controller.signal.aborted) {\n return;\n }\n const normalized = cause instanceof Error ? cause : new Error(String(cause));\n setParsed(null);\n setDiagnostics(collected);\n setStatus('error');\n setError(normalized);\n onError?.(normalized);\n };\n\n setStatus('loading');\n\n if (typeof manifest === 'string') {\n loadManifest(manifest, { language, signal: controller.signal, onDiagnostic: handleDiagnostic })\n .then(finish)\n .catch((cause) => {\n if (cause instanceof DOMException && cause.name === 'AbortError') {\n return;\n }\n fail(cause);\n });\n } else {\n try {\n finish(parseManifest(manifest, { language, onDiagnostic: handleDiagnostic }));\n } catch (cause) {\n fail(cause);\n }\n }\n\n return () => controller.abort();\n // `language` is deliberately excluded: switching language re-resolves labels below rather than\n // re-fetching the manifest.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [manifest, onDiagnostic, onError]);\n\n // Re-resolving is cheap and keeps a single source of truth for language handling.\n const localized = useMemo(() => {\n if (!parsed) {\n return null;\n }\n return parseManifest(parsed.manifest, { language });\n }, [parsed, language]);\n\n const scene = useMemo(() => {\n if (!localized) {\n return null;\n }\n return sceneFromManifest(localized, { displayUnit, space, config, trackball } satisfies ToModelsOptions);\n }, [localized, displayUnit, space, config, trackball]);\n\n useEffect(() => {\n if (status === 'ready' && localized && scene) {\n onLoad?.(localized, scene);\n }\n // Firing only when the parsed result changes; `onLoad` identity is the caller's concern.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [status, localized, scene]);\n\n if (status === 'error' && error) {\n return <>{typeof errorFallback === 'function' ? errorFallback(error) : errorFallback}</>;\n }\n\n if (!scene || !localized) {\n return <>{loadingFallback}</>;\n }\n\n return (\n <ThreeDHopViewer\n {...viewerProps}\n models={scene.models}\n space={scene.space}\n config={scene.config}\n trackball={scene.trackball}\n measurementUnits={viewerProps.measurementUnits ?? scene.displayUnit}\n >\n <IIIFProvider\n status={status}\n error={error}\n diagnostics={diagnostics}\n parsed={localized}\n scene={scene}\n language={language}\n setLanguage={setLanguage}\n >\n {applyInitialCamera && localized.cameras.length > 0 ? <InitialCamera /> : null}\n {children}\n </IIIFProvider>\n </ThreeDHopViewer>\n );\n};\n\n/**\n * Applies the manifest's first camera as the opening view.\n *\n * This waits for the scene framing rather than running on mount: the presenter only knows the\n * scene's centre and radius after the scene has been set, and `goToCamera` is a no-op until then.\n */\nconst InitialCamera: React.FC = () => {\n const [applied, setApplied] = useState(false);\n const { goToCamera, cameras, isSceneReady } = useIIIFManifest();\n\n useEffect(() => {\n if (applied || !isSceneReady || cameras.length === 0) {\n return;\n }\n goToCamera(0, 0);\n setApplied(true);\n }, [applied, cameras.length, goToCamera, isSceneReady]);\n\n return null;\n};\n","import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\nimport { useThreeDHopViewer } from '@ikaros-arch/react-3dhop';\nimport { cameraToView, track2view, view2track, viewToCameraAnnotation, type SceneFraming, type TrackballState } from './iiif/camera.js';\nimport { resolveLanguageMap } from './iiif/language.js';\nimport type { Diagnostic, LocalizableValue, ParsedCamera, ParsedManifest, ParsedMetadata, ParsedModel } from './iiif/types.js';\nimport type { SceneFromManifest } from './iiif/toModels.js';\n\nexport type IIIFStatus = 'idle' | 'loading' | 'ready' | 'error';\n\nexport type IIIFContextValue = {\n status: IIIFStatus;\n error: Error | null;\n /** Non-fatal notes collected while parsing, in the order they were emitted. */\n diagnostics: Diagnostic[];\n parsed: ParsedManifest | null;\n metadata: ParsedMetadata | null;\n models: ParsedModel[];\n cameras: ParsedCamera[];\n languages: string[];\n language: string;\n setLanguage: (language: string) => void;\n /** Resolves any language map from the manifest into the active language. */\n localize: (value: LocalizableValue | undefined) => string;\n measureUnit: string;\n displayUnit: string;\n /**\n * Whether the presenter has established the scene's centre and radius. Camera operations are\n * no-ops until this is true, because there is nothing to convert against yet.\n */\n isSceneReady: boolean;\n /** Animates the camera to the manifest camera at `index`. */\n goToCamera: (index: number, durationSeconds?: number) => void;\n /** Captures the current camera as an IIIF annotation, or `null` if the scene is not ready. */\n saveCurrentView: (label?: string) => Record<string, unknown> | null;\n /** Shows or hides one model. Pass the IIIF annotation id. */\n setModelVisible: (modelId: string, visible: boolean) => void;\n isModelVisible: (modelId: string) => boolean;\n toggleModelTransparency: (modelId: string) => void;\n isModelTransparent: (modelId: string) => boolean;\n};\n\nconst IIIFContext = createContext<IIIFContextValue | null>(null);\n\n/** Access the IIIF manifest state. Must be called from inside an `<IIIFViewer>`. */\nexport function useIIIFManifest(): IIIFContextValue {\n const value = useContext(IIIFContext);\n if (!value) {\n throw new Error('useIIIFManifest must be used within an <IIIFViewer>.');\n }\n return value;\n}\n\nexport type IIIFProviderProps = {\n status: IIIFStatus;\n error: Error | null;\n diagnostics: Diagnostic[];\n parsed: ParsedManifest | null;\n scene: SceneFromManifest | null;\n language: string;\n setLanguage: (language: string) => void;\n children?: React.ReactNode;\n};\n\n/**\n * Supplies IIIF state to descendants and bridges it to the live presenter.\n *\n * Rendered inside `<ThreeDHopViewer>` so it can reach the viewer context, which is the only place\n * the presenter — and with it the scene framing that camera conversion needs — is available.\n */\nexport const IIIFProvider: React.FC<IIIFProviderProps> = ({\n status,\n error,\n diagnostics,\n parsed,\n scene,\n language,\n setLanguage,\n children\n}) => {\n const { presenter, registerSceneObserver } = useThreeDHopViewer();\n const [framing, setFraming] = useState<SceneFraming | null>(null);\n // Held as state, not refs: the panels render these as controlled inputs, so a toggle has to\n // produce a new context value or the consumers never re-render and React reverts the checkbox.\n const [visibility, setVisibility] = useState<Record<string, boolean>>({});\n const [transparency, setTransparency] = useState<Record<string, boolean>>({});\n\n // The presenter only derives sceneCenter/sceneRadiusInv once a scene has been set, so read them\n // when the viewer tells us the scene changed rather than on mount.\n useEffect(() => {\n return registerSceneObserver((instance) => {\n const center = instance.sceneCenter;\n const radiusInv = instance.sceneRadiusInv;\n if (Array.isArray(center) && center.length >= 3 && typeof radiusInv === 'number') {\n setFraming({ sceneCenter: [center[0], center[1], center[2]], sceneRadiusInv: radiusInv });\n }\n // A new scene resets every instance to its declared state.\n setVisibility({});\n setTransparency({});\n });\n }, [registerSceneObserver]);\n\n const localize = useCallback(\n (value: LocalizableValue | undefined) => resolveLanguageMap(value, language),\n [language]\n );\n\n const goToCamera = useCallback(\n (index: number, durationSeconds = 0.5) => {\n if (!parsed || !framing || !presenter) {\n return;\n }\n const camera = parsed.cameras[index];\n if (!camera) {\n return;\n }\n\n const view = cameraToView(camera, framing, parsed.models);\n const trackState = view2track(view, framing);\n\n // The presenter treats a zero duration as \"unspecified\" and animates over its own default,\n // so jumping straight to the view has to bypass the animation entirely.\n if (durationSeconds > 0 && typeof presenter.animateToTrackballPosition === 'function') {\n presenter.animateToTrackballPosition(trackState, durationSeconds);\n } else {\n presenter.setTrackballPosition?.(trackState);\n presenter.repaint?.();\n }\n\n if (camera.type === 'OrthographicCamera') {\n presenter.setCameraOrthographic?.();\n } else {\n presenter.setCameraPerspective?.();\n }\n },\n [framing, parsed, presenter]\n );\n\n const saveCurrentView = useCallback(\n (label?: string) => {\n if (!presenter || !framing) {\n return null;\n }\n\n const trackState = presenter.getTrackballPosition?.();\n if (!Array.isArray(trackState) || trackState.length < 6) {\n return null;\n }\n\n const isOrthographic = presenter.getCameraType?.() === 'orthographic';\n const fov = isOrthographic ? 0 : presenter._scene?.space?.cameraFOV ?? 60;\n\n const view = track2view(trackState as TrackballState, framing, fov);\n return viewToCameraAnnotation(view, { label, sceneId: parsed?.manifest.items?.[0]?.id });\n },\n [framing, parsed, presenter]\n );\n\n const instanceKeyFor = useCallback(\n (modelId: string) => scene?.instanceIdsByModelId[modelId],\n [scene]\n );\n\n const isModelVisible = useCallback(\n (modelId: string) => visibility[modelId] ?? true,\n [visibility]\n );\n\n const setModelVisible = useCallback(\n (modelId: string, visible: boolean) => {\n const key = instanceKeyFor(modelId);\n if (!key || !presenter) {\n return;\n }\n // The presenter only offers a toggle, so state is tracked here to make this idempotent.\n if ((visibility[modelId] ?? true) === visible) {\n return;\n }\n presenter.toggleInstanceVisibilityByName?.(key, true);\n setVisibility((current) => ({ ...current, [modelId]: visible }));\n },\n [instanceKeyFor, presenter, visibility]\n );\n\n const isModelTransparent = useCallback(\n (modelId: string) => transparency[modelId] ?? false,\n [transparency]\n );\n\n const toggleModelTransparency = useCallback(\n (modelId: string) => {\n const key = instanceKeyFor(modelId);\n if (!key || !presenter) {\n return;\n }\n presenter.toggleInstanceTransparencyByName?.(key, true);\n setTransparency((current) => ({ ...current, [modelId]: !(current[modelId] ?? false) }));\n },\n [instanceKeyFor, presenter]\n );\n\n const value = useMemo<IIIFContextValue>(\n () => ({\n status,\n error,\n diagnostics,\n parsed,\n metadata: parsed?.metadata ?? null,\n models: parsed?.models ?? [],\n cameras: parsed?.cameras ?? [],\n languages: parsed?.languages ?? [],\n language,\n setLanguage,\n localize,\n measureUnit: scene?.measureUnit ?? 'mm',\n displayUnit: scene?.displayUnit ?? 'mm',\n isSceneReady: framing !== null,\n goToCamera,\n saveCurrentView,\n setModelVisible,\n isModelVisible,\n toggleModelTransparency,\n isModelTransparent\n }),\n [\n diagnostics,\n error,\n framing,\n goToCamera,\n isModelTransparent,\n isModelVisible,\n language,\n localize,\n parsed,\n saveCurrentView,\n scene,\n setLanguage,\n setModelVisible,\n status,\n toggleModelTransparency\n ]\n );\n\n return <IIIFContext.Provider value={value}>{children}</IIIFContext.Provider>;\n};\n","import type { Vector3 } from './types.js';\n\n/**\n * A minimal 4x4 matrix implementation matching SpiderGL's conventions, so the matrices produced\n * here can be handed straight to 3DHOP.\n *\n * Layout is **column-major**: `m[column * 4 + row]`, the same order WebGL expects. A translation\n * therefore lives in elements 12, 13 and 14. `multiply(a, b)` returns `a · b`, so the rightmost\n * factor is applied to a point first.\n *\n * This is reimplemented rather than delegated to the `SglMat4` global so it can be unit-tested in\n * Node and does not depend on 3DHOP's scripts having loaded.\n */\nexport type Mat4 = number[];\n\nexport function identity(): Mat4 {\n return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];\n}\n\nexport function translation([x, y, z]: Vector3): Mat4 {\n return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1];\n}\n\nexport function scaling([x, y, z]: Vector3): Mat4 {\n return [x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1];\n}\n\nexport function degToRad(degrees: number): number {\n return (degrees * Math.PI) / 180;\n}\n\nexport function radToDeg(radians: number): number {\n return (radians * 180) / Math.PI;\n}\n\n/** Rotation of `angle` radians about `axis`, via Rodrigues' formula. */\nexport function rotationAngleAxis(angle: number, axis: Vector3): Mat4 {\n const length = Math.hypot(axis[0], axis[1], axis[2]);\n if (length === 0) {\n return identity();\n }\n\n const x = axis[0] / length;\n const y = axis[1] / length;\n const z = axis[2] / length;\n\n const s = Math.sin(angle);\n const c = Math.cos(angle);\n const t = 1 - c;\n\n return [\n t * x * x + c,\n t * x * y + z * s,\n t * z * x - y * s,\n 0,\n t * x * y - z * s,\n t * y * y + c,\n t * y * z + x * s,\n 0,\n t * z * x + y * s,\n t * y * z - x * s,\n t * z * z + c,\n 0,\n 0,\n 0,\n 0,\n 1\n ];\n}\n\n/** Returns `a · b`. */\nexport function multiply(a: Mat4, b: Mat4): Mat4 {\n const out: Mat4 = new Array(16);\n\n for (let column = 0; column < 4; column += 1) {\n for (let row = 0; row < 4; row += 1) {\n let sum = 0;\n for (let k = 0; k < 4; k += 1) {\n sum += a[k * 4 + row] * b[column * 4 + k];\n }\n out[column * 4 + row] = sum;\n }\n }\n\n return out;\n}\n\n/** Returns `a · b · c · …`, i.e. the rightmost matrix is applied to a point first. */\nexport function multiplyAll(...matrices: Mat4[]): Mat4 {\n return matrices.reduce<Mat4>((accumulator, matrix) => multiply(accumulator, matrix), identity());\n}\n\n/** Transforms a point (implicit w = 1) and performs the perspective divide. */\nexport function transformPoint(m: Mat4, [x, y, z]: Vector3): Vector3 {\n const w = m[3] * x + m[7] * y + m[11] * z + m[15];\n const divisor = w === 0 ? 1 : w;\n\n return [\n (m[0] * x + m[4] * y + m[8] * z + m[12]) / divisor,\n (m[1] * x + m[5] * y + m[9] * z + m[13]) / divisor,\n (m[2] * x + m[6] * y + m[10] * z + m[14]) / divisor\n ];\n}\n","import { degToRad, radToDeg, multiply, rotationAngleAxis, transformPoint } from './mat4.js';\nimport type { ParsedCamera, ParsedModel, Vector3, View } from './types.js';\n\n/**\n * 3DHOP's turntable trackball state: `[phi, theta, panX, panY, panZ, distance]`.\n *\n * `phi` (heading) and `theta` (elevation) are degrees; the pan and distance components are in\n * scene-radius units, i.e. already divided by the scene radius.\n */\nexport type TrackballState = [number, number, number, number, number, number];\n\n/**\n * The scene framing the presenter derives once a scene is loaded. Both values are needed to move\n * between world coordinates and the normalised space the trackball operates in.\n */\nexport type SceneFraming = {\n sceneCenter: Vector3;\n /** Reciprocal of the scene radius, as the presenter stores it. */\n sceneRadiusInv: number;\n};\n\nconst Y_AXIS: Vector3 = [0, 1, 0];\nconst NEGATIVE_X_AXIS: Vector3 = [-1, 0, 0];\n\n/** Below this, a vector's horizontal component carries no reliable heading. */\nconst DEGENERATE = 1e-9;\n\n/**\n * Converts a world-space camera to a trackball state. The exact inverse of {@link track2view}.\n *\n * Heading is recovered from the view direction, falling back to the up vector only when the camera\n * looks straight up or straight down and the direction has no horizontal component left to read.\n * The fallback is deliberately narrow: a camera parsed out of a manifest has no authored up vector\n * — {@link cameraToView} synthesises world up — so leaning on it for any merely steep view would\n * lose the heading entirely.\n *\n * Both branches use `atan2` rather than `asin`. An `asin` only spans a half-turn and needs a\n * quadrant correction, which is easy to get wrong below the horizon, and it divides by a cosine\n * that vanishes exactly where the input is already ill-conditioned.\n */\nexport function view2track(view: View, framing: SceneFraming): TrackballState {\n const { sceneCenter, sceneRadiusInv } = framing;\n\n const panX = (view.target[0] - sceneCenter[0]) * sceneRadiusInv;\n const panY = (view.target[1] - sceneCenter[1]) * sceneRadiusInv;\n const panZ = (view.target[2] - sceneCenter[2]) * sceneRadiusInv;\n\n const direction: Vector3 = [\n view.target[0] - view.position[0],\n view.target[1] - view.position[1],\n view.target[2] - view.position[2]\n ];\n const length = Math.hypot(direction[0], direction[1], direction[2]);\n\n if (length === 0) {\n return [0, 0, panX, panY, panZ, 0];\n }\n\n const unit: Vector3 = [direction[0] / length, direction[1] / length, direction[2] / length];\n const distance = length * sceneRadiusInv;\n\n const theta = radToDeg(-Math.asin(clamp(unit[1], -1, 1)));\n\n // `theta` comes from an `asin`, so it is always within [-90, 90] and `cos(theta)` is never\n // negative — the view-direction branch needs no sign correction. The up vector's horizontal part\n // is scaled by `sin(theta)` instead, which is negative below the horizon and would otherwise\n // mirror the heading.\n let phi: number;\n if (Math.hypot(unit[0], unit[2]) > DEGENERATE) {\n phi = radToDeg(Math.atan2(-unit[0], -unit[2]));\n } else if (view.up && Math.hypot(view.up[0], view.up[2]) > DEGENERATE) {\n const sign = theta >= 0 ? 1 : -1;\n phi = radToDeg(Math.atan2(sign * -view.up[0], sign * -view.up[2]));\n } else {\n // Looking straight down the Y axis with no usable up vector: every heading is equivalent.\n phi = 0;\n }\n\n return [phi, theta, panX, panY, panZ, distance];\n}\n\n/** Inverse of {@link view2track}. */\nexport function track2view(trackState: TrackballState, framing: SceneFraming, fov = 60): View {\n const { sceneCenter, sceneRadiusInv } = framing;\n const [phi, theta, panX, panY, panZ, normalizedDistance] = trackState;\n\n const target: Vector3 = [\n panX / sceneRadiusInv + sceneCenter[0],\n panY / sceneRadiusInv + sceneCenter[1],\n panZ / sceneRadiusInv + sceneCenter[2]\n ];\n\n // The camera sits at [0, 0, distance] tilted about -X and then swung about Y, relative to target.\n const orientation = multiply(\n rotationAngleAxis(degToRad(phi), Y_AXIS),\n rotationAngleAxis(degToRad(theta), NEGATIVE_X_AXIS)\n );\n\n const distance = normalizedDistance / sceneRadiusInv;\n const offset = transformPoint(orientation, [0, 0, distance]);\n const up = transformPoint(orientation, [0, 1, 0]);\n\n return {\n position: [offset[0] + target[0], offset[1] + target[1], offset[2] + target[2]],\n target,\n up,\n fov\n };\n}\n\n/**\n * Builds the world-space view a manifest camera describes.\n *\n * The look-at point is resolved in priority order: an explicit `lookAt` point, then the position of\n * the model the camera's `lookAt` refers to, then the scene centre.\n */\nexport function cameraToView(camera: ParsedCamera, framing: SceneFraming, models: readonly ParsedModel[] = []): View {\n let target: Vector3 = [...framing.sceneCenter];\n\n if (camera.target) {\n target = camera.target;\n } else if (camera.lookAtId) {\n const referenced = models.find((model) => model.id === camera.lookAtId);\n if (referenced) {\n target = referenced.position;\n }\n }\n\n return {\n position: camera.position,\n target,\n up: [0, 1, 0],\n // An orthographic camera has no field of view; 0 is the sentinel 3DHOP's own tooling uses.\n fov: camera.type === 'OrthographicCamera' ? 0 : camera.fov ?? 60\n };\n}\n\nexport type CameraAnnotationOptions = {\n /** Base for the generated `@id`s. */\n idBase?: string;\n label?: string;\n /** Id of the `Scene` the camera annotation targets. */\n sceneId?: string;\n};\n\nfunction round(value: number, decimals: number): number {\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n}\n\n/**\n * Serialises a view as an IIIF camera annotation, ready to be pasted into a manifest's\n * `AnnotationPage`. The inverse of what {@link cameraToView} consumes.\n */\nexport function viewToCameraAnnotation(\n view: View,\n { idBase = 'https://example.org/iiif/3d', label, sceneId = 'https://example.org/iiif/scene/1' }: CameraAnnotationOptions = {}\n): Record<string, unknown> {\n const timestamp = Date.now();\n const isOrthographic = view.fov === 0;\n\n return {\n id: `${idBase}/camera_${timestamp}`,\n type: 'Annotation',\n motivation: ['painting'],\n body: [\n {\n id: `${idBase}/cameras/${timestamp}`,\n type: isOrthographic ? 'OrthographicCamera' : 'PerspectiveCamera',\n label: { en: [label ?? `Saved View ${new Date().toLocaleString()}`] },\n lookAt: {\n type: 'PointSelector',\n x: round(view.target[0], 3),\n y: round(view.target[1], 3),\n z: round(view.target[2], 3)\n },\n ...(isOrthographic ? {} : { fieldOfView: round(view.fov, 1) })\n }\n ],\n target: [\n {\n type: 'SpecificResource',\n source: { id: sceneId, type: 'Scene' },\n selector: [\n {\n type: 'PointSelector',\n x: round(view.position[0], 3),\n y: round(view.position[1], 3),\n z: round(view.position[2], 3)\n }\n ]\n }\n ]\n };\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n","import type { LanguageMap, LocalizableValue } from './types.js';\n\n/**\n * Languages tried, in order, when the requested one is absent. Mirrors the behaviour of the\n * original viewer, which was authored for a Norwegian institution publishing in English.\n */\nexport const DEFAULT_FALLBACK_LANGUAGES = ['en', 'no', 'nb', 'nn'];\n\n/**\n * Resolves an IIIF language map to a single string.\n *\n * Tries `language`, then each of `fallbacks`, then any remaining language in the map. Returns an\n * empty string when nothing is available, so callers can render without null checks.\n *\n * Unlike the original implementation this takes the language as an argument rather than reading a\n * module-level global, so two viewers on one page can show different languages.\n */\nexport function resolveLanguageMap(\n value: LocalizableValue | undefined | null,\n language: string,\n fallbacks: readonly string[] = DEFAULT_FALLBACK_LANGUAGES\n): string {\n if (value == null) {\n return '';\n }\n\n if (typeof value === 'string') {\n return value;\n }\n\n if (typeof value !== 'object') {\n return '';\n }\n\n const pick = (tag: string): string | undefined => {\n const entry = (value as LanguageMap)[tag];\n if (entry == null) {\n return undefined;\n }\n if (Array.isArray(entry)) {\n return entry.length > 0 ? entry[0] : undefined;\n }\n return entry.length > 0 ? entry : undefined;\n };\n\n const direct = pick(language);\n if (direct !== undefined) {\n return direct;\n }\n\n for (const fallback of fallbacks) {\n if (fallback === language) {\n continue;\n }\n const candidate = pick(fallback);\n if (candidate !== undefined) {\n return candidate;\n }\n }\n\n for (const tag of Object.keys(value)) {\n const candidate = pick(tag);\n if (candidate !== undefined) {\n return candidate;\n }\n }\n\n return '';\n}\n\n/**\n * The properties IIIF defines as language maps. Only these are inspected for language tags.\n *\n * Recognising a language map by shape alone does not work: `{ \"id\": \"…\", \"type\": \"Model\",\n * \"format\": \"Nexus\" }` is also an object whose every value is a string, and treating it as one\n * offers \"id\", \"type\" and \"format\" to the user as languages.\n */\nconst LANGUAGE_MAP_KEYS = new Set(['label', 'value', 'summary']);\n\nfunction isLanguageMap(value: unknown): value is LanguageMap {\n if (value == null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n\n const entries = Object.entries(value);\n return (\n entries.length > 0 &&\n entries.every(\n ([, entry]) =>\n typeof entry === 'string' || (Array.isArray(entry) && entry.every((item) => typeof item === 'string'))\n )\n );\n}\n\n/**\n * Collects every language tag used by the language maps reachable from `value`.\n *\n * IIIF uses the tag `none` for values that carry no language; it is a valid key but not a language\n * a user would ever choose, so it is excluded.\n */\nexport function collectLanguages(value: unknown, into: Set<string> = new Set()): Set<string> {\n if (value == null || typeof value !== 'object') {\n return into;\n }\n\n if (Array.isArray(value)) {\n value.forEach((item) => collectLanguages(item, into));\n return into;\n }\n\n Object.entries(value as Record<string, unknown>).forEach(([key, entry]) => {\n if (LANGUAGE_MAP_KEYS.has(key) && isLanguageMap(entry)) {\n Object.keys(entry).forEach((tag) => {\n if (tag !== 'none') {\n into.add(tag);\n }\n });\n return;\n }\n\n collectLanguages(entry, into);\n });\n\n return into;\n}\n","import { collectLanguages, resolveLanguageMap } from './language.js';\nimport type {\n DiagnosticHandler,\n IIIFAnnotation,\n IIIFAnnotationBody,\n IIIFAnnotationTarget,\n IIIFManifest,\n IIIFModelSource,\n IIIFPointSelector,\n LocalizableValue,\n ParsedCamera,\n ParsedManifest,\n ParsedMetadata,\n ParsedModel,\n Vector3\n} from './types.js';\n\n/**\n * Ranking used when an annotation offers the same model in several formats. Nexus wins because it\n * is the only one 3DHOP streams progressively; glTF ranks last because 3DHOP cannot load it at all\n * and it is only ever a fallback worth reporting.\n */\nexport const FORMAT_PREFERENCE: Record<string, number> = {\n glb: 1,\n gltf: 1,\n 'model/gltf-binary': 1,\n 'model/gltf+json': 1,\n obj: 2,\n 'model/obj': 2,\n ply: 3,\n 'application/ply': 3,\n nexus: 4,\n nxz: 4,\n nxs: 4,\n 'application/octet-stream+nexus': 4\n};\n\nfunction first<T>(value: T | T[] | undefined | null): T | undefined {\n if (Array.isArray(value)) {\n return value.length > 0 ? value[0] : undefined;\n }\n return value ?? undefined;\n}\n\nfunction toVector3(selector: IIIFPointSelector | undefined): Vector3 {\n return [selector?.x ?? 0, selector?.y ?? 0, selector?.z ?? 0];\n}\n\n/** Reads the first `PointSelector` reachable from an annotation target. */\nfunction readPointSelector(target: IIIFAnnotation['target']): IIIFPointSelector | undefined {\n if (!target || typeof target === 'string') {\n return undefined;\n }\n\n const entry = first<IIIFAnnotationTarget>(target as IIIFAnnotationTarget | IIIFAnnotationTarget[]);\n const selector = first(entry?.selector);\n\n return selector?.type === 'PointSelector' || selector?.x !== undefined ? selector : undefined;\n}\n\n/**\n * A `SpecificResource` body always counts as a model here: in the IIIF 3D subset this package\n * supports it exists only to wrap a model with a transform list. Claiming it even when its `source`\n * is missing or empty means the annotation is reported as an unusable model rather than as an\n * unrecognised body type, which is the more useful message for what is really an authoring slip.\n */\nfunction isModelBody(body: IIIFAnnotationBody | undefined): boolean {\n return body?.type === 'Model' || body?.type === 'SpecificResource';\n}\n\nfunction isCameraBody(body: IIIFAnnotationBody | undefined): boolean {\n return body?.type === 'PerspectiveCamera' || body?.type === 'OrthographicCamera';\n}\n\n/** Picks the source this viewer can make the best use of. See {@link FORMAT_PREFERENCE}. */\nexport function selectBestSource(\n source: IIIFModelSource | IIIFModelSource[] | undefined\n): IIIFModelSource | undefined {\n if (!source) {\n return undefined;\n }\n if (!Array.isArray(source)) {\n return source;\n }\n if (source.length <= 1) {\n return source[0];\n }\n\n const rank = (candidate: IIIFModelSource) => FORMAT_PREFERENCE[(candidate.format ?? '').toLowerCase()] ?? 0;\n\n return [...source].sort((a, b) => rank(b) - rank(a))[0];\n}\n\n/**\n * Metadata labels lifted into dedicated fields, keyed by their lowercased English or Norwegian\n * label. Everything else stays in `metadata.fields` untouched.\n */\nconst KNOWN_FIELDS: Record<string, keyof ParsedMetadata> = {\n museum: 'museum',\n 'inventory number': 'inventory',\n inventarnummer: 'inventory',\n 'object id': 'objectId',\n 'objekt-id': 'objectId',\n 'measure unit': 'measureUnit',\n 'måleenhet': 'measureUnit',\n 'display unit': 'displayUnit',\n visningsenhet: 'displayUnit'\n};\n\nexport type ParseOptions = {\n /** Language used to resolve labels and values. Defaults to `'en'`. */\n language?: string;\n onDiagnostic?: DiagnosticHandler;\n};\n\nfunction parseMetadata(manifest: IIIFManifest, language: string): ParsedMetadata {\n const resolve = (value: LocalizableValue | undefined) => resolveLanguageMap(value, language);\n\n const metadata: ParsedMetadata = {\n label: resolve(manifest.label),\n fields: []\n };\n\n const summary = resolve(manifest.summary);\n if (summary) {\n metadata.summary = summary;\n }\n\n const attribution = resolve(manifest.requiredStatement?.value);\n if (attribution) {\n metadata.attribution = attribution;\n }\n\n (manifest.metadata ?? []).forEach((entry) => {\n const localizedLabel = resolve(entry.label);\n const value = resolve(entry.value);\n\n metadata.fields.push({ label: localizedLabel, value });\n\n // Recognised fields are matched on the English label so the mapping survives a language switch.\n const canonicalKey = resolveLanguageMap(entry.label, 'en').trim().toLowerCase();\n const known = KNOWN_FIELDS[canonicalKey];\n if (known) {\n (metadata as Record<string, unknown>)[known] = value;\n }\n });\n\n return metadata;\n}\n\nfunction parseModelAnnotation(\n annotation: IIIFAnnotation,\n body: IIIFAnnotationBody,\n onDiagnostic?: DiagnosticHandler\n): ParsedModel | undefined {\n let url: string | undefined;\n let format: string | undefined;\n let measureUnit: string | undefined;\n let transforms: ParsedModel['transforms'] = [];\n\n if (body.type === 'Model') {\n url = body.id;\n format = body.format;\n measureUnit = body.measureUnit;\n } else {\n const source = selectBestSource(body.source);\n if (!source) {\n onDiagnostic?.({\n level: 'warning',\n message: `Model annotation ${annotation.id ?? '(no id)'} has no usable source; skipping.`\n });\n return undefined;\n }\n url = source.id;\n format = source.format;\n measureUnit = source.measureUnit ?? body.measureUnit;\n\n if (Array.isArray(body.transform)) {\n transforms = body.transform;\n }\n }\n\n if (!url) {\n onDiagnostic?.({\n level: 'warning',\n message: `Model annotation ${annotation.id ?? '(no id)'} has no source URL; skipping.`\n });\n return undefined;\n }\n\n // 3DHOP only has loaders for Nexus and PLY. Anything else is reported here rather than failing\n // silently at load time with nothing on screen to explain it.\n const normalizedFormat = (format ?? '').toLowerCase();\n const unrenderable = normalizedFormat.includes('gltf')\n ? 'glTF'\n : normalizedFormat === 'glb' || normalizedFormat === 'model/gltf-binary'\n ? 'glTF'\n : normalizedFormat === 'obj' || normalizedFormat === 'model/obj'\n ? 'OBJ'\n : undefined;\n\n if (unrenderable) {\n onDiagnostic?.({\n level: 'warning',\n message: `Model ${url} is ${unrenderable}, which 3DHOP cannot render. Convert it to Nexus (.nxz) or PLY.`\n });\n }\n\n return {\n id: annotation.id ?? url,\n rawLabel: annotation.label,\n url,\n format,\n measureUnit,\n position: toVector3(readPointSelector(annotation.target)),\n transforms\n };\n}\n\nfunction parseCameraAnnotation(annotation: IIIFAnnotation, body: IIIFAnnotationBody): ParsedCamera {\n const camera: ParsedCamera = {\n id: body.id,\n type: body.type === 'OrthographicCamera' ? 'OrthographicCamera' : 'PerspectiveCamera',\n rawLabel: body.label ?? annotation.label,\n position: toVector3(readPointSelector(annotation.target))\n };\n\n const fov = body.fieldOfView ?? body.fov;\n if (typeof fov === 'number') {\n camera.fov = fov;\n }\n\n if (body.lookAt) {\n // `lookAt` is either a point in space or a reference to another annotation.\n if (body.lookAt.type === 'PointSelector' || body.lookAt.x !== undefined) {\n camera.target = toVector3(body.lookAt);\n }\n if (body.lookAt.id) {\n camera.lookAtId = body.lookAt.id;\n }\n }\n\n return camera;\n}\n\n/**\n * Parses an already-fetched IIIF manifest into the viewer-ready shape.\n *\n * Unrecognised annotations are reported through `onDiagnostic` and skipped rather than aborting\n * the parse, so a manifest with one bad entry still renders the rest.\n */\nexport function parseManifest(manifest: IIIFManifest, options: ParseOptions = {}): ParsedManifest {\n const { language = 'en', onDiagnostic } = options;\n\n const models: ParsedModel[] = [];\n const cameras: ParsedCamera[] = [];\n\n const scenes = (manifest.items ?? []).filter((item) => item?.type === 'Scene');\n\n if (scenes.length === 0) {\n onDiagnostic?.({\n level: 'warning',\n message: 'Manifest contains no Scene; there is nothing to render.'\n });\n }\n\n if (scenes.length > 1) {\n onDiagnostic?.({\n level: 'info',\n message: `Manifest contains ${scenes.length} scenes; all of them are merged into one view.`\n });\n }\n\n scenes.forEach((scene) => {\n (scene.items ?? []).forEach((page) => {\n if (page?.type !== 'AnnotationPage') {\n return;\n }\n\n (page.items ?? []).forEach((annotation) => {\n const body = first(annotation?.body);\n\n if (isModelBody(body)) {\n const model = parseModelAnnotation(annotation, body as IIIFAnnotationBody, onDiagnostic);\n if (model) {\n models.push(model);\n }\n return;\n }\n\n if (isCameraBody(body)) {\n cameras.push(parseCameraAnnotation(annotation, body as IIIFAnnotationBody));\n return;\n }\n\n onDiagnostic?.({\n level: 'info',\n message: `Skipping annotation ${annotation?.id ?? '(no id)'} of unsupported body type \"${\n body?.type ?? 'undefined'\n }\".`\n });\n });\n });\n });\n\n return {\n manifest,\n metadata: parseMetadata(manifest, language),\n models,\n cameras,\n languages: Array.from(collectLanguages(manifest)).sort()\n };\n}\n\nexport type LoadManifestOptions = ParseOptions & {\n signal?: AbortSignal;\n /** Injectable for testing and for consumers with their own HTTP stack. */\n fetchImpl?: typeof fetch;\n};\n\n/** Fetches a manifest by URL and parses it. Rejects on network, JSON, or HTTP-status failures. */\nexport async function loadManifest(url: string, options: LoadManifestOptions = {}): Promise<ParsedManifest> {\n const { signal, fetchImpl = fetch, ...parseOptions } = options;\n\n const response = await fetchImpl(url, { signal });\n if (!response.ok) {\n throw new Error(`Failed to load IIIF manifest (${response.status} ${response.statusText}): ${url}`);\n }\n\n let json: unknown;\n try {\n json = await response.json();\n } catch (cause) {\n const detail = cause instanceof Error ? cause.message : String(cause);\n throw new Error(`IIIF manifest at ${url} is not valid JSON: ${detail}`);\n }\n\n if (!json || typeof json !== 'object') {\n throw new Error(`IIIF manifest at ${url} is not a JSON object.`);\n }\n\n return parseManifest(json as IIIFManifest, parseOptions);\n}\n","import {\n degToRad,\n identity,\n multiply,\n rotationAngleAxis,\n scaling,\n translation,\n type Mat4\n} from './mat4.js';\nimport type { IIIFTransform, Vector3 } from './types.js';\n\n/**\n * Converts a single IIIF transform to a matrix.\n *\n * `RotateTransform` has two authored forms: per-axis Euler angles (`{ x, y, z }`, degrees) and a\n * single axis-angle (`{ axis: 'y', angle: 45 }`). The Euler form is composed Z, then Y, then X,\n * matching how 3DHOP's presenter interprets its own `rotation` triple.\n */\nexport function transformToMatrix(transform: IIIFTransform): Mat4 {\n switch (transform.type) {\n case 'ScaleTransform':\n return scaling([transform.x ?? 1, transform.y ?? 1, transform.z ?? 1]);\n\n case 'TranslateTransform':\n return translation([transform.x ?? 0, transform.y ?? 0, transform.z ?? 0]);\n\n case 'RotateTransform': {\n if (transform.axis !== undefined || transform.angle !== undefined) {\n const angle = degToRad(transform.angle ?? 0);\n switch (transform.axis) {\n case 'x':\n return rotationAngleAxis(angle, [1, 0, 0]);\n case 'y':\n return rotationAngleAxis(angle, [0, 1, 0]);\n case 'z':\n default:\n return rotationAngleAxis(angle, [0, 0, 1]);\n }\n }\n\n const rx = rotationAngleAxis(degToRad(transform.x ?? 0), [1, 0, 0]);\n const ry = rotationAngleAxis(degToRad(transform.y ?? 0), [0, 1, 0]);\n const rz = rotationAngleAxis(degToRad(transform.z ?? 0), [0, 0, 1]);\n return multiply(multiply(rz, ry), rx);\n }\n\n default:\n return identity();\n }\n}\n\n/**\n * Composes an ordered IIIF transform list into a single matrix.\n *\n * IIIF applies the transforms in the order they are listed, so the first entry acts on the model\n * first. In matrix terms that makes it the rightmost factor: `Tn · … · T2 · T1`.\n *\n * This is why the list must be composed rather than flattened into a single translation/rotation/\n * scale triple: with a flattened triple, `translate` then `rotate` and `rotate` then `translate`\n * produce the same result, when they should not.\n */\nexport function composeTransforms(transforms: readonly IIIFTransform[] | undefined): Mat4 {\n if (!transforms || transforms.length === 0) {\n return identity();\n }\n\n return transforms.reduce<Mat4>(\n (accumulated, transform) => multiply(transformToMatrix(transform), accumulated),\n identity()\n );\n}\n\nexport type ModelMatrixOptions = {\n /** Placement of the model in scene coordinates, from the annotation's `PointSelector`. */\n position?: Vector3;\n /** The annotation's `transform` list, in authored order. */\n transforms?: readonly IIIFTransform[];\n /**\n * Converts scene-level coordinates — the `PointSelector` and any `TranslateTransform` — from the\n * manifest's measure unit to the display unit.\n */\n sceneScale?: number;\n /**\n * Converts the mesh's own vertex coordinates from the unit that model is authored in to the\n * display unit. Differs from `sceneScale` only when the annotation overrides `measureUnit`.\n */\n geometryScale?: number;\n};\n\n/**\n * Builds the full model matrix for one IIIF model annotation.\n *\n * ```text\n * M = S(sceneScale) · T(position) · L · S(geometryScale / sceneScale)\n * ```\n *\n * Read right to left, that is: bring the mesh's vertices from their own unit into the manifest's\n * unit, apply the manifest's ordered transform list, place the result at the `PointSelector`\n * position, then convert the whole scene from the manifest's unit to the display unit. Keeping the\n * unit conversions on the outside and inside — rather than folding them into the instance scale —\n * is what makes positions and translations scale correctly alongside the geometry.\n *\n * When the model does not override `measureUnit`, `geometryScale / sceneScale` is 1 and the\n * innermost factor drops out.\n */\nexport function buildModelMatrix({\n position = [0, 0, 0],\n transforms,\n sceneScale = 1,\n geometryScale = sceneScale\n}: ModelMatrixOptions): Mat4 {\n const relativeGeometryScale = sceneScale === 0 ? 1 : geometryScale / sceneScale;\n\n let matrix = composeTransforms(transforms);\n\n if (relativeGeometryScale !== 1) {\n matrix = multiply(matrix, scaling([relativeGeometryScale, relativeGeometryScale, relativeGeometryScale]));\n }\n\n if (position[0] !== 0 || position[1] !== 0 || position[2] !== 0) {\n matrix = multiply(translation(position), matrix);\n }\n\n if (sceneScale !== 1) {\n matrix = multiply(scaling([sceneScale, sceneScale, sceneScale]), matrix);\n }\n\n return matrix;\n}\n","/**\n * Length units the viewer understands, expressed as their size in metres.\n *\n * `um` and `µm` are both accepted because manifests are hand-authored and the micro sign is\n * awkward to type.\n */\nexport const UNITS_IN_METRES: Record<string, number> = {\n km: 1000,\n m: 1,\n cm: 0.01,\n mm: 0.001,\n um: 0.000001,\n 'µm': 0.000001,\n nm: 0.000000001\n};\n\nexport type UnitName = keyof typeof UNITS_IN_METRES;\n\nexport function isKnownUnit(unit: string | undefined | null): boolean {\n return typeof unit === 'string' && Object.prototype.hasOwnProperty.call(UNITS_IN_METRES, unit.trim());\n}\n\n/**\n * Multiplier that converts a length in `fromUnit` to the same length in `toUnit`.\n *\n * Unknown units are treated as a factor of 1 rather than raising, matching the original viewer:\n * a manifest with a typo'd unit still renders, just unscaled.\n */\nexport function getUnitScaleFactor(fromUnit: string | undefined | null, toUnit: string | undefined | null): number {\n const from = typeof fromUnit === 'string' ? fromUnit.trim() : '';\n const to = typeof toUnit === 'string' ? toUnit.trim() : '';\n\n if (from === to) {\n return 1;\n }\n\n const fromFactor = UNITS_IN_METRES[from] ?? 1;\n const toFactor = UNITS_IN_METRES[to] ?? 1;\n\n return fromFactor / toFactor;\n}\n","import type { ModelDefinition, SceneRenderConfig, SceneSpaceConfig, TrackballConfig } from '@ikaros-arch/react-3dhop';\nimport { buildModelMatrix } from './transforms.js';\nimport { getUnitScaleFactor } from './units.js';\nimport type { ParsedManifest, ParsedModel } from './types.js';\n\n/** Unit assumed when a manifest declares none. Matches the original viewer's behaviour. */\nexport const DEFAULT_MEASURE_UNIT = 'mm';\n\nexport type SceneFromManifest = {\n models: Record<string, ModelDefinition>;\n space: SceneSpaceConfig;\n config: SceneRenderConfig;\n trackball: TrackballConfig;\n /** The unit the scene's coordinates are now in — what measurements should be labelled with. */\n displayUnit: string;\n measureUnit: string;\n /** Maps each generated instance key back to the IIIF annotation it came from. */\n instanceIdsByModelId: Record<string, string>;\n};\n\nexport type ToModelsOptions = {\n /** Overrides the manifest's `display unit` metadata. */\n displayUnit?: string;\n /** Merged over the defaults derived from the manifest. */\n space?: SceneSpaceConfig;\n config?: SceneRenderConfig;\n trackball?: TrackballConfig;\n};\n\nfunction sanitizeKey(value: string, fallback: string): string {\n const cleaned = value.replace(/[^A-Za-z0-9_-]/g, '_').replace(/_+/g, '_').replace(/^_+|_+$/g, '');\n return cleaned.length > 0 ? cleaned : fallback;\n}\n\n/**\n * Translates a parsed manifest into the props `<ThreeDHopViewer>` needs.\n *\n * Models sharing a source URL are collapsed onto a single mesh, so a manifest that places the same\n * object several times downloads it once.\n */\nexport function sceneFromManifest(parsed: ParsedManifest, options: ToModelsOptions = {}): SceneFromManifest {\n const measureUnit = parsed.metadata.measureUnit?.trim() || DEFAULT_MEASURE_UNIT;\n const displayUnit = options.displayUnit?.trim() || parsed.metadata.displayUnit?.trim() || measureUnit;\n\n const sceneScale = getUnitScaleFactor(measureUnit, displayUnit);\n\n const models: Record<string, ModelDefinition> = {};\n const instanceIdsByModelId: Record<string, string> = {};\n const meshIdByUrl = new Map<string, string>();\n const usedKeys = new Set<string>();\n\n parsed.models.forEach((model: ParsedModel, index: number) => {\n let meshId = meshIdByUrl.get(model.url);\n if (!meshId) {\n meshId = `iiif_mesh_${meshIdByUrl.size}`;\n meshIdByUrl.set(model.url, meshId);\n }\n\n let key = sanitizeKey(model.id, `iiif_model_${index}`);\n while (usedKeys.has(key)) {\n key = `${key}_${index}`;\n }\n usedKeys.add(key);\n\n const geometryScale = model.measureUnit\n ? getUnitScaleFactor(model.measureUnit, displayUnit)\n : sceneScale;\n\n models[key] = {\n url: model.url,\n meshId,\n // Pinned, because the scene builder otherwise derives the instance name from the entry key\n // (`model_<key>`) and the panels address instances by the name recorded below.\n instanceId: key,\n transform: {\n matrix: buildModelMatrix({\n position: model.position,\n transforms: model.transforms,\n sceneScale,\n geometryScale\n })\n },\n tags: ['SPECIMEN'],\n color: [0.5, 0.5, 0.5],\n backfaceColor: [0.5, 0.5, 0.5, 3.0],\n specularColor: [0.0, 0.0, 0.0, 256.0]\n };\n\n instanceIdsByModelId[model.id] = key;\n });\n\n const space: SceneSpaceConfig = {\n centerMode: 'scene',\n radiusMode: 'scene',\n cameraNearFar: [0.01, 5.0],\n ...options.space\n };\n\n const config: SceneRenderConfig = {\n pickedpointColor: [1.0, 0.0, 1.0],\n measurementColor: [0.5, 1.0, 0.5],\n showClippingPlanes: true,\n showClippingBorder: true,\n // A half-unit clipping border is invisible on a millimetre-scale object and enormous on a\n // metre-scale one, so the metre case gets its own value.\n clippingBorderSize: displayUnit === 'm' ? 0.002 : 0.5,\n clippingBorderColor: [0.0, 1.0, 1.0],\n ...options.config\n };\n\n const trackball: TrackballConfig = {\n type: 'TurntablePanTrackball',\n ...options.trackball,\n trackOptions: {\n startPhi: 15.0,\n startTheta: 15.0,\n startDistance: 2.0,\n minMaxPhi: [-180, 180],\n minMaxTheta: [-90.0, 90.0],\n minMaxDist: [0.1, 3.0],\n ...options.trackball?.trackOptions\n }\n };\n\n return { models, space, config, trackball, displayUnit, measureUnit, instanceIdsByModelId };\n}\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { ThreeDHopViewer, type ThreeDHopViewerProps } from '@ikaros-arch/react-3dhop';\nimport { IIIFMultiManifestProvider, type IIIFMultiManifestStatus } from './multiManifestContext.js';\nimport { loadManifest, parseManifest } from './iiif/parser.js';\nimport { sceneFromManifests, type SceneFromManifests, type ToMultiModelsOptions } from './iiif/toMultiModels.js';\nimport type { Diagnostic, IIIFManifest, ParsedManifest, Vector3 } from './iiif/types.js';\n\nexport type IIIFMultiManifestViewerProps = Omit<ThreeDHopViewerProps, 'models' | 'modelUrl'> & {\n /** Manifest URLs to fetch, or already-fetched manifest objects, in display order. */\n manifests: Array<string | IIIFManifest>;\n /** Language used for labels. Defaults to the browser's, falling back to `'en'`. */\n language?: string;\n /** Overrides every manifest's `display unit`, converting them all onto one shared scale. */\n displayUnit?: string;\n /** Gap kept between adjacent manifests' layout circles, in the shared displayUnit. */\n gap?: number;\n /** Floor applied to every manifest's placement-spread radius. See `ToMultiModelsOptions.minRadius`. */\n minRadius?: number;\n /** Manifests per row before wrapping onto a new row. */\n columns?: number;\n /** Escape hatch: an explicit offset per manifest key, skipping automatic layout for that manifest. */\n layoutOverrides?: Record<string, Vector3>;\n onLoad?: (scene: SceneFromManifests) => void;\n /** Fired once per manifest that fails to load or parse. */\n onError?: (error: Error, sourceId: string) => void;\n onDiagnostic?: (diagnostic: Diagnostic) => void;\n /** Rendered instead of the viewer while the manifests are being fetched. */\n loadingFallback?: React.ReactNode;\n /** Rendered instead of the viewer when any manifest cannot be loaded or parsed. */\n errorFallback?: React.ReactNode | ((errors: Array<{ sourceId: string; error: Error }>) => React.ReactNode);\n};\n\nfunction defaultLanguage(): string {\n if (typeof navigator !== 'undefined' && navigator.language) {\n return navigator.language.split('-')[0];\n }\n return 'en';\n}\n\nfunction sourceIdFor(manifest: string | IIIFManifest, index: number): string {\n if (typeof manifest === 'string') {\n return manifest;\n }\n return manifest.id ?? `manifest_${index}`;\n}\n\n/**\n * Renders several IIIF 3D manifests together in one 3DHOP viewer, laid out side by side.\n *\n * A parallel component to `<IIIFViewer>` rather than an extension of it: this scene is a merge of\n * N independently-fetched manifests, and fails fast if any one of them can't be loaded — a mix of\n * \"some succeeded, some didn't\" isn't a state a shared scene can represent cleanly for v1.\n */\nexport const IIIFMultiManifestViewer: React.FC<IIIFMultiManifestViewerProps> = ({\n manifests,\n language: languageProp,\n displayUnit,\n gap,\n minRadius,\n columns,\n layoutOverrides,\n onLoad,\n onError,\n onDiagnostic,\n loadingFallback = null,\n errorFallback = null,\n space,\n config,\n trackball,\n children,\n ...viewerProps\n}) => {\n const [language, setLanguage] = useState(() => languageProp ?? defaultLanguage());\n const [status, setStatus] = useState<IIIFMultiManifestStatus>('idle');\n const [error, setError] = useState<Error | null>(null);\n const [parsedList, setParsedList] = useState<ParsedManifest[] | null>(null);\n const [diagnostics, setDiagnostics] = useState<Diagnostic[]>([]);\n\n useEffect(() => {\n if (languageProp) {\n setLanguage(languageProp);\n }\n }, [languageProp]);\n\n useEffect(() => {\n const controller = new AbortController();\n const collected: Diagnostic[] = [];\n const handleDiagnostic = (diagnostic: Diagnostic) => {\n collected.push(diagnostic);\n onDiagnostic?.(diagnostic);\n };\n\n setStatus('loading');\n\n Promise.all(\n manifests.map((manifest, index) => {\n if (typeof manifest === 'string') {\n return loadManifest(manifest, { language, signal: controller.signal, onDiagnostic: handleDiagnostic });\n }\n return Promise.resolve().then(() => parseManifest(manifest, { language, onDiagnostic: handleDiagnostic }));\n })\n )\n .then((results) => {\n if (controller.signal.aborted) {\n return;\n }\n setParsedList(results);\n setDiagnostics(collected);\n setStatus('ready');\n setError(null);\n })\n .catch((cause) => {\n if (controller.signal.aborted || (cause instanceof DOMException && cause.name === 'AbortError')) {\n return;\n }\n const normalized = cause instanceof Error ? cause : new Error(String(cause));\n setParsedList(null);\n setDiagnostics(collected);\n setStatus('error');\n setError(normalized);\n onError?.(normalized, 'unknown');\n });\n\n return () => controller.abort();\n // `language` is deliberately excluded: switching language re-resolves labels below rather than\n // re-fetching every manifest.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [manifests, onDiagnostic, onError]);\n\n const sourceIds = useMemo(() => manifests.map(sourceIdFor), [manifests]);\n\n // Re-resolving is cheap and keeps a single source of truth for language handling.\n const localizedList = useMemo(() => {\n if (!parsedList) {\n return null;\n }\n return parsedList.map((parsed) => parseManifest(parsed.manifest, { language }));\n }, [parsedList, language]);\n\n const scene = useMemo(() => {\n if (!localizedList || localizedList.length === 0) {\n return null;\n }\n return sceneFromManifests(localizedList, sourceIds, {\n displayUnit,\n space,\n config,\n trackball,\n gap,\n minRadius,\n columns,\n layoutOverrides\n } satisfies ToMultiModelsOptions);\n }, [localizedList, sourceIds, displayUnit, space, config, trackball, gap, minRadius, columns, layoutOverrides]);\n\n useEffect(() => {\n if (status === 'ready' && scene) {\n onLoad?.(scene);\n }\n // Firing only when the merged scene changes; `onLoad` identity is the caller's concern.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [status, scene]);\n\n if (status === 'error' && error) {\n return <>{typeof errorFallback === 'function' ? errorFallback([{ sourceId: 'unknown', error }]) : errorFallback}</>;\n }\n\n if (!scene) {\n return <>{loadingFallback}</>;\n }\n\n return (\n <ThreeDHopViewer\n {...viewerProps}\n models={scene.models}\n space={scene.space}\n config={scene.config}\n trackball={scene.trackball}\n measurementUnits={viewerProps.measurementUnits ?? scene.displayUnit}\n >\n <IIIFMultiManifestProvider status={status} error={error} diagnostics={diagnostics} scene={scene}>\n {children}\n </IIIFMultiManifestProvider>\n </ThreeDHopViewer>\n );\n};\n","import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\nimport { useThreeDHopViewer } from '@ikaros-arch/react-3dhop';\nimport type { Diagnostic, ParsedModel } from './iiif/types.js';\nimport type { SceneFromManifests } from './iiif/toMultiModels.js';\n\nexport type IIIFMultiManifestStatus = 'idle' | 'loading' | 'ready' | 'error';\n\nexport type ManifestGroup = {\n /** Unique within this scene. Pass to the `manifestKey` argument of the accessors below. */\n key: string;\n sourceId: string;\n label: string;\n models: ParsedModel[];\n};\n\nexport type IIIFMultiManifestContextValue = {\n status: IIIFMultiManifestStatus;\n error: Error | null;\n diagnostics: Diagnostic[];\n manifests: ManifestGroup[];\n measureUnit: string;\n displayUnit: string;\n /** Whether the presenter has established the scene, so instance toggles have something to act on. */\n isSceneReady: boolean;\n /** Shows or hides one model. `modelId` is the IIIF annotation id, scoped to `manifestKey`. */\n setModelVisible: (manifestKey: string, modelId: string, visible: boolean) => void;\n isModelVisible: (manifestKey: string, modelId: string) => boolean;\n toggleModelTransparency: (manifestKey: string, modelId: string) => void;\n isModelTransparent: (manifestKey: string, modelId: string) => boolean;\n};\n\nconst IIIFMultiManifestContext = createContext<IIIFMultiManifestContextValue | null>(null);\n\n/** Access the multi-manifest scene state. Must be called from inside an `<IIIFMultiManifestViewer>`. */\nexport function useIIIFMultiManifest(): IIIFMultiManifestContextValue {\n const value = useContext(IIIFMultiManifestContext);\n if (!value) {\n throw new Error('useIIIFMultiManifest must be used within an <IIIFMultiManifestViewer>.');\n }\n return value;\n}\n\nexport type IIIFMultiManifestProviderProps = {\n status: IIIFMultiManifestStatus;\n error: Error | null;\n diagnostics: Diagnostic[];\n scene: SceneFromManifests | null;\n children?: React.ReactNode;\n};\n\nfunction compositeKey(manifestKey: string, modelId: string): string {\n return `${manifestKey}::${modelId}`;\n}\n\n/**\n * Supplies multi-manifest scene state to descendants and bridges it to the live presenter.\n *\n * A deliberately smaller sibling of `<IIIFProvider>`: cameras, saved views, metadata and language\n * are per-manifest concepts that don't yet have a defined multi-manifest behaviour, so this only\n * covers per-model visibility/transparency, each scoped by the manifest it came from.\n */\nexport const IIIFMultiManifestProvider: React.FC<IIIFMultiManifestProviderProps> = ({\n status,\n error,\n diagnostics,\n scene,\n children\n}) => {\n const { presenter, registerSceneObserver } = useThreeDHopViewer();\n const [isSceneReady, setIsSceneReady] = useState(false);\n const [visibility, setVisibility] = useState<Record<string, boolean>>({});\n const [transparency, setTransparency] = useState<Record<string, boolean>>({});\n\n useEffect(() => {\n return registerSceneObserver(() => {\n setIsSceneReady(true);\n // A new scene resets every instance to its declared state.\n setVisibility({});\n setTransparency({});\n });\n }, [registerSceneObserver]);\n\n const instanceKeyFor = useCallback(\n (manifestKey: string, modelId: string) =>\n scene?.manifests.find((manifest) => manifest.key === manifestKey)?.instanceIdsByModelId[modelId],\n [scene]\n );\n\n const isModelVisible = useCallback(\n (manifestKey: string, modelId: string) => visibility[compositeKey(manifestKey, modelId)] ?? true,\n [visibility]\n );\n\n const setModelVisible = useCallback(\n (manifestKey: string, modelId: string, visible: boolean) => {\n const key = instanceKeyFor(manifestKey, modelId);\n const stateKey = compositeKey(manifestKey, modelId);\n if (!key || !presenter) {\n return;\n }\n if ((visibility[stateKey] ?? true) === visible) {\n return;\n }\n presenter.toggleInstanceVisibilityByName?.(key, true);\n setVisibility((current) => ({ ...current, [stateKey]: visible }));\n },\n [instanceKeyFor, presenter, visibility]\n );\n\n const isModelTransparent = useCallback(\n (manifestKey: string, modelId: string) => transparency[compositeKey(manifestKey, modelId)] ?? false,\n [transparency]\n );\n\n const toggleModelTransparency = useCallback(\n (manifestKey: string, modelId: string) => {\n const key = instanceKeyFor(manifestKey, modelId);\n const stateKey = compositeKey(manifestKey, modelId);\n if (!key || !presenter) {\n return;\n }\n presenter.toggleInstanceTransparencyByName?.(key, true);\n setTransparency((current) => ({ ...current, [stateKey]: !(current[stateKey] ?? false) }));\n },\n [instanceKeyFor, presenter]\n );\n\n const manifests = useMemo<ManifestGroup[]>(\n () =>\n scene?.manifests.map((manifest) => ({\n key: manifest.key,\n sourceId: manifest.sourceId,\n label: manifest.parsed.metadata.label,\n models: manifest.models\n })) ?? [],\n [scene]\n );\n\n const value = useMemo<IIIFMultiManifestContextValue>(\n () => ({\n status,\n error,\n diagnostics,\n manifests,\n measureUnit: scene?.measureUnit ?? 'mm',\n displayUnit: scene?.displayUnit ?? 'mm',\n isSceneReady,\n setModelVisible,\n isModelVisible,\n toggleModelTransparency,\n isModelTransparent\n }),\n [\n diagnostics,\n error,\n isModelTransparent,\n isModelVisible,\n isSceneReady,\n manifests,\n scene,\n setModelVisible,\n status,\n toggleModelTransparency\n ]\n );\n\n return <IIIFMultiManifestContext.Provider value={value}>{children}</IIIFMultiManifestContext.Provider>;\n};\n","import type { ModelDefinition, SceneRenderConfig, SceneSpaceConfig, TrackballConfig } from '@ikaros-arch/react-3dhop';\nimport { multiply, translation } from './mat4.js';\nimport { sceneFromManifest } from './toModels.js';\nimport type { ParsedManifest, ParsedModel, Vector3 } from './types.js';\n\nexport type ManifestSceneEntry = {\n /** Sanitized id for this manifest, unique within the merged scene. Used to namespace model keys\n * and to disambiguate per-manifest visibility/transparency state. */\n key: string;\n /** The manifest's own id/URL, kept for display/debugging. */\n sourceId: string;\n parsed: ParsedManifest;\n /** `parsed.models`, unmodified — for panels that need per-model metadata/labels. */\n models: ParsedModel[];\n /** IIIF annotation id -> globally-unique instance key in the merged `models` record. */\n instanceIdsByModelId: Record<string, string>;\n /** World-space offset applied to every model belonging to this manifest, in the shared displayUnit. */\n offset: Vector3;\n /** Placement-spread radius used to compute `offset`. Exposed for debugging/tests. */\n layoutRadius: number;\n};\n\nexport type SceneFromManifests = {\n models: Record<string, ModelDefinition>;\n space: SceneSpaceConfig;\n config: SceneRenderConfig;\n trackball: TrackballConfig;\n displayUnit: string;\n measureUnit: string;\n manifests: ManifestSceneEntry[];\n};\n\nexport type ToMultiModelsOptions = {\n /** Shared display unit every manifest is converted into. Defaults to the first manifest's. */\n displayUnit?: string;\n space?: SceneSpaceConfig;\n config?: SceneRenderConfig;\n trackball?: TrackballConfig;\n /** Gap kept between adjacent manifests' layout circles, in the shared displayUnit. Default 50. */\n gap?: number;\n /**\n * Floor applied to every manifest's placement-spread radius.\n *\n * There is no real mesh geometry size available at this point — meshes stream in later, and the\n * manifest only tells us where each annotation is *placed*, not how big it is. Most manifests\n * place a single model at the origin, which has a spread of 0; without this floor every such\n * manifest would land on top of the others. Tune this per dataset. Default 100.\n */\n minRadius?: number;\n /** Manifests per row before wrapping onto a new row. Default: unlimited (single row). */\n columns?: number;\n /** Escape hatch: an explicit offset per manifest key, skipping automatic layout for that manifest. */\n layoutOverrides?: Record<string, Vector3>;\n};\n\nfunction sanitizeKey(value: string, fallback: string): string {\n const cleaned = value.replace(/[^A-Za-z0-9_-]/g, '_').replace(/_+/g, '_').replace(/^_+|_+$/g, '');\n return cleaned.length > 0 ? cleaned : fallback;\n}\n\n/** Radius of the smallest circle centred on the centroid that covers every model's placement. */\nfunction placementSpreadRadius(models: ParsedModel[]): number {\n if (models.length <= 1) {\n return 0;\n }\n\n const centroid = models.reduce<Vector3>(\n (sum, model) => [sum[0] + model.position[0], sum[1] + model.position[1], sum[2] + model.position[2]],\n [0, 0, 0]\n );\n centroid[0] /= models.length;\n centroid[1] /= models.length;\n centroid[2] /= models.length;\n\n return models.reduce((max, model) => Math.max(max, Math.hypot(\n model.position[0] - centroid[0],\n model.position[1] - centroid[1],\n model.position[2] - centroid[2]\n )), 0);\n}\n\n/**\n * Arranges circles of the given radii on the X/Z plane, packed left-to-right and wrapped every\n * `columns` entries, each separated by `gap`. Returns one offset per input radius, re-centred so\n * the layout's bounding box sits on the origin (cosmetic only — `centerMode: 'scene'` reframes the\n * camera around the actual rendered geometry regardless).\n */\nexport function layoutManifests(radii: number[], options: { gap: number; columns: number }): Vector3[] {\n const { gap, columns } = options;\n const offsets: Vector3[] = [];\n\n let cursorX = 0;\n let cursorZ = 0;\n let rowMaxRadius = 0;\n let previousRadius = 0;\n\n radii.forEach((radius, index) => {\n const column = columns > 0 ? index % columns : index;\n if (column === 0 && index > 0) {\n cursorZ += rowMaxRadius + gap + radius;\n cursorX = 0;\n rowMaxRadius = 0;\n previousRadius = 0;\n } else if (index > 0) {\n cursorX += previousRadius + gap + radius;\n }\n\n offsets.push([cursorX, 0, cursorZ]);\n rowMaxRadius = Math.max(rowMaxRadius, radius);\n previousRadius = radius;\n });\n\n if (offsets.length === 0) {\n return offsets;\n }\n\n const minX = Math.min(...offsets.map((offset) => offset[0]));\n const maxX = Math.max(...offsets.map((offset) => offset[0]));\n const minZ = Math.min(...offsets.map((offset) => offset[2]));\n const maxZ = Math.max(...offsets.map((offset) => offset[2]));\n const centerX = (minX + maxX) / 2;\n const centerZ = (minZ + maxZ) / 2;\n\n return offsets.map(([x, y, z]) => [x - centerX, y, z - centerZ]);\n}\n\n/**\n * Translates several parsed manifests into the props `<ThreeDHopViewer>` needs for a single,\n * combined scene — one manifest per `ParsedManifest`, laid out side by side so their models don't\n * overlap even when their native coordinates coincide (see {@link ToMultiModelsOptions.minRadius}).\n *\n * Delegates all per-manifest unit conversion and matrix building to {@link sceneFromManifest}, then\n * re-keys and offsets the result so it can be merged into one flat model dictionary.\n */\nexport function sceneFromManifests(\n parsedList: ParsedManifest[],\n sourceIds: string[],\n options: ToMultiModelsOptions = {}\n): SceneFromManifests {\n const gap = options.gap ?? 50;\n const minRadius = options.minRadius ?? 100;\n const columns = options.columns ?? parsedList.length;\n const displayUnit =\n options.displayUnit?.trim() || parsedList[0]?.metadata.displayUnit?.trim() || parsedList[0]?.metadata.measureUnit?.trim() || 'mm';\n\n const perManifestScenes = parsedList.map((parsed) => sceneFromManifest(parsed, { displayUnit }));\n const radii = perManifestScenes.map((_, index) =>\n Math.max(minRadius, placementSpreadRadius(parsedList[index].models))\n );\n const autoOffsets = layoutManifests(radii, { gap, columns });\n\n const models: Record<string, ModelDefinition> = {};\n const usedManifestKeys = new Set<string>();\n const manifests: ManifestSceneEntry[] = [];\n\n parsedList.forEach((parsed, index) => {\n const sourceId = sourceIds[index] ?? `manifest_${index}`;\n let manifestKey = sanitizeKey(parsed.manifest.id ?? sourceId, `manifest_${index}`);\n while (usedManifestKeys.has(manifestKey)) {\n manifestKey = `${manifestKey}_${index}`;\n }\n usedManifestKeys.add(manifestKey);\n\n const offset = options.layoutOverrides?.[manifestKey] ?? autoOffsets[index] ?? [0, 0, 0];\n const offsetMatrix = translation(offset);\n\n const manifestScene = perManifestScenes[index];\n const instanceIdsByModelId: Record<string, string> = {};\n\n Object.entries(manifestScene.models).forEach(([localKey, modelDef]) => {\n const globalKey = `${manifestKey}__${localKey}`;\n models[globalKey] = {\n ...modelDef,\n meshId: `${manifestKey}__${modelDef.meshId}`,\n instanceId: globalKey,\n transform: {\n matrix: multiply(offsetMatrix, modelDef.transform!.matrix!)\n }\n };\n });\n\n Object.entries(manifestScene.instanceIdsByModelId).forEach(([modelId, localKey]) => {\n instanceIdsByModelId[modelId] = `${manifestKey}__${localKey}`;\n });\n\n manifests.push({\n key: manifestKey,\n sourceId,\n parsed,\n models: parsed.models,\n instanceIdsByModelId,\n offset,\n layoutRadius: radii[index]\n });\n });\n\n const space: SceneSpaceConfig = {\n centerMode: 'scene',\n radiusMode: 'scene',\n cameraNearFar: [0.01, 5.0],\n ...options.space\n };\n\n const config: SceneRenderConfig = {\n pickedpointColor: [1.0, 0.0, 1.0],\n measurementColor: [0.5, 1.0, 0.5],\n showClippingPlanes: true,\n showClippingBorder: true,\n clippingBorderSize: displayUnit === 'm' ? 0.002 : 0.5,\n clippingBorderColor: [0.0, 1.0, 1.0],\n ...options.config\n };\n\n const trackball: TrackballConfig = {\n type: 'TurntablePanTrackball',\n ...options.trackball,\n trackOptions: {\n startPhi: 15.0,\n startTheta: 15.0,\n startDistance: 2.0,\n minMaxPhi: [-180, 180],\n minMaxTheta: [-90.0, 90.0],\n minMaxDist: [0.1, 3.0],\n ...options.trackball?.trackOptions\n }\n };\n\n return { models, space, config, trackball, displayUnit, measureUnit: displayUnit, manifests };\n}\n","import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\nimport { loadCollection, parseCollection } from './iiif/collection.js';\nimport type { Diagnostic, IIIFCollection, ParsedCollectionItem } from './iiif/types.js';\n\nexport type IIIFCollectionStatus = 'idle' | 'loading' | 'ready' | 'error';\n\nexport type IIIFCollectionContextValue = {\n status: IIIFCollectionStatus;\n error: Error | null;\n diagnostics: Diagnostic[];\n label: string;\n summary: string | null;\n items: ParsedCollectionItem[];\n /** id of the manifest currently selected, e.g. to pass straight into `<IIIFViewer manifest={...}>`. */\n selectedId: string | null;\n selectedIndex: number;\n selectedItem: ParsedCollectionItem | null;\n selectManifest: (id: string) => void;\n next: () => void;\n previous: () => void;\n};\n\nconst IIIFCollectionContext = createContext<IIIFCollectionContextValue | null>(null);\n\n/** Access the IIIF collection state. Must be called from inside an `<IIIFCollectionProvider>`. */\nexport function useIIIFCollection(): IIIFCollectionContextValue {\n const value = useContext(IIIFCollectionContext);\n if (!value) {\n throw new Error('useIIIFCollection must be used within an <IIIFCollectionProvider>.');\n }\n return value;\n}\n\nexport type IIIFCollectionProviderProps = {\n /** A collection URL to fetch, or an already-fetched collection object. */\n collection: string | IIIFCollection;\n /** Language used for item labels. Defaults to `'en'`. */\n language?: string;\n /** Selects this manifest id once the collection loads, instead of the first item. */\n initialManifestId?: string;\n onLoad?: (items: ParsedCollectionItem[]) => void;\n onError?: (error: Error) => void;\n onDiagnostic?: (diagnostic: Diagnostic) => void;\n children?: React.ReactNode;\n};\n\n/**\n * Fetches and parses a IIIF Collection, and tracks which of its manifests is selected.\n *\n * Unlike `<IIIFViewer>`, this renders nothing itself — it only supplies `useIIIFCollection()` to\n * descendants, such as `<IIIFCollectionPicker>`, `<IIIFCollectionCarousel>`, and the `<IIIFViewer>`\n * that should render `selectedId`. Keeping it separate lets the collection state outlive remounts\n * of the viewer (e.g. `key={selectedId}`) that discard camera and visibility state per manifest.\n */\nexport const IIIFCollectionProvider: React.FC<IIIFCollectionProviderProps> = ({\n collection,\n language = 'en',\n initialManifestId,\n onLoad,\n onError,\n onDiagnostic,\n children\n}) => {\n const [status, setStatus] = useState<IIIFCollectionStatus>('idle');\n const [error, setError] = useState<Error | null>(null);\n const [label, setLabel] = useState('');\n const [summary, setSummary] = useState<string | null>(null);\n const [items, setItems] = useState<ParsedCollectionItem[]>([]);\n const [diagnostics, setDiagnostics] = useState<Diagnostic[]>([]);\n const [selectedId, setSelectedId] = useState<string | null>(initialManifestId ?? null);\n\n useEffect(() => {\n const controller = new AbortController();\n const collected: Diagnostic[] = [];\n const handleDiagnostic = (diagnostic: Diagnostic) => {\n collected.push(diagnostic);\n onDiagnostic?.(diagnostic);\n };\n\n const finish = (parsed: { label: string; summary?: string; items: ParsedCollectionItem[] }) => {\n if (controller.signal.aborted) {\n return;\n }\n setLabel(parsed.label);\n setSummary(parsed.summary ?? null);\n setItems(parsed.items);\n setDiagnostics(collected);\n setStatus('ready');\n setError(null);\n // Only defaults to the first item on the initial load; later reloads keep whatever the caller\n // (or the user, via selectManifest) already picked.\n setSelectedId((current) => current ?? parsed.items[0]?.id ?? null);\n onLoad?.(parsed.items);\n };\n\n const fail = (cause: unknown) => {\n if (controller.signal.aborted) {\n return;\n }\n const normalized = cause instanceof Error ? cause : new Error(String(cause));\n setStatus('error');\n setError(normalized);\n setDiagnostics(collected);\n onError?.(normalized);\n };\n\n setStatus('loading');\n\n if (typeof collection === 'string') {\n loadCollection(collection, { language, signal: controller.signal, onDiagnostic: handleDiagnostic })\n .then(finish)\n .catch((cause) => {\n if (cause instanceof DOMException && cause.name === 'AbortError') {\n return;\n }\n fail(cause);\n });\n } else {\n try {\n finish(parseCollection(collection, { language, onDiagnostic: handleDiagnostic }));\n } catch (cause) {\n fail(cause);\n }\n }\n\n return () => controller.abort();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [collection, language, onLoad, onError]);\n\n const selectedIndex = useMemo(() => items.findIndex((item) => item.id === selectedId), [items, selectedId]);\n const selectedItem = selectedIndex >= 0 ? items[selectedIndex] : null;\n\n const selectManifest = useCallback((id: string) => {\n setSelectedId(id);\n }, []);\n\n const step = useCallback(\n (delta: number) => {\n if (items.length === 0) {\n return;\n }\n const base = selectedIndex >= 0 ? selectedIndex : 0;\n const nextIndex = (base + delta + items.length) % items.length;\n setSelectedId(items[nextIndex].id);\n },\n [items, selectedIndex]\n );\n\n const next = useCallback(() => step(1), [step]);\n const previous = useCallback(() => step(-1), [step]);\n\n const value = useMemo<IIIFCollectionContextValue>(\n () => ({\n status,\n error,\n diagnostics,\n label,\n summary,\n items,\n selectedId,\n selectedIndex,\n selectedItem,\n selectManifest,\n next,\n previous\n }),\n [status, error, diagnostics, label, summary, items, selectedId, selectedIndex, selectedItem, selectManifest, next, previous]\n );\n\n return <IIIFCollectionContext.Provider value={value}>{children}</IIIFCollectionContext.Provider>;\n};\n","import { resolveLanguageMap } from './language.js';\nimport type {\n DiagnosticHandler,\n IIIFCollection,\n IIIFCollectionItem,\n ParsedCollection,\n ParsedCollectionItem\n} from './types.js';\n\nexport type ParseCollectionOptions = {\n /** Language used to resolve labels and summaries. Defaults to `'en'`. */\n language?: string;\n onDiagnostic?: DiagnosticHandler;\n};\n\n/** The collection format only ever needs the first thumbnail; a carousel has no use for the rest. */\nfunction firstThumbnail(item: IIIFCollectionItem): string | undefined {\n const thumbnail = Array.isArray(item.thumbnail) ? item.thumbnail[0] : item.thumbnail;\n return thumbnail?.id;\n}\n\n/**\n * Parses an already-fetched IIIF Collection into the listing a picker or carousel needs.\n *\n * Items are expected to be `Manifest` references; anything else (e.g. a nested `Collection`) is\n * reported through `onDiagnostic` and skipped rather than aborting the parse.\n */\nexport function parseCollection(collection: IIIFCollection, options: ParseCollectionOptions = {}): ParsedCollection {\n const { language = 'en', onDiagnostic } = options;\n const resolve = (value: IIIFCollectionItem['label']) => resolveLanguageMap(value, language);\n\n const rawItems = collection.items ?? [];\n if (rawItems.length === 0) {\n onDiagnostic?.({ level: 'warning', message: 'Collection contains no items.' });\n }\n\n const items: ParsedCollectionItem[] = [];\n\n rawItems.forEach((item) => {\n if (item?.type && item.type !== 'Manifest') {\n onDiagnostic?.({\n level: 'info',\n message: `Skipping collection item ${item.id ?? '(no id)'} of unsupported type \"${item.type}\".`\n });\n return;\n }\n\n if (!item?.id) {\n onDiagnostic?.({ level: 'warning', message: 'Collection item has no id; skipping.' });\n return;\n }\n\n const fields = (item.metadata ?? []).map((entry) => ({\n label: resolve(entry.label),\n value: resolve(entry.value)\n }));\n\n items.push({\n id: item.id,\n label: resolve(item.label) || item.id,\n summary: resolve(item.summary) || undefined,\n thumbnail: firstThumbnail(item),\n fields\n });\n });\n\n return {\n collection,\n label: resolve(collection.label) || 'Untitled Collection',\n summary: resolve(collection.summary) || undefined,\n items\n };\n}\n\nexport type LoadCollectionOptions = ParseCollectionOptions & {\n signal?: AbortSignal;\n /** Injectable for testing and for consumers with their own HTTP stack. */\n fetchImpl?: typeof fetch;\n};\n\n/** Fetches a collection by URL and parses it. Rejects on network, JSON, or HTTP-status failures. */\nexport async function loadCollection(url: string, options: LoadCollectionOptions = {}): Promise<ParsedCollection> {\n const { signal, fetchImpl = fetch, ...parseOptions } = options;\n\n const response = await fetchImpl(url, { signal });\n if (!response.ok) {\n throw new Error(`Failed to load IIIF collection (${response.status} ${response.statusText}): ${url}`);\n }\n\n let json: unknown;\n try {\n json = await response.json();\n } catch (cause) {\n const detail = cause instanceof Error ? cause.message : String(cause);\n throw new Error(`IIIF collection at ${url} is not valid JSON: ${detail}`);\n }\n\n if (!json || typeof json !== 'object') {\n throw new Error(`IIIF collection at ${url} is not a JSON object.`);\n }\n\n return parseCollection(json as IIIFCollection, parseOptions);\n}\n","import React from 'react';\nimport { useIIIFCollection } from '../collectionContext.js';\n\nexport type IIIFCollectionPickerProps = {\n label?: React.ReactNode;\n emptyMessage?: React.ReactNode;\n className?: string;\n labelClassName?: string;\n selectClassName?: string;\n};\n\n/** A `<select>` of every manifest in the collection. Pass the selected id straight to `<IIIFViewer>`. */\nexport const IIIFCollectionPicker: React.FC<IIIFCollectionPickerProps> = ({\n label = 'Object',\n emptyMessage = 'No objects in this collection.',\n className = 'iiif-collection-picker',\n labelClassName = 'iiif-collection-picker__label',\n selectClassName = 'iiif-collection-picker__select'\n}) => {\n const { items, selectedId, selectManifest, status } = useIIIFCollection();\n\n if (status === 'ready' && items.length === 0) {\n return <p className={`${className}__empty`}>{emptyMessage}</p>;\n }\n\n return (\n <div className={className}>\n {label ? (\n <label className={labelClassName} htmlFor=\"iiif-collection-select\">\n {label}\n </label>\n ) : null}\n <select\n id=\"iiif-collection-select\"\n className={selectClassName}\n value={selectedId ?? ''}\n onChange={(event) => selectManifest(event.target.value)}\n >\n {items.map((item) => (\n <option key={item.id} value={item.id}>\n {item.label}\n </option>\n ))}\n </select>\n </div>\n );\n};\n","import React from 'react';\nimport { useIIIFCollection } from '../collectionContext.js';\n\nexport type IIIFCollectionCarouselProps = {\n previousLabel?: string;\n nextLabel?: string;\n emptyMessage?: React.ReactNode;\n className?: string;\n trackClassName?: string;\n itemClassName?: string;\n activeItemClassName?: string;\n thumbnailClassName?: string;\n labelClassName?: string;\n controlClassName?: string;\n};\n\n/** A scrollable strip of thumbnails, one per manifest in the collection, with prev/next controls. */\nexport const IIIFCollectionCarousel: React.FC<IIIFCollectionCarouselProps> = ({\n previousLabel = 'Previous object',\n nextLabel = 'Next object',\n emptyMessage = 'No objects in this collection.',\n className = 'iiif-carousel',\n trackClassName = 'iiif-carousel__track',\n itemClassName = 'iiif-carousel__item',\n activeItemClassName = 'iiif-carousel__item--active',\n thumbnailClassName = 'iiif-carousel__thumbnail',\n labelClassName = 'iiif-carousel__label',\n controlClassName = 'iiif-carousel__control'\n}) => {\n const { items, selectedId, selectManifest, next, previous, status } = useIIIFCollection();\n\n if (status === 'ready' && items.length === 0) {\n return <p className={`${className}__empty`}>{emptyMessage}</p>;\n }\n\n return (\n <div className={className}>\n <button\n type=\"button\"\n className={controlClassName}\n onClick={previous}\n disabled={items.length < 2}\n aria-label={previousLabel}\n >\n ‹\n </button>\n <ul className={trackClassName}>\n {items.map((item) => {\n const active = item.id === selectedId;\n return (\n <li key={item.id} className={active ? `${itemClassName} ${activeItemClassName}` : itemClassName}>\n <button type=\"button\" onClick={() => selectManifest(item.id)} aria-current={active || undefined}>\n {item.thumbnail ? (\n <img className={thumbnailClassName} src={item.thumbnail} alt=\"\" loading=\"lazy\" />\n ) : (\n <span className={thumbnailClassName} aria-hidden=\"true\" />\n )}\n <span className={labelClassName}>{item.label}</span>\n </button>\n </li>\n );\n })}\n </ul>\n <button\n type=\"button\"\n className={controlClassName}\n onClick={next}\n disabled={items.length < 2}\n aria-label={nextLabel}\n >\n ›\n </button>\n </div>\n );\n};\n","import React from 'react';\nimport { useIIIFManifest } from '../context.js';\n\nexport type IIIFSummaryProps = {\n className?: string;\n summaryClassName?: string;\n attributionClassName?: string;\n};\n\n/**\n * The manifest's `summary` and the attribution from its `requiredStatement`.\n *\n * Renders nothing when the manifest supplies neither.\n */\nexport const IIIFSummary: React.FC<IIIFSummaryProps> = ({\n className = 'iiif-summary',\n summaryClassName = 'iiif-summary__text',\n attributionClassName = 'iiif-summary__attribution'\n}) => {\n const { metadata } = useIIIFManifest();\n\n const summary = metadata?.summary;\n const attribution = metadata?.attribution;\n\n if (!summary && !attribution) {\n return null;\n }\n\n return (\n <div className={className}>\n {summary ? <p className={summaryClassName}>{summary}</p> : null}\n {attribution ? (\n <p className={attributionClassName}>\n <small>{attribution}</small>\n </p>\n ) : null}\n </div>\n );\n};\n","import React, { useMemo } from 'react';\nimport { useIIIFManifest } from '../context.js';\nimport type { ParsedMetadata } from '../iiif/types.js';\n\n/**\n * Fields shown first, in this order, when the manifest provides them. Anything else the manifest\n * carries follows underneath, in manifest order.\n */\nconst PRIORITY_FIELDS: Array<{ key: keyof ParsedMetadata; label: string }> = [\n { key: 'label', label: 'Title' },\n { key: 'museum', label: 'Museum' },\n { key: 'inventory', label: 'Inventory' },\n { key: 'objectId', label: 'Object ID' },\n { key: 'measureUnit', label: 'Measure unit' },\n { key: 'displayUnit', label: 'Display unit' },\n { key: 'summary', label: 'Description' },\n { key: 'attribution', label: 'Attribution' }\n];\n\nexport type IIIFMetadataPanelProps = {\n heading?: React.ReactNode;\n /** Shown when the manifest carries no metadata at all. */\n emptyMessage?: React.ReactNode;\n /** Hides the metadata entries that are already shown as priority fields. */\n hideDuplicateFields?: boolean;\n className?: string;\n headingClassName?: string;\n tableClassName?: string;\n labelClassName?: string;\n valueClassName?: string;\n};\n\n/** The manifest's descriptive metadata as a definition table. */\nexport const IIIFMetadataPanel: React.FC<IIIFMetadataPanelProps> = ({\n heading = 'Metadata',\n emptyMessage = 'No metadata available',\n hideDuplicateFields = true,\n className = 'iiif-metadata',\n headingClassName = 'iiif-metadata__heading',\n tableClassName = 'iiif-metadata__table',\n labelClassName = 'iiif-metadata__label',\n valueClassName = 'iiif-metadata__value'\n}) => {\n const { metadata } = useIIIFManifest();\n\n const rows = useMemo(() => {\n if (!metadata) {\n return [];\n }\n\n const entries: Array<{ label: string; value: string }> = [];\n const shown = new Set<string>();\n\n PRIORITY_FIELDS.forEach(({ key, label }) => {\n const value = metadata[key];\n if (typeof value === 'string' && value.length > 0) {\n entries.push({ label, value });\n shown.add(value);\n }\n });\n\n metadata.fields.forEach((field) => {\n if (!field.value) {\n return;\n }\n if (hideDuplicateFields && shown.has(field.value)) {\n return;\n }\n entries.push(field);\n });\n\n return entries;\n }, [hideDuplicateFields, metadata]);\n\n return (\n <section className={className}>\n {heading ? <h2 className={headingClassName}>{heading}</h2> : null}\n {rows.length === 0 ? (\n <p className=\"iiif-metadata__empty\">{emptyMessage}</p>\n ) : (\n <table className={tableClassName}>\n <tbody>\n {rows.map((row, index) => (\n <tr key={`${row.label}-${index}`}>\n <th scope=\"row\" className={labelClassName}>\n {row.label}\n </th>\n <td className={valueClassName}>{row.value}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </section>\n );\n};\n","import React from 'react';\nimport { useIIIFManifest } from '../context.js';\nimport type { ParsedModel } from '../iiif/types.js';\n\n/** Falls back to the source filename when an annotation carries no label. */\nfunction fallbackName(model: ParsedModel, index: number): string {\n const filename = model.url.split('/').pop() ?? '';\n const stem = filename.split('?')[0].split('#')[0].split('.')[0];\n return stem || `Model ${index + 1}`;\n}\n\nexport type IIIFModelsPanelProps = {\n heading?: React.ReactNode;\n emptyMessage?: React.ReactNode;\n visibilityLabel?: string;\n transparencyLabel?: string;\n className?: string;\n headingClassName?: string;\n listClassName?: string;\n itemClassName?: string;\n};\n\n/** Per-model visibility and transparency toggles, one row per model annotation. */\nexport const IIIFModelsPanel: React.FC<IIIFModelsPanelProps> = ({\n heading = 'Models',\n emptyMessage = 'No models in manifest',\n visibilityLabel = 'Show model',\n transparencyLabel = 'Toggle transparency',\n className = 'iiif-models',\n headingClassName = 'iiif-models__heading',\n listClassName = 'iiif-models__list',\n itemClassName = 'iiif-models__item'\n}) => {\n const { models, localize, isModelVisible, setModelVisible, isModelTransparent, toggleModelTransparency } =\n useIIIFManifest();\n\n return (\n <section className={className}>\n {heading ? <h2 className={headingClassName}>{heading}</h2> : null}\n {models.length === 0 ? (\n <p className=\"iiif-models__empty\">{emptyMessage}</p>\n ) : (\n <ul className={listClassName}>\n {models.map((model, index) => {\n const name = localize(model.rawLabel) || fallbackName(model, index);\n const visible = isModelVisible(model.id);\n const transparent = isModelTransparent(model.id);\n\n return (\n <li key={model.id} className={itemClassName}>\n <label className=\"iiif-models__visibility\">\n <input\n type=\"checkbox\"\n checked={visible}\n onChange={(event) => setModelVisible(model.id, event.target.checked)}\n aria-label={`${visibilityLabel}: ${name}`}\n />\n <span className=\"iiif-models__name\">{name}</span>\n </label>\n <label className=\"iiif-models__transparency\">\n <input\n type=\"checkbox\"\n checked={transparent}\n onChange={() => toggleModelTransparency(model.id)}\n aria-label={`${transparencyLabel}: ${name}`}\n />\n <span className=\"iiif-models__transparency-text\">{transparencyLabel}</span>\n </label>\n </li>\n );\n })}\n </ul>\n )}\n </section>\n );\n};\n","import React from 'react';\nimport { useIIIFMultiManifest } from '../multiManifestContext.js';\nimport type { ParsedModel } from '../iiif/types.js';\n\n/** Falls back to the source filename when an annotation carries no label. */\nfunction fallbackName(model: ParsedModel, index: number): string {\n const filename = model.url.split('/').pop() ?? '';\n const stem = filename.split('?')[0].split('#')[0].split('.')[0];\n return stem || `Model ${index + 1}`;\n}\n\nexport type IIIFMultiManifestModelsPanelProps = {\n heading?: React.ReactNode;\n emptyMessage?: React.ReactNode;\n visibilityLabel?: string;\n transparencyLabel?: string;\n className?: string;\n headingClassName?: string;\n groupClassName?: string;\n groupHeadingClassName?: string;\n listClassName?: string;\n itemClassName?: string;\n};\n\n/** Per-model visibility and transparency toggles, grouped under a heading per source manifest. */\nexport const IIIFMultiManifestModelsPanel: React.FC<IIIFMultiManifestModelsPanelProps> = ({\n heading = 'Models',\n emptyMessage = 'No manifests selected',\n visibilityLabel = 'Show model',\n transparencyLabel = 'Toggle transparency',\n className = 'iiif-multi-models',\n headingClassName = 'iiif-multi-models__heading',\n groupClassName = 'iiif-multi-models__group',\n groupHeadingClassName = 'iiif-multi-models__group-heading',\n listClassName = 'iiif-multi-models__list',\n itemClassName = 'iiif-multi-models__item'\n}) => {\n const { manifests, isModelVisible, setModelVisible, isModelTransparent, toggleModelTransparency } =\n useIIIFMultiManifest();\n\n return (\n <section className={className}>\n {heading ? <h2 className={headingClassName}>{heading}</h2> : null}\n {manifests.length === 0 ? (\n <p className=\"iiif-multi-models__empty\">{emptyMessage}</p>\n ) : (\n manifests.map((manifest) => (\n <div key={manifest.key} className={groupClassName}>\n <h3 className={groupHeadingClassName}>{manifest.label}</h3>\n <ul className={listClassName}>\n {manifest.models.map((model, index) => {\n const name = model.rawLabel && typeof model.rawLabel === 'string' ? model.rawLabel : fallbackName(model, index);\n const visible = isModelVisible(manifest.key, model.id);\n const transparent = isModelTransparent(manifest.key, model.id);\n\n return (\n <li key={model.id} className={itemClassName}>\n <label className=\"iiif-multi-models__visibility\">\n <input\n type=\"checkbox\"\n checked={visible}\n onChange={(event) => setModelVisible(manifest.key, model.id, event.target.checked)}\n aria-label={`${visibilityLabel}: ${name}`}\n />\n <span className=\"iiif-multi-models__name\">{name}</span>\n </label>\n <label className=\"iiif-multi-models__transparency\">\n <input\n type=\"checkbox\"\n checked={transparent}\n onChange={() => toggleModelTransparency(manifest.key, model.id)}\n aria-label={`${transparencyLabel}: ${name}`}\n />\n <span className=\"iiif-multi-models__transparency-text\">{transparencyLabel}</span>\n </label>\n </li>\n );\n })}\n </ul>\n </div>\n ))\n )}\n </section>\n );\n};\n","import React, { useState } from 'react';\nimport { useIIIFManifest } from '../context.js';\n\nexport type IIIFSavedViewsPanelProps = {\n heading?: React.ReactNode;\n emptyMessage?: React.ReactNode;\n /** Hides the \"save current view\" control, leaving only the manifest's own cameras. */\n hideSaveControl?: boolean;\n saveLabel?: string;\n /**\n * Called with the IIIF camera annotation for the current view. When omitted, the annotation is\n * shown in the panel so it can be copied into a manifest.\n */\n onSaveView?: (annotation: Record<string, unknown>) => void;\n className?: string;\n headingClassName?: string;\n listClassName?: string;\n buttonClassName?: string;\n};\n\n/** Buttons for the manifest's camera annotations, plus a way to capture the current view. */\nexport const IIIFSavedViewsPanel: React.FC<IIIFSavedViewsPanelProps> = ({\n heading = 'Saved views',\n emptyMessage = 'No saved views in manifest',\n hideSaveControl = false,\n saveLabel = 'Save current view',\n onSaveView,\n className = 'iiif-views',\n headingClassName = 'iiif-views__heading',\n listClassName = 'iiif-views__list',\n buttonClassName = 'iiif-views__button'\n}) => {\n const { cameras, localize, goToCamera, saveCurrentView, isSceneReady } = useIIIFManifest();\n const [captured, setCaptured] = useState<string | null>(null);\n\n const handleSave = () => {\n const annotation = saveCurrentView();\n if (!annotation) {\n return;\n }\n if (onSaveView) {\n onSaveView(annotation);\n return;\n }\n setCaptured(JSON.stringify(annotation, null, 2));\n };\n\n return (\n <section className={className}>\n {heading ? <h2 className={headingClassName}>{heading}</h2> : null}\n\n {cameras.length === 0 ? (\n <p className=\"iiif-views__empty\">{emptyMessage}</p>\n ) : (\n <ul className={listClassName}>\n {cameras.map((camera, index) => (\n <li key={camera.id ?? index}>\n <button\n type=\"button\"\n className={buttonClassName}\n onClick={() => goToCamera(index)}\n disabled={!isSceneReady}\n >\n {localize(camera.rawLabel) || `View ${index + 1}`}\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {hideSaveControl ? null : (\n <button\n type=\"button\"\n className=\"iiif-views__save\"\n onClick={handleSave}\n disabled={!isSceneReady}\n >\n {saveLabel}\n </button>\n )}\n\n {captured ? (\n <pre className=\"iiif-views__output\">\n <code>{captured}</code>\n </pre>\n ) : null}\n </section>\n );\n};\n","import React from 'react';\nimport { useIIIFManifest } from '../context.js';\n\n/** Endonyms for the languages this collection publishes in; anything else falls back to the tag. */\nexport const LANGUAGE_NAMES: Record<string, string> = {\n en: 'English',\n no: 'Norsk',\n nn: 'Nynorsk',\n nb: 'Bokmål',\n de: 'Deutsch',\n fr: 'Français',\n es: 'Español',\n it: 'Italiano',\n se: 'Davvisámegiella'\n};\n\nexport type IIIFLanguageSwitcherProps = {\n label?: React.ReactNode;\n /** Merged over {@link LANGUAGE_NAMES} to name additional languages. */\n languageNames?: Record<string, string>;\n /** Renders the switcher even when the manifest offers only one language. */\n alwaysShow?: boolean;\n className?: string;\n labelClassName?: string;\n selectClassName?: string;\n};\n\n/**\n * Switches the language used for labels and metadata.\n *\n * Hidden when the manifest has one language or fewer, since there is nothing to choose between.\n */\nexport const IIIFLanguageSwitcher: React.FC<IIIFLanguageSwitcherProps> = ({\n label = 'Language',\n languageNames,\n alwaysShow = false,\n className = 'iiif-language',\n labelClassName = 'iiif-language__label',\n selectClassName = 'iiif-language__select'\n}) => {\n const { languages, language, setLanguage } = useIIIFManifest();\n\n if (!alwaysShow && languages.length <= 1) {\n return null;\n }\n\n const names = languageNames ? { ...LANGUAGE_NAMES, ...languageNames } : LANGUAGE_NAMES;\n\n // The active language may not be one the manifest advertises, e.g. when it came from the browser\n // and the manifest fell back. Showing it keeps the control from silently misreporting.\n const options = languages.includes(language) ? languages : [language, ...languages];\n\n return (\n <div className={className}>\n {label ? (\n <label className={labelClassName} htmlFor=\"iiif-language-select\">\n {label}\n </label>\n ) : null}\n <select\n id=\"iiif-language-select\"\n className={selectClassName}\n value={language}\n onChange={(event) => setLanguage(event.target.value)}\n >\n {options.map((tag) => (\n <option key={tag} value={tag}>\n {names[tag] ?? tag.toUpperCase()}\n </option>\n ))}\n </select>\n </div>\n );\n};\n"],"mappings":"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","names":["import_react","import_react_3dhop","value","import_jsx_runtime","import_react","import_react_3dhop","import_react","import_react_3dhop","import_jsx_runtime","sanitizeKey","import_jsx_runtime","defaultLanguage","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","fallbackName","import_react","import_jsx_runtime","import_jsx_runtime"]}
|