Skip to content
/ cdgraphics Public

A fast, flexible CD+Graphics (CD+G) renderer

License

Notifications You must be signed in to change notification settings

bhj/cdgraphics

Repository files navigation

cdgraphics

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

Installation

$ npm i cdgraphics

API

new CDGraphics(canvas, [options])

  • canvas: Your <canvas> element. Required.
  • options: Object with one or more options.
import CDGraphics from 'cdgraphics'

const canvas = document.getElementById('my-canvas')
const cdg = new CDGraphics(canvas, { forceKey: true }) // force background transparency

Options

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.

.load(buffer)

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))

.render([number])

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.

.setOptions(object)

Sets one or more options and re-renders.

Demo

To run the demo and see how it all comes together:

  1. Clone the repo
  2. Place your audio and .cdg file in the demo folder
  3. Update lines 1 and 2 of demo/demo.js with those filenames
  4. $ npm i
  5. $ npm run demo
  6. Browse to http://localhost:8080 (the demo is served by webpack-dev-server)

Resources

License

ISC