openapi: 3.0.3 info: title: Video Shader Toys Control API version: 0.1.0 description: | REST API exposed by the local Video Shader Toys control server. The API is intended for local control tools and the bundled React UI. All mutating endpoints return a small action result object. Successful mutating requests also broadcast the latest runtime state over the `/ws` WebSocket. WebSocket state streaming is not described by OpenAPI; connect to `ws://127.0.0.1:{port}/ws` to receive full runtime state JSON messages whenever state changes. servers: - url: http://127.0.0.1:8080 description: Default local control server tags: - name: State description: Runtime state and status. - name: Layers description: Layer stack control. - name: Stack Presets description: Save and recall layer stack presets. - name: Runtime description: Runtime actions. paths: /api/state: get: tags: [State] summary: Get current runtime state operationId: getRuntimeState responses: "200": description: Current runtime state. content: application/json: schema: $ref: "#/components/schemas/RuntimeState" /api/layers/add: post: tags: [Layers] summary: Add a layer using a shader package operationId: addLayer requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddLayerRequest" responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/layers/remove: post: tags: [Layers] summary: Remove a layer operationId: removeLayer requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/LayerIdRequest" responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/layers/move: post: tags: [Layers] summary: Move a layer by direction description: Moves a layer up or down by one or more positions, depending on the signed direction value. operationId: moveLayer requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/MoveLayerRequest" responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/layers/reorder: post: tags: [Layers] summary: Move a layer to an absolute index operationId: reorderLayer requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ReorderLayerRequest" responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/layers/set-bypass: post: tags: [Layers] summary: Set layer bypass state operationId: setLayerBypass requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SetBypassRequest" responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/layers/set-shader: post: tags: [Layers] summary: Change the shader package used by a layer operationId: setLayerShader requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SetShaderRequest" responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/layers/update-parameter: post: tags: [Layers] summary: Update a layer parameter value operationId: updateLayerParameter requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateParameterRequest" responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/layers/reset-parameters: post: tags: [Layers] summary: Reset a layer's parameters to shader defaults operationId: resetLayerParameters requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/LayerIdRequest" responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/stack-presets/save: post: tags: [Stack Presets] summary: Save the current layer stack as a preset operationId: saveStackPreset requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PresetNameRequest" responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/stack-presets/load: post: tags: [Stack Presets] summary: Load a layer stack preset operationId: loadStackPreset requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PresetNameRequest" responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/reload: post: tags: [Runtime] summary: Reload shaders description: Rescans the shader library, re-reads manifests, queues shader compilation, and refreshes shader availability/errors. If a changed shader fails, the previous working stack remains active where possible. operationId: reloadShaders requestBody: required: false content: application/json: schema: type: object additionalProperties: false responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" /api/screenshot: post: tags: [Runtime] summary: Queue a PNG screenshot of the final output render target description: Captures the next completed output render target and writes it under `runtime/screenshots/`. operationId: queueScreenshot requestBody: required: false content: application/json: schema: type: object additionalProperties: false responses: "200": $ref: "#/components/responses/ActionOk" "400": $ref: "#/components/responses/ActionError" components: responses: ActionOk: description: Action succeeded. content: application/json: schema: $ref: "#/components/schemas/ActionResponse" example: ok: true ActionError: description: Action failed or request JSON was invalid. content: application/json: schema: $ref: "#/components/schemas/ActionResponse" example: ok: false error: Unknown layer id. schemas: ActionResponse: type: object required: [ok] properties: ok: type: boolean error: type: string description: Present when the request fails or when the runtime returns a diagnostic. additionalProperties: false AddLayerRequest: type: object required: [shaderId] properties: shaderId: type: string example: studio-color additionalProperties: false LayerIdRequest: type: object required: [layerId] properties: layerId: type: string example: layer-1 additionalProperties: false MoveLayerRequest: type: object required: [layerId, direction] properties: layerId: type: string direction: type: integer description: Signed movement direction. Negative moves toward the top of the stack; positive moves toward the bottom. example: -1 additionalProperties: false ReorderLayerRequest: type: object required: [layerId, targetIndex] properties: layerId: type: string targetIndex: type: integer minimum: 0 example: 0 additionalProperties: false SetBypassRequest: type: object required: [layerId, bypass] properties: layerId: type: string bypass: type: boolean additionalProperties: false SetShaderRequest: type: object required: [layerId, shaderId] properties: layerId: type: string shaderId: type: string example: vhs additionalProperties: false UpdateParameterRequest: type: object required: [layerId, parameterId, value] properties: layerId: type: string parameterId: type: string example: brightness value: description: Parameter value. Type depends on the shader parameter definition. oneOf: - type: number - type: boolean - type: string - type: array items: type: number example: 1.25 additionalProperties: false PresetNameRequest: type: object required: [presetName] properties: presetName: type: string example: live-show-look additionalProperties: false RuntimeState: type: object properties: app: $ref: "#/components/schemas/AppState" runtime: $ref: "#/components/schemas/RuntimeStatus" video: $ref: "#/components/schemas/VideoStatus" decklink: $ref: "#/components/schemas/DeckLinkStatus" videoIO: $ref: "#/components/schemas/VideoIOStatus" performance: $ref: "#/components/schemas/PerformanceStatus" backendPlayout: $ref: "#/components/schemas/BackendPlayoutStatus" runtimeEvents: $ref: "#/components/schemas/RuntimeEventStatus" shaders: type: array items: $ref: "#/components/schemas/ShaderSummary" stackPresets: type: array items: type: string layers: type: array items: $ref: "#/components/schemas/LayerState" AppState: type: object properties: serverPort: type: number oscPort: type: number oscBindAddress: type: string oscSmoothing: type: number autoReload: type: boolean maxTemporalHistoryFrames: type: number previewFps: type: number enableExternalKeying: type: boolean inputVideoFormat: type: string inputFrameRate: type: string outputVideoFormat: type: string outputFrameRate: type: string RuntimeStatus: type: object properties: layerCount: type: number compileSucceeded: type: boolean compileMessage: type: string VideoStatus: type: object properties: hasSignal: type: boolean width: type: number height: type: number modeName: type: string DeckLinkStatus: type: object deprecated: true description: Legacy DeckLink-specific status object. Prefer `videoIO` for new clients. properties: modelName: type: string supportsInternalKeying: type: boolean supportsExternalKeying: type: boolean keyerInterfaceAvailable: type: boolean externalKeyingRequested: type: boolean externalKeyingActive: type: boolean statusMessage: type: string VideoIOStatus: type: object properties: backend: type: string example: decklink modelName: type: string supportsInternalKeying: type: boolean supportsExternalKeying: type: boolean keyerInterfaceAvailable: type: boolean externalKeyingRequested: type: boolean externalKeyingActive: type: boolean statusMessage: type: string PerformanceStatus: type: object properties: frameBudgetMs: type: number renderMs: type: number smoothedRenderMs: type: number budgetUsedPercent: type: number completionIntervalMs: type: number smoothedCompletionIntervalMs: type: number maxCompletionIntervalMs: type: number lateFrameCount: type: number droppedFrameCount: type: number flushedFrameCount: type: number BackendPlayoutStatus: type: object properties: lifecycleState: type: string example: running degraded: type: boolean statusMessage: type: string lateFrameCount: type: number droppedFrameCount: type: number flushedFrameCount: type: number readyQueue: $ref: "#/components/schemas/BackendReadyQueueStatus" outputRender: $ref: "#/components/schemas/BackendOutputRenderStatus" recovery: $ref: "#/components/schemas/BackendPlayoutRecoveryStatus" BackendReadyQueueStatus: type: object properties: depth: type: number description: Current number of ready output frames. capacity: type: number description: Maximum ready output frames currently allowed. minDepth: type: number description: Minimum observed ready queue depth since backend worker start. maxDepth: type: number description: Maximum observed ready queue depth since backend worker start. zeroDepthCount: type: number description: Number of observed samples where the ready queue was empty. pushedCount: type: number poppedCount: type: number droppedCount: type: number underrunCount: type: number BackendOutputRenderStatus: type: object properties: renderMs: type: number description: Most recent output render duration in milliseconds. smoothedRenderMs: type: number description: Smoothed output render duration in milliseconds. maxRenderMs: type: number description: Maximum observed output render duration in milliseconds. acquireFrameMs: type: number description: Time spent acquiring a writable backend output frame in milliseconds. renderRequestMs: type: number description: Time spent executing the render-thread output frame request in milliseconds. endAccessMs: type: number description: Time spent ending write access to the backend output frame in milliseconds. queueWaitMs: type: number description: Time the output render request spent waiting for the render thread in milliseconds. drawMs: type: number description: Time spent drawing, blitting, packing, and flushing the output frame in milliseconds. fenceWaitMs: type: number description: Time spent waiting for the async readback fence in milliseconds. mapMs: type: number description: Time spent mapping the async readback pixel buffer in milliseconds. readbackCopyMs: type: number description: Time spent copying async readback bytes into the backend output frame in milliseconds. cachedCopyMs: type: number description: Time spent copying the cached output frame when async readback is not ready in milliseconds. asyncQueueMs: type: number description: Time spent queueing the next async readback in milliseconds. asyncQueueBufferMs: type: number description: Time spent orphaning or allocating the async readback pixel buffer in milliseconds. asyncQueueSetupMs: type: number description: Time spent applying readback pixel-store, framebuffer, and pixel-pack-buffer state in milliseconds. asyncQueueReadPixelsMs: type: number description: Time spent issuing glReadPixels for the async readback in milliseconds. asyncQueueFenceMs: type: number description: Time spent creating the async readback fence in milliseconds. syncReadMs: type: number description: Time spent in bootstrap synchronous readback in milliseconds. asyncReadbackMissCount: type: number description: Count of output render requests where async readback was not ready. cachedFallbackCount: type: number description: Count of output render requests served from the cached output frame. syncFallbackCount: type: number description: Count of output render requests that used bootstrap synchronous readback. BackendPlayoutRecoveryStatus: type: object properties: completionResult: type: string enum: [Completed, DisplayedLate, Dropped, Flushed, Unknown] completedFrameIndex: type: number scheduledFrameIndex: type: number scheduledLeadFrames: type: number measuredLagFrames: type: number catchUpFrames: type: number lateStreak: type: number dropStreak: type: number RuntimeEventStatus: type: object properties: queue: $ref: "#/components/schemas/RuntimeEventQueueStatus" dispatch: $ref: "#/components/schemas/RuntimeEventDispatchStatus" RuntimeEventQueueStatus: type: object properties: name: type: string depth: type: number capacity: type: number droppedCount: type: number oldestEventAgeMs: type: number RuntimeEventDispatchStatus: type: object properties: dispatchCallCount: type: number dispatchedEventCount: type: number handlerInvocationCount: type: number handlerFailureCount: type: number lastDispatchDurationMs: type: number maxDispatchDurationMs: type: number ShaderSummary: type: object properties: id: type: string name: type: string description: type: string category: type: string available: type: boolean description: False when the shader package exists but failed manifest or compile validation. error: type: string description: Error text for unavailable shader packages. temporal: $ref: "#/components/schemas/TemporalState" feedback: $ref: "#/components/schemas/FeedbackState" TemporalState: type: object properties: enabled: type: boolean historySource: type: string enum: [source, preLayerInput, none] requestedHistoryLength: type: number effectiveHistoryLength: type: number FeedbackState: type: object properties: enabled: type: boolean writePass: type: string LayerState: type: object properties: id: type: string shaderId: type: string shaderName: type: string bypass: type: boolean temporal: $ref: "#/components/schemas/TemporalState" parameters: type: array items: $ref: "#/components/schemas/ParameterState" ParameterState: type: object properties: id: type: string label: type: string description: type: string description: Short helper text shown under the parameter label in the control UI. type: type: string enum: [float, vec2, color, bool, enum, text, trigger] defaultValue: description: Default parameter value from the shader manifest. oneOf: - type: number - type: boolean - type: string - type: array items: type: number min: type: array items: type: number max: type: array items: type: number step: type: array items: type: number options: type: array items: $ref: "#/components/schemas/ParameterOption" maxLength: type: number description: Maximum length for text parameters. font: type: string description: Font asset id used by text parameters, when declared. value: description: Current parameter value. oneOf: - type: number - type: boolean - type: string - type: array items: type: number ParameterOption: type: object properties: value: type: string label: type: string