A piano roll for the web, inspired by Synthesia. Search a song and its MIDI falls onto an 88 key piano to watch, learn, or play someone else.
Live at kinesthesia.h4ks.com.
cp .env.example .env
bun install
bun run dev
With Docker, built here:
docker compose up
or from the published image, built for amd64 and arm64:
docker run -p 3000:3000 -v kinesthesia:/app/data ghcr.io/h4ks-com/kinesthesia:latest
.env.example documents every setting.
The API documents itself at /api/docs, with the OpenAPI spec at
/api/openapi.json.
The same tools run over MCP at /api/mcp (streamable HTTP), so an agent can
search for songs, read a file's length and tracks, build player links, and
edit MIDI projects.
The endpoint takes a bearer token. The server stores only the token's SHA-256 hash, so generate the pair and keep the key:
key=$(openssl rand -hex 32)
echo "key: $key"
printf %s "$key" | shasum -a 256 | cut -d' ' -f1
Put the hash in MCP_TOKEN_HASH and give clients the key. Add it to a client:
claude mcp add --transport http kinesthesia https://kinesthesia.h4ks.com/api/mcp \
--header "Authorization: Bearer $key"
or with JSON config:
{
"mcpServers": {
"kinesthesia": {
"type": "http",
"url": "https://kinesthesia.h4ks.com/api/mcp",
"headers": { "Authorization": "Bearer <key>" }
}
}
}Swap in http://localhost:3000/api/mcp when running locally. Leaving
MCP_TOKEN_HASH unset keeps the endpoint open in development and refuses every
request in production.
MIDI files come from several sources, listed at /sources. A ?url= player
link also plays a direct .mid from the app's own origin or an origin set in
MIDI_TRUSTED_ORIGINS; player_link accepts such a url too.
