cables DocumentationHow To UseWorking with filesKeyboard ShortcutsUser Interface WalkthroughBeginner TutorialBeginner 1: Drawing A CircleBeginner 2: TransformationsBeginner 3: ColorMore TransformationsIntermediateImage CompositionsPost-Processing 3D ScenesExporting And EmbeddingHow to serve files externally and fix CORS headersExporting PatchesExport using the cables command line interfaceExport via IframeExport creating a standalone executableExport to github (pages)Export and deploy to netlifyExport full PatchHTML ExportExternal triggers / functionsUsing variablesPreviewing / uploading exported cables patchesExamples for EmbeddingImporting patchesBackupsPermissionsUsersPatchesTeamsOpsMultiplayerPatchlistsCoding OpsUsing Op AttachmentsGeneral op/Port CallbacksPortsMultiPortsArray PortsBoolean portsInteger Number PortsObject PortsString portsTrigger PortsFloating Point Number PortsGUI/UI attributesHello Op - Part 1LibrariesDeveloping OpsRenaming / Creating a new versionCreating Viz OpsGuidelinesObject PortsPatching Ops / SubPatchOpsWriting ShadersWeb Audio Op DevelopmentDeveloping CablesRepositoriesSet up local environmentScriptsHow to work with forksGenerated DocumentationUsing standalone to develop cablesCables StandaloneGeneralCoding OpsSharing opsUsing NPMImport/ExportStandalone - FAQLightingLightsShadowsWorking With AudioBasic Audio SetupWorking with EffectsReal-Time Audio Analyzation & Audio VisualizationOffline Audio Visualization & AnalyzationCommunicationCables APIOptimizing Performance In PatchesTools for debugging your patchHow to optimize cables patches with the Performance opHow to optimize cables patches with the ProfilerCommon pitfalls with the "usual suspects"Optimizing arraysDebugging Shaders with ShaderInfoFAQAudio in web browsersHow to make demoscene demos with cables.glEmbeddingHow to integrate my cables patch into my CMS (webflow/wix/squarespace/...)?How to remove grey rectangles on touch (mobile)?Why doesn't the DownloadTexture op work on iOS?How to disable page scrolling on mobile?Mobile tippsHow to run exported patches on your local machineTransparent CanvasFeatures and SupportHow to contribute code to cablesWill there be support for (animated) GIFs?Can i use a website as a texture?Screenshots and Video recordingHow to report a bug in cablesHow can I share a patch to get help?How can I support cables?Video playback in cablesGeneral questionsWhat is dev.cables.glHTML And CSS In CablesJavascript Frameworkscordova / phonegapelectronreactvuejsLicenses and paymentWhat license do i need to use cables?Will I have to pay for it in the future?How is my work licensed when using cables?Does cables support midi and OSC?Patch PermissionsMy User Profile & Social MediaShadertoyCables at schools and universitiesTechnical questionsWebGL1 and WebGL2

Using Op Attachments

Attachments are files that can be created and read as a string in the Op they are attached to. They can contain any kind of data that your op might need for working. Attachments are a good way to separate data from your opcode, add WebWorkers or even work with WASM files.

Add Attachment

An attachment file can be created by clicking on an Op and then clicking the create button

create_attachment

You then need to give your attachment a name that will later be used to access its content in your Op. An attachment named my_attachment will be accessible in the Op via attachments["my_attachment"]

Hint: All dots (.) in the name entered will be converted to underscores (_), so myattachment.js will be attachments["myattachment_js"]!

Editing Attachment

After you created the attachment, the cables-editor will open and let you edit its content.

You can open the editor again later by clicking the edit button

edit_attachment

Using attachments

The attachment can now be accessed inside of your op, select the op and press 'e' to enter edit mode.

This snippet will output the contents of your attachment (e.g. "hello attachment"):

console.log(attachments["my_attachment"]);

Using inc_ attachments

If the name of your attachment starts with inc_ the contents of the attachment will be included (and executed) before your op code. This can be useful to stucture your code, branch things out into classes or just to have less "boilerplate" code visible in the op editor.

Given an attachment named inc_context with the following code:

class MyOpContext {
    getRandomNumber() {
        return Math.random();
    }
}

And an op with the code:

const context = new MyOpContext();
console.log("this is in the op:", context.getRandomNumber());

Your console will output something like:

this is in the op: 0.5711111111111111

WebWorkers

WebWorkers usually reside in separate files from their main code to run in different threads. You can use attachments, create specially crafted urls from the content and load these workers to use in ops.

Check this example of a simple echo-service using WebWorkers:

Create an attachment named "worker", with this content:

onmessage = function (event) {
  console.log('Received message from main thread:', event.data);
  // Send the result back to the main thread
  postMessage(event.data);
};

Edit the Op code to call the worker:

// read the contents of the attachment into
const blob = new Blob([attachments["worker"]], {type: 'application/javascript'});
const workerUrl = URL.createObjectURL(blob)

// create worker using your code/url
var worker = new Worker(workerUrl);
worker.postMessage("ECHO");

worker.onmessage = function (event) {
  console.log('Received message from worker:', event.data);
};

Running this op (by saving the code), will print this in the dev-console, showing the working echo-service:

Received message from main thread: ECHO
Received message from worker: ECHO

WASM

You can use attachments to work with WebAssembly modules in your cables Ops.

We will create an op, following the example from MSDN by encoding their simple.wasm file to Base64 and storing that into an attachment called "wasm":

AGFzbQEAAAABCAJgAX8AYAAAAh4BDG15X25hbWVzcGFjZQ1pbXBvcnRlZF9mdW5jAAADAgEBBxEBDWV4cG9ydGVkX2Z1bmMAAQoIAQYAQSoQAAs=

Now, in the Op code, add this:

// create data url from base64 wasm code
const simpleWasm = "data:application/wasm;base64," + attachments.wasm;

// define callable functions
const importObject = {
    "my_namespace": { "imported_func": (arg) => { return console.log(arg); } },
};

// fetch code from dataurl and instantiate wasm
fetch(simpleWasm).then((g) =>
{
    WebAssembly.instantiateStreaming(g, importObject).then(
        (obj) =>
        {
            // call wasm-function
            obj.instance.exports.exported_func();
        }
    );
});

As stated in the example:

"The net result of this is that we call our exported WebAssembly function exported_func, which in turn calls our imported JavaScript function imported_func, which logs the value provided inside the WebAssembly instance (42) to the console."


Found a problem? Edit this file on github and contribute to cables!