01 / start
Install and register
The current public release is an alpha. Install it from the next channel:
npm install @brightblur/bbp-viewer@next<script type="module">
import '@brightblur/bbp-viewer';
</script>
<bbp-viewer src="/photos/example.bbp.jpg"></bbp-viewer>Importing the package registers <bbp-viewer>. The element works in plain HTML and in frameworks that support custom elements. View the package on npm ↗
02 / files and URLs
Image sources
The src attribute accepts a URL string. Remote resources such as S3 or R2 must allow the site's origin through CORS.
<bbp-viewer
src="https://images.example.com/example.bbp.jpg">
</bbp-viewer>Use the property for a browser File, Blob, URL, ArrayBuffer, or Uint8Array.
const viewer = document.querySelector('bbp-viewer');
input.addEventListener('change', () => {
viewer.src = input.files?.[0] ?? null;
});<img> is not enough: the component fetches its bytes so it can parse the BBP payload.03 / instance access
Instance keys
The property accepts strings, Uint8Array, or ArrayBuffer. Strings may be 64-character hexadecimal or base64. Assigning keys triggers a new local render.
const viewer = document.querySelector('bbp-viewer');
viewer.privateKeys = [
firstPrivateKey,
secondPrivateKey
];
viewer.clearKeys();An explicit instance key list overrides the shared page keyring until useSharedPrivateKeys() is called.
05 / declarative API
Attributes and properties
By default, the component shows the image recomposed with its available keys. Use compare for the draggable safe-base comparison or mask-only for the safe base alone.
| Name | Kind | Purpose |
|---|---|---|
src | Attribute or property | URL string as an attribute; URL, Blob, File, ArrayBuffer, or Uint8Array as a property. |
private-keys | Attribute | A JSON array of hex or base64 key strings. Prefer the property when keys are already in JavaScript. |
privateKeys | Property | Instance-specific private keys. |
source | Property | Alias for src. |
mask-only | Boolean attribute | Show only the undeciphered safe base. |
reveal-only | Boolean attribute | Explicitly select the default recomposed view. |
compare | Boolean attribute | Overlay the recomposed image and safe base with an accessible comparison slider. |
<bbp-viewer
src="/photos/example.bbp.jpg"
private-keys='["base64-private-key"]'>
</bbp-viewer>Embedding secrets in HTML can expose them to page source, logs, extensions, and analytics. The property or shared keyring is usually the safer integration.
06 / lifecycle
Rendering events
bbp-rendered fires after a successful render. For BBP files it reports the version, number of opened entities, total entity count, and accessible metadata. N-party intersections report an epochs array.
viewer.addEventListener('bbp-rendered', (event) => {
console.log(event.detail);
// {
// version: 1,
// openedEntities: 2,
// entityCount: 4,
// entities: [
// { kind: 'region', bbox, epoch: 3 },
// { kind: 'intersection', bbox, epochs: [3, 7, 2] }
// ]
// }
});
viewer.addEventListener('bbp-error', (event) => {
console.error(event.detail.error);
});A normal image reports kind: 'normal' and renders identically in both panes.
07 / frameworks
Framework integration
Use the web component directly where possible. Add a wrapper only for framework-specific behaviour that the component does not provide.
React
// Set non-string properties through a ref.
const viewer = viewerRef.current;
viewer.src = file;
viewer.privateKeys = keys;Svelte
Svelte assigns these values to the element's properties. Changes to file or keys update the viewer reactively.
<script>
import '@brightblur/bbp-viewer';
let { file, keys } = $props();
</script>
<bbp-viewer
src={file}
privateKeys={keys}
></bbp-viewer>08 / custom carriers
Carrier adapter
The payload and cryptography do not change between carriers. An adapter recognises the base format and adds, extracts, or removes one ancillary JUMBF binding.
type CarrierAdapter = {
detect(bytes: Uint8Array): boolean;
embed(base: Uint8Array, jumbf: Uint8Array): Uint8Array;
extract(file: Uint8Array): Uint8Array | null;
strip(file: Uint8Array): Uint8Array;
};- Implement structural detection from bytes.
- Embed the unchanged JUMBF superbox at an ancillary location.
- Extract only payloads with the BBP UUID.
- Strip only the BBP binding while preserving a decodable safe base.
- Add positive, negative, unrelated-metadata, and embed/extract/strip round-trip tests.
- Add the carrier to public detection and dispatch.
Current adapters are in packages/bbp/src/container.ts ↗.
09 / Apple platforms
Native macOS viewer
The repository includes a native macOS example app built with SwiftUI and AppKit. It parses JPEG, WebP, PNG, and HEIF carriers in Swift and calls the Rust crypto core through its C ABI.
pnpm build:macos-app
pnpm test:macos10 / operational boundary
Security notes
- Private keys stay in browser memory, but the host page still controls its JavaScript environment.
- Serve integrations over HTTPS and keep third-party scripts to a minimum.
- Do not place private keys in URLs, storage, analytics fields, or server-rendered markup.
- Use sensible limits before accepting large or adversarial files.
- The protocol is still a draft and has not completed an independent security audit.