A browser-based split-flap / Vestaboard-style board built with HTML, CSS, and JavaScript.
The project is designed as a generic flip-board engine:
flip.jsis the reusable board rendererflip_sound.jshandles optional flip sound effects- individual HTML pages act as the use-case layer, deciding what data to fetch, transform, and display
This means the same board engine can be used for:
- incident counters
- weather boards
- status dashboards
- countdowns
- custom messages
- any other board-style display
index.html— incident counter example pageweather_board.html— weather example page using a real weather APIflip.css— board styling and flip-panel visualsflip.js— reusable flip-board engineflip_sound.js— modular audio helpers for flip soundsincident.json— sample incident data sourceflip.html— original/reference markup experiment
The project is split into two layers:
The engine lives in flip.js and exposes:
createFlipBoard(options)
That function creates a board instance and returns an API you can use to:
- render lines
- add lines
- clear the board
- replay the animation
- change theme
- change perspective
- enable/disable sound
- test sound
Each HTML page imports createFlipBoard() and decides:
- what board settings to use
- what data to fetch
- how to transform that data into board lines
- what colors/alignment/padding to apply
This keeps business logic out of the engine.
Because some pages use fetch() to load local JSON or call APIs, open the project through a local web server rather than directly as a file:// page.
Open the project folder in VS Code and launch the page with Live Server.
python3 -m http.server 8000Then open:
http://localhost:8000/index.html
You can also open other pages the same way, for example:
http://localhost:8000/weather_board.html
Opening index.html directly in the browser may show the page shell and background, but requests like:
fetch('./incident.json')are commonly blocked by browser security rules for local files.
Use Live Server or a local HTTP server instead.
flip.js exports:
import { createFlipBoard } from './flip.js'Basic usage:
const board = createFlipBoard({
boardSelector: '.board',
columns: 16,
theme: 'dark',
perspective: 1,
sound: true,
})
board.renderLines([
{ text: 'hello world' },
{ text: 'flip-board', color: 'hsl(44, 100%, 50%)' },
{ text: 'ready', alignment: 'right' },
]){
boardSelector: '.board',
columns: 16,
perspective: 1,
theme: 'dark',
sound: true,
characters: 'abcdefghijklmnopqrstuvwxyz0123456789 .,:!?-/'
}{
text: 'example',
alignment: 'left', // or 'right'
color: 'hsl(0,0%,90%)',
pad: 0,
length: 16,
characters: 'abcdefghijklmnopqrstuvwxyz0123456789 .,:!?-/'
}A created board instance provides:
board.renderLines(lines)— clears and renders a full set of linesboard.addLine(line)— appends a single lineboard.clear()— clears the boardboard.replay()— replays the current linesboard.setTheme(theme)— updates the themeboard.setPerspective(value)— updates flip perspectiveboard.setSound(enabled)— enables/disables soundboard.testSound()— plays a sound test
index.html is an example that:
- creates a board
- fetches
incident.json - filters incident keys ending in
.date - finds the most recent incident
- calculates days since that incident
- renders the result as board lines
{
"incident.5.date": "2025-12-10",
"_comment_incident_2025-12-10": "Example incident note",
"incident.4.date": "2025-10-23",
"incident.3.date": "2025-08-18",
"incident.2.date": "2025-06-03",
"incident.1.date": "2025-05-15"
}Comment fields are fine as long as the page logic filters only keys ending in .date.
weather_board.html is an example that:
- creates a board
- geocodes a place name
- calls a live weather API
- transforms the weather response into board lines
This page demonstrates that flip.js is generic and can drive a completely different board without changing the engine itself.
Flip sound support is handled by flip_sound.js.
Notes:
- sound is optional
- browsers typically require a user interaction before audio playback is allowed
- use
board.testSound()if you want to verify that audio is working
flip.css handles:
- split-flap layout
- board appearance
- tile shaping
- light/dark theme behavior
- background grid styling
The board width is determined by the number of columns created in JavaScript, not just CSS.
This project can be adapted for many board scenarios, including:
- incident counter boards
- weather boards
- release countdown boards
- service health/status boards
- motivational message boards
- custom dashboard widgets
This project has evolved from a prototype into a reusable engine, but it is still a lightweight front-end project and can be refined further.
Likely future improvements:
- additional example pages
- better theming controls
- optional control panel module
- real recorded flap audio samples
- external config/data adapters
- packaging as a reusable component
- Serve the project over HTTP, not
file:// - Keep page-specific logic in the HTML page or a page-specific module
- Keep board rendering logic in
flip.js - Keep audio logic in
flip_sound.js