Cache the Database
Don't fetch canvas.json on every song change. Load it once on startup and cache it locally. Refresh periodically (e.g., every 30 minutes) to pick up new community contributions.
Use the Echo Music Canvas database to add beautiful looping motion visuals to your music player, website, or application. It's open, free, and community-driven.
The Echo Music Canvas database is a single JSON file hosted on GitHub. It maps song + artist pairs to looping video URLs. You fetch the JSON, match songs by name, and play the corresponding video as a background visual.
canvas.json
The primary endpoint to fetch the complete canvas database:
https://canvas.echomusic.fun/canvas.json
This URL always serves the latest version from the main branch. Cache it on your server for performance.
The JSON file follows this structure:
{
"items": [
{
"song": "Blinding Lights",
"artist": "The Weeknd",
"url": "https://canvas.echomusic.app/Song/20.m3u8"
},
{
"song": "Dracula",
"artist": "Tame Impala",
"url": "https://canvas.echomusic.app/Song/1.mp4"
}
]
}
| Field | Type | Description |
|---|---|---|
items | Array | The list of all canvas entries |
items[].song | String | The song title (case-sensitive as contributed) |
items[].artist | String | The artist or band name |
items[].url | String | Direct URL to the canvas video (.mp4 or .m3u8) |
Fetch the database and find a canvas for a playing song:
const CANVAS_URL = 'https://canvas.echomusic.fun/canvas.json';
// Fetch and cache the canvas database
async function loadCanvasDB() {
const res = await fetch(CANVAS_URL);
const data = await res.json();
return data.items || [];
}
// Find a canvas for a given song + artist
function findCanvas(items, songTitle, artistName) {
const query = `${songTitle} ${artistName}`.toLowerCase();
return items.find(item => {
const entry = `${item.song} ${item.artist}`.toLowerCase();
return entry === query;
});
}
// Usage
const canvasDB = await loadCanvasDB();
const match = findCanvas(canvasDB, 'Blinding Lights', 'The Weeknd');
if (match) {
const video = document.getElementById('canvas-player');
video.src = match.url;
video.loop = true;
video.muted = true;
video.play();
}
A minimal HTML structure to render a canvas behind your music player:
<div class="player-container" style="position: relative;">
<!-- Canvas background -->
<video id="canvas-player"
loop muted playsinline
style="position: absolute; inset: 0;
width: 100%; height: 100%;
object-fit: cover; z-index: 0;
opacity: 0.85;">
</video>
<!-- Your player UI goes on top -->
<div style="position: relative; z-index: 1;">
<h2 id="song-title">Blinding Lights</h2>
<p id="artist-name">The Weeknd</p>
<!-- playback controls, progress bar, etc. -->
</div>
</div>
Use ExoPlayer to play canvas videos in your Android app:
// 1. Add ExoPlayer dependency in build.gradle
// implementation("androidx.media3:media3-exoplayer:1.3.0")
// implementation("androidx.media3:media3-ui:1.3.0")
// 2. Fetch canvas.json (using OkHttp / Retrofit)
suspend fun fetchCanvasDB(): List<CanvasEntry> {
val response = httpClient.get(CANVAS_JSON_URL)
val json = JSONObject(response.body.string())
val items = json.getJSONArray("items")
return (0 until items.length()).map { i ->
val obj = items.getJSONObject(i)
CanvasEntry(
song = obj.getString("song"),
artist = obj.getString("artist"),
url = obj.getString("url")
)
}
}
// 3. Play the canvas video
fun playCanvas(url: String, playerView: PlayerView) {
val player = ExoPlayer.Builder(context).build()
playerView.player = player
val mediaItem = MediaItem.fromUri(url)
player.setMediaItem(mediaItem)
player.repeatMode = Player.REPEAT_MODE_ONE
player.volume = 0f // muted background visual
player.prepare()
player.play()
}
Use AVPlayer to play canvas videos in your iOS app:
import AVKit
struct CanvasEntry: Codable {
let song: String
let artist: String
let url: String
}
struct CanvasDB: Codable {
let items: [CanvasEntry]
}
// Fetch the canvas database
func loadCanvasDB() async throws -> [CanvasEntry] {
let url = URL(string: "https://canvas.echomusic.fun/canvas.json")!
let (data, _) = try await URLSession.shared.data(from: url)
let db = try JSONDecoder().decode(CanvasDB.self, from: data)
return db.items
}
// Play canvas in a view
func playCanvas(urlString: String, in view: UIView) {
guard let url = URL(string: urlString) else { return }
let player = AVPlayer(url: url)
player.isMuted = true
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resizeAspectFill
playerLayer.frame = view.bounds
view.layer.insertSublayer(playerLayer, at: 0)
// Loop playback
NotificationCenter.default.addObserver(
forName: .AVPlayerItemDidPlayToEndTime,
object: player.currentItem,
queue: .main
) { _ in
player.seek(to: .zero)
player.play()
}
player.play()
}
Useful for Discord bots, Telegram bots, or backend services:
import requests
CANVAS_URL = "https://canvas.echomusic.fun/canvas.json"
def load_canvas_db():
"""Fetch the full canvas database."""
response = requests.get(CANVAS_URL)
response.raise_for_status()
return response.json().get("items", [])
def find_canvas(items, song_title, artist_name):
"""Find a matching canvas entry."""
query = f"{song_title} {artist_name}".lower()
for item in items:
entry = f"{item['song']} {item['artist']}".lower()
if entry == query:
return item
return None
# Example usage
db = load_canvas_db()
canvas = find_canvas(db, "Starboy (feat. Daft Punk)", "The Weeknd")
if canvas:
print(f"Canvas URL: {canvas['url']}")
Don't fetch canvas.json on every song change. Load it once on startup and cache it locally. Refresh periodically (e.g., every 30 minutes) to pick up new community contributions.
Song titles may not match exactly due to special characters, casing, or feat. tags. Use case-insensitive matching and strip common suffixes like (feat. …) for better hit rates.
Canvas URLs can be .mp4 (direct video) or .m3u8 (HLS stream). On web, use hls.js for HLS. On mobile, most players support HLS natively.
Canvas videos are visual-only backgrounds. Always set them to muted and loop. This also enables autoplay on most browsers without user interaction.
The canvas database is GPL-3.0 licensed. You're free to use it in any project — commercial or personal.
Please credit Echo Music Canvas in your app or website with a link back to canvas.echomusic.fun.
The JSON is hosted on GitHub raw CDN. Avoid polling more than once per minute. For high-traffic apps, mirror the data on your own CDN.
If your users discover new canvases, encourage them to submit via the Contribute Portal so the whole community benefits.