← demo catalog · docs

tify-plugins

Note: This code was generated with AI assistance — opencode, powered by GLM (Z.ai).

Plugins for TIFY (tify@0.36.2), the slim IIIF document viewer, published as individual npm modules under @projektemacher/tify-plugin-* from this monorepo. TIFY has no formal plugin registry, so plugins here are wrapper modules around a live Tify instance: (tify, options) => { destroy() }, using the instance API (ready, setPage, setView, …) plus the exposed OpenSeadragon viewer (tify.viewer).

Packages

Each workspace is independently publishable: it carries its own package.json, README, example, and translations; npm publish --workspace … ships only dist/ (plus core's stylesheets) — examples and sources stay dev-only.

Package npm name What it does
packages/core @projektemacher/tify-plugin-core Plugin contract, i18n, IIIF/dock helpers, panel styles
packages/plugin-side-panel @projektemacher/tify-plugin-side-panel Custom metadata panel beside the viewer
packages/plugin-image-overlays @projektemacher/tify-plugin-image-overlays OpenSeadragon overlays synced to pages (TEI word boxes)
packages/plugin-hdr @projektemacher/tify-plugin-hdr HDR canvas status + image service check
packages/plugin-c2pa @projektemacher/tify-plugin-c2pa Per-tile C2PA provenance with trust anchors
packages/plugin-annotorious @projektemacher/tify-plugin-annotorious Display-only Annotorious annotations from the manifest
packages/plugin-musicxml @projektemacher/tify-plugin-musicxml Rendered MusicXML score with playback (from the homr TEI)

Rules that keep this shippable: tify (and openseadragon where imported directly) are peerDependencies — the viewer must exist exactly once. Third-party runtime deps (hdr-canvas, c2pa-web, @annotorious/openseadragon, opensheetmusicdisplay) are bundled into their plugin. Consumers need skipLibCheck (TIFY itself ships no types; each package documents this). The C2PA package embeds the WASM binary (~11MB, ~4MB gzipped) via c2pa-web's inline entry — the only option that survives installation as a dependency, since a library cannot assume the host serves its internal asset paths.

Generating IIIF images

The Image API side (tiles + info.json) consumed by the examples and plugins can be generated with fliiifenleger, a static Java IIIF tiler. The wrapping Presentation manifest — what the examples actually load — is authored separately (IIIF Cookbook style).

Package fliiifenleger settings
side-panel, basic examples generate with --iiif-version V3 — any plain image service works
image-overlays same as above; the TEI transcription linked via canvas seeAlso is authored separately (not a fliiifenleger feature)
hdr --source ultrahdr --sink ultrahdr — UltraHDR tiles advertise exactly the https://christianmahnke.de/iiif/hdr/ service this plugin detects
c2pa --sink c2pa with --iiif-version V3; --sink-opt trust-anchor=… advertises the trustAnchor URI this plugin's trustAnchors option validates against
annotorious default generate; the xywh annotations are added afterwards at the Presentation-manifest level
musicxml score data (staff TEI + embedded MusicXML) comes from the homr OMR pipeline; image services themselves are plain generate output

Examples

Every workspace ships its own example under packages/*/example/ — the six plugin packages plus core's info panel. The root demo (index.html) is a catalog linking them all:

npm run dev      # http://localhost:5173/  (catalog)
                 # /packages/plugin-side-panel/example/, /packages/core/example/, …

Examples always run against the workspace sources (dev aliases); production builds use the packages' built dist/ output, exactly like an external consumer. Append ?lang=de to any example URL to check the German strings.

Develop

npm install
npm run dev            # catalog + all package examples (dev aliases → src)
npm run typecheck      # root demo + all packages/examples (via tsconfig paths)
npm run lint           # eslint + stylelint + prettier --check (repo-wide)
npm run lint:fix       # auto-fix + prettier --write
npm run test:i18n      # root demo + every package's own catalogue coverage
npm run test:e2e       # Playwright catalog suite (all browsers; E2E_PREVIEW=1 for the built app)
npm run test:e2e --workspaces --if-present  # per-package example suites
npm run test:e2e --workspace @projektemacher/tify-plugin-musicxml  # one package's suite
# …or from inside the workspace itself:
cd packages/plugin-musicxml && npm run test:e2e  # same suite, shared root server
npm run build          # core → plugins → catalog + examples (dist)
npm run preview

Per-module checks (as in CI, each with its own status check):

npm run lint --workspace @projektemacher/tify-plugin-hdr
npm run test:i18n --workspace @projektemacher/tify-plugin-hdr
npm run test:tei --workspace @projektemacher/tify-plugin-image-overlays

Use one of the plugins standalone:

npm install @projektemacher/tify-plugin-side-panel
import { sidePanelPlugin } from '@projektemacher/tify-plugin-side-panel';
import '@projektemacher/tify-plugin-core/style.css';

The same packages are also published to GitHub Packages under the @cmahnke scope (@cmahnke/tify-plugin-*, mirroring the npmjs releases). Releases run the Publish workflow (publish.yml: publishing a GitHub Release, or manually from the Actions tab), which gates on the full CI run and publishes only the packages whose version changed since the previous release tag — so re-running is a no-op. Installing from there needs authentication — add to .npmrc:

@cmahnke:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=<personal-access-token>

then npm install @cmahnke/tify-plugin-side-panel. The inter-package dependency (@projektemacher/tify-plugin-core) still resolves from npmjs, so no extra registry configuration is needed for it.

Plugin translations (English + German)

English source strings are the keys; each workspace owns its catalogue at src/i18n/translations/de.json ($language first, keys sorted). Lookup precedence mirrors TIFY: per-instance tify.options.translations[lang][key] override → catalogue → English. The language follows tify.options.language (so tify.setLanguage('de') switches plugin UI too), then ?lang=de, then the browser language. Every workspace's npm run test:i18n scans its own static t('…') / data-i18n keys and fails on missing, unused, empty, or mis-sorted catalogue entries (scripts/check-i18n.js <dir>).

Citing

This project is citable via Citation File Format (CITATION.cff, which GitHub renders in the sidebar) and Codemeta (codemeta.json, JSON-LD for software metadata exchange). Both name the author, license (AGPL-3.0-or-later), the repository, and TIFY as the wrapped viewer.

Version bumps must update both files' version (and date-released / dateModified) — the publish guard (npm run test:citation) fails otherwise, before any release.

node scripts/ci-publish-guard.mjs --metadata

License

AGPL-3.0-or-later, see LICENSE (matches TIFY's license; each package carries a copy).