Skip to the developer guide
casset/Casset AppsDeveloper guide
Explore native AppsHeadless APISign in
Start hereBuild your first appCapabilitiesAvailabilityReference

Casset Apps · Quickstart

0.2 alpha · local development

Build your first Casset App in five minutes.

Download the React starter, install it, and run it with sample artist and Catalog data. You do not need Casset credentials. The local project works today; third-party production installation and submission are not open.

Step 1

Download and run the React Profile App.

Terminalshell
curl -L https://casset.fm/downloads/casset-apps/casset-react-profile-app-v0.2.0-alpha.0.zip \
  -o casset-react-profile-app-v0.2.0-alpha.0.zip
unzip casset-react-profile-app-v0.2.0-alpha.0.zip
cd casset-react-profile-app
pnpm install
pnpm dev

Repository-local dependency

The ZIP vendors @casset/apps at vendor/casset-apps-sdk and rewrites the dependency to a local file path. Do not run pnpm add @casset/apps; the package is not published to npm.

Step 2

Name your App and request only what it needs.

The starter imports this JSON and calls parseCassetAppManifest during startup. Unknown fields, invalid permissions, and illegal context combinations fail loudly.
casset-app.jsonjson
{
  "schema": "casset.app-manifest.v1",
  "id": "studio.release-letter",
  "slug": "release-letter",
  "name": "Release Letter",
  "shortDescription": "An intimate release artifact for an artist's living Profile World.",
  "description": "Release Letter stages a host-approved release and sends narrow playback requests back to Casset.",
  "developer": { "name": "Your studio" },
  "version": "0.1.0",
  "icon": "/icon.svg",
  "screenshots": [],
  "category": "RELEASE",
  "context": "PROFILE_SURFACE",
  "placements": ["MEDIA_FOOTER", "ARTIST_APP_ROUTE"],
  "permissions": [
    "artist.profile.read",
    "artist.theme.read",
    "catalog.tracks.read",
    "catalog.releases.read",
    "playback.read",
    "playback.control"
  ],
  "supportedFanAccess": ["FREE"],
  "compatibility": { "mobile": true, "desktop": true, "pwa": true },
  "trackApplicability": null
}

Step 3

Build the experience inside the artist profile.

Artist context

Use the data Casset supplies

Read artist identity, safe theme values, approved Tracks, and the active release only when their data states are ready.

Native surface

Keep Casset controls in place

Do not add global navigation, authentication, checkout, or a replacement MediaFooter.

Normal states

Design the missing states

Loading, empty, unavailable, permission-denied, missing artwork, and a closed host are normal states.

Step 4

Ask the host to play an approved Track.

A Profile App may request PLAY_TRACK only when both the permission and host capability are present. Casset still decides whether the request is accepted.
Guarded host requesttsx
import {
  hasCassetPermission,
  hostSupports,
  isCassetDataReady,
  type CassetAppHost,
} from "@casset/apps"

export async function askCassetToPlay(host: CassetAppHost, trackId: string) {
  const snapshot = host.getSnapshot()
  if (snapshot.context.kind !== "PROFILE_SURFACE") return
  if (!isCassetDataReady(snapshot.context.catalog)) return
  if (!hasCassetPermission(snapshot.context, "playback.control")) return
  if (!hostSupports(host, "PROFILE_PLAY_TRACK")) return
  if (!snapshot.context.catalog.data.tracks.some((track) => track.id === trackId)) return

  return host.request({ type: "PLAY_TRACK", trackId })
}

One playback authority

Never add an audio element, Web Audio graph, playback store, interval, or RAF clock. Track Runtime is read-only in this alpha and exposes no playback command bridge.

Step 5

Subscribe once. Clean up completely.

The host can update context or close the App. Every mount must release its subscription and local listeners on deactivation.
Lifecycle cleanupts
const render = (snapshot: CassetHostSnapshot) => {
  // Render only the latest host-approved snapshot.
}

const unsubscribe = host.subscribe(render)
render(host.getSnapshot())

return () => {
  unsubscribe()
  root.replaceChildren()
}

Finish

Exercise the states that production will enforce.

  • Use the fixture selector for loading, ready, empty, unavailable, and permission-denied context.
  • Test accepted, denied, and unsupported PLAY_TRACK decisions.
  • Inspect 320×568, 390×844, and desktop widths; then test keyboard-only input and reduced motion.
  • Call host.close() and confirm the App releases subscriptions and stops reacting.
  • Treat disablement and uninstallation as loss of future host access; a local fixture cannot prove server authorization.
Validate the startershell
pnpm test
pnpm build

Next

Review the capabilities, inspect the SDK, or compare all three starter kits.

Casset Apps · Build for musicians.

Native AppsHeadless APICasset reference docs