diff --git a/README.md b/README.md index cdc501e..16fd008 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,8 @@ Visualizations are written in JavaScript and use HTML Canvas (2d or 3d) to rende ## Writing Visualizations -See the [developer guide](./docs/dev-guide.md). +- [SKQW developer guide - intro](./docs/dev-guide.md) +- [SKQW API Docs](./docs/api.md) ## Building From Source (Windows) diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..dd82ec3 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,113 @@ +# SKQW APIs + +This is a description of the APIs for authoring visualizations in SKQW. +For a general overview, see the [dev guide](./dev-guide.md). + +## `skqw` object +The `skqw` object is passed as an argument to most of the lifecycle +functions (see Visualization interface below). + +```TypeScript +interface ISkqw { + createCanvas: (domElement?: HTMLCanvasElement) => HTMLCanvasElement; + dimensions: { + width: number; + height: number; + }; + sample: { + ts: number[]; + ft: number[]; + } +} +``` + +#### `skqw.createCanvas()` + +If called with no arguments, it will create a new `` element +and return it. + +Alternatively you may create the canvas element yourself, and pass it +as an argument to `createCanvas()`. This is useful, for example, when +using a library such as Three.js, which will provide you with a canvas +element itself, which can then be handed over to SKQW. + +#### `skqw.dimensions.width` + +The width of the canvas in pixels. + +#### `skqw.dimensions.height` + +The height of the canvas in pixels. + +#### `skqw.sample.ts` + +An array of numbers representing the time series of the audio +sample (time domain). Also known as a waveform. + +#### `skqw.sample.ft` + +An array of numbers representing the fast fourier transform of the +signal (frequency domain). Also known as a frequency spectrum. + +## Visualization Interfaces + +```TypeScript + +interface IVisualization { + name: string; + init: (skqw: ISkqw) => void; + tick: (skqw: ISkqw, timestamp: number) => void; + resize?: (skqw: ISkqw) => void; + destroy?: (skqw: ISkqw) => void; + paramChange?: (change: IParamUpdate) => void; + params?: { [name: string]: IParameter } +} + +interface IParameter { + value: number | boolean; + type: 'range' | 'boolean'; + label: string; + min?: number; + max?: number; + step?: number; +} + +interface IParamUpdate { + paramKey: string; + newValue: number | boolean; +} +``` + +#### `visualization.name` + +The name which will be displayed in the app UI. + +#### `visualization.init(skqw)` + +Called once when the visualization is selected in the UI. + +#### `visualization.tick(skqw, timestamp)` + +Called for each frame of the visualization animation, roughly 60 times +per second. The `timestamp` is a [DOMHighResTimeStamp](https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp) +provided by the [requestAnimationFrame()](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) +method which is used internally. + +#### `visualization.resize(skqw)` + +Called whenever the app window is resized. + +#### `visualization.destroy(skqw)` + +Called just before unloading the visualization, as when a different +visualization is selected in the UI. + +#### `visualization.paramChange(change)` + +Called whenever the user changes a param in the UI. + +#### `visualization.params` + +An object describing the user-configurable parameters which may be +changed at run time to alter the way the visualization renders. + diff --git a/docs/dev-guide.md b/docs/dev-guide.md index 33c4ce0..cdb45c6 100644 --- a/docs/dev-guide.md +++ b/docs/dev-guide.md @@ -6,6 +6,21 @@ recent versions of Node and Chrome, you are free to use (most) ES2015 language features. One notable exception is that module imports and exports must be in the [Node commonjs](https://nodejs.org/docs/latest/api/modules.html) (`module.exports` and `require()`) format. +## File Location & Naming + +A visualization main file must be located in a subdirectory of the +"library path" (as set in the UI), and must be named "index.js": + +``` +// "visualizations" is set as the library path in the app. + +- visualizations/ + | + |- myVis/ + | |- index.js + | +``` + ## Basic Example Here is a bare-bones visualization: @@ -92,9 +107,9 @@ red bar whose height is proportional to the value of that frequency. #### `module.exports` Finally, we export the required information as a [Node commonjs](https://nodejs.org/docs/latest/api/modules.html) module. -There are more functions and properties which SKQW can read, which lets -us write richer visualizations, but the three shown are the bare minimum -required for things to work. +There are more functions and properties which SKQW can read (see the +[API docs](./api.md)), which lets us write richer visualizations, but the +three shown are the bare minimum required for things to work. ## Parameters @@ -170,10 +185,10 @@ SKQW knows about them. ## Next Steps Now you should know enough to start playing around with SKQW -visualizations and creating some cool visuals. +visualizations and creating some cool visuals! There are a few more parts of the API not covered above. For a full -rundown of all APIs, see the API Reference. +rundown of all APIs, see the [API Reference](./api.md). -Another great way to learn is to take a look at the source code of the -standard library of visualizations. \ No newline at end of file +Another great way to learn is to take a look at the [source code of the +standard library of visualizations](../visualizations). diff --git a/src/common/models.ts b/src/common/models.ts index 6c69744..4524d5d 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -8,6 +8,18 @@ export interface ISample { ts: number[]; } +export interface ISkqw { + createCanvas: (domElement?: HTMLCanvasElement) => HTMLCanvasElement; + dimensions: { + width: number; + height: number; + }; + sample: { + ts: number[]; + ft: number[]; + } +} + export interface IParameter { value: number | boolean; type: 'range' | 'boolean'; @@ -22,11 +34,11 @@ export interface IParameter { */ export interface IVisualization { name: string; - init: (skqw: any) => void; - tick: (skqw: any, timestamp: number) => void; - resize?: (skqw: any) => void; - destroy?: (skqw: any) => void; - paramChange?: (change: { [paramKey: string]: any }) => void; + init: (skqw: ISkqw) => void; + tick: (skqw: ISkqw, timestamp: number) => void; + resize?: (skqw: ISkqw) => void; + destroy?: (skqw: ISkqw) => void; + paramChange?: (change: IParamUpdate) => void; params?: { [name: string]: IParameter } } diff --git a/src/render/components/visualizer/visualizer.component.ts b/src/render/components/visualizer/visualizer.component.ts index 366eaf5..ec50af0 100644 --- a/src/render/components/visualizer/visualizer.component.ts +++ b/src/render/components/visualizer/visualizer.component.ts @@ -1,5 +1,5 @@ import {Component, ElementRef, Input, SimpleChange} from '@angular/core'; -import {IVisualization, ISample, IParamUpdate} from '../../../common/models'; +import {IVisualization, ISample, IParamUpdate, ISkqw} from '../../../common/models'; import {defaultVis} from './defaultVisualization'; export interface IDimensions { @@ -23,7 +23,7 @@ export class Visualizer { @Input() sample: ISample; @Input() visualization: IVisualization; - private skqw; + private skqw: ISkqw; private canvases: HTMLCanvasElement[] = []; private dimensions: IDimensions = { width: 0, height: 0 }; private resizeTimer: any;