@contractspec/example.video-api-showcase 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,104 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Build API Video -- Construct a VideoProject from contract spec metadata
3
+ // ---------------------------------------------------------------------------
4
+
5
+ import type { VideoProject } from '@contractspec/lib.contracts-integrations/integrations/providers/video';
6
+ import { VIDEO_FORMATS } from '@contractspec/lib.video-gen/design/layouts';
7
+ import { resolveRenderConfig } from '@contractspec/lib.video-gen/renderers/config';
8
+ import type { QualityPreset } from '@contractspec/lib.video-gen/renderers/config';
9
+ import type { RenderConfig } from '@contractspec/lib.contracts-integrations/integrations/providers/video';
10
+ import type { ApiSpecDefinition } from './sample-specs';
11
+
12
+ const DEFAULT_FPS = 30;
13
+ const DEFAULT_DURATION_FRAMES = 450; // 15 seconds
14
+
15
+ /** Options for building an API showcase video. */
16
+ export interface BuildApiVideoOptions {
17
+ /** Duration in frames. Default: 450 (15s at 30fps). */
18
+ durationInFrames?: number;
19
+ /** Tagline shown at the end. */
20
+ tagline?: string;
21
+ /** FPS. Default: 30. */
22
+ fps?: number;
23
+ }
24
+
25
+ /**
26
+ * Build a VideoProject from a contract spec definition.
27
+ *
28
+ * This demonstrates manual project construction using the ApiOverview
29
+ * composition -- useful when you know the exact video structure.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { buildApiVideo } from "@contractspec/example.video-api-showcase/build-api-video";
34
+ * import { createUserSpec } from "@contractspec/example.video-api-showcase/sample-specs";
35
+ *
36
+ * const project = buildApiVideo(createUserSpec);
37
+ * // project.scenes[0].compositionId === "ApiOverview"
38
+ * ```
39
+ */
40
+ export function buildApiVideo(
41
+ spec: ApiSpecDefinition,
42
+ options?: BuildApiVideoOptions
43
+ ): VideoProject {
44
+ const fps = options?.fps ?? DEFAULT_FPS;
45
+ const durationInFrames = options?.durationInFrames ?? DEFAULT_DURATION_FRAMES;
46
+
47
+ return {
48
+ id: `api-video-${spec.specName.toLowerCase()}-${Date.now().toString(36)}`,
49
+ scenes: [
50
+ {
51
+ id: 'scene-api-overview',
52
+ compositionId: 'ApiOverview',
53
+ props: {
54
+ specName: spec.specName,
55
+ method: spec.method,
56
+ endpoint: spec.endpoint,
57
+ specCode: spec.specCode,
58
+ generatedOutputs: spec.generatedOutputs,
59
+ tagline: options?.tagline ?? 'One spec. Every surface.',
60
+ },
61
+ durationInFrames,
62
+ },
63
+ ],
64
+ totalDurationInFrames: durationInFrames,
65
+ fps,
66
+ format: VIDEO_FORMATS.landscape,
67
+ };
68
+ }
69
+
70
+ /**
71
+ * Build a render configuration for the API video.
72
+ *
73
+ * Demonstrates using quality presets to configure rendering.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * const config = buildRenderConfig("out/api-overview.mp4", "high");
78
+ * // config.crf === 12, config.codec === "h264"
79
+ * ```
80
+ */
81
+ export function buildRenderConfig(
82
+ outputPath: string,
83
+ preset: QualityPreset = 'standard'
84
+ ): RenderConfig {
85
+ return resolveRenderConfig({ outputPath }, preset);
86
+ }
87
+
88
+ /**
89
+ * Build video projects for multiple specs at once.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * import { createUserSpec, listTransactionsSpec } from "./sample-specs";
94
+ *
95
+ * const projects = buildApiVideoSuite([createUserSpec, listTransactionsSpec]);
96
+ * // projects.length === 2
97
+ * ```
98
+ */
99
+ export function buildApiVideoSuite(
100
+ specs: ApiSpecDefinition[],
101
+ options?: BuildApiVideoOptions
102
+ ): VideoProject[] {
103
+ return specs.map((spec) => buildApiVideo(spec, options));
104
+ }
@@ -0,0 +1 @@
1
+ import './video-api-showcase.docblock';
@@ -0,0 +1,70 @@
1
+ import type { DocBlock } from '@contractspec/lib.contracts-spec/docs';
2
+ import { registerDocBlocks } from '@contractspec/lib.contracts-spec/docs';
3
+
4
+ const blocks: DocBlock[] = [
5
+ {
6
+ id: 'docs.examples.video-api-showcase',
7
+ title: 'Video API Showcase (example)',
8
+ summary:
9
+ 'Spec-driven example: build API overview videos directly from contract spec metadata using manual VideoProject construction.',
10
+ kind: 'reference',
11
+ visibility: 'public',
12
+ route: '/docs/examples/video-api-showcase',
13
+ tags: ['video', 'api', 'spec-driven', 'example'],
14
+ body: `## What this example shows
15
+
16
+ - Manually constructing a \`VideoProject\` from contract spec metadata (name, method, endpoint, code, outputs).
17
+ - Using the \`ApiOverview\` composition to visualize how a spec generates multiple API surfaces.
18
+ - Configuring render settings with quality presets (\`draft\`, \`standard\`, \`high\`).
19
+ - Building video scenes with explicit composition IDs and props.
20
+
21
+ ## Key concepts
22
+
23
+ - **Spec-to-Video**: Contract spec metadata (name, method, endpoint, code snippet) becomes the input props for the \`ApiOverview\` composition.
24
+ - **Manual project construction**: Instead of using \`VideoGenerator\`, this example builds the \`VideoProject\` directly -- useful when you know exactly which composition and props to use.
25
+ - **Render configuration**: Shows how to use \`resolveRenderConfig()\` with quality presets for different output needs.
26
+
27
+ ## Notes
28
+
29
+ - This approach is ideal when the video structure is known ahead of time (e.g., always an API overview).
30
+ - For dynamic scene planning from content briefs, use \`VideoGenerator\` instead (see the video-marketing-clip example).
31
+ `,
32
+ },
33
+ {
34
+ id: 'docs.examples.video-api-showcase.usage',
35
+ title: 'Video API Showcase -- Usage',
36
+ summary:
37
+ 'How to generate API overview videos from contract spec definitions.',
38
+ kind: 'usage',
39
+ visibility: 'public',
40
+ route: '/docs/examples/video-api-showcase/usage',
41
+ tags: ['video', 'api', 'usage'],
42
+ body: `## Usage
43
+
44
+ \`\`\`ts
45
+ import { buildApiVideo } from "@contractspec/example.video-api-showcase/build-api-video";
46
+ import { createUserSpec, listTransactionsSpec } from "@contractspec/example.video-api-showcase/sample-specs";
47
+
48
+ // Build a video project for a single API spec
49
+ const project = buildApiVideo(createUserSpec);
50
+
51
+ console.log(project.scenes[0].compositionId); // "ApiOverview"
52
+ console.log(project.format); // { type: "landscape", width: 1920, height: 1080 }
53
+
54
+ // Build with custom duration and tagline
55
+ const custom = buildApiVideo(listTransactionsSpec, {
56
+ durationInFrames: 600,
57
+ tagline: "From spec to production in seconds.",
58
+ });
59
+ \`\`\`
60
+
61
+ ## Guardrails
62
+
63
+ - The \`specCode\` field should be a concise snippet (10-20 lines) for readability in the video.
64
+ - Generated outputs list should contain 3-8 items for optimal visual layout.
65
+ - Tagline should be short (under 40 characters) to fit within the composition frame.
66
+ `,
67
+ },
68
+ ];
69
+
70
+ registerDocBlocks(blocks);
package/src/example.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { defineExample } from '@contractspec/lib.contracts-spec';
2
+
3
+ const example = defineExample({
4
+ meta: {
5
+ key: 'video-api-showcase',
6
+ version: '1.0.0',
7
+ title: 'Video API Showcase',
8
+ description:
9
+ 'Generate API documentation videos from contract spec definitions using the ApiOverview composition.',
10
+ kind: 'script',
11
+ visibility: 'public',
12
+ stability: 'experimental',
13
+ owners: ['@platform.core'],
14
+ tags: ['video', 'api', 'documentation', 'spec-driven'],
15
+ },
16
+ docs: {
17
+ rootDocId: 'docs.examples.video-api-showcase',
18
+ usageDocId: 'docs.examples.video-api-showcase.usage',
19
+ },
20
+ entrypoints: {
21
+ packageName: '@contractspec/example.video-api-showcase',
22
+ docs: './docs',
23
+ },
24
+ surfaces: {
25
+ templates: true,
26
+ sandbox: { enabled: true, modes: ['markdown'] },
27
+ studio: { enabled: true, installable: true },
28
+ mcp: { enabled: true },
29
+ },
30
+ });
31
+
32
+ export default example;
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './sample-specs';
2
+ export * from './build-api-video';
3
+
4
+ export { default as example } from './example';
5
+
6
+ import './docs';
@@ -0,0 +1,129 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Sample Contract Spec Definitions for API Video Generation
3
+ // ---------------------------------------------------------------------------
4
+
5
+ /**
6
+ * Spec metadata used to build API overview videos.
7
+ * Maps directly to ApiOverviewProps.
8
+ */
9
+ export interface ApiSpecDefinition {
10
+ /** Contract spec name (e.g., "CreateUser") */
11
+ specName: string;
12
+ /** HTTP method */
13
+ method: string;
14
+ /** Endpoint path */
15
+ endpoint: string;
16
+ /** Contract spec code snippet */
17
+ specCode: string;
18
+ /** Generated output surfaces */
19
+ generatedOutputs: string[];
20
+ }
21
+
22
+ /**
23
+ * CreateUser -- user registration endpoint.
24
+ */
25
+ export const createUserSpec: ApiSpecDefinition = {
26
+ specName: 'CreateUser',
27
+ method: 'POST',
28
+ endpoint: '/api/users',
29
+ specCode: `export const createUser = defineCommand({
30
+ meta: {
31
+ name: "CreateUser",
32
+ version: "1.0.0",
33
+ stability: "Stable",
34
+ },
35
+ io: {
36
+ input: z.object({
37
+ email: z.string().email(),
38
+ name: z.string(),
39
+ role: z.enum(["admin", "user"]),
40
+ }),
41
+ output: z.object({
42
+ id: z.string().uuid(),
43
+ email: z.string(),
44
+ createdAt: z.date(),
45
+ }),
46
+ },
47
+ });`,
48
+ generatedOutputs: [
49
+ 'REST Endpoint',
50
+ 'GraphQL Mutation',
51
+ 'Prisma Model',
52
+ 'TypeScript SDK',
53
+ 'MCP Tool',
54
+ 'OpenAPI Spec',
55
+ ],
56
+ };
57
+
58
+ /**
59
+ * ListTransactions -- financial transaction listing.
60
+ */
61
+ export const listTransactionsSpec: ApiSpecDefinition = {
62
+ specName: 'ListTransactions',
63
+ method: 'GET',
64
+ endpoint: '/api/transactions',
65
+ specCode: `export const listTransactions = defineQuery({
66
+ meta: {
67
+ name: "ListTransactions",
68
+ version: "1.0.0",
69
+ stability: "Stable",
70
+ },
71
+ io: {
72
+ input: z.object({
73
+ accountId: z.string().uuid(),
74
+ from: z.date().optional(),
75
+ to: z.date().optional(),
76
+ limit: z.number().default(50),
77
+ }),
78
+ output: z.object({
79
+ transactions: z.array(transactionSchema),
80
+ total: z.number(),
81
+ hasMore: z.boolean(),
82
+ }),
83
+ },
84
+ });`,
85
+ generatedOutputs: [
86
+ 'REST Endpoint',
87
+ 'GraphQL Query',
88
+ 'Prisma Query',
89
+ 'TypeScript SDK',
90
+ 'OpenAPI Spec',
91
+ ],
92
+ };
93
+
94
+ /**
95
+ * SendNotification -- push notification dispatch.
96
+ */
97
+ export const sendNotificationSpec: ApiSpecDefinition = {
98
+ specName: 'SendNotification',
99
+ method: 'POST',
100
+ endpoint: '/api/notifications',
101
+ specCode: `export const sendNotification = defineCommand({
102
+ meta: {
103
+ name: "SendNotification",
104
+ version: "1.0.0",
105
+ stability: "Beta",
106
+ },
107
+ io: {
108
+ input: z.object({
109
+ userId: z.string().uuid(),
110
+ channel: z.enum(["push", "email", "sms"]),
111
+ title: z.string(),
112
+ body: z.string(),
113
+ }),
114
+ output: z.object({
115
+ notificationId: z.string().uuid(),
116
+ deliveredAt: z.date().nullable(),
117
+ status: z.enum(["sent", "failed", "queued"]),
118
+ }),
119
+ },
120
+ });`,
121
+ generatedOutputs: [
122
+ 'REST Endpoint',
123
+ 'GraphQL Mutation',
124
+ 'TypeScript SDK',
125
+ 'MCP Tool',
126
+ 'OpenAPI Spec',
127
+ 'Event Schema',
128
+ ],
129
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "@contractspec/tool.typescript/react-library.json",
3
+ "include": ["src"],
4
+ "exclude": ["node_modules", "dist"],
5
+ "compilerOptions": {
6
+ "rootDir": "src",
7
+ "outDir": "dist"
8
+ }
9
+ }
@@ -0,0 +1,3 @@
1
+ import { moduleLibrary } from '@contractspec/tool.bun';
2
+
3
+ export default { ...moduleLibrary };