TPTruPDF

@trupdf/threed

3D PDF support. Detects /Subtype /3D and /Subtype /RichMedia annotations, classifies the embedded geometry stream (U3D vs PRC via the /3DD stream header), and renders the static poster appearance as a positioned layer in the page composition stack.

Scope is poster preview by design. Interactive U3D / PRC rendering is intentionally not provided — customers needing interactive CAD viewing use a desktop tool outside the viewer. The package is installed separately (it is not part of the rolled-up @trupdf/viewer bundle) and stays independent of the annotation engine, so hosts without 3D content ship zero extra bytes.

Detection

import { detectThreeDAnnotations } from '@trupdf/threed';
 
const threeDs = detectThreeDAnnotations(await page.getAnnotations());
// ThreeDAnnotation[] — empty for pages without 3D content
ExportPurpose
detectThreeDAnnotations(annotations)Filter + classify a page's raw annotations
classifyAnnotation(raw)One raw annotation → classified record (or null)
classifyKind(raw)'3d' | 'richmedia' subtype detection
classifyStreamFormat(bytes)'u3d' | 'prc' | 'unknown' from the stream magic
normalizeRect(rect)Normalise a /Rect array into PdfRect
pdfRectToScreen(rect, viewport)PDF user space → screen-space ScreenRect
interface ThreeDAnnotation {
  id: string;
  kind: ThreeDKind;      // '3d' | 'richmedia'
  format: ThreeDFormat;  // 'u3d' | 'prc' | 'unknown'
  rect: PdfRect;         // /Rect in PDF user space
  posterUrl: string | null;
  streamBytes: Uint8Array | null; // the embedded geometry stream
  // …crop/position metadata
}

Poster rendering

import { renderPostersForPage, posterCanvasToDataUrl } from '@trupdf/threed';
 
const posters = await renderPostersForPage(page, threeDs, {
  annotationModeEnableValue: 1, // the render engine's ENABLE annotation mode
  scale: 1,
  signal,
});
const dataUrl = posterCanvasToDataUrl(posters.get(threeDs[0].id)!);

renderPostersForPage(page, annotations, options) renders each 3D annotation's appearance-stream poster to its own canvas and returns a PosterCanvasMap. An empty annotation array is a no-op and is not license-gated.

ThreeDLayer (React)

The positioned page layer the viewer mounts automatically. Use it directly when composing your own page stack:

<ThreeDLayer
  pageNumber={pageNumber}
  annotations={threeDs}
  viewport={viewport} // same object the page layers use — keeps pixel alignment
  secureMode={false}
  eventBus={engine} // optional; emits threed.* events
/>

In secureMode every annotation renders as the fallback with reason 'secure-mode' — no embedded stream is touched.

PosterFallback ({ annotation }) is the labelled placeholder shown when no poster can be produced.

Events

Emitted on the supplied eventBus:

EventPayload
threed.detected{ pageIndex, kind, format, rendered }
threed.rendered{ pageIndex, format: 'u3d' }
threed.fallback{ pageIndex, reason, format }

ThreeDFallbackReason: 'prc-unsupported' | 'no-renderer-available' | 'parse-failure' | 'no-3dd-stream' | 'secure-mode'.

License gate

Poster rendering and the layer require the threed feature (gate.require('threed')). Trial tokens cannot render 3D posters.