Flipdisc Server
A canvas rendering REST server for flipdisc displays.
Install
$ pip install pyzmq opencv-python mediapipe
$ npm install flipdisc-server
Start Server
import { createServer } from 'flipdisc-server'
const server = createServer({
dir: './scenes'
})
// add your scenes to ./scene
Getting Started Project
https://github.com/kelly/flipdisc-example
Simple Scene
import { createScene,
ImageView } from 'flipdisc-server'
const schema = {
title: 'Image',
properties: {
url: {
type: 'string',
default: 'image.png',
},
}
}
const image = function(opts) {
const scene = createScene()
scene.once('loaded', () => {
const img = new ImageView(opts.url)
scene.add(img)
})
return scene;
}
// must return scene and schema, optionally a task
export { image as scene, schema }
Matter, Pixi, Three
const scene = createScene()
// easy access to pixi, three, matter
scene.pixi.add(new PIXI.Graphics())
scene.three.add(new THREE.Mesh())
scene.matter.add(new Matter.Body())
// you can also do:
scene.add(new Matter.Body(), new THREE.Mesh())
// it'll automatically add to the correct engine
// scene.remove() works in the same manner.
// or directly access canvas
scene.ctx.fillRect(0, 0, 100, 100)
Custom Views
import { ImageView, TextView,
CardView, ListView } from 'flipdisc-server'
const text = new TextView('Hello World')
const image = new ImageView('http://image.png')
scene.add(text, image)
Rendering
// force render
scene.render()
// shouldn't have to do this unless you're
// doing something custom
// render loop
const fps = 50
scene.useLoop((i, clock) => {
// update scene
}, fps)
Shaders
const shader = `
precision mediump float;
uniform float time;
uniform vec2 resolution;
void main() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
gl_FragColor = vec4(uv, 0.0, 1.0);
}
`
const scene = createScene()
scene.useShader(shader)
Interaction
import { PoseEmitter,
VoiceEmitter,
GestureEmitter } from 'flipdisc-server'
const pose = new PoseEmitter()
const voice = new VoiceEmitter({
trigger: 'hey flippy'
})
const gesture = new GestureEmitter()
pose.on('update', (data) => {
console.log(data)
})
voice.on('trigger', (data) => {
console.log(data)
})
gesture.on('update', (data) => {
console.log(data)
})
Tasks
const task = createTask(async () => {
const api = await import(`./spotify/api.js`);
const current = await api.getCurrentlyPlaying();
if (current?.is_playing) {
return {
props: {
playing: current,
},
wait: false
}
}
}, 'every 10 minutes')
API Routes
GET /api/playing
Retrieves the currently playing item.
GET /api/display
Retrieves the display settings.
GET /api/queue
Retrieves the current queue.
GET /api/queue/settings
Retrieves the queue settings.
GET /api/scenes/:id
Retrieves a specific scene by ID.
GET /api/scenes
Retrieves all scenes.
POST /api/scenes/next
Moves to the next scene.
POST /api/scenes/previous
Moves to the previous scene.
POST /api/playing
Sets the currently playing item.
POST /api/playing/pause
Pauses the currently playing item.
POST /api/playing/resume
Resumes the currently playing item.
POST /api/playing/toggle
Toggles the play/pause state of the currently playing item.
POST /api/playing/user/clear
Clears user input
POST /api/queue/settings
Updates the queue settings.
POST /api/queue
Adds an item to the queue.
POST /api/queue/sort
Sorts the queue.
POST /api/queue/next
Moves to the next item in the queue.
POST /api/queue/previous
Moves to the previous item in the queue.
DELETE /api/queue/:id
Deletes an item from the queue by ID.
Headless
You may need to use the command xvfb-run
to enable a virtual frame buffer.
xvfb-run node app.js