{"_id":"@appvideostudio/sdk","_rev":"2-c9f098c6c3bf64bf79ddff3988c16b37","name":"@appvideostudio/sdk","dist-tags":{"latest":"0.1.4"},"versions":{"0.1.0":{"name":"@appvideostudio/sdk","version":"0.1.0","keywords":["appvideostudio","video","composition","player","embed","canvas","template","sdk"],"license":"MIT","_id":"@appvideostudio/sdk@0.1.0","maintainers":[{"name":"growthboot","email":"andyware@gmail.com"}],"homepage":"https://appvideostudio.com/api/sdk/","bugs":{"url":"https://github.com/growthboot/appvideostudio-sdk/issues"},"dist":{"shasum":"e6536765c3b0273da424046bd7e40b938e4688fc","tarball":"https://registry.npmjs.org/@appvideostudio/sdk/-/sdk-0.1.0.tgz","fileCount":16,"integrity":"sha512-x86bueiHtMOvXolg8r4p3gacm3tppsSg8EuwKI80eM5lGF2WSssnBUW2qhFYYrfcg1WdKHM80iUCRtWX34WA/g==","signatures":[{"sig":"MEYCIQDD0yqx9A3b2kN2ITgiYmYyXlA1axo5CBc6NTmAeB07fAIhAOWUUSEnQI4G9VnfjNFEDoLUN65rO8C9yPdtNawkOhbq","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51970},"type":"module","types":"./index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./index.d.ts","default":"./index.js"},"./player":{"types":"./player/player-element.d.ts","default":"./player/player-element.js"},"./document":{"types":"./document/document.d.ts","default":"./document/document.js"},"./test-harness":{"types":"./test-harness.d.ts","default":"./test-harness.js"}},"gitHead":"add7c036a70e4497c90642c77daa78426fda267d","_npmUser":{"name":"growthboot","email":"andyware@gmail.com"},"repository":{"url":"git+https://github.com/growthboot/appvideostudio-sdk.git","type":"git"},"_npmVersion":"11.9.0","description":"SDK for building, validating, and previewing AppVideoStudio video compositions","directories":{},"sideEffects":false,"_nodeVersion":"25.6.1","_hasShrinkwrap":false,"peerDependencies":{"@playwright/test":">=1.40.0"},"peerDependenciesMeta":{"@playwright/test":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.0_1774327097013_0.39298723778525013","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@appvideostudio/sdk","version":"0.1.4","type":"module","description":"SDK for building, validating, and previewing AppVideoStudio video compositions","exports":{".":{"types":"./index.d.ts","default":"./index.js"},"./document":{"types":"./document/document.d.ts","default":"./document/document.js"},"./player":{"types":"./player/player-element.d.ts","default":"./player/player-element.js"},"./test-harness":{"types":"./test-harness.d.ts","default":"./test-harness.js"}},"sideEffects":false,"engines":{"node":">=18.0.0"},"peerDependencies":{"@playwright/test":">=1.40.0"},"peerDependenciesMeta":{"@playwright/test":{"optional":true}},"keywords":["appvideostudio","video","composition","player","embed","canvas","template","sdk"],"homepage":"https://appvideostudio.com/api/sdk/","bugs":{"url":"https://github.com/growthboot/appvideostudio-sdk/issues"},"repository":{"type":"git","url":"git+https://github.com/growthboot/appvideostudio-sdk.git"},"license":"MIT","gitHead":"c3803f0522a4e627c77cdef9bf0873eacc5f17ea","types":"./index.d.ts","_id":"@appvideostudio/sdk@0.1.4","_nodeVersion":"25.6.1","_npmVersion":"11.9.0","dist":{"integrity":"sha512-L3lVbxGUs5BQq1d8D83YFZfzoyRaJCb84QS49UNlugXejxjMXqP3XelHIRSC/Pm/Hqd7NQVyOy4C8zaI0IFqqQ==","shasum":"cf259b81033eb3571405bfe2098b9164c273a442","tarball":"https://registry.npmjs.org/@appvideostudio/sdk/-/sdk-0.1.4.tgz","fileCount":16,"unpackedSize":52178,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGlY1V5q42tcxh9tp0atEktrAb+xFu9CTrDsLm/ShMX0AiEAytpJj0IJcOJrAQmoDdC8vDDRstwe5mXDnIliL0ceKHM="}]},"_npmUser":{"name":"growthboot","email":"andyware@gmail.com"},"directories":{},"maintainers":[{"name":"growthboot","email":"andyware@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.1.4_1774329209528_0.8698525435892652"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-24T04:38:16.927Z","modified":"2026-03-24T05:13:29.830Z","0.1.0":"2026-03-24T04:38:17.165Z","0.1.4":"2026-03-24T05:13:29.723Z"},"bugs":{"url":"https://github.com/growthboot/appvideostudio-sdk/issues"},"license":"MIT","homepage":"https://appvideostudio.com/api/sdk/","keywords":["appvideostudio","video","composition","player","embed","canvas","template","sdk"],"repository":{"type":"git","url":"git+https://github.com/growthboot/appvideostudio-sdk.git"},"description":"SDK for building, validating, and previewing AppVideoStudio video compositions","maintainers":[{"name":"growthboot","email":"andyware@gmail.com"}],"readme":"# @appvideostudio/sdk\n\n> SDK for building, validating, and previewing AppVideoStudio video compositions.\n\n## Install\n\n```bash\nnpm install @appvideostudio/sdk\n```\n\n## Quick Start\n\n### Create a video document\n\n```js\nimport {\n  createEmptyVideoDocument,\n  validateVideoDocument,\n} from '@appvideostudio/sdk';\n\nconst doc = createEmptyVideoDocument({\n  name: 'My Video',\n  width: 1080,\n  height: 1920,\n  timelineDuration: 10,\n});\n\ndoc.timeline.push({\n  id: 'comp-1',\n  componentType: 'text-basic',\n  layerId: 'layer-1',\n  startTime: 0,\n  duration: 5,\n  params: { text: 'Hello world' },\n  assetBindings: {},\n  customLabel: null,\n  color: '#6366f1',\n});\n\nconst errors = validateVideoDocument(doc);\nconsole.log(errors); // []\n```\n\n### Embed the player (browser)\n\n```js\nimport {\n  AVSPlayerElement,\n  defineAVSPlayerElement,\n} from '@appvideostudio/sdk/player';\n\ndefineAVSPlayerElement();\n\nconst player = document.createElement('avs-player');\ndocument.body.appendChild(player);\n\nawait player.ready;\nawait player.load(doc);\nawait player.play();\n```\n\n> **Note:** The `<avs-player>` element creates an iframe to the AppVideoStudio player runtime at `https://create.appvideostudio.com`. The hosted runtime must be reachable for playback to work.\n\n### Test with Playwright\n\n```js\nimport { test } from '@playwright/test';\nimport { createPlayerHarness } from '@appvideostudio/sdk/test-harness';\nimport { createEmptyVideoDocument } from '@appvideostudio/sdk';\n\ntest('screenshot at 2s', async ({ page }) => {\n  const doc = createEmptyVideoDocument({ name: 'Test' });\n  doc.timeline.push({\n    id: 'comp-1',\n    componentType: 'text-basic',\n    layerId: 'layer-1',\n    startTime: 0,\n    duration: 5,\n    params: { text: 'Hello' },\n    assetBindings: {},\n    customLabel: null,\n    color: '#6366f1',\n  });\n\n  const harness = await createPlayerHarness(page, { document: doc });\n  const screenshot = await harness.screenshotAt(2);\n  // assert on screenshot buffer\n  await harness.destroy();\n});\n```\n\n> **Note:** The test harness requires `@playwright/test` as a peer dependency (`>=1.40.0`).\n\n## Entry Points\n\n| Import | Environment | Description |\n|---|---|---|\n| `@appvideostudio/sdk` | Node + Browser | Document helpers |\n| `@appvideostudio/sdk/document` | Node + Browser | Document module directly |\n| `@appvideostudio/sdk/player` | Browser only | `<avs-player>` web component |\n| `@appvideostudio/sdk/test-harness` | Node (Playwright) | Test automation |\n\n## Document Model\n\n### VideoDocument shape\n\n```json\n{\n  \"schemaVersion\": 1,\n  \"metadata\": { \"id\": null, \"name\": \"My Video\" },\n  \"projectDimensions\": { \"width\": 1080, \"height\": 1920 },\n  \"timelineDuration\": 24,\n  \"layers\": [\n    { \"id\": \"layer-1\", \"name\": \"Layer 1\", \"color\": \"#2563eb\" }\n  ],\n  \"assets\": [\n    {\n      \"id\": \"asset-1\",\n      \"type\": \"image\",\n      \"name\": \"Background\",\n      \"url\": \"https://example.com/bg.png\",\n      \"posterUrl\": null,\n      \"duration\": null,\n      \"width\": 1080,\n      \"height\": 1920,\n      \"mimeType\": \"image/png\"\n    }\n  ],\n  \"timeline\": [\n    {\n      \"id\": \"comp-1\",\n      \"componentType\": \"text-basic\",\n      \"layerId\": \"layer-1\",\n      \"startTime\": 0,\n      \"duration\": 5,\n      \"params\": { \"text\": \"Hello world\" },\n      \"assetBindings\": {},\n      \"customLabel\": null,\n      \"color\": \"#6366f1\"\n    }\n  ]\n}\n```\n\n## API Reference\n\n### Document Functions\n\n#### `createEmptyVideoDocument(options?)`\n\nCreate a new empty video document with default layers.\n\n| Option | Type | Default |\n|---|---|---|\n| `id` | `string` | `null` |\n| `name` | `string` | `\"Untitled video\"` |\n| `width` | `number` | `1080` |\n| `height` | `number` | `1920` |\n| `timelineDuration` | `number` | `24` |\n| `layers` | `LayerDefinition[]` | 3 default layers |\n\n#### `validateVideoDocument(document, options?)`\n\nValidate a video document and return an array of `ValidationError` objects. Returns `[]` if valid.\n\nOptions: `{ knownTemplateIds?: Set<string> }` — pass a set of known template IDs to validate `componentType` references.\n\n#### `normalizeVideoDocument(input?, options?)`\n\nNormalize a partial or malformed document into a valid `VideoDocument`.\n\n#### `exportVideoDocumentFromState(state?)`\n\nExport a video document from internal editor state.\n\n#### `getDocumentDuration(document)`\n\nReturns the effective duration — the greater of `timelineDuration` and the end time of the last timeline component.\n\n#### `getDocumentTimelineEnd(document)`\n\nReturns the end time of the last timeline component.\n\n#### `getTimelineWindow(components?, range?)`\n\nFilter and sort timeline components that overlap a time range `{ startTime?, endTime? }`.\n\n#### `sortTimeline(components?)`\n\nSort timeline components by `startTime`, then by `id`.\n\n#### `createDefaultLayers(count?)`\n\nCreate an array of default layer definitions (default: 3).\n\n### Constants\n\n| Constant | Value |\n|---|---|\n| `DEFAULT_PROJECT_DIMENSIONS` | `{ width: 1080, height: 1920 }` |\n| `DEFAULT_TIMELINE_DURATION` | `24` |\n| `PLAYER_SCHEMA_VERSION` | `1` |\n\n### Player Element\n\n#### `defineAVSPlayerElement()`\n\nRegister the `<avs-player>` custom element. Safe to call multiple times.\n\n#### `AVSPlayerElement`\n\nExtends `HTMLElement`. Observed attributes: `src`, `autoplay`, `loop`, `no-controls`.\n\n**Properties:**\n- `ready: Promise` — resolves when the player iframe is ready\n\n**Playback:**\n- `load(document)` — load a video document\n- `loadFromUrl(url)` — load a document from a URL\n- `preloadAssets()` — preload all assets\n- `play()` / `pause()` / `stop()` / `seek(time)` / `destroy()`\n\n**Document:**\n- `createEmptyProject(options?)` — create a new empty project\n- `getDocument()` / `exportDocument()` / `replaceDocument(document)` / `validateDocument(document)`\n\n**Status:**\n- `getStatus()` / `getErrors()`\n\n**Assets:**\n- `getAssets()` / `getAsset(assetId)` / `addAsset(asset)` / `updateAsset(assetId, patch)` / `removeAsset(assetId)`\n\n**Timeline:**\n- `getTimeline(range?)` / `getComponent(componentId)` / `addComponent(definition)` / `removeComponent(componentId)` / `clearTimeline()`\n- `updateComponent(componentId, patch)` / `updateComponentParams(componentId, patch)` / `updateComponentTiming(componentId, patch)` / `updateComponentAssets(componentId, patch)` / `updateComponentMetadata(componentId, patch)`\n- `moveComponent(componentId, patch)` / `moveComponents(moves)`\n\n**Layers:**\n- `getLayers()` / `addLayer(patch?)` / `updateLayer(layerId, patch)` / `removeLayer(layerId)` / `reorderLayers(layerIds)`\n\n**Templates:**\n- `listTemplates()` / `getTemplate(templateId)` / `getComponentPanel(componentId)`\n\n**Events:**\n- `on(eventName, handler)` — returns unsubscribe function\n- `off(eventName, handler)`\n\n### Test Harness\n\n#### `createPlayerHarness(page, options)`\n\nCreate a Playwright test harness.\n\n| Option | Type | Default |\n|---|---|---|\n| `document` | `VideoDocument` | *required* |\n| `playerUrl` | `string` | `\"https://create.appvideostudio.com\"` |\n| `validate` | `boolean` | `true` |\n| `width` | `number` | `1280` |\n| `height` | `number` | `720` |\n| `readyTimeout` | `number` | `15000` |\n\nReturns a `PlayerHarness` with methods: `play`, `pause`, `seek`, `stop`, `getDocument`, `exportDocument`, `getStatus`, `getErrors`, `getAssets`, `getTimeline`, `getComponent`, `addComponent`, `updateComponentParams`, `updateComponentTiming`, `updateComponentAssets`, `removeComponent`, `replaceDocument`, `listTemplates`, `getTemplate`, `screenshot`, `screenshotAt`, `screenshotSequence`, `destroy`.\n\n## Component Catalog\n\nBrowse the full interactive catalog at [appvideostudio.com/api/components](https://appvideostudio.com/api/components/).\n\nMachine-readable metadata: [appvideostudio.com/api/catalog.json](https://appvideostudio.com/api/catalog.json)\n\n## Examples\n\n### Minimal embed\n\n```html\n<script type=\"module\">\n  import { defineAVSPlayerElement } from '@appvideostudio/sdk/player';\n  defineAVSPlayerElement();\n</script>\n\n<avs-player src=\"https://create.appvideostudio.com/player/\"></avs-player>\n```\n\n### Build a document programmatically\n\n```js\nimport {\n  createEmptyVideoDocument,\n  validateVideoDocument,\n} from '@appvideostudio/sdk';\n\nconst doc = createEmptyVideoDocument({\n  name: 'Programmatic Video',\n  timelineDuration: 15,\n});\n\ndoc.assets.push({\n  id: 'bg-asset',\n  type: 'image',\n  name: 'Background',\n  url: 'https://example.com/bg.jpg',\n  posterUrl: null,\n  duration: null,\n  width: 1080,\n  height: 1920,\n  mimeType: 'image/jpeg',\n});\n\ndoc.timeline.push({\n  id: 'bg-comp',\n  componentType: 'image-fill',\n  layerId: 'layer-1',\n  startTime: 0,\n  duration: 15,\n  params: {},\n  assetBindings: { source: 'bg-asset' },\n  customLabel: 'Background',\n  color: '#2563eb',\n});\n\nconst errors = validateVideoDocument(doc);\nif (errors.length === 0) {\n  console.log('Document is valid:', JSON.stringify(doc, null, 2));\n}\n```\n\n### Playwright screenshot test\n\n```js\nimport { test, expect } from '@playwright/test';\nimport { createPlayerHarness } from '@appvideostudio/sdk/test-harness';\nimport { createEmptyVideoDocument } from '@appvideostudio/sdk';\n\ntest('visual regression at key frames', async ({ page }) => {\n  const doc = createEmptyVideoDocument({ name: 'Regression Test' });\n  // ... add components to doc ...\n\n  const harness = await createPlayerHarness(page, { document: doc });\n\n  const frames = await harness.screenshotSequence([0, 2, 5, 10]);\n  for (const { time, buffer } of frames) {\n    expect(buffer).toMatchSnapshot(`frame-${time}s.png`);\n  }\n\n  await harness.destroy();\n});\n```\n\n### Load from URL\n\n```js\nimport { defineAVSPlayerElement } from '@appvideostudio/sdk/player';\n\ndefineAVSPlayerElement();\n\nconst player = document.createElement('avs-player');\ndocument.body.appendChild(player);\n\nawait player.ready;\nawait player.loadFromUrl('https://example.com/my-video.json');\nawait player.play();\n```\n\n## Links\n\n- [Documentation](https://appvideostudio.com/api/sdk/)\n- [Playground](https://appvideostudio.com/api/playground/)\n- [Component Catalog](https://appvideostudio.com/api/components/)\n- [GitHub](https://github.com/growthboot/appvideostudio-sdk)\n\n## License\n\nMIT\n","readmeFilename":"README.md"}