> Converting SPX to OGraf Converting a native [[Documentation/Graphic Templates/Formats/HTML|SPX HTML template]] into an [[Documentation/Graphic Templates/Formats/OGraf|OGraf]]-compliant graphic is a "wrapping" process. By utilizing an **iframe** within the OGraf JavaScript logic, you can load your existing HTML templates without rewriting their core animation code. This transition requires three main steps: organizing your files into a resource-based structure, mapping your SPX field definitions to the **OGraf manifest** (JSON schema), and bridging the play/stop actions between the OGraf controller and the SPX internal functions. --- ## Importing the SPX Template First you need to import the [[Documentation/Graphic Templates/Formats/HTML|SPX Template]] into your OGraf template directory preferably into a resources folder for clarity: ``` . └── templates/ └── softpix/ └── OGrafTemplates/ ├── resources/ │ └── SPXTemplate.HTML ├── manifest.ograf.json └── graphic.mjs ``` ## Modifying the manifest After this you should modify the manifest file to have the same datafields as the SPX Template. For example in the SPX Template: ```json { "field" : "f0", "ftype" : "textfield", "title" : "Name", "value" : "Tomppa" }, ``` You would add these values to the manifests schema properties: ```json "schema": { "type": "object", "properties": { "Name": { "type": "string", "title": "Name", "default": "Tomppa" } } }, ``` You can also add SPX specific settings by adding a "v_spx" property to the schema properties: ```json "f99": { "v_spx": { "ftype": "filelist", "assetfolder": "./resources/Name_left/themes/", "extension": "css" }, "type": "string", "title": "Visual Theme", "default": "./resources/Name_left/themes/Default.css" } ``` and also at the end of the manifest: ```json "v_spx": { "playserver": "OVERLAY", "playchannel": "1", "playlayer": "1", "webplayout": "1", "out": "manual", "uicolor": "0" } ``` Your end product should look something like this: ```json { "$schema": "https://ograf.ebu.io/v1/specification/json-schemas/graphics/schema.json", "name": "Name Left Graphic", "description": "This graphic includes a name on the left side of the screen.", "id": "name-left-graphic", "version": "1", "supportsRealTime": true, "supportsNonRealTime": false, "main": "NAME_LEFT.mjs", "schema": { "type": "object", "properties": { "comment": { "type": "string", "title": "Nickname of this item on the rundown", "default": "[ Item nickname ]" }, "instruction": { "v_spx": { "ftype": "instruction" }, "type": "string", "title": "Instruction", "default": "You can leave any field empty for a different style. This is an example from the default template pack. For more templates see ▶ spxgraphics.com/store" }, "f0": { "type": "string", "title": "Fullname", "default": "Tomppa" }, "f1": { "type": "string", "title": "Title", "default": "Ograf expert" }, "f2": { "type": "string", "title": "Company or Location", "default": "SPX Graphics" }, "f99": { "v_spx": { "ftype": "filelist", "assetfolder": "./resources/Name_left/themes/", "extension": "css" }, "type": "string", "title": "Visual Theme", "default": "./resources/Name_left/themes/Default.css" } } }, "v_spx": { "playserver": "OVERLAY", "playchannel": "1", "playlayer": "1", "webplayout": "1", "out": "manual", "uicolor": "3" } } ``` ## Modifying the graphic.mjs file The way to make SPX Templates work in ograf is to use an iframe for the html file. In the load function you should create an iframe, import the SPX Template into the iframe and also set the params.data values into the datafields. Make sure the path is correct for filepaths. In this example f99 needs to have "resources/Name_left/" removed: ```js async load(params) { if (params.renderType !== "realtime") throw new Error("Only realtime rendering is supported by this graphic"); const iframe = document.createElement("iframe"); iframe.width = "100%"; iframe.height = "100%"; iframe.src = import.meta.resolve("./resources/Name_left/NAME_LEFT.html"); iframe.onload = () => { const document = iframe.contentWindow.document; document.getElementById("f0").innerText = params.data.f0; document.getElementById("f1").innerText = params.data.f1; document.getElementById("f2").innerText = params.data.f2; document.getElementById("f99").innerText = params.data.f99.replace("resources/Name_left/", ""); } this.appendChild(iframe); this.iframe = iframe; // When everything is loaded we can return: return { statusCode: 200, }; } ``` After this, modify the different actions to use the SPX Templates functions. For example playAction() will be: ```js async playAction(_params) { if (this.iframe.contentWindow) { this.iframe.contentWindow.play(); } else { console.error("Error"); } } ``` Your graphic.mjs file should look something like this: ```js class Graphic extends HTMLElement { connectedCallback() { // Called when the element is added to the DOM // Note: Don't paint any pixels at this point, wait for load() to be called } async load(params) { if (params.renderType !== "realtime") throw new Error("Only realtime rendering is supported by this graphic"); const iframe = document.createElement("iframe"); iframe.width = "100%"; iframe.height = "100%"; iframe.src = import.meta.resolve("./resources/Name_left/NAME_LEFT.html"); iframe.onload = () => { const document = iframe.contentWindow.document; document.getElementById("f0").innerText = params.data.f0; document.getElementById("f1").innerText = params.data.f1; document.getElementById("f2").innerText = params.data.f2; document.getElementById("f99").innerText = params.data.f99.replace("resources/Name_left/", ""); } this.appendChild(iframe); this.iframe = iframe; // When everything is loaded we can return: return { statusCode: 200, }; } async dispose(_params) { this.innerHTML = ""; } async getStatus(_params) { return { statusCode: 200, status: { // nothing }, }; } async updateAction(_params) { if (this.iframe.contentWindow) { this.iframe.contentWindow.update(_params); } } async playAction(_params) { if (this.iframe.contentWindow) { this.iframe.contentWindow.play(); } else { console.error("Error"); } } async stopAction(_params) { if (this.iframe.contentWindow) { this.iframe.contentWindow.stop(); } else { console.error("Error"); } } async customAction(params) { // No actions are implemented in this minimal example } } export default Graphic; ``` ## Modifying the spx_interface.js file Finally make sure to modify the spx_interface.js file inside the spx template you are converting. The only modification you need is to make sure that the update handler has a check that if the data argument is already a json, dont parse it. Additionnally to remove unwanted errors, you need to modify the fString to replace the "resources/templatename/". These modifications also allow the resource template to be run in plain spx if needed. Below is an example of a solution for the update function: ```js function update(data) { // console.log('----- Update handler called.', data); if (typeof data === "string") { try { data = JSON.parse(data); } catch (e) { console.log('Data already JSON'); } } var templateData = data; let arg; if (templateData.data) { arg = templateData.data; } else { arg = templateData; } for (var dataField in arg) { var idField = document.getElementById(dataField); if (idField) { let fString = arg[dataField].replace("resources/Name_left/",""); // remove path from name_left resources if present if ( fString != 'undefined' && fString != 'null' ) { idField.innerText = fString } else { idField.innerText = ''; } } else { switch (dataField) { case 'comment': case 'instruction': case 'epochID': // console.warn('FYI: Optional #' + dataField + ' missing from SPX template...'); break; default: console.error('ERROR Placeholder #' + dataField + ' missing from SPX template.'); } } } if (typeof runTemplateUpdate === "function") { runTemplateUpdate() // Play will follow } else { console.error('runTemplateUpdate() function missing from SPX template.') } } ``` --- ## Read Next - [[Documentation/Graphic Templates/Formats/OGraf|OGraf Format]] - Complete OGraf format specification - [[Documentation/Graphic Templates/Formats/HTML|HTML Template Format]] - SPX HTML template documentation - [[Documentation/Graphic Templates/Overview|Graphic Templates Overview]] - Overview of all template formats - [[Guides/Tutorials/My first HTML template|My first HTML template]] - Create your first SPX HTML template