<oim-player> Web Component Guide
The <oim-player> is a lightweight, framework-agnostic Custom Element that decodes and renders .oim interactive images directly in any web browser. Encapsulated inside an open Shadow DOM, it guarantees zero CSS conflicts with the host application.
1. Quick Installation & CDN Setup
You can load <oim-player> either from modern package registries or directly via CDN script tag:
<!-- Import standalone bundle via CDN -->
<script type="module" src="https://cdn.oim.media/player/v1/oim-player.js"></script>
<!-- Or install via npm/pnpm -->
<!-- pnpm add @oim-media/player-oim -->Usage in standard HTML markup:
<oim-player
src="https://cdn.oim.media/demo/imagen-muestra.oim.png"
lang="en"
fit="contain"
allow-dynamic-colors="true">
</oim-player>2. Observed DOM Attributes
<oim-player> observes attributes and updates the render tree dynamically upon changes:
| Attribute | Type | Default | Description |
|---|---|---|---|
src | string (URL or Blob) | "" | Source path of the .oim.png or .oim file |
lang | string | "en" | Currently active language code ("en", "es", etc.) |
fit | "contain" | "cover" | "contain" | Aspect-ratio fitting mode inside parent container |
align | "center" | "top" | "bottom" | "center" | Vertical alignment positioning |
placeholder | string | "" | Image URL to display while binary metadata loads |
allow-dynamic-colors | "true" | "false" | "true" | Enables semantic CSS custom property themes |
palette | string | (none) | Named palette from the .oim palettes to apply; without it the player follows prefers-color-scheme when the file has dark and light, else defaultPalette |
allow-zoom | "true" | "false" | "false" | Enables smooth interactive pan-and-zoom controls |
disable-animations | "true" | "false" | "false" | Halts all loops (respects prefers-reduced-motion) |
auto-rotate-lang | number | "false" | "false" | Interval in ms to automatically cycle languages |
3. Public JavaScript API & Methods
The custom element instance exposes imperative methods on the DOM node:
const player = document.querySelector('oim-player');
// Get the verified metadata object extracted from the PNG
const metadata = await player.getMetadata();
console.log('Document ID:', metadata.oim_id);
// Switch language programmatically in real-time
player.setLang('es');
// Inspect cryptographic signature verification status
const security = player.getSecurityStatus(); // "verified" | "unsigned" | "invalid"
// Control interactive zoom (1.0x to 4.0x)
player.setZoom(1.5);
// Teardown and clean observers
player.destroy();4. Custom Events & Event Handling
The player dispatches native Custom Events that bubble up to the host application:
| Event Name | Detail Payload | Description |
|---|---|---|
oim:loaded | { type: string, metadata: object } | Fired when metadata is extracted and validated |
oim:langchange | { lang: string } | Fired when the active language changes |
oim:action | { slot, name, trigger, targets } | Fired when a user interacts with a slot |
oim:incomplete | { missing_capabilities: string[] } | Fired if asset requires unsupported features |
error | { message: string, code: string } | Fired upon network or decompression failure |
Intercepting Actions with preventDefault()
When a user clicks on an interactive slot with an action, the host app can intercept and control the navigation:
player.addEventListener('oim:action', (event) => {
const { slot, name } = event.detail;
if (name === 'buy_button') {
event.preventDefault(); // Stop default navigation
openCustomCheckoutModal(slot.id);
}
});5. Security & Shadow DOM Isolation
The internal structure is isolated from global CSS:
- Shadow DOM: Uses
mode: 'open'with internal<style>injection. - Dynamic Colors Sanitization: Color values are strictly sanitized through
isSafeCssColorbefore application to CSS variables (var(--oim-color-*)). - Signature Verification: Verifies ECDSA P-256 signatures against public keys embedded in the player at build time, so rendering a file contacts no server and tells no one who is looking. Only a file signed with a key this build does not know makes the player ask for it, at
https://api.oim.media/v1/media/keysby default; a self-hosted fork can point elsewhere withwindow.OIM_PLAYER_CONFIG = { keysUrl: "..." }before loading the player.
6. Loading, Zoom and Styling from the Host Page
The player ships clean: it does only what the format needs and carries no decoration of its own. How it looks around the artwork belongs to the page that embeds it, through CSS custom properties. They inherit into the Shadow DOM, so set them on <oim-player> or any ancestor.
First load: one reveal, no piecemeal build
The artwork stays behind a veil (blurred and transparent) while it is built. Every layer is placed at its final size and opacity underneath, and the veil lifts once fonts, embedded layer images and Lottie animations are ready, then two frames later so layout and scale are applied. Visitors never see shapes appearing one by one or text growing into place. The wait is capped at 1.2 s, so a broken asset can never leave the artwork hidden.
A later re-render (for example a language switch) never drops the veil back: a language change uses its own short blur, or a plain fade when the visitor asked for reduced motion.
CSS custom properties
| Property | Default | Effect |
|---|---|---|
--oim-reveal-blur | 14px | Blur of the veil on first load. 0px for a plain fade. |
--oim-reveal-duration | 0.32s | How long the veil takes to lift. |
--oim-color-<role> | the author's colour | Recolours a semantic role (primary, on-primary, secondary, on-secondary, surface, on-surface, outline, accent). See Dynamic Colors. |
oim-player {
--oim-reveal-blur: 6px;
--oim-reveal-duration: 0.2s;
--oim-color-primary: #2563eb;
}A role you leave unset falls back to the colour the author saved in each layer. Use allow-dynamic-colors="false" to exempt one artwork from your palette.
The palette attribute picks one of the named palettes the artwork ships (for example palette="light"). Changing it updates the player without a reload. Your own --oim-color-* variables still win over the palette.
Zoom
With allow-zoom="true", the wheel and trackpad zoom proportionally to how far they move (one mouse-wheel notch is about 5%), between 1x and 4x. A pinch (ctrl + wheel) responds faster than scrolling. Small back-and-forth deltas at the end of a trackpad gesture barely move the zoom, so the artwork does not shake.