Documentation Index
Fetch the complete documentation index at: https://mintlify.com/TextAliveJp/textalive-app-api/llms.txt
Use this file to discover all available pages before exploring further.
Get an app token
Register your application at developer.textalive.jp to obtain an app token. The token authenticates your app with the TextAlive API server and is required to load songs and lyrics data. Install the package
Install the textalive-app-api package:npm install textalive-app-api
Then import Player in your source file:import { Player } from "textalive-app-api";
Add these two <script> tags to your HTML. axios must be loaded first because the API depends on it:<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/textalive-app-api/dist/index.js"></script>
After both scripts load, the global TextAliveApp object is available:const { Player } = TextAliveApp;
Create a Player and attach listeners
Instantiate a Player with your app token, then call addListener to register event callbacks. The two most important events for a lyric app are onVideoReady (lyrics data is loaded and ready) and onTimerReady (the audio timer is ready, meaning you can call requestPlay).import { Player, IVideo, Timer, IChar } from "textalive-app-api";
// Create the player. Point mediaElement at a container div for the audio widget.
const player = new Player({
app: { token: "your_app_token_here" },
mediaElement: document.querySelector("#media"),
});
// Track the current lyric character so we can render it.
let currentChar: IChar | null = null;
player.addListener({
// Called once song metadata and lyrics timing data are loaded.
onVideoReady(v: IVideo) {
console.log("Video ready:", v.charCount, "characters");
},
// Called when the audio timer is initialised — safe to call requestPlay() after this.
onTimerReady(timer: Timer) {
console.log("Timer ready");
},
// Called when playback starts.
onPlay() {
console.log("Playback started");
},
// Called on every animation frame while the song is playing.
// position is the current playback position in milliseconds.
onTimeUpdate(position: number) {
// findChar returns the IChar being vocalized at this position,
// or null if nothing is being sung right now.
currentChar = player.video.findChar(position);
if (currentChar) {
// Render the character — update a DOM element, canvas, etc.
document.querySelector("#lyric").textContent = currentChar.text;
} else {
document.querySelector("#lyric").textContent = "";
}
},
onPause() {
console.log("Playback paused");
},
onStop() {
console.log("Playback stopped");
},
});
addListener accepts any object that implements some or all of the PlayerListener interface. All callback properties are optional — only define the ones you need.
Load a song and control playback
Call createFromSongUrl with a TextAlive song URL to begin loading the song’s map and lyrics data. Once onTimerReady fires, you can start, pause, and stop playback.// Load a song. This returns a Promise<IVideo> that resolves after
// the video object is constructed (same point onVideoReady fires).
await player.createFromSongUrl("https://piapro.jp/t/hZ35/20240130103028");
// Wire up playback controls.
document.querySelector("#play").addEventListener("click", () => {
player.requestPlay();
});
document.querySelector("#pause").addEventListener("click", () => {
player.requestPause();
});
document.querySelector("#stop").addEventListener("click", () => {
// requestStop pauses and seeks back to the beginning.
player.requestStop();
});
Check player.app.managed at startup. When your app is embedded in a TextAlive host (such as the TextAlive editor), the host controls song selection. In that case you do not need to call createFromSongUrl — the host sends an onAppMediaChange event when it wants your app to load a different song.
Complete example
Below is a self-contained HTML file using the CDN build. It shows character-by-character lyric display in action.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>TextAlive lyric app</title>
<style>
body { font-family: sans-serif; text-align: center; padding: 2rem; }
#lyric { font-size: 4rem; min-height: 5rem; }
#media { margin: 1rem auto; }
button { margin: 0.25rem; padding: 0.5rem 1rem; font-size: 1rem; }
</style>
</head>
<body>
<div id="lyric"></div>
<div id="media"></div>
<div>
<button id="play">Play</button>
<button id="pause">Pause</button>
<button id="stop">Stop</button>
</div>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/textalive-app-api/dist/index.js"></script>
<script>
const { Player } = TextAliveApp;
const lyricEl = document.querySelector("#lyric");
const playBtn = document.querySelector("#play");
const pauseBtn = document.querySelector("#pause");
const stopBtn = document.querySelector("#stop");
// Disable controls until the timer is ready.
playBtn.disabled = true;
pauseBtn.disabled = true;
stopBtn.disabled = true;
const player = new Player({
app: { token: "your_app_token_here" },
mediaElement: document.querySelector("#media"),
});
player.addListener({
onVideoReady(v) {
console.log("Video ready —", v.charCount, "characters");
},
onTimerReady(timer) {
// Enable controls once audio is ready.
playBtn.disabled = false;
pauseBtn.disabled = false;
stopBtn.disabled = false;
},
onPlay() {
playBtn.disabled = true;
pauseBtn.disabled = false;
},
onPause() {
playBtn.disabled = false;
pauseBtn.disabled = true;
},
onStop() {
playBtn.disabled = false;
pauseBtn.disabled = true;
lyricEl.textContent = "";
},
onTimeUpdate(position) {
// position is in milliseconds.
const char = player.video.findChar(position);
lyricEl.textContent = char ? char.text : "";
},
});
// Load the song.
player.createFromSongUrl("https://piapro.jp/t/hZ35/20240130103028");
playBtn.addEventListener("click", () => player.requestPlay());
pauseBtn.addEventListener("click", () => player.requestPause());
stopBtn.addEventListener("click", () => player.requestStop());
</script>
</body>
</html>