@opensite/img
v0.1.4
Published
OpenSite optimal img component with dynamic srcset generation
Downloads
53
Readme
@opensite/img
High‑performance, native‑like dynamic img rendering engine for the OpenSite ecosystem. It accepts a numeric mediaId, fetches the optimal variants from the DashTrack CDN, and renders the best source for the viewer’s device and browser. It wraps the srcset variants list inside a <picture> tag and can be treated like a standard html <img> tag.
Key points
- Renders a plain
<picture>element (no wrapper, no default styles). - Accepts all native
<img>props and ref; drop‑in replacement. - Chooses the best source: Webp → jpg → png.
Installation
Core (required):
pnpm install @opensite/imgQuick Start
Minimal (progressive playback, tiny bundle):
import { Image } from '@opensite/img';
export function Hero({ mediaId }: { mediaId: number }) {
return (
<Image
mediaId={mediaId}
className="hero-video"
/>
);
}TODO: CONTINUE WRITING OUT DOCS FROM HERE - @opensite/video's README.md below for an example
Upgrade to adaptive streaming only on user interaction (e.g., first play):
<Video mediaId={mediaId} controls streamingOnInteraction />Force adaptive streaming immediately (if available):
<Video mediaId={mediaId} controls adaptiveStreaming />Prefer a progressive codec/size (optional):
<Video mediaId={mediaId} preferCodec="WEBM" preferSize="medium" />Poster behavior:
poster={"https://…"}→ use provided URL.poster={false}→ disable poster entirely.- Poster omitted → auto‑use
cover.urlfrom CDN payload if provided.
Props
Required
mediaId: number— DashTrack media record ID used to fetch the media snapshot.
Optional
cdnHost?: string— Override CDN origin. Default:https://cdn.ing.adaptiveStreaming?: boolean— Immediately attach HLS/DASH adapter when applicable.streamingOnInteraction?: boolean— Progressive first, upgrade on first play.streamingUpgrade?: boolean— Allow upgrades at all (default: true). Set false to force progressive.preferCodec?: 'HLS' | 'DASH' | 'WEBM' | 'MP4'— Preferred codec when multiple are present.preferSize?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge'— Preferred progressive size variant.poster?: string | false— Poster override or disable; omitted defaults to CDNcover.url.onImageData?: (data: ImageData) => void— Callback when CDN payload is loaded.- All native
<video>attributes (e.g.,controls,muted,playsInline,style,className, etc.).
Direct src fallback
- You can omit
mediaIdand providesrcto play a direct progressive asset (MP4/WebM). In this mode, no CDN request is performed and streaming adapters are not attached.
Ref
- The component forwards a
refto the underlying<video>element for direct control and event subscriptions.
CDN Integration
- Default fetch URL:
https://cdn.ing/assets/videos/<mediaId>. - Override origin via
cdnHostprop; path shape is fixed by the module. - The response is cached at the module level to avoid redundant network calls.
Expected payload (subset)
type ImageData = {
id: number;
cover?: { url: string; width?: number; height?: number };
variants_data: {
variants: {
HLS?: { cdn_master_playlist_url: string; rungs?: { bandwidth?: number; resolution?: string; codecs?: string }[] };
DASH?: { cdn_manifest_url: string; rungs?: { bandwidth?: number; resolution?: string; codecs?: string }[] };
PROGRESSIVE_MP4?: Partial<Record<'tiny'|'small'|'medium'|'large'|'xlarge', string>>;
WEBM?: Partial<Record<'tiny'|'small'|'medium'|'large'|'xlarge', string>>;
};
};
};Source Selection Logic
Order of preference (auto mode)
- Native HLS (Safari/iOS) via
application/vnd.apple.mpegurl. - Progressive WebM (modern browsers) by preferred/available size.
- Progressive MP4 (universal fallback) by preferred/available size.
- If only streaming manifests exist and not natively supported, attach
hls.jsordashjswhen allowed.
You can override with preferCodec and preferSize as hints; the component will still ensure the final result is playable on the current browser.
Streaming Options
adaptiveStreaming— Attach streaming adapter immediately if an HLS or DASH manifest exists and the browser needs an adapter.streamingOnInteraction— Keep progressive first, then upgrade on firstplayevent (recommended to minimize initial JS).streamingUpgrade={false}— Disable all upgrades and stick to progressive assets.
Adapters (dynamic imports)
- HLS (non‑Safari):
hls.jsviasrc/streaming/hls-adapter. - DASH:
dashjsviasrc/streaming/dash-adapter.
These imports happen only when required by the chosen streaming path.
Styling & Layout
- The component renders a plain
<video>element. - No wrapper
<div>and no default CSS are applied. - Style it exactly as you would a native tag (e.g., with
className, inlinestyle, utility classes, etc.).
Example
<Video mediaId={mediaId} className="w-full h-auto rounded-xl shadow" />SSR & Environments
- All network requests and capability detection happen in
useEffect, so nothing runs on the server. - On the server, the component renders a bare
<video>; sources are applied after mount. - If immediate poster visibility is required with potential network latency, pass
posterexplicitly so it shows before the CDN payload loads.
TypeScript
Types are exported from the root module:
import type { ImageData, PreferredCodec, PreferredSize } from '@opensite/video';Useful types
ImageData,Variants,VariantRungBrowserCapabilities,SelectedSourcePreferredCodec,PreferredSize
Tree‑Shakable Exports
Recommended
import { Video } from '@opensite/video';Sub‑paths (advanced)
@opensite/video/core— capability/source helpers@opensite/video/streaming/hls— HLS adapter (dynamic import normally handles this)@opensite/video/streaming/dash— DASH adapter (dynamic import normally handles this)
Package.json sets sideEffects: false and an exports map for optimal tree‑shaking.
Examples
Hero/Background (progressive only)
<Video mediaId={mediaId} autoPlay muted loop controls={false} preload="metadata" streamingUpgrade={false} />Interactive B‑Roll (upgrade on play)
<Video mediaId={mediaId} controls streamingOnInteraction />Short‑Form (full streaming)
<Video mediaId={mediaId} controls adaptiveStreaming />Custom poster and sizing
<Video mediaId={mediaId} poster="https://cdn.example.com/posters/123.jpg" style={{ aspectRatio: '16 / 9', width: '100%' }} />Using a ref
const ref = useRef<HTMLVideoElement>(null);
<Video mediaId={mediaId} controls ref={ref} />
// later
ref.current?.play();Accessibility (reduced motion)
const prefersReducedMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
<Video mediaId={mediaId} autoPlay={!prefersReducedMotion} muted loop />Browser Support
- Safari/iOS: native HLS supported.
- Chrome/Edge/Firefox: progressive WebM/MP4; optional HLS/DASH via adapters.
- The component automatically chooses the best playable source.
Troubleshooting
- No video appears
- Check
mediaIdand network tab for the CDN request. - Verify your CDN returns at least one progressive asset or a streaming manifest.
- Check
- Streaming doesn’t start on non‑Safari
- Install
hls.jsand/ordashjs. - Ensure
adaptiveStreamingorstreamingOnInteractionis set.
- Install
- Poster not shown
- If
posteris omitted and the payload has nocover.url, no poster will be used.
- If
Architecture Notes
- Capability detection and source selection are in
src/core/. - Streaming adapters (HLS/DASH) live in
src/streaming/and are imported dynamically. - CDN integration is isolated in
src/utils/api.tswith lightweight caching. - The module follows the patterns outlined in
ECOSYSTEM_GUIDELINES.md.
Contributing
- Keep the component free of wrappers and default CSS.
- Preserve progressive‑first behavior; treat streaming as an upgrade.
- Maintain tree‑shakability and small initial bundle size.
- When extending functionality (e.g., custom controls), ensure features are optional and tree‑shakable.
License
Private module for the OpenSite ecosystem.
