Plugin System
Triiiceratops features a flexible, component-based plugin system that allows you to extend the viewer's functionality by adding custom panels to the left or right sidebars.
For Svelte integrations, plugins can now be combined with direct manifestJson loading and a custom searchProvider, which makes it easier to build app-specific IIIF workflows without adding a separate HTTP layer.
Quick Start
Load the viewer and plugin bundles via script tags, then assign plugins to the viewer:
<!DOCTYPE html>
<html>
<head>
<!-- Load the viewer (self-contained, includes all dependencies) -->
<script src="https://unpkg.com/triiiceratops/dist/triiiceratops-element.iife.js"></script>
<!-- Load plugins -->
<script src="https://unpkg.com/triiiceratops/dist/triiiceratops-plugin-image-manipulation.iife.js"></script>
</head>
<body>
<triiiceratops-viewer manifest-id="https://example.com/manifest.json"></triiiceratops-viewer>
<script>
customElements.whenDefined('triiiceratops-viewer').then(() => {
const viewer = document.querySelector('triiiceratops-viewer');
viewer.plugins = [window.TriiiceratopsPlugins.ImageManipulation];
});
</script>
</body>
</html>
Import the viewer and plugin, then pass plugins via the plugins prop:
<script>
import { TriiiceratopsViewer } from 'triiiceratops';
import 'triiiceratops/style.css';
import { ImageManipulationPlugin } from 'triiiceratops/plugins/image-manipulation';
</script>
<div style="height: 600px;">
<TriiiceratopsViewer
manifestId="https://example.com/manifest.json"
plugins={[ImageManipulationPlugin]}
/>
</div>
How the Plugin System Works
Build System Overview
Triiiceratops provides two distribution formats to support different use cases:
| Format | Use Case | Plugins Loaded Via |
|---|---|---|
| IIFE Bundles | Static HTML pages, no build step | Script tags + window.TriiiceratopsPlugins |
| ES Modules | Vite/Svelte projects with bundlers | import statements |
IIFE Bundles (Script Tags)
The IIFE (Immediately Invoked Function Expression) bundles are self-contained JavaScript files that work in any browser without a build system.
How it works:
-
triiiceratops-element.iife.js(~700KB) bundles:- The
<triiiceratops-viewer>custom element - Svelte runtime
- OpenSeadragon image viewer
- All core dependencies
- Exposes a shared Svelte runtime for plugins
- The
-
Plugin IIFE bundles (e.g.,
triiiceratops-plugin-image-manipulation.iife.js):- Bundle the plugin's Svelte components and icons
- Use the shared Svelte runtime from the main element bundle
- Register themselves on
window.TriiiceratopsPlugins
Svelte Runtime Sharing
The viewer exposes its Svelte runtime on window.__TriiiceratopsSvelteRuntime, which plugins use to ensure getContext() and other Svelte features work correctly across bundle boundaries.
ES Module Exports
For projects using Vite, SvelteKit, or other bundlers, Triiiceratops exports package-built ES modules that are compiled by the consuming app's Svelte pipeline. This avoids runtime clashes while still enabling tree-shaking and normal bundler integration:
// Main Svelte component
import { TriiiceratopsViewer } from 'triiiceratops';
// Plugin components for manual assembly
import {
ImageManipulationController,
SlidersIcon,
} from 'triiiceratops/plugins/image-manipulation';
Plugin Definition
A plugin is defined by a PluginDef object:
import type { Component } from 'svelte';
interface PluginDef {
id?: string; // Unique identifier (auto-generated if not provided)
name: string; // Title shown in tooltips/headers
icon: Component; // Icon component (e.g., from phosphor-svelte)
panel: Component; // The Svelte component to render in the sidebar
position?: 'left' | 'right' | 'bottom' | 'overlay'; // Panel position (default: 'left')
props?: Record<string, unknown>; // Optional props to pass to the panel
}
If you plan to control plugin UI state through config.plugins, set an explicit, stable id on each plugin. Auto-generated IDs are not stable across re-registration.
Plugin panels render in the same left and right sidebar stacks as built-in panels. When multiple panels are assigned to the same side, they stack vertically. Sidebar width is configured per side with leftPanelWidth and rightPanelWidth in the viewer configuration; plugin UI config does not define a per-plugin or per-panel width.
Controlling Plugin UI Through Config
Plugin toolbar button visibility and plugin panel open/closed state can be controlled through the same config object used for built-in panes.
Configuration shape:
type ViewerConfig = {
plugins?: Record<
string,
{
visible?: boolean; // show/hide the plugin toolbar button
open?: boolean; // open/close the plugin panel
}
>;
};
Live Updates In Svelte
Update config.plugins reactively to change plugin UI at runtime.
<script lang="ts">
import { TriiiceratopsViewer } from 'triiiceratops';
import { PdfExportPlugin } from 'triiiceratops/plugins/pdf-export';
let config = $state({
plugins: {
'pdf-export': {
visible: true,
open: false,
},
},
});
function hidePdfButtonAndOpenPanel() {
config.plugins['pdf-export'] = {
visible: false,
open: true,
};
}
</script>
<button onclick={hidePdfButtonAndOpenPanel}>
Hide PDF button + open PDF panel
</button>
<TriiiceratopsViewer manifestId="..." plugins={[PdfExportPlugin]} {config} />
Live Updates In Web Component Hosts
When using <triiiceratops-viewer>, assign a new config object from JavaScript.
<triiiceratops-viewer id="viewer"></triiiceratops-viewer>
<script>
const viewer = document.getElementById('viewer');
viewer.config = {
plugins: {
'pdf-export': {
visible: false,
open: true,
},
},
};
</script>
Notes:
visible: falsehides only the plugin toolbar button.open: truekeeps the panel open if the plugin is registered.config.pluginskeys must match each plugin'sid.
Adding Plugins
When using the <triiiceratops-viewer> custom element, you cannot pass complex objects via HTML attributes. Instead, set the plugins property using JavaScript after the element is defined.
Script Tags (No Build Required):
<!-- Load the viewer -->
<script src="https://unpkg.com/triiiceratops/dist/triiiceratops-element.iife.js"></script>
<!-- Load plugins -->
<script src="https://unpkg.com/triiiceratops/dist/triiiceratops-plugin-image-manipulation.iife.js"></script>
<triiiceratops-viewer
manifest-id="https://iiif.wellcomecollection.org/presentation/v3/b18035723"
></triiiceratops-viewer>
<script>
customElements.whenDefined('triiiceratops-viewer').then(() => {
const viewer = document.querySelector('triiiceratops-viewer');
// Plugins are pre-configured objects on window.TriiiceratopsPlugins
viewer.plugins = [
window.TriiiceratopsPlugins.ImageManipulation
];
});
</script>
With a Build System:
If you're using the web component in a project with a bundler (Vite, Webpack, etc.):
When using the TriiiceratopsViewer Svelte component directly, pass plugins via the plugins prop.
<script>
import { TriiiceratopsViewer } from 'triiiceratops';
import 'triiiceratops/style.css';
import { ImageManipulationPlugin } from 'triiiceratops/plugins/image-manipulation';
</script>
<div style="height: 600px;">
<TriiiceratopsViewer
manifestId="https://example.com/manifest.json"
plugins={[ImageManipulationPlugin]}
/>
</div>
Multiple Plugins:
<script>
import { TriiiceratopsViewer } from 'triiiceratops';
import 'triiiceratops/style.css';
import { ImageManipulationPlugin } from 'triiiceratops/plugins/image-manipulation';
import MyCustomPlugin from './MyCustomPlugin.svelte';
import CustomIcon from './CustomIcon.svelte';
const plugins = [
ImageManipulationPlugin,
{
name: 'My Custom Feature',
icon: CustomIcon,
panel: MyCustomPlugin,
position: 'right'
}
];
</script>
<div style="height: 600px;">
<TriiiceratopsViewer manifestId="..." {plugins} />
</div>
Customizing Built-in Plugins:
If you need to customize the name, position, or other properties of a built-in plugin, you can import the individual components:
<script>
import { TriiiceratopsViewer } from 'triiiceratops';
import 'triiiceratops/style.css';
import { ImageManipulationController, SlidersIcon } from 'triiiceratops/plugins/image-manipulation';
const plugins = [
{
name: 'Custom Name',
icon: SlidersIcon,
panel: ImageManipulationController,
position: 'right' // Override default position
}
];
</script>
<div style="height: 600px;">
<TriiiceratopsViewer manifestId="..." {plugins} />
</div>
Available Plugins
Image Manipulation
Provides brightness, contrast, saturation, invert, and grayscale controls for the displayed image.
PDF Export
Exports a flat range of canvases as a browser-generated PDF, with one PDF page per selected canvas.
Feature summary:
- range-based export from the plugin panel
- one PDF page per selected canvas
- optional static or dynamic consumer-provided download filename
- optional cover sheet with consumer-provided label/value metadata
- selectable OCR text when the canvas exposes IIIF OCR annotations
- configurable browser image request settings for public or authenticated image services
- optional consumer callback for the currently selected start and end canvases
By default, PdfExportPlugin uses:
- an automatically generated filename based on the manifest and selected canvas range
- no cover sheet
- public-friendly image fetching with
credentials: "same-origin" - OCR text embedding only when suitable IIIF OCR annotations are present
Basic Usage
Script-tag usage exposes the default preconfigured plugin and a factory for configured instances:
Configuring The Plugin
Use createPdfExportPlugin(...) when you want a custom filename, a cover sheet, a specific OCR annotation source, export-only OCR overlays, or custom image request behavior.
import { createPdfExportPlugin } from 'triiiceratops/plugins/pdf-export';
const pdfExportPlugin = createPdfExportPlugin({
getFilename: ({ manifestLabel, startIndex, endIndex, defaultFilename }) =>
manifestLabel
? `${manifestLabel}-${startIndex + 1}-${endIndex + 1}.pdf`
: defaultFilename,
coverSheet: {
title: 'Digitization Summary',
fields: [
{ label: 'Repository', value: 'Example Library' },
{ label: 'Call Number', value: 'MS 123' },
],
},
ocrAnnotationSource: 'https://example.org/canvas/1/ocr',
async getCanvasOcrOverlays({ canvasId }) {
const response = await fetch(
`/api/ocr-overlays?canvas=${encodeURIComponent(canvasId)}`,
);
if (!response.ok) {
return [];
}
const overlays = await response.json();
return overlays.map((overlay) => ({
...overlay,
// Use 'image' when your OCR API returns coordinates in the
// selected source image's pixel space instead of canvas pixels.
coordinateSpace: 'image',
}));
},
imageRequest: {
credentials: 'same-origin',
},
onSelectionChange({ startCanvas, endCanvas, startIndex, endIndex }) {
console.log('Selected PDF export range', {
startCanvas,
endCanvas,
startIndex,
endIndex,
});
},
});
For script-tag/web component hosts, use the factory exposed on the IIFE plugin global when you need configuration callbacks:
<script>
viewer.plugins = [
window.TriiiceratopsPlugins.PdfExport.createPdfExportPlugin({
onSelectionChange({ startCanvas, endCanvas, startIndex, endIndex }) {
console.log('Selected PDF export range', {
startCanvas,
endCanvas,
startIndex,
endIndex,
});
}
})
];
</script>
For image services that cannot be fetched directly by the browser, you can also provide a custom image loader:
import { createPdfExportPlugin } from 'triiiceratops/plugins/pdf-export';
const pdfExportPlugin = createPdfExportPlugin({
loadImageBlob: async ({ imageUrl }) => {
const response = await fetch(
`/api/pdf-image?url=${encodeURIComponent(imageUrl)}`,
);
if (!response.ok) {
throw new Error('Unable to load image for PDF export.');
}
return response.blob();
},
});
You can use that configured plugin in either a Svelte app or a bundler-based host app that assigns plugins to the web component:
import { createPdfExportPlugin } from 'triiiceratops/plugins/pdf-export';
const pdfExportPlugin = createPdfExportPlugin({
coverSheet: {
title: 'Export Summary',
fields: [{ label: 'Collection', value: 'Example collection' }],
},
});
viewer.plugins = [pdfExportPlugin];
Configuration shape:
type PdfExportConfig = {
filename?: string;
getFilename?: (context: {
manifestId: string | null;
manifestLabel?: string | null;
startIndex: number;
endIndex: number;
indices: number[];
canvases: any[];
exportedCount: number;
failedCanvases: string[];
defaultFilename: string;
}) => Promise<string | null | undefined> | string | null | undefined;
coverSheet?: {
title?: string;
fields: { label: string; value: string }[];
};
ocrAnnotationSource?: string;
ocrPlacementMode?: 'fit-box' | 'word-anchor';
ocrSizingMode?: 'fit-box' | 'height-only';
ocrVisibilityMode?: 'transparent' | 'invisible' | 'debug';
onSelectionChange?: (selection: {
startIndex: number | null;
endIndex: number | null;
startCanvas: any | null;
endCanvas: any | null;
}) => void;
getCanvasOcrOverlays?: (context: {
manifestId: string | null;
canvasId: string;
canvas: any;
canvasIndex: number;
}) =>
| Promise<
| {
text: string;
x: number;
y: number;
width: number;
height: number;
coordinateSpace?: 'canvas' | 'image';
}[]
| null
| undefined
>
| {
text: string;
x: number;
y: number;
width: number;
height: number;
coordinateSpace?: 'canvas' | 'image';
}[]
| null
| undefined;
imageRequest?: {
credentials?: RequestCredentials;
headers?: HeadersInit;
mode?: RequestMode;
referrerPolicy?: ReferrerPolicy;
};
loadImageBlob?: (params: {
canvas: any;
canvasId: string;
imageUrl: string;
manifestId: string | null;
targetWidth: number;
imageRequest: RequestInit;
resolvedImage: any | null;
}) => Promise<Blob> | Blob;
};
Filename
Set filename when the consuming application should control the downloaded PDF name with a static value. The value is passed directly to the browser download link, so include the .pdf extension when you want it shown in the saved file name.
Set getFilename when the consuming application should compute the downloaded PDF name for each export. The callback receives the manifest identifier and label, normalized selected range, selected canvases, export counts, failed canvas labels, and the generated defaultFilename.
If both filename and getFilename are configured, filename takes precedence and getFilename is not called. If getFilename returns null, undefined, or an empty string, the plugin uses the generated filename fallback.
When both filename and getFilename are omitted, the plugin generates a PDF filename from the manifest label or identifier and the selected canvas range.
Cover Sheet
When coverSheet is configured, the exported PDF begins with a generated summary page.
The cover sheet includes:
- each consumer-provided
label/valuepair - the PDF creation date and time
- the current page URL, when available in the browser
The export UI does not ask end users to edit these fields. They are supplied by the consuming application at plugin creation time.
OCR Support
When a canvas includes IIIF OCR annotations, the plugin embeds selectable text into the exported PDF.
The plugin reads OCR from IIIF annotation data, not from IIIF Search responses. Search hits alone are not enough because the PDF export needs stable text plus canvas-relative bounding boxes.
Manifest OCR annotations are normalized automatically when their xywh boxes are in the selected source image's pixel space instead of the canvas pixel space.
If your app stores OCR outside the IIIF manifest, configure getCanvasOcrOverlays to supply PDF text overlays directly during export. This callback runs only for canvases included in the selected PDF export range. It is not used during normal canvas navigation, search, thumbnail rendering, or viewer startup.
Provider overlay coordinates default to canvas space for backward compatibility. If your provider returns original image pixel coordinates, set coordinateSpace: 'image' on each overlay so the exporter can normalize them before PDF placement.
Supported OCR annotation patterns include:
- IIIF Presentation 3 annotations using
TextualBodyplusmotivation: "supplementing" - legacy IIIF Presentation 2 text annotation lists in
otherContent, includingcnt:ContentAsTextbodies that usesc:paintingfor line text
OCR is resolved in this order during export:
- if
getCanvasOcrOverlaysreturns a non-null value, that result is used and manifest OCR is skipped for that canvas - otherwise, if
ocrAnnotationSourceis set, the plugin loads OCR from that specific annotation page/listid - otherwise, the plugin reads OCR-compatible annotations from every available canvas annotation source
Callback result semantics:
- return
[]to mark the canvas as handled and export it without OCR text - return
nullorundefinedto fall back to manifest-based OCR loading - if the callback throws, the export logs a PDF-scoped warning and falls back to manifest-based OCR loading
OCR rendering options:
ocrPlacementMode: 'fit-box'preserves the existing box-fitting behaviorocrPlacementMode: 'word-anchor'keeps each word anchored to its suppliedxand top-originyposition without vertical recenteringocrSizingMode: 'fit-box'uses both overlay width and height to size the textocrSizingMode: 'height-only'sizes from overlay height only and does not stretch words to fill the OCR widthocrVisibilityMode: 'transparent'uses the existing near-transparent text layer behaviorocrVisibilityMode: 'invisible'prefers PDF invisible text rendering semantics when supported by the PDF layerocrVisibilityMode: 'debug'draws OCR text visibly for placement checks
Default OCR rendering behavior remains backward-compatible:
Recommended settings for word-level OCR overlays:
To make exported PDF text selectable, provide OCR as canvas-linked IIIF annotations with these properties:
- the canvas
widthandheightmust use the same coordinate space as the OCR bounding boxes - each OCR annotation should target a rectangle using
#xywh=x,y,w,hor aFragmentSelectorwithxywh=... - each OCR annotation should use
motivation: "supplementing" - each OCR annotation body should be a
TextualBodywith plain text invalue - embedded and external
AnnotationPageresources are both supported - the original ALTO, hOCR, or other OCR file can also be linked via
seeAlso, but the plugin reads the IIIF annotations directly
Example canvas with an external OCR page:
{
"id": "https://example.org/canvas/1",
"type": "Canvas",
"width": 3000,
"height": 4000,
"annotations": [
{
"id": "https://example.org/canvas/1/ocr",
"type": "AnnotationPage"
}
],
"seeAlso": [
{
"id": "https://example.org/canvas/1/ocr/alto.xml",
"type": "Dataset",
"format": "application/xml",
"label": {
"en": ["ALTO OCR"]
}
}
]
}
Example OCR annotation page:
{
"id": "https://example.org/canvas/1/ocr",
"type": "AnnotationPage",
"items": [
{
"id": "https://example.org/canvas/1/ocr/line/1",
"type": "Annotation",
"motivation": "supplementing",
"body": {
"type": "TextualBody",
"value": "This is one OCR line.",
"format": "text/plain"
},
"target": "https://example.org/canvas/1#xywh=240,380,1620,52"
}
]
}
Tesseract guidance:
- convert each OCR line or word into one IIIF annotation item
- line-level annotations are the easiest starting point for usable PDF text selection, but word-level overlays are also supported
- if your Tesseract boxes are in raw image pixels, make sure the canvas
widthandheightmatch that same pixel space, or scale the boxes during annotation generation
Image Request Notes
The plugin fetches canvas images with credentials: "same-origin" by default. This avoids common CORS failures on public IIIF servers that respond with Access-Control-Allow-Origin: *.
For IIIF-backed exports, the plugin automatically requests wide or spread canvases by height instead of width so landscape pages are not capped by the viewer-width-derived export size. Portrait and square canvases continue to use width-constrained requests.
For IIIF Image API level 0 services, the plugin prefers the painting body's declared image URL instead of synthesizing an arbitrary sized IIIF image request. This is more compatible with services that expose only a fixed image URL alongside a level 0 service description.
Some IIIF image services block browser access entirely. Typical symptoms are:
- no
Access-Control-Allow-Originresponse header 401or403responses for cross-origin image fetches- browser errors such as
TypeError: Failed to fetch
In those cases, a purely client-side export is not possible from a different origin. Configure loadImageBlob so your application can fetch the image through a same-origin proxy, a backend endpoint, or another authenticated path that the browser is allowed to read.
If your image service requires cookies or another authenticated browser session, configure the plugin explicitly:
import { createPdfExportPlugin } from 'triiiceratops/plugins/pdf-export';
const plugin = createPdfExportPlugin({
imageRequest: {
credentials: 'include',
mode: 'cors',
headers: {
Authorization: 'Bearer <token>',
},
},
});
Supported imageRequest fields are passed directly to fetch(...):
credentialsheadersmodereferrerPolicy
Use loadImageBlob when imageRequest is still not enough because the remote service does not allow browser access at all.
Only use credentials: "include" when the IIIF image service is configured for credentialed CORS.
Annotation Editor
Provides optional annotation authoring on top of the read-only viewer. The plugin supports rectangle, polygon, and point drawing tools, pluggable persistence, and host-provided extension hooks for app-specific workflows.
Out of the box, AnnotationEditorPlugin uses a LocalStorageAdapter. Use createAnnotationEditorPlugin(...) when you want to persist elsewhere or inject host logic.
Custom Storage Adapters
The plugin persistence layer is framework-agnostic. Supply an AnnotationStorageAdapter to back annotations with your own API, IndexedDB, SQLite bridge, or another local/remote store.
import {
createAnnotationEditorPlugin,
type AnnotationStorageAdapter,
} from 'triiiceratops/plugins/annotation-editor';
const adapter: AnnotationStorageAdapter = {
id: 'my-adapter',
name: 'My Adapter',
async load(manifestId, canvasId) {
return [];
},
async hydrate(manifestId, canvasId, annotationId) {
return null;
},
async create(manifestId, canvasId, annotation) {},
async update(manifestId, canvasId, annotation) {},
async delete(manifestId, canvasId, annotationId) {},
};
const plugin = createAnnotationEditorPlugin({ adapter });
hydrate(...) is optional. Implement it when you want to load lightweight annotation headers first and fetch large bodies only when a specific annotation is selected.
Host Extension Hooks
For app-specific behavior, prefer the extension API over forking the plugin. This keeps the annotation editor reusable in both the Svelte package and the web component build.
import {
createAnnotationEditorPlugin,
type AnnotationEditorExtension,
} from 'triiiceratops/plugins/annotation-editor';
const extension: AnnotationEditorExtension<{ selectedText: string | null }> = {
getContext: () => ({ selectedText: window.appSelection ?? null }),
canCreate: ({ hostContext }) => !!hostContext?.selectedText,
getCreateDisabledReason: ({ hostContext }) =>
hostContext?.selectedText
? null
: 'Select text before creating an annotation.',
prepareDraft: (annotation, { hostContext }) => ({
...annotation,
body: hostContext?.selectedText
? [
{
type: 'TextualBody',
purpose: 'commenting',
value: hostContext.selectedText,
},
]
: [],
}),
beforeSave: async (annotation, context) => annotation,
onSelectionChange: (annotation, context) => {},
};
const plugin = createAnnotationEditorPlugin({ extension });
The extension context includes the active manifest/canvas, current editing state, selected annotation, current user, and your host-specific context object.
Backward-Compatible Hooks
prepareAnnotation, canCreateAnnotation, and getCreateDisabledReason remain available for simple integrations. New work should prefer extension because it works as a single, portable surface for creation rules, draft enrichment, save-time transforms, and selection callbacks.
Export Paths
triiiceratops/plugins/annotation-editortriiiceratops/plugins/annotation-editor.iife
Creating Custom Plugins
Custom plugins are Svelte components that receive props from the plugin system and can access the viewer's state via Svelte context.
Plugin Component Props
Your plugin component receives these props:
| Prop | Type | Description |
|---|---|---|
isOpen |
boolean |
Whether the plugin panel is currently open |
close |
() => void |
Function to close the plugin panel |
Accessing Viewer State
Use Svelte's getContext to access the viewer's reactive state:
<script>
import { getContext } from 'svelte';
// Props from the plugin system
let { isOpen, close } = $props();
// Access the viewer's reactive state
const viewerState = getContext('triiiceratops:viewerState');
function handleZoomIn() {
viewerState.osdViewer?.viewport.zoomBy(1.5);
}
function handleNextCanvas() {
viewerState.nextCanvas();
}
</script>
<div class="p-4">
<h3>My Custom Plugin</h3>
<p>Current canvas: {viewerState.canvasId}</p>
<div class="flex gap-2">
<button onclick={handleZoomIn}>Zoom In</button>
<button onclick={handleNextCanvas}>Next Canvas</button>
<button onclick={close}>Close</button>
</div>
</div>
ViewerState Properties
The viewerState context provides access to:
| Property | Type | Description |
|---|---|---|
manifestId |
string \| null |
Current manifest URL |
canvasId |
string \| null |
Current canvas ID |
currentCanvasIndex |
number |
Index of current canvas (-1 if none) |
canvases |
any[] |
Array of canvas objects from manifest |
osdViewer |
OpenSeadragon.Viewer \| null |
OpenSeadragon instance |
showAnnotations |
boolean |
Whether annotations are visible |
showThumbnailGallery |
boolean |
Whether the thumbnail gallery is open |
showSearchPanel |
boolean |
Whether the search panel is open |
searchQuery |
string |
Current search query |
searchResults |
any[] |
Array of search results |
isSearching |
boolean |
Whether a search is in progress |
isFullScreen |
boolean |
Whether the viewer is in fullscreen mode |
dockSide |
string |
Current dock side for gallery |
hasNext |
boolean |
Whether there is a next canvas |
hasPrevious |
boolean |
Whether there is a previous canvas |
And methods:
| Method | Description |
|---|---|
nextCanvas() |
Navigate to the next canvas |
previousCanvas() |
Navigate to the previous canvas |
setCanvas(id) |
Navigate to a specific canvas by ID |
setManifest(id) |
Load a new manifest |
toggleFullScreen() |
Toggle fullscreen mode |
toggleAnnotations() |
Toggle annotation visibility |
toggleThumbnailGallery() |
Toggle thumbnail gallery |
toggleSearchPanel() |
Toggle search panel |
search(query) |
Perform a search (async) |
Registering Your Custom Plugin
Custom plugins for script-tag usage require building your own IIFE bundle that:
- Uses Svelte from
window.__TriiiceratopsSvelteRuntime - Registers on
window.TriiiceratopsPlugins
See vite.config.plugins-iife.ts in the Triiiceratops source for an example build configuration.
Simply import your custom component and add it to the plugins array:
<script>
import { TriiiceratopsViewer } from 'triiiceratops';
import 'triiiceratops/style.css';
import MyCustomPanel from './MyCustomPanel.svelte';
import MyIcon from 'phosphor-svelte/lib/Star'; // or your own icon
const plugins = [
{
name: 'My Custom Plugin',
icon: MyIcon,
panel: MyCustomPanel,
position: 'right'
}
];
</script>
<div style="height: 600px;">
<TriiiceratopsViewer manifestId="..." {plugins} />
</div>
Package Exports Reference
| Export Path | Description |
|---|---|
triiiceratops |
Main Svelte component and utilities |
triiiceratops/element |
Web component IIFE bundle |
triiiceratops/plugins/annotation-editor |
Annotation editor plugin (ES module) |
triiiceratops/plugins/annotation-editor.iife |
Annotation editor plugin (IIFE bundle) |
triiiceratops/plugins/image-manipulation |
Image manipulation plugin (ES module) |
triiiceratops/plugins/image-manipulation.iife |
Image manipulation plugin (IIFE bundle) |
triiiceratops/style.css |
Stylesheet (for Svelte component usage) |