API Reference
This reference covers the MotionPrint JavaScript/TypeScript SDK for embedding and verifying cryptographic watermarks in animation files.
Installationโ
npm install @thirdrez/motionprint
# or
pnpm add @thirdrez/motionprint
Quick Startโ
import { embedGLB, verifyGLB, generateNonce } from '@thirdrez/motionprint';
// Embed a watermark
const signedGlb = await embedGLB(
originalBuffer,
'animation.glb',
payload,
privateKeyHex
);
// Verify a watermark
const result = await verifyGLB(
signedGlb,
'animation.glb',
publicKeyHex
);
Typesโ
Payloadโ
The watermark payload containing provenance information.
interface Payload {
/** Creator identifier (max 64 chars) */
creatorId: string;
/** License identifier: 'restricted' | 'commercial' | 'cc-by' | etc. */
licenseId: string;
/** ISO 8601 timestamp */
issuedAt: string;
/** Embedding method */
method: 'extras-v1' | 'bvh-header-v1';
/** 128-bit hex nonce (32 chars) */
nonce: string;
}
VerificationResultโ
The result of a verification operation.
interface VerificationResult {
/** True if signature is valid */
ok: boolean;
/** SHA-256 hash of canonical payload */
wmHash: string;
/** File metadata */
fileMeta: {
name: string;
size: number;
type: 'glb' | 'bvh';
};
/** Extracted watermark (if present) */
watermark?: Payload;
/** Ed25519 signature hex (if present) */
signature?: string;
/** Error reason (if !ok) */
reason?: string;
}
Core Functionsโ
embedGLBโ
Embeds a signed watermark into a GLB file.
function embedGLB(
buffer: ArrayBuffer,
filename: string,
payload: Payload,
privateKeyHex: string
): Promise<ArrayBuffer>
Parameters:
| Name | Type | Description |
|---|---|---|
buffer | ArrayBuffer | Original GLB file contents |
filename | string | Filename (for metadata) |
payload | Payload | Watermark payload |
privateKeyHex | string | Ed25519 private key (hex encoded) |
Returns: Promise<ArrayBuffer> - The signed GLB file
Example:
const payload: Payload = {
creatorId: 'studio_alpha',
licenseId: 'commercial',
issuedAt: new Date().toISOString(),
method: 'extras-v1',
nonce: generateNonce(),
};
const signed = await embedGLB(glbBuffer, 'walk.glb', payload, PRIVATE_KEY);
downloadFile(signed, 'walk_signed.glb');
verifyGLBโ
Verifies a MotionPrint watermark in a GLB file.
function verifyGLB(
buffer: ArrayBuffer,
filename: string,
publicKeyHex: string
): Promise<VerificationResult>
Parameters:
| Name | Type | Description |
|---|---|---|
buffer | ArrayBuffer | GLB file contents |
filename | string | Filename (for metadata) |
publicKeyHex | string | Ed25519 public key (hex encoded) |
Returns: Promise<VerificationResult>
Example:
const result = await verifyGLB(glbBuffer, 'animation.glb', PUBLIC_KEY);
if (result.ok) {
console.log('Creator:', result.watermark?.creatorId);
console.log('License:', result.watermark?.licenseId);
console.log('Registered:', result.watermark?.issuedAt);
} else {
console.error('Verification failed:', result.reason);
}
embedBVHโ
Embeds a signed watermark into a BVH file.
function embedBVH(
buffer: ArrayBuffer,
filename: string,
payload: Payload,
privateKeyHex: string
): Promise<ArrayBuffer>
Same interface as embedGLB but for BVH files.
verifyBVHโ
Verifies a MotionPrint watermark in a BVH file.
function verifyBVH(
buffer: ArrayBuffer,
filename: string,
publicKeyHex: string
): Promise<VerificationResult>
Same interface as verifyGLB but for BVH files.
generateNonceโ
Generates a cryptographically secure 128-bit nonce.
function generateNonce(): string
Returns: 32-character hex string
Example:
const nonce = generateNonce();
// Returns: "f707614d6a07ff66d51933d6eeb3e0b0"
canonicalPayloadโ
Creates the canonical string representation of a payload for signing.
function canonicalPayload(payload: Payload): string
Returns: JSON string with ordered keys + trailing newline
Example:
const msg = canonicalPayload(payload);
// Ready for signing
Low-Level Functionsโ
extractWatermarkโ
Extracts watermark data without verifying signature.
function extractWatermark(
buffer: ArrayBuffer,
type: 'glb' | 'bvh'
): { payload: Payload; signature: string } | null
signPayloadโ
Signs a canonical payload with Ed25519.
function signPayload(
payload: Payload,
privateKeyHex: string
): Promise<string>
Returns: Hex-encoded signature (128 chars)
verifySignatureโ
Verifies an Ed25519 signature.
function verifySignature(
message: string,
signatureHex: string,
publicKeyHex: string
): Promise<boolean>
Constantsโ
/** Maximum creator ID length */
export const MAX_CREATOR_ID_LENGTH = 64;
/** MotionPrint protocol version */
export const PROTOCOL_VERSION = '1.0';
/** Supported file types */
export const SUPPORTED_FORMATS = ['glb', 'bvh'] as const;
Error Handlingโ
The SDK throws typed errors for common issues:
import {
MotionPrintError,
InvalidPayloadError,
SigningError,
UnsupportedFormatError
} from '@thirdrez/motionprint';
try {
const signed = await embedGLB(buffer, 'test.glb', payload, key);
} catch (error) {
if (error instanceof InvalidPayloadError) {
console.error('Bad payload:', error.field);
} else if (error instanceof SigningError) {
console.error('Signing failed:', error.message);
} else if (error instanceof UnsupportedFormatError) {
console.error('Format not supported');
}
}
Browser Usageโ
For browser environments, import from the ESM bundle:
<script type="module">
import { verifyGLB } from 'https://cdn.thirdrez.com/motionprint/v1.0/motionprint.esm.js';
const fileInput = document.getElementById('file');
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
const buffer = await file.arrayBuffer();
const result = await verifyGLB(buffer, file.name, PUBLIC_KEY);
console.log(result);
});
</script>
React Hookโ
import { useMotionPrintVerify } from '@thirdrez/motionprint/react';
function VerifyComponent() {
const { verify, result, isLoading, error } = useMotionPrintVerify(PUBLIC_KEY);
const handleFile = async (file: File) => {
await verify(file);
};
return (
<div>
<input type="file" onChange={(e) => handleFile(e.target.files[0])} />
{isLoading && <p>Verifying...</p>}
{result?.ok && <p>โ Verified: {result.watermark?.creatorId}</p>}
{error && <p>Error: {error.message}</p>}
</div>
);
}
Rate Limitsโ
The registry API has the following limits:
| Operation | Limit |
|---|---|
| Registration | 100 / hour per creator |
| Certificate fetch | 1000 / hour per IP |
| Batch registration | 50 files / request |
Note: Verification is entirely client-side and has no rate limits.
Need help integrating? Contact [email protected]