├── CNAME
├── v1
├── examples
│ ├── .gitignore
│ ├── l3rd-name
│ │ ├── README.md
│ │ ├── l3rd.ograf.json
│ │ ├── lib
│ │ │ ├── ograf-logo-app.svg
│ │ │ ├── TextPlugin.js
│ │ │ └── utils
│ │ │ │ └── strings.js
│ │ └── graphic.mjs
│ ├── README.md
│ ├── renderer-test
│ │ ├── README.md
│ │ ├── manifest.ograf.json
│ │ └── graphic.mjs
│ ├── minimal
│ │ ├── README.md
│ │ ├── minimal.ograf.json
│ │ └── graphic.mjs
│ └── ograf-logo
│ │ ├── README.md
│ │ ├── logo.ograf.json
│ │ ├── graphic.mjs
│ │ └── lib
│ │ └── ograf-logo-app.svg
├── typescript-definitions
│ ├── .npmignore
│ ├── .gitignore
│ ├── src
│ │ ├── definitions
│ │ │ ├── vendor.ts
│ │ │ ├── types.ts
│ │ │ └── render.ts
│ │ ├── main.ts
│ │ ├── apis
│ │ │ └── graphicsAPI.ts
│ │ └── generated
│ │ │ └── graphics-manifest.ts
│ ├── package.json
│ ├── scripts
│ │ ├── generate-types.js
│ │ └── local-testing.js
│ ├── README.md
│ ├── tsconfig.json
│ └── package-lock.json
└── specification
│ ├── json-schemas
│ ├── lib
│ │ ├── constraints
│ │ │ ├── boolean.json
│ │ │ ├── string.json
│ │ │ └── number.json
│ │ └── action.json
│ └── graphics
│ │ └── schema.json
│ └── docs
│ └── images
│ ├── step-model1.svg
│ ├── step-model2.svg
│ ├── step-model3.svg
│ └── components.svg
├── .gitignore
├── CHANGELOG.md
├── README.md
├── .github
└── workflows
│ └── publish-npm.yml
└── docs
└── logo
├── og-logo-colour.svg
├── og-logo-mono-black.svg
├── og-logo-mono-white.svg
├── ograf-logo-app.svg
├── ograf-logo-colour.svg
├── ograf-logo-mono-black.svg
└── ograf-logo-mono-white.svg
/CNAME:
--------------------------------------------------------------------------------
1 | ograf.ebu.io
--------------------------------------------------------------------------------
/v1/examples/.gitignore:
--------------------------------------------------------------------------------
1 | **/*.zip
2 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | scripts
3 | tsconfig.json
4 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | tsconfig.tsbuildinfo
4 |
--------------------------------------------------------------------------------
/v1/examples/l3rd-name/README.md:
--------------------------------------------------------------------------------
1 | # Reference: Lower 3rd - Name
2 |
3 | This is a simple lower 3rd that displays a name.
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | *.iml
3 | .DS_Store
4 |
5 | __old_from_tmp_repo/
6 |
7 | # scripts used in local testing
8 | local-scripts/
9 |
--------------------------------------------------------------------------------
/v1/examples/README.md:
--------------------------------------------------------------------------------
1 | # OGraf Examples
2 |
3 | [Click here to download this folder as a zip file](https://download-directory.github.io/?url=https%3A%2F%2Fgithub.com%2Febu%2Fograf%2Ftree%2Fmain%2Fv1%2Fexamples)
4 |
--------------------------------------------------------------------------------
/v1/examples/renderer-test/README.md:
--------------------------------------------------------------------------------
1 | # Renderer Test Graphic
2 |
3 | This Graphic presents a number of steps for the renderer to perform.
4 |
5 | It intended to be used to test the functionality of a renderer.
6 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/src/definitions/vendor.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Vendors MUST use the prefix "v_" in any additional properties to ensure forward compatibility. For example "v_SuperFlyFluxCapacitorStatus".
3 | */
4 | export type VendorSpecific = `v_${VendorName}${string}`;
5 | type VendorName = string;
6 |
--------------------------------------------------------------------------------
/v1/examples/minimal/README.md:
--------------------------------------------------------------------------------
1 | # Reference: Minimal Graphic
2 |
3 | This is a minimal implementation of a Graphic.
4 | It contains the minimum required properties and methods to be a valid Graphic.
5 |
6 | _Note: This is intended to be used when developing and validating renderer systems._
7 | _If you're looking for a good starting point for developing Graphics, use the [L3rd Name example](../l3rd-name/) instead._
8 |
--------------------------------------------------------------------------------
/v1/examples/minimal/minimal.ograf.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ograf.ebu.io/v1/specification/json-schemas/graphics/schema.json",
3 | "name": "Minimal Test Graphic",
4 | "description": "This Graphic includes the bare minimum required to be a valid OGraf Graphic. It displays a 'Hello World!' message.",
5 | "id": "minimal-example",
6 | "main": "graphic.mjs",
7 | "supportsRealTime": true,
8 | "supportsNonRealTime": false
9 | }
10 |
--------------------------------------------------------------------------------
/v1/examples/ograf-logo/README.md:
--------------------------------------------------------------------------------
1 | # Reference: Minimal Graphic
2 |
3 | This is a version of minimal implementation of a Graphic.
4 | It fades IN and OUT a image-file.
5 | It contains the minimum required properties and methods to be a valid Graphic.
6 |
7 | _Note: This is intended to be used when developing and validating renderer systems._
8 | _If you're looking for a good starting point for developing Graphics, use the [L3rd Name example](../l3rd-name/) instead._
9 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/src/main.ts:
--------------------------------------------------------------------------------
1 | export * as GraphicsAPI from "./apis/graphicsAPI";
2 |
3 | export * from "./definitions/render";
4 | export * from "./definitions/types";
5 | export * from "./definitions/vendor";
6 | import * as GeneratedGraphicsManifest from "./generated/graphics-manifest";
7 |
8 | export { GeneratedGraphicsManifest }
9 |
10 | // Also export the GraphicsManifest types using simplified names
11 | export type GraphicsManifest = GeneratedGraphicsManifest.HttpsOgrafEbuIoV1SpecificationJsonSchemasGraphicsSchemaJson
12 | export type GraphicsManifestCustomAction = GeneratedGraphicsManifest.HttpsOgrafEbuIoV1SpecificationJsonSchemasLibActionJson
13 |
14 |
--------------------------------------------------------------------------------
/v1/examples/ograf-logo/logo.ograf.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ograf.ebu.io/v1/specification/json-schemas/graphics/schema.json",
3 | "name": "Minimal Test Graphics",
4 | "description": "This Graphic shows an OGraf logo",
5 | "id": "minimal-logo",
6 | "main": "graphic.mjs",
7 | "supportsRealTime": true,
8 | "supportsNonRealTime": false,
9 | "author": {
10 | "name": "Markus Nygård, YLE"
11 | },
12 | "renderRequirements": [
13 | {
14 | "resolution": {
15 | "width": { "min": 600, "max": 4000, "ideal": 1920 }
16 | },
17 | "frameRate": { "min": 1, "max": 240, "ideal": 60 }
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ograf",
3 | "version": "1.0.0",
4 | "main": "dist/main.js",
5 | "types": "dist/main.d.ts",
6 | "license": "MIT",
7 | "description": "TypeScript definitions for Ograf graphics",
8 | "repository": {
9 | "url": "https://github.com/ebu/ograf"
10 | },
11 | "homepage": "https://ograf.ebu.io",
12 | "keywords": [
13 | "ograf",
14 | "types",
15 | "typescript",
16 | "ebu",
17 | "broadcast",
18 | "graphics"
19 | ],
20 | "scripts": {
21 | "build": "tsc --build",
22 | "watch": "tsc --watch",
23 | "generate-types": "node scripts/generate-types.js"
24 | },
25 | "devDependencies": {
26 | "typescript": "^5.6.3",
27 | "json-schema-to-typescript": "^15.0.3"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/v1/specification/json-schemas/lib/constraints/boolean.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json-schema.org/draft/2020-12/schema",
3 | "$id": "https://ograf.ebu.io/v1/specification/json-schemas/lib/constraints/boolean.json",
4 | "type": "object",
5 | "description": "The boolean constraint is used to specify a constraint for a boolean property. (Inspired by https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#constrainboolean)",
6 | "properties": {
7 | "exact": {
8 | "description": "A boolean specifying a specific, required, value the property must have to be considered acceptable.",
9 | "type": "boolean"
10 | },
11 | "ideal": {
12 | "description": "A boolean specifying an ideal value for the property. If possible, this value will be used, but if it's not possible, the user agent will use the closest possible match.",
13 | "type": "boolean"
14 | }
15 | },
16 | "patternProperties": {
17 | "^v_.*": {}
18 | },
19 | "additionalProperties": false
20 | }
21 |
--------------------------------------------------------------------------------
/v1/examples/l3rd-name/l3rd.ograf.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ograf.ebu.io/v1/specification/json-schemas/graphics/schema.json",
3 | "name": "Lower 3rd - Name",
4 | "description": "Name lower third",
5 | "id": "l3rd-name",
6 | "main": "graphic.mjs",
7 | "version": "0",
8 | "author": {
9 | "name": "Johan Nyman, SuperFly.tv"
10 | },
11 | "customActions": [
12 | {
13 | "id": "highlight",
14 | "name": "Highlight",
15 | "description": "Highlight the name",
16 | "schema": null
17 | }
18 | ],
19 | "supportsRealTime": true,
20 | "supportsNonRealTime": true,
21 | "schema": {
22 | "type": "object",
23 | "properties": {
24 | "name": {
25 | "type": "string",
26 | "title": "Name",
27 | "default": "John Doe"
28 | },
29 | "title": {
30 | "type": "string",
31 | "title": "Title",
32 | "default": "Ograf expert"
33 | }
34 | }
35 | },
36 | "v_myLittleNote": "Vendor-specific properties can be added using the 'v_' prefix, like this!"
37 | }
38 |
--------------------------------------------------------------------------------
/v1/examples/renderer-test/manifest.ograf.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ograf.ebu.io/v1/specification/json-schemas/graphics/schema.json",
3 | "name": "Renderer Test Graphic",
4 | "description": "This Graphic is used to validate a Renderer",
5 | "id": "renderer-test",
6 | "main": "graphic.mjs",
7 | "supportsRealTime": true,
8 | "supportsNonRealTime": false,
9 | "schema": {
10 | "type": "object",
11 | "properties": {
12 | "message": {
13 | "type": "string",
14 | "title": "Message",
15 | "default": "Hello"
16 | }
17 | }
18 | },
19 | "customActions": [
20 | {
21 | "id": "highlight",
22 | "name": "Highlight",
23 | "schema": null
24 | },
25 | {
26 | "id": "setColor",
27 | "name": "Set Color",
28 | "schema": {
29 | "type": "object",
30 | "properties": {
31 | "color": {
32 | "type": "string",
33 | "title": "Color",
34 | "default": "red"
35 | }
36 | }
37 | }
38 | }
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | This log lists changes between versions.
4 |
5 |
6 |
7 |
8 | ## Version 1
9 |
10 | The log below details the changes during development of this version:
11 |
12 | * 2025-03-27: Draft 0 made public.
13 | * 2025-04-23: Fix in JSON-schemas: Changed `main` property in Graphics manifest to be **mandatory**.
14 | (Before, it was defined as mandatory in the specification document, but not in the JSON-schemas.)
15 | * 2025-05-16: Add `renderRequirements` property to Graphics manifest
16 | * 2025-05-16: Add `data` argument to the `load` method.
17 | Before, the `data`-payload was only sent using the `updateData()` method. Now it must be sent on `load()` as well.
18 | * 2025-05-16: Change return values of Graphic methods to optionally be `undefined`.
19 | (An `undefined` value should be treated as `{ statusCode: 200 }`)
20 | * 2025-06-09: Rename the "v1-draft-0" to "v1" in preparation for the first release.
21 | * 2025-06-13: Add requirement on manifest file name.
22 | The manifest file must now have the suffix `".ograf"`.
23 | Before, there where no requirements on the manifest file name.
24 | * 2025-06-13: Add optional `skipAnimation` argument to `updateAction` and `customAction`.
25 | Before, it was only included in `playAction` and `stopAction`.
26 | * 2025-07-02: Change requirement on manifest file name.
27 | The manifest file must now have the suffix `".ograf.json"`.
28 | Before, it was `".ograf"`.
29 |
--------------------------------------------------------------------------------
/v1/specification/json-schemas/lib/constraints/string.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json-schema.org/draft/2020-12/schema",
3 | "$id": "https://ograf.ebu.io/v1/specification/json-schemas/lib/constraints/string.json",
4 | "type": "object",
5 | "description": "The string constraint is used to specify a constraint for a string property. (Inspired by https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#constraindomstring)",
6 | "properties": {
7 | "exact": {
8 | "description": "A string or an array of strings, one of which must be the value of the property. If the property can't be set to one of the listed values, matching will fail.",
9 | "type": "string"
10 | },
11 | "ideal": {
12 | "description": "A string (or an array of strings), specifying ideal values for the property. If possible, one of the listed values will be used, but if it's not possible, the user agent will use the closest possible match.",
13 | "oneOf": [
14 | {
15 | "type": "string"
16 | },
17 | {
18 | "type": "array",
19 | "items": {
20 | "type": "string"
21 | }
22 | }
23 | ]
24 | }
25 | },
26 | "patternProperties": {
27 | "^v_.*": {}
28 | },
29 | "additionalProperties": false
30 | }
31 |
--------------------------------------------------------------------------------
/v1/examples/minimal/graphic.mjs:
--------------------------------------------------------------------------------
1 | class Graphic extends HTMLElement {
2 | connectedCallback() {
3 | // Called when the element is added to the DOM
4 | // Note: Don't paint any pixels at this point, wait for load() to be called
5 | }
6 |
7 | async load(params) {
8 | if (params.renderType !== "realtime")
9 | throw new Error("Only realtime rendering is supported by this graphic");
10 |
11 | const elText = document.createElement("p");
12 | elText.style.backgroundColor = "#ffffff";
13 | elText.style.color = "#000000";
14 | elText.style.display = "inline-block";
15 | elText.style.padding = "10px";
16 | elText.style.border = "1px solid #000000";
17 | elText.innerHTML = "Hello world!";
18 | this.appendChild(elText);
19 |
20 | // When everything is loaded we can return:
21 | return {
22 | statusCode: 200,
23 | };
24 | }
25 | async dispose(_params) {
26 | this.innerHTML = "";
27 | }
28 | async updateAction(_params) {
29 | // No actions are implemented in this minimal example
30 | }
31 | async playAction(_params) {
32 | // No actions are implemented in this minimal example
33 | }
34 | async stopAction(_params) {
35 | // No actions are implemented in this minimal example
36 | }
37 | async customAction(params) {
38 | // No actions are implemented in this minimal example
39 | }
40 | }
41 |
42 | export default Graphic;
43 |
44 | // Note: The renderer will render the component
45 |
--------------------------------------------------------------------------------
/v1/specification/json-schemas/lib/action.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json-schema.org/draft/2020-12/schema",
3 | "$id": "https://ograf.ebu.io/v1/specification/json-schemas/lib/action.json",
4 | "type": "object",
5 | "properties": {
6 | "id": {
7 | "type": "string",
8 | "description": "The identity of the action. The id must be unique within the graphic."
9 | },
10 | "name": {
11 | "type": "string",
12 | "description": "The name of the action. This is displayed to the user."
13 | },
14 | "description": {
15 | "type": "string",
16 | "description": "A longer description of the action. This is displayed to the user."
17 | },
18 | "schema": {
19 | "description": "The schema of the action. This is used to validate the action parameters as well as auto-generate a GUI for the action. If the action does not require any parameters, set this to null.",
20 | "oneOf": [
21 | {
22 | "type": "object",
23 | "$ref": "https://superflytv.github.io/GraphicsDataDefinition/gdd-meta-schema/v1/lib/object.json"
24 | },
25 | {
26 | "type": "null"
27 | }
28 | ]
29 | }
30 | },
31 | "required": [
32 | "id",
33 | "name"
34 | ],
35 | "patternProperties": {
36 | "^v_.*": {}
37 | },
38 | "additionalProperties": false
39 | }
40 |
--------------------------------------------------------------------------------
/v1/specification/json-schemas/lib/constraints/number.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json-schema.org/draft/2020-12/schema",
3 | "$id": "https://ograf.ebu.io/v1/specification/json-schemas/lib/constraints/number.json",
4 | "type": "object",
5 | "description": "The number constraint is used to specify a constraint for a numerical property. (Inspired by https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#constraindouble)",
6 | "properties": {
7 | "max": {
8 | "description": "A number specifying the largest permissible value of the property it describes. If the value cannot remain equal to or less than this value, matching will fail.",
9 | "type": "number"
10 | },
11 | "min": {
12 | "description": "A number specifying the smallest permissible value of the property it describes. If the value cannot remain equal to or greater than this value, matching will fail.",
13 | "type": "number"
14 | },
15 | "exact": {
16 | "description": "A number specifying a specific, required, value the property must have to be considered acceptable.",
17 | "type": "number"
18 | },
19 | "ideal": {
20 | "description": "A number specifying an ideal value for the property. If possible, this value will be used, but if it's not possible, the user agent will use the closest possible match.",
21 | "type": "number"
22 | }
23 | },
24 | "patternProperties": {
25 | "^v_.*": {}
26 | },
27 | "additionalProperties": false
28 | }
29 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/src/definitions/types.ts:
--------------------------------------------------------------------------------
1 | import { VendorSpecific } from "./vendor";
2 |
3 | /**
4 | * Default return data of any action
5 | */
6 | export type ReturnPayload = {
7 | /**
8 | * HTTP response code. 200 if the method was executed successfully, 4xx if client error, 5xx if server error
9 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
10 | */
11 | statusCode: number;
12 | /**
13 | * (Optional) A human-readable message to help understand the statusCode.
14 | */
15 | statusMessage?: string;
16 | } & VendorExtend;
17 |
18 | /**
19 | * This indicates that a payload is empty
20 | * (but a vendor may choose to add their own vendor-specific properties)
21 | */
22 | export type EmptyPayload = VendorExtend;
23 |
24 | /**
25 | * This indicates that the Parameters object is empty
26 | * (but a vendor may choose to add their own vendor-specific properties)
27 | */
28 | export type EmptyParams = VendorExtend;
29 |
30 | /**
31 | * All parameters and return values can be extended with vendor-specific properties
32 | */
33 | export interface VendorExtend {
34 | [vendorSpecific: VendorSpecific]: unknown;
35 | }
36 |
37 | /** Payload when invoking an action of a GraphicInstance or a Renderer */
38 | export type ActionInvokeParams = {
39 | /** Graphic id, as defined by the Graphic manifest*/
40 | id: string;
41 | /** Params to send into the method */
42 | payload: unknown;
43 | } & VendorExtend;
44 |
45 | export type PlayActionReturnPayload = ReturnPayload & {
46 | /** The resulting step from a PlayAction */
47 | currentStep: number;
48 | };
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OGraf
2 |
3 |
4 |
5 | **OGraf** is an Open specification for HTML based Graphics, used in live television and post production workflows.
6 |
7 | * [Link to Project Web Page](https://ograf.ebu.io)
8 | * [Link to Project Github repository ](https://github.com/ebu/ograf)
9 |
10 | ## Project status
11 |
12 | * **The OGraf Graphics specification** (version 1) is production ready and considered stable. Additional features and non-breaking changes will be added continously.
13 | * **The OGraf Control API specification** is under development.
14 |
15 | EBU members as well as the general industry is invited to join the [HTML Graphics Working Group](https://tech.ebu.ch/groups/html_graphics) to participate in discussions and development of the OGraf specification.
16 |
17 | Feedback can also be submitted using [GitHub Issues](https://github.com/ebu/ograf/issues).
18 |
19 | Graphics and Render system developers are encouraged to follow changes in the [Changelog](./CHANGELOG.md).
20 |
21 | ### Time plan
22 |
23 | - **Done:**
24 | - Version 1 of **Graphics definition**
25 | - Early 2026:
26 | - First draft of **Server API** to be presented.
27 | - Mid 2026:
28 | - Version 1 to be extended with **Server API** definitions.
29 |
30 | ## Introduction
31 |
32 | The OGraf specification defines a way to create HTML based graphics as well as an (upcoming) Control API.
33 | It allows for vendor interoperability between Graphics, Rendering systems and Control systems.
34 |
35 | ## Getting Started
36 |
37 | Useful resources:
38 | * [Examples of OGraf Graphics](https://github.com/ebu/ograf/tree/main/v1/examples).
39 | * [OGraf Specification](./v1/specification/docs/Specification.md).
40 |
41 |
42 | ### Tools
43 |
44 | * The **[OGraf Devtool](https://github.com/SuperFlyTV/ograf-devtool)** is a tool for developing OGraf graphics.
45 | * The **[Simple Rendering system](https://github.com/SuperFlyTV/ograf-server)** can be used to play OGraf Graphics in a browser (for use in any existing system capable of rendering HTML graphics).
46 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/scripts/generate-types.js:
--------------------------------------------------------------------------------
1 | const { compile, compileFromFile } = require("json-schema-to-typescript");
2 | const path = require("path");
3 | const fs = require("fs");
4 |
5 | async function main() {
6 |
7 |
8 | const outputPath = path.resolve("./src/generated");
9 | const schemaPath = path.resolve("../specification/json-schemas/graphics");
10 | const options = {
11 | bannerComment: `/* eslint-disable */
12 | /**
13 | * This file was automatically generated by json-schema-to-typescript.
14 | * DO NOT MODIFY IT BY HAND! Instead, modify the source JSON Schema file,
15 | * and run 'npm run generate-types' to regenerate this file.
16 | */`,
17 | customName: (schema, name) => {
18 | // console.log("name", name, schema);
19 | return undefined;
20 | },
21 | };
22 |
23 | // Compile JSON schemas to TypeScript types:
24 | await saveFile(
25 | path.join(outputPath, "graphics-manifest.ts"),
26 | await compileFromFile(
27 | path.join(schemaPath, "schema.json"),
28 | options
29 | )
30 | );
31 | // await saveFile(
32 | // path.join(outputPath, "renderer-manifest.d.ts"),
33 | // await compileFromFile(
34 | // path.join(schemaPath, "renderer-manifest/schema.json"),
35 | // options
36 | // )
37 | // );
38 |
39 | console.log(`Generated types at: ${outputPath}`);
40 | }
41 | async function saveFile(savePath, contents) {
42 | // Ensure the folder exists:
43 | await fs.promises.mkdir(path.dirname(savePath), { recursive: true });
44 |
45 | // The ^v_.* are generated as [k: string]: unknown, fix that:
46 | contents = contents.replaceAll(/(v_.+\n.*\n[ \t]+)(\[k: string\]: unknown)/g, '$1[k: `v_${string}`]: unknown')
47 |
48 |
49 | // Replace contents in case of using localhost during testing:
50 | contents = contents.replaceAll('HttpLocalhost8080', 'HttpsOgrafEbuIo')
51 | contents = contents.replaceAll('Http1270018081V1', 'HttpsOgrafEbuIoV1')
52 |
53 | await fs.promises.writeFile(savePath, contents);
54 | }
55 |
56 | main().catch((err) => {
57 | console.error(err);
58 | process.exit(1);
59 | });
60 |
--------------------------------------------------------------------------------
/.github/workflows/publish-npm.yml:
--------------------------------------------------------------------------------
1 | name: Publish to NPM
2 |
3 | on:
4 | # Allows you to run this workflow manually from the Actions tab
5 | workflow_dispatch:
6 |
7 | permissions:
8 | id-token: write # Required for OIDC
9 | contents: read
10 |
11 | jobs:
12 | Publish:
13 | name: Publish to NPM
14 | runs-on: ubuntu-latest
15 | timeout-minutes: 15
16 | defaults:
17 | run:
18 | working-directory: ./v1/typescript-definitions
19 | steps:
20 | - uses: actions/checkout@v5
21 | - uses: actions/setup-node@v5
22 | with:
23 | node-version: 24
24 | registry-url: "https://registry.npmjs.org"
25 |
26 | # Ensure npm 11.5.1 or later is installed:
27 | # - name: Update npm
28 | # run: npm install -g npm@latest
29 |
30 | - name: Prepare Environment
31 | # Install from package-lock.json:
32 | run: npm ci
33 | env:
34 | CI: true
35 |
36 | - name: Determine type of release
37 | id: release-tag
38 | run: |
39 | if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
40 | echo "Publish latest"
41 | echo "tag=latest" >> $GITHUB_OUTPUT
42 | else
43 | echo "Publish nightly"
44 | echo "tag=nightly" >> $GITHUB_OUTPUT
45 | fi
46 |
47 | - name: Bump version to prerelease
48 | if: github.ref != 'refs/heads/main'
49 | run: |
50 | COMMIT_TIMESTAMP=$(git log -1 --pretty=format:%ct HEAD)
51 | COMMIT_DATE=$(date -d @$COMMIT_TIMESTAMP +%Y%m%d-%H%M%S)
52 | GIT_HASH=$(git rev-parse --short HEAD)
53 | PRERELEASE_TAG=nightly-$(echo "${{ github.ref_name }}" | sed -r 's/[^a-z0-9]+/-/gi')
54 | npm version prerelease --preid $PRERELEASE_TAG-$COMMIT_DATE-$GIT_HASH
55 |
56 | - name: Generate types
57 | run: npm run generate-types
58 | env:
59 | CI: true
60 |
61 | - name: Build
62 | run: npm run build
63 | env:
64 | CI: true
65 |
66 | - name: Publish to NPM
67 | run: npm publish --tag ${{ steps.release-tag.outputs.tag }}
68 | env:
69 | CI: true
70 |
--------------------------------------------------------------------------------
/v1/examples/ograf-logo/graphic.mjs:
--------------------------------------------------------------------------------
1 | class Graphic extends HTMLElement {
2 | connectedCallback() {
3 | // Called when the element is added to the DOM
4 | // Note: Don't paint any pixels at this point, wait for load() to be called
5 | }
6 |
7 | async load(params) {
8 | if (params.renderType !== "realtime")
9 | throw new Error("Only realtime rendering is supported by this graphic");
10 |
11 | const logo = document.createElement("img");
12 | logo.src = await this._loadImage(
13 | import.meta.resolve("./lib/ograf-logo-app.svg")
14 | );
15 | logo.style.opacity = 0;
16 | logo.style.position = "absolute";
17 | logo.style.left = `calc(5%)`;
18 | logo.style.bottom = `calc(85%)`;
19 | logo.style.width = "50px";
20 | logo.style.boxShadow = "0 0 10px rgba(0,0,0,0.5)";
21 | logo.style.borderRadius = "5px";
22 | this.appendChild(logo);
23 |
24 |
25 | this.elements = {
26 | logo,
27 | };
28 |
29 | // When everything is loaded we can return:
30 | return {
31 | statusCode: 200,
32 | };
33 | }
34 | async dispose(_params) {
35 | this.innerHTML = "";
36 | }
37 | async updateAction(_params) {
38 | // No updateActions are implemented in this example
39 | }
40 | async playAction(_params) {
41 | // Fade in logo
42 | this.elements.logo.style.transition = "opacity 1s";
43 | this.elements.logo.style.opacity = "1";
44 | }
45 | async stopAction(_params) {
46 | // fade out logo
47 | this.elements.logo.style.transition = "opacity 1s";
48 | this.elements.logo.style.opacity = "0";
49 | }
50 | async customAction(params) {
51 | // No customAction are implemented in this example
52 | }
53 | async goToTime(_payload) {
54 | throw new Error("Non-realtime not supported!");
55 | }
56 | async setActionsSchedule(_payload) {
57 | throw new Error("Non-realtime not supported!");
58 | }
59 | _loadImage(url) {
60 | return new Promise((resolve, reject) => {
61 | const newImg = new Image();
62 | newImg.onload = function () {
63 | resolve(this.src);
64 | };
65 | newImg.onerror = reject;
66 | newImg.src = url;
67 | });
68 | }
69 | }
70 |
71 | export default Graphic;
72 |
73 | // Note: The renderer will render the component
74 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/README.md:
--------------------------------------------------------------------------------
1 | # OGraf Typescript Definitions
2 |
3 | These are Typescript definitions for the OGraf API.
4 |
5 | https://github.com/ebu/ograf
6 |
7 | ## Getting Started
8 |
9 | ```typescript
10 |
11 | import { GraphicsAPI } from 'ograf';
12 |
13 |
14 | // Setup my OGraf graphic WebComponent:
15 | class MyOGrafGraphic extends HTMLElement implements GraphicsAPI.Graphic {
16 | connectedCallback() {
17 | // Called when the element is added to the DOM
18 | // Note: Don't paint any pixels at this point, wait for load() to be called
19 | }
20 |
21 | async load(params) {
22 | if (params.renderType !== "realtime")
23 | throw new Error("Only realtime rendering is supported by this graphic");
24 |
25 | const elText = document.createElement("p");
26 | elText.innerHTML = "Hello world!";
27 | this.appendChild(elText);
28 |
29 | // When everything is loaded we can return:
30 | return {
31 | statusCode: 200,
32 | };
33 | }
34 | async dispose(_params) {
35 | this.innerHTML = "";
36 | }
37 | async updateAction(_params) {
38 | // No actions are implemented in this minimal example
39 | }
40 | async playAction(_params) {
41 | // No actions are implemented in this minimal example
42 | }
43 | async stopAction(_params) {
44 | // No actions are implemented in this minimal example
45 | }
46 | async customAction(params) {
47 | // No actions are implemented in this minimal example
48 | }
49 | async goToTime(_payload) {
50 | throw new Error("Non-realtime not supported!");
51 | }
52 | async setActionsSchedule(_payload) {
53 | throw new Error("Non-realtime not supported!");
54 | }
55 | }
56 |
57 | ```
58 |
59 |
60 | ## For Developers
61 |
62 | The instructions below are for developers who want to work on the Typescript definitions.
63 |
64 | ### Install & build
65 |
66 | ```bash
67 |
68 | npm install
69 | npm run generate-types # If any of the specification has changed
70 | npm run build
71 | # or
72 | npm run watch
73 |
74 | ```
75 |
76 | ### Publish to NPM
77 |
78 | To publish a new version to NPM:
79 |
80 | 1. Bump the version `npm version major|minor|patch`
81 | 2. Commit and push to GitHub
82 | 3. Go to the Actions tab and trigger the "Publish to NPM" workflow
83 |
84 | To publish a nightly build to NPM:
85 |
86 | 1. Go to the Actions tab and trigger the "Publish nightly to NPM" workflow
87 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/src/definitions/render.ts:
--------------------------------------------------------------------------------
1 | import { VendorExtend } from "./types";
2 |
3 | /**
4 | * A RenderCharacteristics is a set of characteristics / capabilities
5 | * of the Renderer, that affects how the Graphic will be rendered.
6 | */
7 | export type RenderCharacteristics = {
8 | resolution?: {
9 | width: number;
10 | height: number;
11 | } & VendorExtend;
12 | /** Which frameRate the renderer will be rendering in. Examples: 50, 60, 29.97 */
13 | frameRate?: number;
14 |
15 | /** Whether the renderer has access to the public internet (so the graphic can fetch resources) */
16 | accessToPublicInternet?: boolean
17 |
18 | // Ideas for future:
19 | // webcamInputs
20 | // keyer?: boolean; //
21 |
22 | } & VendorExtend;
23 |
24 | // These are inspired by the MediaTrackConstraints Web API.
25 | // see https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
26 |
27 | export type ConstrainBoolean = {
28 | /** A Boolean which must be the value of the property. If the property can't be set to this value, matching will fail. */
29 | exact?: boolean;
30 |
31 | /** A Boolean specifying an ideal value for the property. If possible, this value will be used, but if it's not possible, the user agent will use the closest possible match. */
32 | ideal?: boolean;
33 | } & VendorExtend;
34 |
35 | export type ConstrainNumber = {
36 | /** A number specifying the largest permissible value of the property it describes. If the value cannot remain equal to or less than this value, matching will fail. */
37 | max?: number;
38 |
39 | /** A number specifying the smallest permissible value of the property it describes. If the value cannot remain equal to or greater than this value, matching will fail. */
40 | min?: number;
41 |
42 | /** A number specifying a specific, required, value the property must have to be considered acceptable. */
43 | exact?: number;
44 |
45 | /** A number specifying an ideal value for the property. If possible, this value will be used, but if it's not possible, the user agent will use the closest possible match. */
46 | ideal?: number;
47 | } & VendorExtend;
48 |
49 | /** The ConstrainString constraint type is used to specify a constraint for a property whose value is a string. */
50 | export type ConstrainString = {
51 | /** A string or an array of strings, one of which must be the value of the property. If the property can't be set to one of the listed values, matching will fail. */
52 | exact: T | T[];
53 |
54 | /** A string or an array of strings, specifying ideal values for the property. If possible, one of the listed values will be used, but if it's not possible, the user agent will use the closest possible match. */
55 | ideal: T | T[];
56 | } & VendorExtend;
57 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/scripts/local-testing.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const path = require("path");
3 |
4 | /*
5 | *************************************************************************************************
6 |
7 | This scripts replaces URLs in the manifest with local paths, for testing purposes.
8 | Usage:
9 | * `node scripts/local-testing.js` to replace URLs with local paths
10 | * `node scripts/local-testing.js --restore` to restore the original URLs
11 | *
12 |
13 | This is useful when testing the json-manifests locally.
14 | One simple way to serve the files locally is:
15 | * `cd ograf`
16 | * `npm install -g http-server`
17 | * `http-server -p 8080` // serves the files on http://localhost:8080
18 |
19 | *************************************************************************************************
20 | */
21 |
22 | let restore = false;
23 | process.argv.forEach((arg) => {
24 | if (arg === "--restore") restore = true;
25 | });
26 |
27 | let replacements = [
28 | {
29 | from: "https://ograf.ebu.io/",
30 | to: "http://localhost:8080/",
31 | },
32 | ];
33 |
34 | if (restore) {
35 | replacements = replacements.map((r) => {
36 | return {
37 | from: r.to,
38 | to: r.from,
39 | };
40 | });
41 | }
42 |
43 | let updateCount = 0;
44 |
45 | async function replaceInAllFiles(folderPath) {
46 | const files = await fs.promises.readdir(folderPath);
47 |
48 | for (const file of files) {
49 | if (file === "node_modules") continue;
50 | if (file === "local-testing.js") continue;
51 | // Only process these file types:
52 |
53 | const filePath = path.join(folderPath, file);
54 |
55 | // is dir?
56 | if ((await fs.promises.stat(filePath)).isDirectory()) {
57 | await replaceInAllFiles(filePath);
58 | } else {
59 | // Only process these file types:
60 | if (
61 | !file.endsWith(".ts") &&
62 | !file.endsWith(".js") &&
63 | !file.endsWith(".json")
64 | )
65 | continue;
66 |
67 | const fileContents = await fs.promises.readFile(filePath, "utf-8");
68 |
69 | let newContents = fileContents;
70 |
71 | for (const replacement of replacements) {
72 | newContents = newContents.replaceAll(replacement.from, replacement.to);
73 | }
74 |
75 | if (newContents !== fileContents) {
76 | await fs.promises.writeFile(filePath, newContents);
77 | console.log(`Updated ${filePath}`);
78 | updateCount++;
79 | }
80 | }
81 | }
82 | }
83 |
84 | const basePath = path.resolve(__dirname, "../..");
85 | replaceInAllFiles(basePath)
86 | .then(() => {
87 | if (!restore) {
88 | console.log(`Updated ${updateCount} files.`);
89 | console.log("To restore, run `node scripts/local-testing.js --restore`");
90 | } else {
91 | console.log(`${updateCount} Files restored`);
92 | }
93 | })
94 | .catch(console.error);
95 |
--------------------------------------------------------------------------------
/docs/logo/og-logo-colour.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/docs/logo/og-logo-mono-black.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/docs/logo/og-logo-mono-white.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/docs/logo/ograf-logo-app.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/v1/examples/l3rd-name/lib/ograf-logo-app.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/v1/examples/ograf-logo/lib/ograf-logo-app.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/src/apis/graphicsAPI.ts:
--------------------------------------------------------------------------------
1 | import { RenderCharacteristics } from "../definitions/render";
2 | import {
3 | PlayActionReturnPayload,
4 | ActionInvokeParams,
5 | ReturnPayload,
6 | EmptyPayload,
7 | EmptyParams,
8 | VendorExtend,
9 | } from "../definitions/types";
10 |
11 | /**
12 | * ================================================================================================
13 | *
14 | * The GraphicsAPI is a javascript interface, ie javascript methods exposed by the OGraf Graphics WebComponent.
15 | *
16 | * ================================================================================================
17 | */
18 |
19 | /**
20 | * This interface defines the methods that the Renderer can call on the Graphic.
21 | * @example class MyOGrafGraphic extends HTMLElement implements GraphicsAPI.Graphic {}
22 | *
23 | */
24 | export interface Graphic {
25 | /**
26 | * Called by the Renderer when the Graphic has been loaded into the DOM
27 | * @returns a Promise that resolves when the Graphic has finished loading it's resources.
28 | */
29 | load: (
30 | params: {
31 | /** The data send here is defined in the manifest "schema". Note: This data MUST HAVE the same type as the `data` argument in updateAction method. */
32 | data: unknown;
33 |
34 | /** Whether the rendering is done in realtime or non-realtime */
35 | renderType: "realtime" | "non-realtime";
36 |
37 | /** A set of characteristics / capabilities of the Renderer, that affects how the Graphic will be rendered. */
38 | renderCharacteristics: RenderCharacteristics;
39 | } & VendorExtend
40 | ) => Promise;
41 |
42 | /**
43 | * Called by the Renderer to force the Graphic to terminate/dispose/clear any loaded resources.
44 | * This is called after the Renderer has unloaded the Graphic from the DOM.
45 | */
46 | dispose: (params: EmptyParams) => Promise;
47 |
48 | /** This is called whenever user send a new data payload. */
49 | updateAction: (
50 | params: {
51 | /** The data send here is defined in the manifest "schema". Note: This data MUST HAVE the same type as the `data` argument in the load method. */
52 | data: unknown;
53 | /** If true, skips animation (defaults to false) */
54 | skipAnimation?: boolean;
55 | } & VendorExtend
56 | ) => Promise;
57 |
58 | /** This is called when user calls the "play" action. */
59 | playAction: (
60 | params: {
61 | /** How far to advance. 1 = next step/segment. (defaults to 1) */
62 | delta: number;
63 | /** Jump to a specific step/segment (defaults to undefined) */
64 | goto: number;
65 | /** If true, skips animation (defaults to false) */
66 | skipAnimation?: boolean;
67 | } & VendorExtend
68 | ) => Promise;
69 |
70 | /** This is called when user calls the "stop" action. */
71 | stopAction: (
72 | params: {
73 | /** If true, skips animation (defaults to false) */
74 | skipAnimation?: boolean
75 | } & VendorExtend
76 | ) => Promise;
77 |
78 | /**
79 | * Called by the Renderer to invoke an Action on the Graphic
80 | * @returns The return value of the invoked method (vendor-specific)
81 | */
82 | customAction: (
83 | params: ActionInvokeParams
84 | ) => Promise;
85 |
86 | /**
87 | * If the Graphic supports non-realtime rendering, this is called to make the graphic jump to a certain point in time.
88 | * @returns A Promise that resolves when the Graphic has finished rendering the requested frame.
89 | */
90 | goToTime: (
91 | params: { timestamp: number } & VendorExtend
92 | ) => Promise;
93 |
94 | /**
95 | * If the Graphic supports non-realtime rendering, this is called to schedule actions to be invoked at a certain point in time.
96 | * When this is called, the Graphic is expected to store the scheduled actions and invoke them when the time comes.
97 | * (A call to this replaces any previous scheduled actions.)
98 | * @returns A Promise that resolves when the Graphic has stored the scheduled actions.
99 | */
100 | setActionsSchedule: (
101 | params: {
102 | /**
103 | * A list of the scheduled actions to call at certain points in time.
104 | */
105 | schedule: {
106 | timestamp: number;
107 | action:
108 | | ({
109 | type: "updateAction";
110 | params: Parameters[0];
111 | } & VendorExtend)
112 | | ({
113 | type: "playAction";
114 | params: Parameters[0];
115 | } & VendorExtend)
116 | | ({
117 | type: "stopAction";
118 | params: Parameters[0];
119 | } & VendorExtend)
120 | | ({
121 | type: "customAction";
122 | params: Parameters[0];
123 | } & VendorExtend);
124 | }[];
125 | } & VendorExtend
126 | ) => Promise;
127 | }
128 |
--------------------------------------------------------------------------------
/v1/examples/l3rd-name/lib/TextPlugin.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * TextPlugin 3.12.5
3 | * https://gsap.com
4 | *
5 | * @license Copyright 2008-2024, GreenSock. All rights reserved.
6 | * Subject to the terms at https://gsap.com/standard-license or for
7 | * Club GSAP members, the agreement issued with that membership.
8 | * @author: Jack Doyle, jack@greensock.com
9 | */
10 |
11 | /* eslint-disable */
12 | import { emojiSafeSplit, getText, splitInnerHTML } from "./utils/strings.js";
13 |
14 | var gsap,
15 | _tempDiv,
16 | _getGSAP = function _getGSAP() {
17 | return gsap || typeof window !== "undefined" && (gsap = window.gsap) && gsap.registerPlugin && gsap;
18 | };
19 |
20 | export var TextPlugin = {
21 | version: "3.12.5",
22 | name: "text",
23 | init: function init(target, value, tween) {
24 | typeof value !== "object" && (value = {
25 | value: value
26 | });
27 |
28 | var i = target.nodeName.toUpperCase(),
29 | data = this,
30 | _value = value,
31 | newClass = _value.newClass,
32 | oldClass = _value.oldClass,
33 | preserveSpaces = _value.preserveSpaces,
34 | rtl = _value.rtl,
35 | delimiter = data.delimiter = value.delimiter || "",
36 | fillChar = data.fillChar = value.fillChar || (value.padSpace ? " " : ""),
37 | _short,
38 | text,
39 | original,
40 | j,
41 | condensedText,
42 | condensedOriginal,
43 | aggregate,
44 | s;
45 |
46 | data.svg = target.getBBox && (i === "TEXT" || i === "TSPAN");
47 |
48 | if (!("innerHTML" in target) && !data.svg) {
49 | return false;
50 | }
51 |
52 | data.target = target;
53 |
54 | if (!("value" in value)) {
55 | data.text = data.original = [""];
56 | return;
57 | }
58 |
59 | original = splitInnerHTML(target, delimiter, false, preserveSpaces);
60 | _tempDiv || (_tempDiv = document.createElement("div"));
61 | _tempDiv.innerHTML = value.value;
62 | text = splitInnerHTML(_tempDiv, delimiter, false, preserveSpaces);
63 | data.from = tween._from;
64 |
65 | if ((data.from || rtl) && !(rtl && data.from)) {
66 | // right-to-left or "from()" tweens should invert things (but if it's BOTH .from() and rtl, inverting twice equals not inverting at all :)
67 | i = original;
68 | original = text;
69 | text = i;
70 | }
71 |
72 | data.hasClass = !!(newClass || oldClass);
73 | data.newClass = rtl ? oldClass : newClass;
74 | data.oldClass = rtl ? newClass : oldClass;
75 | i = original.length - text.length;
76 | _short = i < 0 ? original : text;
77 |
78 | if (i < 0) {
79 | i = -i;
80 | }
81 |
82 | while (--i > -1) {
83 | _short.push(fillChar);
84 | }
85 |
86 | if (value.type === "diff") {
87 | j = 0;
88 | condensedText = [];
89 | condensedOriginal = [];
90 | aggregate = "";
91 |
92 | for (i = 0; i < text.length; i++) {
93 | s = text[i];
94 |
95 | if (s === original[i]) {
96 | aggregate += s;
97 | } else {
98 | condensedText[j] = aggregate + s;
99 | condensedOriginal[j++] = aggregate + original[i];
100 | aggregate = "";
101 | }
102 | }
103 |
104 | text = condensedText;
105 | original = condensedOriginal;
106 |
107 | if (aggregate) {
108 | text.push(aggregate);
109 | original.push(aggregate);
110 | }
111 | }
112 |
113 | value.speed && tween.duration(Math.min(0.05 / value.speed * _short.length, value.maxDuration || 9999));
114 | data.rtl = rtl;
115 | data.original = original;
116 | data.text = text;
117 |
118 | data._props.push("text");
119 | },
120 | render: function render(ratio, data) {
121 | if (ratio > 1) {
122 | ratio = 1;
123 | } else if (ratio < 0) {
124 | ratio = 0;
125 | }
126 |
127 | if (data.from) {
128 | ratio = 1 - ratio;
129 | }
130 |
131 | var text = data.text,
132 | hasClass = data.hasClass,
133 | newClass = data.newClass,
134 | oldClass = data.oldClass,
135 | delimiter = data.delimiter,
136 | target = data.target,
137 | fillChar = data.fillChar,
138 | original = data.original,
139 | rtl = data.rtl,
140 | l = text.length,
141 | i = (rtl ? 1 - ratio : ratio) * l + 0.5 | 0,
142 | applyNew,
143 | applyOld,
144 | str;
145 |
146 | if (hasClass && ratio) {
147 | applyNew = newClass && i;
148 | applyOld = oldClass && i !== l;
149 | str = (applyNew ? "" : "") + text.slice(0, i).join(delimiter) + (applyNew ? "" : "") + (applyOld ? "" : "") + delimiter + original.slice(i).join(delimiter) + (applyOld ? "" : "");
150 | } else {
151 | str = text.slice(0, i).join(delimiter) + delimiter + original.slice(i).join(delimiter);
152 | }
153 |
154 | if (data.svg) {
155 | //SVG text elements don't have an "innerHTML" in Microsoft browsers.
156 | target.textContent = str;
157 | } else {
158 | target.innerHTML = fillChar === " " && ~str.indexOf(" ") ? str.split(" ").join(" ") : str;
159 | }
160 | }
161 | };
162 | TextPlugin.splitInnerHTML = splitInnerHTML;
163 | TextPlugin.emojiSafeSplit = emojiSafeSplit;
164 | TextPlugin.getText = getText;
165 | _getGSAP() && gsap.registerPlugin(TextPlugin);
166 | export { TextPlugin as default };
--------------------------------------------------------------------------------
/docs/logo/ograf-logo-colour.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/docs/logo/ograf-logo-mono-black.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/docs/logo/ograf-logo-mono-white.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/v1/specification/json-schemas/graphics/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json-schema.org/draft/2020-12/schema",
3 | "$id": "https://ograf.ebu.io/v1/specification/json-schemas/graphics/schema.json",
4 | "type": "object",
5 | "properties": {
6 | "$schema": {
7 | "type": "string",
8 | "const": "https://ograf.ebu.io/v1/specification/json-schemas/graphics/schema.json",
9 | "description": "Reference to the JSON-schema for this manifest"
10 | },
11 | "id": {
12 | "type": "string",
13 | "description": "The id of the Graphic uniquely identifies it. It is recommended to use a reverse domain name notation. For example: com.my-company.my-lowerthird."
14 | },
15 | "version": {
16 | "type": "string",
17 | "description": "The version of the Graphic. The version SHOULD be alphabetically sortable. Examples: ['0', '1', '2'], ['1.0', '1.1', '1.2'], ['2024-07-01_final', '2024-07-01_final_final2']"
18 | },
19 | "main": {
20 | "type": "string",
21 | "description": "The main entry point, ie the path to the main javascript file of the Graphic."
22 | },
23 | "name": {
24 | "type": "string",
25 | "description": "Name of the Graphic"
26 | },
27 | "description": {
28 | "type": "string",
29 | "description": "(optional) A longer description of the Graphic"
30 | },
31 | "author": {
32 | "type": "object",
33 | "description": "(optional) About the author",
34 | "properties": {
35 | "name": {
36 | "type": "string",
37 | "description": "Name of the author"
38 | },
39 | "email": {
40 | "type": "string",
41 | "description": "(optional) Email of the author"
42 | },
43 | "url": {
44 | "type": "string",
45 | "description": "(optional) URL of the author"
46 | }
47 | },
48 | "required": [
49 | "name"
50 | ],
51 | "patternProperties": {
52 | "^v_.*": {}
53 | },
54 | "additionalProperties": false
55 | },
56 | "customActions": {
57 | "type": "array",
58 | "description": "Custom Actions that can be invoked on the Graphic.",
59 | "items": {
60 | "$ref": "https://ograf.ebu.io/v1/specification/json-schemas/lib/action.json"
61 | }
62 | },
63 | "supportsRealTime": {
64 | "type": "boolean",
65 | "description": "Indicates if the Graphic supports real-time rendering"
66 | },
67 | "supportsNonRealTime": {
68 | "type": "boolean",
69 | "description": "Indicates if the Graphic supports non-real-time rendering. Note: If true, the Graphic must implement the 'goToTime()' and the 'setActionsSchedule()' methods."
70 | },
71 | "stepCount": {
72 | "type": "number",
73 | "description": "The number of steps a Graphic consists of. If the Graphic is simply triggered by a play, then a stop, this is considered a stepCount of 1 (which is the default behavior if left undefined). A value of -1 indicates that a Graphic as a dynamic/unknown number of steps.",
74 | "default": 1,
75 | "minimum": -1
76 | },
77 | "schema": {
78 | "description": "The schema is used by a Graphic to define the data parameters of the 'update' method.",
79 | "type": "object",
80 | "$ref": "https://superflytv.github.io/GraphicsDataDefinition/gdd-meta-schema/v1/lib/object.json"
81 | },
82 | "renderRequirements": {
83 | "description": "A list of requirements that this Graphic has for the rendering environment. At least one of the requirements must be met for the graphic to be expected to work.",
84 | "type": "array",
85 | "items": {
86 | "type": "object",
87 | "properties": {
88 | "resolution": {
89 | "description": "If set, specifies requirements for the resolution of the Renderer.",
90 | "type": "object",
91 | "properties": {
92 | "width": {
93 | "$ref": "https://ograf.ebu.io/v1/specification/json-schemas/lib/constraints/number.json"
94 | },
95 | "height": {
96 | "$ref": "https://ograf.ebu.io/v1/specification/json-schemas/lib/constraints/number.json"
97 | }
98 | }
99 | },
100 | "frameRate": {
101 | "description": "If set, specifies requirements for frame rate of the Renderer. Example: 60 fps",
102 | "$ref": "https://ograf.ebu.io/v1/specification/json-schemas/lib/constraints/number.json"
103 | },
104 | "accessToPublicInternet": {
105 | "description": "If set, specifies requirement on whether the renderer has access to the public internet or not.",
106 | "$ref": "https://ograf.ebu.io/v1/specification/json-schemas/lib/constraints/boolean.json"
107 | }
108 |
109 | },
110 | "patternProperties": {
111 | "^v_.*": {}
112 | },
113 | "additionalProperties": false
114 | }
115 | }
116 | },
117 | "required": [
118 | "$schema",
119 | "id",
120 | "name",
121 | "main",
122 | "supportsRealTime",
123 | "supportsNonRealTime"
124 | ],
125 | "patternProperties": {
126 | "^v_.*": {}
127 | },
128 | "additionalProperties": false
129 | }
130 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Basic Options */
4 | // "incremental": true, /* Enable incremental compilation */
5 | "target": "ES2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
6 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
7 | "lib": ["ES2018"], /* Specify library files to be included in the compilation. */
8 | // "allowJs": true, /* Allow javascript files to be compiled. */
9 | // "checkJs": true, /* Report errors in .js files. */
10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
11 | "declaration": true, /* Generates corresponding '.d.ts' file. */
12 | "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
13 | // "sourceMap": true, /* Generates corresponding '.map' file. */
14 | // "outFile": "./", /* Concatenate and emit output to single file. */
15 | "outDir": "./dist", /* Redirect output structure to the directory. */
16 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
17 | // "composite": true, /* Enable project compilation */
18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
19 | // "removeComments": true, /* Do not emit comments to output. */
20 | // "noEmit": true, /* Do not emit outputs. */
21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
24 |
25 | /* Strict Type-Checking Options */
26 | "strict": true, /* Enable all strict type-checking options. */
27 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
28 | // "strictNullChecks": true, /* Enable strict null checks. */
29 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
30 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
31 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
32 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
33 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
34 |
35 | /* Additional Checks */
36 | // "noUnusedLocals": true, /* Report errors on unused locals. */
37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
40 |
41 | /* Module Resolution Options */
42 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
46 | // "typeRoots": [], /* List of folders to include type definitions from. */
47 | // "types": [], /* Type declaration files to be included in compilation. */
48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
49 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
52 |
53 | /* Source Map Options */
54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
58 |
59 | /* Experimental Options */
60 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
61 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
62 |
63 | /* Advanced Options */
64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
65 | },
66 | "exclude": [
67 | "./test",
68 | "./dist"
69 | ]
70 | }
71 |
--------------------------------------------------------------------------------
/v1/specification/docs/images/step-model1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ograf",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "ograf",
9 | "version": "1.0.0",
10 | "license": "MIT",
11 | "devDependencies": {
12 | "json-schema-to-typescript": "^15.0.3",
13 | "typescript": "^5.6.3"
14 | }
15 | },
16 | "node_modules/@apidevtools/json-schema-ref-parser": {
17 | "version": "11.7.2",
18 | "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz",
19 | "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==",
20 | "dev": true,
21 | "dependencies": {
22 | "@jsdevtools/ono": "^7.1.3",
23 | "@types/json-schema": "^7.0.15",
24 | "js-yaml": "^4.1.0"
25 | },
26 | "engines": {
27 | "node": ">= 16"
28 | },
29 | "funding": {
30 | "url": "https://github.com/sponsors/philsturgeon"
31 | }
32 | },
33 | "node_modules/@jsdevtools/ono": {
34 | "version": "7.1.3",
35 | "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
36 | "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
37 | "dev": true
38 | },
39 | "node_modules/@types/json-schema": {
40 | "version": "7.0.15",
41 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
42 | "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
43 | "dev": true
44 | },
45 | "node_modules/@types/lodash": {
46 | "version": "4.17.13",
47 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.13.tgz",
48 | "integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==",
49 | "dev": true
50 | },
51 | "node_modules/argparse": {
52 | "version": "2.0.1",
53 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
54 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
55 | "dev": true
56 | },
57 | "node_modules/fdir": {
58 | "version": "6.4.2",
59 | "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz",
60 | "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==",
61 | "dev": true,
62 | "peerDependencies": {
63 | "picomatch": "^3 || ^4"
64 | },
65 | "peerDependenciesMeta": {
66 | "picomatch": {
67 | "optional": true
68 | }
69 | }
70 | },
71 | "node_modules/is-extglob": {
72 | "version": "2.1.1",
73 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
74 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
75 | "dev": true,
76 | "engines": {
77 | "node": ">=0.10.0"
78 | }
79 | },
80 | "node_modules/is-glob": {
81 | "version": "4.0.3",
82 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
83 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
84 | "dev": true,
85 | "dependencies": {
86 | "is-extglob": "^2.1.1"
87 | },
88 | "engines": {
89 | "node": ">=0.10.0"
90 | }
91 | },
92 | "node_modules/js-yaml": {
93 | "version": "4.1.0",
94 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
95 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
96 | "dev": true,
97 | "dependencies": {
98 | "argparse": "^2.0.1"
99 | },
100 | "bin": {
101 | "js-yaml": "bin/js-yaml.js"
102 | }
103 | },
104 | "node_modules/json-schema-to-typescript": {
105 | "version": "15.0.3",
106 | "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.3.tgz",
107 | "integrity": "sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==",
108 | "dev": true,
109 | "dependencies": {
110 | "@apidevtools/json-schema-ref-parser": "^11.5.5",
111 | "@types/json-schema": "^7.0.15",
112 | "@types/lodash": "^4.17.7",
113 | "is-glob": "^4.0.3",
114 | "js-yaml": "^4.1.0",
115 | "lodash": "^4.17.21",
116 | "minimist": "^1.2.8",
117 | "prettier": "^3.2.5",
118 | "tinyglobby": "^0.2.9"
119 | },
120 | "bin": {
121 | "json2ts": "dist/src/cli.js"
122 | },
123 | "engines": {
124 | "node": ">=16.0.0"
125 | }
126 | },
127 | "node_modules/lodash": {
128 | "version": "4.17.21",
129 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
130 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
131 | "dev": true
132 | },
133 | "node_modules/minimist": {
134 | "version": "1.2.8",
135 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
136 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
137 | "dev": true,
138 | "funding": {
139 | "url": "https://github.com/sponsors/ljharb"
140 | }
141 | },
142 | "node_modules/picomatch": {
143 | "version": "4.0.2",
144 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
145 | "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
146 | "dev": true,
147 | "engines": {
148 | "node": ">=12"
149 | },
150 | "funding": {
151 | "url": "https://github.com/sponsors/jonschlinkert"
152 | }
153 | },
154 | "node_modules/prettier": {
155 | "version": "3.4.0",
156 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.0.tgz",
157 | "integrity": "sha512-/OXNZcLyWkfo13ofOW5M7SLh+k5pnIs07owXK2teFpnfaOEcycnSy7HQxldaVX1ZP/7Q8oO1eDuQJNwbomQq5Q==",
158 | "dev": true,
159 | "bin": {
160 | "prettier": "bin/prettier.cjs"
161 | },
162 | "engines": {
163 | "node": ">=14"
164 | },
165 | "funding": {
166 | "url": "https://github.com/prettier/prettier?sponsor=1"
167 | }
168 | },
169 | "node_modules/tinyglobby": {
170 | "version": "0.2.10",
171 | "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz",
172 | "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==",
173 | "dev": true,
174 | "dependencies": {
175 | "fdir": "^6.4.2",
176 | "picomatch": "^4.0.2"
177 | },
178 | "engines": {
179 | "node": ">=12.0.0"
180 | }
181 | },
182 | "node_modules/typescript": {
183 | "version": "5.6.3",
184 | "dev": true,
185 | "license": "Apache-2.0",
186 | "bin": {
187 | "tsc": "bin/tsc",
188 | "tsserver": "bin/tsserver"
189 | },
190 | "engines": {
191 | "node": ">=14.17"
192 | }
193 | }
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/v1/examples/renderer-test/graphic.mjs:
--------------------------------------------------------------------------------
1 | class Graphic extends HTMLElement {
2 | connectedCallback() {
3 | // Called when the element is added to the DOM
4 | // Note: Don't paint any pixels at this point, wait for load() to be called
5 | }
6 |
7 | async load(params) {
8 | this.style.fontSize = "24px";
9 |
10 | // Note: the OGraf specification says that the load() method should not paint any pixels.
11 | // This directive is ignored in this test graphic.
12 |
13 | const infoMessageContainer = document.createElement("div");
14 | infoMessageContainer.style.color = "#000";
15 | infoMessageContainer.style.position = "absolute";
16 | infoMessageContainer.style.top = "25%";
17 | infoMessageContainer.style.left = "0%";
18 | infoMessageContainer.style.right = "0%";
19 | infoMessageContainer.style.textAlign = "center";
20 | infoMessageContainer.style.zIndex = 1;
21 | this.appendChild(infoMessageContainer);
22 |
23 |
24 | const infoMessage = document.createElement("div");
25 | infoMessage.style.backgroundColor = "#ffffff";
26 | infoMessage.style.display = "inline-block";
27 | infoMessage.style.padding = "1em";
28 | infoMessageContainer.appendChild(infoMessage);
29 | this.infoMessage = infoMessage
30 |
31 | this._infoMessage('Starting up...')
32 |
33 | if (params.renderCharacteristics &&
34 | params.renderCharacteristics.resolution
35 | ) {
36 | // This fills the background with a red box, which should be covered by the blue fill below
37 | const fullContainer = document.createElement("div");
38 | fullContainer.style.position = "absolute";
39 | fullContainer.style.top = '0'
40 | fullContainer.style.left = '0'
41 | fullContainer.style.right = '0'
42 | fullContainer.style.bottom = '0'
43 | fullContainer.style.backgroundColor = "#f00";
44 | this.appendChild(fullContainer);
45 |
46 | // This paints a blue box, which should be the size of the renderer
47 | const sizedContainer = document.createElement("div");
48 | sizedContainer.style.position = "absolute";
49 | sizedContainer.style.top = '0'
50 | sizedContainer.style.left = '0'
51 | sizedContainer.style.width = `${params.renderCharacteristics.resolution.width}px`
52 | sizedContainer.style.height = `${params.renderCharacteristics.resolution.height}px`
53 | sizedContainer.style.backgroundColor = "#87a0de";
54 | this.appendChild(sizedContainer);
55 |
56 | }
57 |
58 | return this._handleAction('load', params);
59 | }
60 | async dispose(_params) {
61 | this.innerHTML = "";
62 | }
63 | async updateAction(params) {
64 | return this._handleAction('updateAction', params);
65 | }
66 | async playAction(params) {
67 | return this._handleAction('playAction', params);
68 | }
69 | async stopAction(params) {
70 | return this._handleAction('stopAction', params);
71 | }
72 | async customAction(params) {
73 | return this._handleAction('customAction', params);
74 | }
75 |
76 | loggedActions = []
77 | _handleAction(type, params) {
78 | const lastAction = { type, params }
79 | this.loggedActions.push(lastAction);
80 |
81 | const currentStep = this.steps[this.stepIndex]
82 | if (!currentStep) {
83 | return this._infoMessage('No more steps to verify, this test is completed');
84 | }
85 | let error = currentStep.verify(lastAction)
86 |
87 |
88 | if (!error) {
89 | this.stepIndex++
90 |
91 | const nextStep = this.steps[this.stepIndex]
92 |
93 | if (nextStep) {
94 | return this._infoMessage(`${currentStep.completed ? `${currentStep.completed}\n` : ''}Step ${this.stepIndex} completed.\nNext, ${nextStep.prompt}`);
95 | } else {
96 | return this._infoMessage('No more steps to verify, this test is completed');
97 | }
98 | } else {
99 |
100 | this._errorMessage(`Expected ${currentStep.prompt}\n${error}`)
101 |
102 | }
103 | }
104 |
105 |
106 | _errorMessage(error) {
107 | this.infoMessage.innerHTML = this._formatText(error)
108 | this.infoMessage.style.backgroundColor = "#bb0000";
109 | this.infoMessage.style.color = "#fff";
110 |
111 | return {
112 | statusCode: 400,
113 | statusMessage: error
114 | }
115 | }
116 | _infoMessage(str) {
117 | this.infoMessage.innerHTML = this._formatText(str)
118 | this.infoMessage.style.backgroundColor = "#fff";
119 | this.infoMessage.style.color = "#000";
120 |
121 | return {
122 | statusCode: 200,
123 | statusMessage: str
124 | }
125 | }
126 | _formatText(str) {
127 | return str.replaceAll(/\n/g, "
");
128 | }
129 |
130 |
131 | steps = [
132 | {
133 | prompt: 'N/A',
134 | completed: 'load() method seems okay!',
135 | verify: (lastAction) => {
136 | if (lastAction.type !== 'load') return 'Expected the load() method to be called'
137 | if (lastAction.params.renderType !== 'realtime') return 'Only realtime rendering is supported by this graphic!'
138 | if (!lastAction.params.data) return 'No `data` argument provided to the load() method'
139 | if (!lastAction.params.data.message) return 'Expected a `message` argument in the `data` object provided to the load() method'
140 | }
141 | },
142 | {
143 | prompt: 'call the playAction() method (with no skipAnimation set)',
144 | verify: (lastAction) => {
145 | if (lastAction.type !== 'playAction') return 'Expected the playAction() method to be called';
146 | if (lastAction.params.skipAnimation) return 'Expected "skipAnimation" to be undefined or false, got true';
147 | }
148 | },
149 | {
150 | prompt: 'call the playAction() method, with skipAnimation set to true.',
151 | verify: (lastAction) => {
152 | if (lastAction.type !== 'playAction') return 'Expected the playAction() method to be called';
153 | if (lastAction.params.skipAnimation !== true) return `Expected the playAction to be called with { skipAnimation: true }, got ${JSON.stringify(lastAction.params)}`;
154 | }
155 | },
156 | {
157 | prompt: `call the playAction() method, with 'goto' set to 4.`,
158 | verify: (lastAction) => {
159 | if (lastAction.type !== 'playAction') return 'Expected the playAction() method to be called';
160 | if (lastAction.params.goto !== 4) return `Expected the playAction to be called with 'goto' set to 4, got ${JSON.stringify(lastAction.params)}`;
161 | if (lastAction.params.delta !== undefined) return `Expected the playAction to be called with 'delta' being undefined, got ${JSON.stringify(lastAction.params)}`;
162 | }
163 | },
164 | {
165 | prompt: `call the playAction() method, with 'delta' set to -1.`,
166 | verify: (lastAction) => {
167 | if (lastAction.type !== 'playAction') return 'Expected the playAction() method to be called';
168 | if (lastAction.params.delta !== -1) return `Expected the playAction to be called with 'delta' set to -1, got ${JSON.stringify(lastAction.params)}`;
169 | if (lastAction.params.goto !== undefined) return `Expected the playAction to be called with 'goto' being undefined, got ${JSON.stringify(lastAction.params)}`;
170 | }
171 | },
172 | {
173 | prompt: `call the updateAction() method, with data { message: 'Hello' }`,
174 | verify: (lastAction) => {
175 | if (lastAction.type !== 'updateAction') return 'Expected the updateAction() method to be called';
176 | if (lastAction.params.data.message !== 'Hello') return `Expected the updateAction to be called with 'delta' set to -1, got ${JSON.stringify(lastAction.params)}`;
177 | }
178 | },
179 | {
180 | prompt: `call the stopAction() method`,
181 | verify: (lastAction) => {
182 | if (lastAction.type !== 'stopAction') return 'Expected the stopAction() method to be called';
183 | }
184 | },
185 | {
186 | prompt: 'call the stopAction() method, with skipAnimation set to true.',
187 | verify: (lastAction) => {
188 | if (lastAction.type !== 'stopAction') return 'Expected the stopAction() method to be called';
189 | if (lastAction.params.skipAnimation !== true) return `Expected the stopAction to be called with { skipAnimation: true }, got ${JSON.stringify(lastAction.params)}`;
190 | }
191 | },
192 | {
193 | prompt: 'call the customAction() method for the "highlight" action',
194 | verify: (lastAction) => {
195 | if (lastAction.type !== 'customAction') return 'Expected the customAction() method to be called';
196 | if (lastAction.params.id !== 'highlight') return `Expected the customAction() method to be called with id "highlight", got ${JSON.stringify(lastAction.params)}`;
197 | }
198 | },
199 | {
200 | prompt: 'call the customAction() method for the "setColor" action, with payload { color: "red" }',
201 | verify: (lastAction) => {
202 | if (lastAction.type !== 'customAction') return 'Expected the customAction() method to be called';
203 | if (lastAction.params.id !== 'setColor') return `Expected the customAction() method to be called with id "setColor", got ${JSON.stringify(lastAction.params)}`;
204 | if (typeof lastAction.params.payload !== 'object') return `Property "payload" is missing in argument, got ${JSON.stringify(lastAction.params)}`;
205 | if (lastAction.params.payload.color !== 'red') return `Expected property "payload.color" to have the value "red", got ${JSON.stringify(lastAction.params)}`;
206 | }
207 | },
208 | ]
209 |
210 | stepIndex = 0
211 | }
212 |
213 | export default Graphic;
214 |
--------------------------------------------------------------------------------
/v1/examples/l3rd-name/lib/utils/strings.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * strings: 3.12.5
3 | * https://gsap.com
4 | *
5 | * Copyright 2008-2024, GreenSock. All rights reserved.
6 | * Subject to the terms at https://gsap.com/standard-license or for
7 | * Club GSAP members, the agreement issued with that membership.
8 | * @author: Jack Doyle, jack@greensock.com
9 | */
10 |
11 | /* eslint-disable */
12 | var _trimExp = /(?:^\s+|\s+$)/g;
13 | export var emojiExp = /([\uD800-\uDBFF][\uDC00-\uDFFF](?:[\u200D\uFE0F][\uD800-\uDBFF][\uDC00-\uDFFF]){2,}|\uD83D\uDC69(?:\u200D(?:(?:\uD83D\uDC69\u200D)?\uD83D\uDC67|(?:\uD83D\uDC69\u200D)?\uD83D\uDC66)|\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D(?:\uD83D\uDC69\u200D)?\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D(?:\uD83D\uDC69\u200D)?\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]\uFE0F|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC6F\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3C-\uDD3E\uDDD6-\uDDDF])\u200D[\u2640\u2642]\uFE0F|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F\u200D[\u2640\u2642]|(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642])\uFE0F|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2695\u2696\u2708]|\uD83D\uDC69\u200D[\u2695\u2696\u2708]|\uD83D\uDC68(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708]))\uFE0F|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83D\uDC69\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|\uD83D\uDC68(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC66\u200D\uD83D\uDC66|(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|(?:\uD83C[\uDFFB-\uDFFF])\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]))|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDD1-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\u200D(?:(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC67|(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC66)|\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC69\uDC6E\uDC70-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD26\uDD30-\uDD39\uDD3D\uDD3E\uDDD1-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])?|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDEEB\uDEEC\uDEF4-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])\uFE0F)/;
14 | export function getText(e) {
15 | var type = e.nodeType,
16 | result = "";
17 |
18 | if (type === 1 || type === 9 || type === 11) {
19 | if (typeof e.textContent === "string") {
20 | return e.textContent;
21 | } else {
22 | for (e = e.firstChild; e; e = e.nextSibling) {
23 | result += getText(e);
24 | }
25 | }
26 | } else if (type === 3 || type === 4) {
27 | return e.nodeValue;
28 | }
29 |
30 | return result;
31 | }
32 | export function splitInnerHTML(element, delimiter, trim, preserveSpaces) {
33 | var node = element.firstChild,
34 | result = [],
35 | s;
36 |
37 | while (node) {
38 | if (node.nodeType === 3) {
39 | s = (node.nodeValue + "").replace(/^\n+/g, "");
40 |
41 | if (!preserveSpaces) {
42 | s = s.replace(/\s+/g, " ");
43 | }
44 |
45 | result.push.apply(result, emojiSafeSplit(s, delimiter, trim, preserveSpaces));
46 | } else if ((node.nodeName + "").toLowerCase() === "br") {
47 | result[result.length - 1] += "
";
48 | } else {
49 | result.push(node.outerHTML);
50 | }
51 |
52 | node = node.nextSibling;
53 | }
54 |
55 | s = result.length;
56 |
57 | while (s--) {
58 | result[s] === "&" && result.splice(s, 1, "&");
59 | }
60 |
61 | return result;
62 | }
63 | /*
64 | //smaller kb version that only handles the simpler emoji's, which is often perfectly adequate.
65 |
66 | let _emoji = "[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2694-\u2697]|\uD83E[\uDD10-\uDD5D]|[\uD800-\uDBFF][\uDC00-\uDFFF]",
67 | _emojiExp = new RegExp(_emoji),
68 | _emojiAndCharsExp = new RegExp(_emoji + "|.", "g"),
69 | _emojiSafeSplit = (text, delimiter, trim) => {
70 | if (trim) {
71 | text = text.replace(_trimExp, "");
72 | }
73 | return ((delimiter === "" || !delimiter) && _emojiExp.test(text)) ? text.match(_emojiAndCharsExp) : text.split(delimiter || "");
74 | };
75 | */
76 |
77 | export function emojiSafeSplit(text, delimiter, trim, preserveSpaces) {
78 | text += ""; // make sure it's cast as a string. Someone may pass in a number.
79 |
80 | trim && (text = text.trim ? text.trim() : text.replace(_trimExp, "")); // IE9 and earlier compatibility
81 |
82 | if (delimiter && delimiter !== "") {
83 | return text.replace(/>/g, ">").replace(/= 0xD800 && character.charCodeAt(0) <= 0xDBFF || text.charCodeAt(i + 1) >= 0xFE00 && text.charCodeAt(i + 1) <= 0xFE0F) {
96 | //special emoji characters use 2 or 4 unicode characters that we must keep together.
97 | j = ((text.substr(i, 12).split(emojiExp) || [])[1] || "").length || 2;
98 | character = text.substr(i, j);
99 | result.emoji = 1;
100 | i += j - 1;
101 | }
102 |
103 | result.push(character === ">" ? ">" : character === "<" ? "<" : preserveSpaces && character === " " && (text.charAt(i - 1) === " " || text.charAt(i + 1) === " ") ? " " : character);
104 | }
105 |
106 | return result;
107 | }
--------------------------------------------------------------------------------
/v1/specification/docs/images/step-model2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/v1/examples/l3rd-name/graphic.mjs:
--------------------------------------------------------------------------------
1 |
2 |
3 | /**
4 | * Note:
5 | *
6 | * @typedef { import('../../typescript-definitions/src/main').GraphicsAPI.Graphic } Graphic
7 | */
8 |
9 | /** @implements { Graphic } */
10 | class MyGraphic extends HTMLElement {
11 | constructor() {
12 | super();
13 | this.nonRealTimeState = {};
14 | this.displayState = {}
15 | }
16 | connectedCallback() {
17 | // Called when the element is added to the DOM
18 | // Note: Don't paint any pixels at this point, wait for load() to be called
19 | }
20 |
21 | async load(loadParams) {
22 | // 1. Load resources
23 | // 2. Setup the DOM
24 | // 3. Initialize the GSAP timeline
25 |
26 |
27 | // Load the GSAP scripts ---------------------------------------------------
28 | const importsPromises = {
29 | gsap: import(import.meta.resolve("./lib/gsap-core.js")),
30 | CSSPlugin: import(import.meta.resolve("./lib/CSSPlugin.js")),
31 | TextPlugin: import(import.meta.resolve("./lib/TextPlugin.js")),
32 | };
33 |
34 | this.g = await importsPromises.gsap;
35 | this.g.gsap.registerPlugin((await importsPromises.CSSPlugin).CSSPlugin);
36 | this.g.gsap.registerPlugin((await importsPromises.TextPlugin).TextPlugin);
37 |
38 | // Setup our DOM -----------------------------------------------------------
39 | const container = document.createElement("div");
40 | this.appendChild(container);
41 |
42 | container.style.position = "absolute";
43 | container.style.left = "calc(10% + 60px)";
44 | container.style.bottom = "calc(10% + 30px)";
45 | container.style.height = "32px";
46 |
47 | container.style.padding = "6px 20px";
48 | container.style.backgroundColor = "#f00";
49 | container.style.color = "#fff";
50 | container.style.fontFamily = "Roboto, sans-serif";
51 | container.style.fontSize = "28px";
52 | container.style.fontWeight = "bold";
53 | container.style.zIndex = "2";
54 | container.style.borderBottomRightRadius = "20px";
55 | container.style.borderTopRightRadius = "20px";
56 | container.style.borderTopLeftRadius = "20px";
57 |
58 | const nameText = document.createElement("div");
59 | nameText.innerText = "";
60 | container.appendChild(nameText);
61 |
62 | const container2 = document.createElement("div");
63 | this.appendChild(container2);
64 |
65 | container2.style.position = "absolute";
66 | container2.style.left = "calc(10% + 60px)";
67 | container2.style.bottom = "10%";
68 | container2.style.height = "23px";
69 | container2.style.padding = "5px 20px 2px 20px";
70 | container2.style.backgroundColor = "#b00";
71 | container2.style.color = "#fff";
72 | container2.style.fontFamily = "Roboto, sans-serif";
73 | container2.style.fontSize = "18px";
74 | container2.style.fontWeight = "bold";
75 | container2.style.zIndex = "1";
76 | container2.style.borderBottomRightRadius = "10px";
77 | container2.style.borderBottomLeftRadius = "10px";
78 |
79 | const nameText2 = document.createElement("div");
80 | nameText2.innerText = "";
81 | container2.appendChild(nameText2);
82 |
83 | const logo = document.createElement("img");
84 | logo.src = await this._loadImage(import.meta.resolve("./lib/ograf-logo-app.svg"))
85 | logo.style.position = "absolute";
86 | logo.style.left = `calc(10%)`
87 | logo.style.bottom = `calc(10% + 10px)`
88 | logo.style.width = "50px";
89 | logo.style.boxShadow = "0 0 10px rgba(0,0,0,0.5)";
90 | logo.style.borderRadius = "5px";
91 | this.appendChild(logo);
92 |
93 |
94 |
95 | this.elements = {
96 | container,
97 | nameText,
98 | container2,
99 | nameText2,
100 | logo
101 | };
102 |
103 | // Initialize the GSAP timeline --------------------------------------------
104 | this.timeline = this.g.gsap.timeline();
105 | this._resetTimeline();
106 |
107 | if (loadParams.renderType === "realtime") {
108 | this.timeline.play(); // not really needed, it's playing by default
109 | } else if (loadParams.renderType === "non-realtime") {
110 | this.timeline.pause();
111 | } else throw new Error("Unsupported renderType: " + loadParams.renderType);
112 |
113 | // Load initial data:
114 | this.initialData = loadParams.data
115 | await this._doAction("updateAction", {
116 | data: this.initialData || {},
117 | skipAnimation: true
118 | });
119 |
120 | // When everything is loaded we can return:
121 | return;
122 | }
123 | async dispose(_params) {
124 | this.innerHTML = "";
125 | this.g = null;
126 | }
127 | async updateAction(params) {
128 | // params.data
129 | // console.log("params", params);
130 |
131 | await this._doAction("updateAction", params);
132 | }
133 | async playAction(params) {
134 | // params.delta
135 | // params.goto
136 | // params.skipAnimation
137 |
138 | await this._doAction("playAction", params);
139 | }
140 | async stopAction(params) {
141 | // params.skipAnimation
142 |
143 | await this._doAction("stopAction", params);
144 | }
145 | async customAction(params) {
146 | // params.id
147 | // params.payload
148 |
149 | await this._doAction('customAction', params);
150 | }
151 | async _doAction(type, params) {
152 | const timeline = this.g.gsap.timeline();
153 |
154 | // Retrieve the timeline for the action:
155 | // Add the tweens to the timeline, so that they'll animate:
156 | const actionTimeline = this._getActionAnimation(type, params);
157 |
158 | timeline.add(actionTimeline, 0);
159 |
160 | // Wait for timeline to finish animating:
161 | await timeline.then();
162 | }
163 | async goToTime(payload) {
164 | this.nonRealTimeState.timestamp = payload.timestamp;
165 |
166 | await this._updateState();
167 | }
168 | async setActionsSchedule(payload) {
169 | this.nonRealTimeState.schedule = payload.schedule;
170 |
171 | await this._updateState();
172 | }
173 | async _updateState() {
174 | this._resetTimeline();
175 |
176 | // Initial state:
177 |
178 | // Load initial data:
179 | await this._doAction("updateAction", {
180 | data: this.initialData || {},
181 | skipAnimation: true
182 | });
183 |
184 | for (const event of (this.nonRealTimeState.schedule || [])) {
185 | const eventTimeline = this._getActionAnimation(
186 | event.action.type,
187 | event.action.params
188 | )
189 |
190 | this.timeline.add(eventTimeline, event.timestamp / 1000);
191 | }
192 |
193 | this.timeline.seek(this.nonRealTimeState.timestamp / 1000);
194 | }
195 | _getActionAnimation(type, params) {
196 | let tweens = []
197 |
198 | if (type === "updateAction") {
199 | tweens = this._getUpdateAnimation(params);
200 | } else if (type === "playAction") {
201 | tweens = this._getPlayAnimation(params);
202 | } else if (type === "stopAction") {
203 | tweens = this._getStopAnimation(params);
204 | } else if (type === "customAction") {
205 | if (params.id === 'highlight') {
206 | tweens = this._getHighlightAnimation(params.payload);
207 | } else {
208 | throw new Error(`Unknown customAction id "${params.id}"`);
209 | }
210 | } else {
211 | throw new Error(`Unknown action type "${type}"`);
212 | }
213 |
214 | const actionTimeline = this.g.gsap.timeline();
215 |
216 | for (const tween of tweens) {
217 | actionTimeline.add(tween, 0);
218 | }
219 |
220 | if (params.skipAnimation) {
221 | actionTimeline.timeScale(999999)
222 | }
223 | }
224 | _resetTimeline() {
225 | const gsap = this.g.gsap;
226 |
227 | this.displayState = {}
228 |
229 | // Clear the timeline:
230 | this.timeline.clear();
231 |
232 | // Initial animation state:
233 | const tweens = [
234 | gsap.set(this.elements.container, {
235 | x: -30,
236 | backgroundColor: "#f00",
237 | color: "#fff",
238 | opacity: 0,
239 | }),
240 | gsap.set(this.elements.nameText, {
241 | text: "",
242 | }),
243 | gsap.set(this.elements.container2, {
244 | y: -20,
245 | opacity: 0,
246 | }),
247 | gsap.set(this.elements.nameText2, {
248 | text: "",
249 | }),
250 | gsap.set(this.elements.logo, {
251 | scale: 0.5,
252 | opacity: 0
253 | }),
254 | ];
255 |
256 | // Add Tweens to the beginning of the timeline:
257 | for (const tween of tweens) {
258 | this.timeline.add(tween, 0);
259 | }
260 | }
261 |
262 | // -------------------- Actions --------------------
263 | _getUpdateAnimation(params) {
264 | const gsap = this.g.gsap;
265 |
266 |
267 | this.displayState.data = params.data || {}
268 |
269 |
270 |
271 | const showTitle = this.displayState.data.title
272 | const isPlaying = this.displayState.isPlaying
273 |
274 | return [
275 | gsap.to(this.elements.nameText, {
276 | duration: 0.4,
277 | text: this.displayState.data.name,
278 | }),
279 | gsap.to(this.elements.nameText2, {
280 | duration: 0.4,
281 | text: this.displayState.data.title,
282 | }),
283 | (
284 | isPlaying &&
285 | gsap.to(this.elements.container2, {
286 | duration: 0.3,
287 | y: 0,
288 | opacity: showTitle ? 1 : 0,
289 | ease: "power2.out",
290 | })
291 | ),
292 | (
293 | isPlaying &&
294 | gsap.to(this.elements.container, {
295 | duration: 0.3,
296 | borderBottomLeftRadius: showTitle ? "0" : "20px",
297 | ease: "power2.out",
298 | })
299 | )
300 | ];
301 | }
302 | _getPlayAnimation(params) {
303 | const gsap = this.g.gsap;
304 |
305 | this.displayState.isPlaying = true
306 |
307 | const showTitle = Boolean(this.displayState.data.title)
308 |
309 |
310 | return [
311 | gsap.to(this.elements.container, {
312 | duration: 0.8,
313 | x: 0,
314 | opacity: 1,
315 | borderBottomLeftRadius: showTitle ? "0" : "20px",
316 | ease: "power2.out",
317 | }),
318 |
319 | gsap.to(this.elements.container2, {
320 | delay: 0.3,
321 | duration: 0.8,
322 | y: 0,
323 | opacity: showTitle ? 1 : 0,
324 | ease: "power2.out",
325 | }),
326 | gsap.to(this.elements.nameText2, {
327 | delay: 0.7,
328 | duration: 0.8,
329 | }),
330 | gsap.to(this.elements.logo, {
331 | duration: 0.5,
332 | opacity: 1,
333 | }),
334 | gsap.to(this.elements.logo, {
335 | duration: 1.5,
336 | rotation: 360,
337 | scale: 1
338 | }),
339 | ];
340 | }
341 | _getStopAnimation(params) {
342 | const gsap = this.g.gsap;
343 |
344 | this.displayState.isPlaying = false
345 |
346 | return [
347 | gsap.to(this.elements.container, {
348 | delay: 0.3,
349 | duration: 0.8,
350 | x: -30,
351 | opacity: 0,
352 | ease: "power2.in",
353 | }),
354 | gsap.to(this.elements.container2, {
355 | duration: 0.5,
356 | y: -20,
357 | opacity: 0,
358 | ease: "power2.in",
359 | }),
360 | gsap.to(this.elements.logo, {
361 | duration: 0.8,
362 | rotation: 180,
363 | scale: 0.8,
364 | opacity: 0
365 | }),
366 | ];
367 | }
368 | _getHighlightAnimation(params) {
369 | const gsap = this.g.gsap;
370 |
371 | return [
372 | gsap.to(this.elements.container, {
373 | duration: 0.8,
374 | backgroundColor: "#ff0",
375 | color: "#000",
376 |
377 | ease: "power2.in",
378 | }),
379 | gsap
380 | .to(this.elements.container, {
381 | delay: 2,
382 | duration: 0.8,
383 | backgroundColor: "#f00",
384 | color: "#fff",
385 |
386 | ease: "power2.in",
387 | }),
388 | gsap.to(this.elements.logo, {
389 | duration: 1,
390 | scale: 1.5,
391 | ease: "bounce.out",
392 | }),
393 | gsap.to(this.elements.logo, {
394 | delay: 1,
395 | duration: 1,
396 | scale: 1,
397 | }),
398 |
399 | ];
400 | }
401 | _loadImage(url) {
402 | return new Promise((resolve, reject) => {
403 | const newImg = new Image;
404 | newImg.onload = function() {
405 | resolve(this.src)
406 | }
407 | newImg.onerror = reject;
408 | newImg.src = url
409 | })
410 | }
411 | }
412 |
413 | export default MyGraphic;
414 |
415 | // Note: The renderer will render the component
416 |
--------------------------------------------------------------------------------
/v1/specification/docs/images/step-model3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/v1/specification/docs/images/components.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/v1/typescript-definitions/src/generated/graphics-manifest.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /**
3 | * This file was automatically generated by json-schema-to-typescript.
4 | * DO NOT MODIFY IT BY HAND! Instead, modify the source JSON Schema file,
5 | * and run 'npm run generate-types' to regenerate this file.
6 | */
7 |
8 | export type HttpsSuperflytvGithubIoGraphicsDataDefinitionGddMetaSchemaV1LibObjectJson =
9 | CoreAndValidationSpecificationsMetaSchema &
10 | HttpsSuperflytvGithubIoGraphicsDataDefinitionGddMetaSchemaV1LibGddTypesJson &
11 | HttpsSuperflytvGithubIoGraphicsDataDefinitionGddMetaSchemaV1LibBasicTypesJson & {
12 | type: "boolean" | "string" | "number" | "integer" | "array" | "object";
13 | gddType?: string;
14 | gddOptions?: {
15 | [k: string]: unknown;
16 | };
17 | [k: string]: unknown;
18 | };
19 | export type CoreAndValidationSpecificationsMetaSchema = CoreVocabularyMetaSchema &
20 | ApplicatorVocabularyMetaSchema &
21 | UnevaluatedApplicatorVocabularyMetaSchema &
22 | ValidationVocabularyMetaSchema &
23 | MetaDataVocabularyMetaSchema &
24 | FormatVocabularyMetaSchemaForAnnotationResults &
25 | ContentVocabularyMetaSchema & {
26 | /**
27 | * @deprecated
28 | */
29 | definitions?: {
30 | [k: string]: {
31 | [k: string]: unknown;
32 | };
33 | };
34 | /**
35 | * @deprecated
36 | */
37 | dependencies?: {
38 | [k: string]:
39 | | {
40 | [k: string]: unknown;
41 | }
42 | | string[];
43 | };
44 | /**
45 | * @deprecated
46 | */
47 | $recursiveAnchor?: string;
48 | /**
49 | * @deprecated
50 | */
51 | $recursiveRef?: string;
52 | [k: string]: unknown;
53 | } & (
54 | | {
55 | /**
56 | * @deprecated
57 | */
58 | definitions?: {
59 | [k: string]: {
60 | [k: string]: unknown;
61 | };
62 | };
63 | /**
64 | * @deprecated
65 | */
66 | dependencies?: {
67 | [k: string]:
68 | | {
69 | [k: string]: unknown;
70 | }
71 | | string[];
72 | };
73 | /**
74 | * @deprecated
75 | */
76 | $recursiveAnchor?: string;
77 | /**
78 | * @deprecated
79 | */
80 | $recursiveRef?: string;
81 | [k: string]: unknown;
82 | }
83 | | boolean
84 | );
85 | export type CoreVocabularyMetaSchema = {
86 | $id?: string;
87 | $schema?: string;
88 | $ref?: string;
89 | $anchor?: string;
90 | $dynamicRef?: string;
91 | $dynamicAnchor?: string;
92 | $vocabulary?: {
93 | [k: string]: boolean;
94 | };
95 | $comment?: string;
96 | $defs?: {
97 | [k: string]: {
98 | [k: string]: unknown;
99 | };
100 | };
101 | [k: string]: unknown;
102 | } & (
103 | | {
104 | $id?: string;
105 | $schema?: string;
106 | $ref?: string;
107 | $anchor?: string;
108 | $dynamicRef?: string;
109 | $dynamicAnchor?: string;
110 | $vocabulary?: {
111 | [k: string]: boolean;
112 | };
113 | $comment?: string;
114 | $defs?: {
115 | [k: string]: {
116 | [k: string]: unknown;
117 | };
118 | };
119 | [k: string]: unknown;
120 | }
121 | | boolean
122 | );
123 | export type ApplicatorVocabularyMetaSchema = {
124 | /**
125 | * @minItems 1
126 | */
127 | prefixItems?: [
128 | {
129 | [k: string]: unknown;
130 | },
131 | ...{
132 | [k: string]: unknown;
133 | }[]
134 | ];
135 | items?: {
136 | [k: string]: unknown;
137 | };
138 | contains?: {
139 | [k: string]: unknown;
140 | };
141 | additionalProperties?: {
142 | [k: string]: unknown;
143 | };
144 | properties?: {
145 | [k: string]: {
146 | [k: string]: unknown;
147 | };
148 | };
149 | patternProperties?: {
150 | [k: string]: {
151 | [k: string]: unknown;
152 | };
153 | };
154 | dependentSchemas?: {
155 | [k: string]: {
156 | [k: string]: unknown;
157 | };
158 | };
159 | propertyNames?: {
160 | [k: string]: unknown;
161 | };
162 | if?: {
163 | [k: string]: unknown;
164 | };
165 | then?: {
166 | [k: string]: unknown;
167 | };
168 | else?: {
169 | [k: string]: unknown;
170 | };
171 | /**
172 | * @minItems 1
173 | */
174 | allOf?: [
175 | {
176 | [k: string]: unknown;
177 | },
178 | ...{
179 | [k: string]: unknown;
180 | }[]
181 | ];
182 | /**
183 | * @minItems 1
184 | */
185 | anyOf?: [
186 | {
187 | [k: string]: unknown;
188 | },
189 | ...{
190 | [k: string]: unknown;
191 | }[]
192 | ];
193 | /**
194 | * @minItems 1
195 | */
196 | oneOf?: [
197 | {
198 | [k: string]: unknown;
199 | },
200 | ...{
201 | [k: string]: unknown;
202 | }[]
203 | ];
204 | not?: {
205 | [k: string]: unknown;
206 | };
207 | [k: string]: unknown;
208 | } & (
209 | | {
210 | /**
211 | * @minItems 1
212 | */
213 | prefixItems?: [
214 | {
215 | [k: string]: unknown;
216 | },
217 | ...{
218 | [k: string]: unknown;
219 | }[]
220 | ];
221 | items?: {
222 | [k: string]: unknown;
223 | };
224 | contains?: {
225 | [k: string]: unknown;
226 | };
227 | additionalProperties?: {
228 | [k: string]: unknown;
229 | };
230 | properties?: {
231 | [k: string]: {
232 | [k: string]: unknown;
233 | };
234 | };
235 | patternProperties?: {
236 | [k: string]: {
237 | [k: string]: unknown;
238 | };
239 | };
240 | dependentSchemas?: {
241 | [k: string]: {
242 | [k: string]: unknown;
243 | };
244 | };
245 | propertyNames?: {
246 | [k: string]: unknown;
247 | };
248 | if?: {
249 | [k: string]: unknown;
250 | };
251 | then?: {
252 | [k: string]: unknown;
253 | };
254 | else?: {
255 | [k: string]: unknown;
256 | };
257 | /**
258 | * @minItems 1
259 | */
260 | allOf?: [
261 | {
262 | [k: string]: unknown;
263 | },
264 | ...{
265 | [k: string]: unknown;
266 | }[]
267 | ];
268 | /**
269 | * @minItems 1
270 | */
271 | anyOf?: [
272 | {
273 | [k: string]: unknown;
274 | },
275 | ...{
276 | [k: string]: unknown;
277 | }[]
278 | ];
279 | /**
280 | * @minItems 1
281 | */
282 | oneOf?: [
283 | {
284 | [k: string]: unknown;
285 | },
286 | ...{
287 | [k: string]: unknown;
288 | }[]
289 | ];
290 | not?: {
291 | [k: string]: unknown;
292 | };
293 | [k: string]: unknown;
294 | }
295 | | boolean
296 | );
297 | export type UnevaluatedApplicatorVocabularyMetaSchema = {
298 | unevaluatedItems?: {
299 | [k: string]: unknown;
300 | };
301 | unevaluatedProperties?: {
302 | [k: string]: unknown;
303 | };
304 | [k: string]: unknown;
305 | } & (
306 | | {
307 | unevaluatedItems?: {
308 | [k: string]: unknown;
309 | };
310 | unevaluatedProperties?: {
311 | [k: string]: unknown;
312 | };
313 | [k: string]: unknown;
314 | }
315 | | boolean
316 | );
317 | export type ValidationVocabularyMetaSchema = {
318 | type?:
319 | | ("array" | "boolean" | "integer" | "null" | "number" | "object" | "string")
320 | | [
321 | "array" | "boolean" | "integer" | "null" | "number" | "object" | "string",
322 | ...("array" | "boolean" | "integer" | "null" | "number" | "object" | "string")[]
323 | ];
324 | const?: unknown;
325 | enum?: unknown[];
326 | multipleOf?: number;
327 | maximum?: number;
328 | exclusiveMaximum?: number;
329 | minimum?: number;
330 | exclusiveMinimum?: number;
331 | maxLength?: number;
332 | minLength?: number;
333 | pattern?: string;
334 | maxItems?: number;
335 | minItems?: number;
336 | uniqueItems?: boolean;
337 | maxContains?: number;
338 | minContains?: number;
339 | maxProperties?: number;
340 | minProperties?: number;
341 | required?: string[];
342 | dependentRequired?: {
343 | [k: string]: string[];
344 | };
345 | [k: string]: unknown;
346 | } & (
347 | | {
348 | type?:
349 | | ("array" | "boolean" | "integer" | "null" | "number" | "object" | "string")
350 | | [
351 | "array" | "boolean" | "integer" | "null" | "number" | "object" | "string",
352 | ...("array" | "boolean" | "integer" | "null" | "number" | "object" | "string")[]
353 | ];
354 | const?: unknown;
355 | enum?: unknown[];
356 | multipleOf?: number;
357 | maximum?: number;
358 | exclusiveMaximum?: number;
359 | minimum?: number;
360 | exclusiveMinimum?: number;
361 | maxLength?: number;
362 | minLength?: number;
363 | pattern?: string;
364 | maxItems?: number;
365 | minItems?: number;
366 | uniqueItems?: boolean;
367 | maxContains?: number;
368 | minContains?: number;
369 | maxProperties?: number;
370 | minProperties?: number;
371 | required?: string[];
372 | dependentRequired?: {
373 | [k: string]: string[];
374 | };
375 | [k: string]: unknown;
376 | }
377 | | boolean
378 | );
379 | export type MetaDataVocabularyMetaSchema = {
380 | title?: string;
381 | description?: string;
382 | default?: unknown;
383 | deprecated?: boolean;
384 | readOnly?: boolean;
385 | writeOnly?: boolean;
386 | examples?: unknown[];
387 | [k: string]: unknown;
388 | } & (
389 | | {
390 | title?: string;
391 | description?: string;
392 | default?: unknown;
393 | deprecated?: boolean;
394 | readOnly?: boolean;
395 | writeOnly?: boolean;
396 | examples?: unknown[];
397 | [k: string]: unknown;
398 | }
399 | | boolean
400 | );
401 | export type FormatVocabularyMetaSchemaForAnnotationResults = {
402 | format?: string;
403 | [k: string]: unknown;
404 | } & (
405 | | {
406 | format?: string;
407 | [k: string]: unknown;
408 | }
409 | | boolean
410 | );
411 | export type ContentVocabularyMetaSchema = {
412 | contentEncoding?: string;
413 | contentMediaType?: string;
414 | contentSchema?: {
415 | [k: string]: unknown;
416 | };
417 | [k: string]: unknown;
418 | } & (
419 | | {
420 | contentEncoding?: string;
421 | contentMediaType?: string;
422 | contentSchema?: {
423 | [k: string]: unknown;
424 | };
425 | [k: string]: unknown;
426 | }
427 | | boolean
428 | );
429 | export type HttpsSuperflytvGithubIoGraphicsDataDefinitionGddMetaSchemaV1LibGddTypesJson = {
430 | [k: string]: unknown;
431 | };
432 | export type HttpsSuperflytvGithubIoGraphicsDataDefinitionGddMetaSchemaV1LibBasicTypesJson = {
433 | [k: string]: unknown;
434 | };
435 | /**
436 | * The schema is used by a Graphic to define the data parameters of the 'update' method.
437 | */
438 | export type HttpsSuperflytvGithubIoGraphicsDataDefinitionGddMetaSchemaV1LibObjectJson1 =
439 | CoreAndValidationSpecificationsMetaSchema &
440 | HttpsSuperflytvGithubIoGraphicsDataDefinitionGddMetaSchemaV1LibGddTypesJson &
441 | HttpsSuperflytvGithubIoGraphicsDataDefinitionGddMetaSchemaV1LibBasicTypesJson & {
442 | type: "boolean" | "string" | "number" | "integer" | "array" | "object";
443 | gddType?: string;
444 | gddOptions?: {
445 | [k: string]: unknown;
446 | };
447 | [k: string]: unknown;
448 | };
449 |
450 | export interface HttpsOgrafEbuIoV1SpecificationJsonSchemasGraphicsSchemaJson {
451 | /**
452 | * Reference to the JSON-schema for this manifest
453 | */
454 | $schema: "https://ograf.ebu.io/v1/specification/json-schemas/graphics/schema.json";
455 | /**
456 | * The id of the Graphic uniquely identifies it. It is recommended to use a reverse domain name notation. For example: com.my-company.my-lowerthird.
457 | */
458 | id: string;
459 | /**
460 | * The version of the Graphic. The version SHOULD be alphabetically sortable. Examples: ['0', '1', '2'], ['1.0', '1.1', '1.2'], ['2024-07-01_final', '2024-07-01_final_final2']
461 | */
462 | version?: string;
463 | /**
464 | * The main entry point, ie the path to the main javascript file of the Graphic.
465 | */
466 | main: string;
467 | /**
468 | * Name of the Graphic
469 | */
470 | name: string;
471 | /**
472 | * (optional) A longer description of the Graphic
473 | */
474 | description?: string;
475 | /**
476 | * (optional) About the author
477 | */
478 | author?: {
479 | /**
480 | * Name of the author
481 | */
482 | name: string;
483 | /**
484 | * (optional) Email of the author
485 | */
486 | email?: string;
487 | /**
488 | * (optional) URL of the author
489 | */
490 | url?: string;
491 | /**
492 | * This interface was referenced by `undefined`'s JSON-Schema definition
493 | * via the `patternProperty` "^v_.*".
494 | */
495 | [k: `v_${string}`]: unknown;
496 | };
497 | /**
498 | * Custom Actions that can be invoked on the Graphic.
499 | */
500 | customActions?: HttpsOgrafEbuIoV1SpecificationJsonSchemasLibActionJson[];
501 | /**
502 | * Indicates if the Graphic supports real-time rendering
503 | */
504 | supportsRealTime: boolean;
505 | /**
506 | * Indicates if the Graphic supports non-real-time rendering. Note: If true, the Graphic must implement the 'goToTime()' and the 'setActionsSchedule()' methods.
507 | */
508 | supportsNonRealTime: boolean;
509 | /**
510 | * The number of steps a Graphic consists of.
511 | * If the Graphic is simply triggered by a play, then a stop, this is considered a stepCount of 1
512 | * (which is the default behavior if left undefined).
513 | * A value of -1 indicates that a Graphic as a dynamic/unknown number of steps.
514 | */
515 | stepCount?: number;
516 | schema?: HttpsSuperflytvGithubIoGraphicsDataDefinitionGddMetaSchemaV1LibObjectJson1;
517 | /**
518 | * A list of requirements that this Graphic has for the rendering environment. At least one of the requirements must be met for the graphic to be expected to work.
519 | */
520 | renderRequirements?: {
521 | /**
522 | * If set, specifies requirements for the resolution of the Renderer.
523 | */
524 | resolution?: {
525 | width?: HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsNumberJson;
526 | height?: HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsNumberJson;
527 | [k: string]: unknown;
528 | };
529 | frameRate?: HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsNumberJson1;
530 | accessToPublicInternet?: HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsBooleanJson;
531 | /**
532 | * This interface was referenced by `undefined`'s JSON-Schema definition
533 | * via the `patternProperty` "^v_.*".
534 | */
535 | [k: `v_${string}`]: unknown;
536 | }[];
537 | /**
538 | * This interface was referenced by `HttpsOgrafEbuIoV1SpecificationJsonSchemasGraphicsSchemaJson`'s JSON-Schema definition
539 | * via the `patternProperty` "^v_.*".
540 | */
541 | [k: `v_${string}`]: unknown;
542 | }
543 | export interface HttpsOgrafEbuIoV1SpecificationJsonSchemasLibActionJson {
544 | /**
545 | * The identity of the action. The id must be unique within the graphic.
546 | */
547 | id: string;
548 | /**
549 | * The name of the action. This is displayed to the user.
550 | */
551 | name: string;
552 | /**
553 | * A longer description of the action. This is displayed to the user.
554 | */
555 | description?: string;
556 | /**
557 | * The schema of the action. This is used to validate the action parameters as well as auto-generate a GUI for the action. If the action does not require any parameters, set this to null.
558 | */
559 | schema?: HttpsSuperflytvGithubIoGraphicsDataDefinitionGddMetaSchemaV1LibObjectJson | null;
560 | /**
561 | * This interface was referenced by `HttpsOgrafEbuIoV1SpecificationJsonSchemasLibActionJson`'s JSON-Schema definition
562 | * via the `patternProperty` "^v_.*".
563 | */
564 | [k: `v_${string}`]: unknown;
565 | }
566 | /**
567 | * The number constraint is used to specify a constraint for a numerical property. (Inspired by https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#constraindouble)
568 | */
569 | export interface HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsNumberJson {
570 | /**
571 | * A number specifying the largest permissible value of the property it describes. If the value cannot remain equal to or less than this value, matching will fail.
572 | */
573 | max?: number;
574 | /**
575 | * A number specifying the smallest permissible value of the property it describes. If the value cannot remain equal to or greater than this value, matching will fail.
576 | */
577 | min?: number;
578 | /**
579 | * A number specifying a specific, required, value the property must have to be considered acceptable.
580 | */
581 | exact?: number;
582 | /**
583 | * A number specifying an ideal value for the property. If possible, this value will be used, but if it's not possible, the user agent will use the closest possible match.
584 | */
585 | ideal?: number;
586 | /**
587 | * This interface was referenced by `HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsNumberJson`'s JSON-Schema definition
588 | * via the `patternProperty` "^v_.*".
589 | *
590 | * This interface was referenced by `HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsNumberJson1`'s JSON-Schema definition
591 | * via the `patternProperty` "^v_.*".
592 | */
593 | [k: `v_${string}`]: unknown;
594 | }
595 | /**
596 | * The number constraint is used to specify a constraint for a numerical property. (Inspired by https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#constraindouble)
597 | */
598 | export interface HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsNumberJson1 {
599 | /**
600 | * A number specifying the largest permissible value of the property it describes. If the value cannot remain equal to or less than this value, matching will fail.
601 | */
602 | max?: number;
603 | /**
604 | * A number specifying the smallest permissible value of the property it describes. If the value cannot remain equal to or greater than this value, matching will fail.
605 | */
606 | min?: number;
607 | /**
608 | * A number specifying a specific, required, value the property must have to be considered acceptable.
609 | */
610 | exact?: number;
611 | /**
612 | * A number specifying an ideal value for the property. If possible, this value will be used, but if it's not possible, the user agent will use the closest possible match.
613 | */
614 | ideal?: number;
615 | /**
616 | * This interface was referenced by `HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsNumberJson`'s JSON-Schema definition
617 | * via the `patternProperty` "^v_.*".
618 | *
619 | * This interface was referenced by `HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsNumberJson1`'s JSON-Schema definition
620 | * via the `patternProperty` "^v_.*".
621 | */
622 | [k: `v_${string}`]: unknown;
623 | }
624 | /**
625 | * If set, specifies requirement on whether the renderer has access to the public internet or not.
626 | */
627 | export interface HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsBooleanJson {
628 | /**
629 | * A boolean specifying a specific, required, value the property must have to be considered acceptable.
630 | */
631 | exact?: boolean;
632 | /**
633 | * A boolean specifying an ideal value for the property. If possible, this value will be used, but if it's not possible, the user agent will use the closest possible match.
634 | */
635 | ideal?: boolean;
636 | /**
637 | * This interface was referenced by `HttpsOgrafEbuIoV1SpecificationJsonSchemasLibConstraintsBooleanJson`'s JSON-Schema definition
638 | * via the `patternProperty` "^v_.*".
639 | */
640 | [k: `v_${string}`]: unknown;
641 | }
642 |
--------------------------------------------------------------------------------