A CD+Graphics (CD+G) implementation in JavaScript that draws to an HTML5 canvas. It's based on the player by Luke Tucker with improvements from Keith McKnight's fork.
- 60fps rendering with requestAnimationFrame
- Audio synchronization with currentTime
- Optional background keying (transparency) and shadow effects
- Supports callbacks for changes in CD+G title's background and content bounds
- Supports rewind and random seek
- ES2015+ with no dependencies
$ npm i cdgraphics
import CDGraphics from 'cdgraphics'
const canvas = document.getElementById('my-canvas')
const cdg = new CDGraphics(canvas, { forceKey: true }) // force background transparency
Property | Type | Description | Default |
---|---|---|---|
forceKey | boolean | Force backgrounds to be transparent, even if the CD+G title did not explicitly specify it. | false |
onBackgroundChange | function | Called when the CD+G title's background color or alpha changes. The RGBA color is passed as an array like [r, g, b, a] with alpha being 0 or 1 . The reported alpha includes the effect of the forceKey option, if enabled. |
undefined |
onContentBoundsChange | function | Called when the coordinates of a bounding box that fits the CD+G title's content changes. The reported coordinates are passed as an array like [x1, y1, x2, y2] and account for any canvas scaling. Only useful when forceKey is enabled. |
undefined |
shadowBlur | number | CanvasRenderingContext2D.shadowBlur (You likely also want to enable forceKey) | 0 |
shadowColor | string | CanvasRenderingContext2D.shadowColor (Alpha is defaulted to 1 here so that any shadowBlur is visible without explicitly specifying this option) |
rgba(0,0,0,1) |
shadowOffsetX | number | CanvasRenderingContext2D.shadowOffsetX | 0 |
shadowOffsetY | number | CanvasRenderingContext2D.shadowOffsetY | 0 |
Note: When using shadow* options, graphics may render smaller and/or offset to fit the canvas as needed to avoid clipping the shadow.
Loads a CD+G file. Expects an ArrayBuffer, which can be had via the Response of a fetch().
fetch(cdgFileUrl)
.then(response => response.arrayBuffer())
.then(buffer => cdg.load(buffer))
Renders the frame at the given playback position (in seconds). Calling without a parameter will re-paint the last-rendered frame to the canvas. You must load()
a CD+G file (see above) before calling render()
.
This method is designed to be used with requestAnimationFrame and the currentTime property of an HTMLMediaElement (usually an <audio>
element). The following excerpt shows a basic render loop:
let frameId
// methods for render loop
const play = () => {
frameId = requestAnimationFrame(play)
cdg.render(audio.currentTime)
}
const pause = () => cancelAnimationFrame(frameId)
// link with <audio> element
audio.addEventListener('play', play)
audio.addEventListener('pause', pause)
audio.addEventListener('ended', pause)
audio.addEventListener('seeked', () => cdg.render(audio.currentTime))
See the demo code for a complete example.
Sets one or more options and re-renders.
To run the demo and see how it all comes together:
- Clone the repo
- Place your audio and .cdg file in the
demo
folder - Update lines 1 and 2 of
demo/demo.js
with those filenames $ npm i
$ npm run demo
- Browse to
http://localhost:8080
(the demo is served by webpack-dev-server)
- Jim Bumgardner's CD+G Revealed document/specification