# MusicOptions

> Talos next · Since 0.6

## Signature

```ts
export interface MusicOptions {
  /** Seconds to cross-fade over, starting at the bar line. Default 0. */
  crossfade?: number
}
```

Import: `import type { MusicOptions } from "@argus/api"`

## Members

| Member | Signature | Description |
|---|---|---|
| `crossfade` | `crossfade?: number` | Seconds to cross-fade over, starting at the bar line. Default 0. |

## Example

The tested fixture `fixtures/host/kitchen-sink.ts`.

```ts
import type { Behavior, Vec3 } from "@argus/api"
// Touches every Ctx member once, so both the Rust bindings and the TS types are exercised by one script.
type State = { hits: string[]; audio?: number }
export default {
  init(ctx) {
    ctx.state.hits = []
    ctx.events.on("ping", (ev) => ctx.log("ping", ev.data))
    ctx.events.once("ping", () => ctx.state.hits.push("once"))
  },
  update(ctx, dt) {
    const e = ctx.entity
    const log = (s: string) => ctx.state.hits.push(s)
    // entity
    const p: Vec3 = e.position; e.position = [p[0], p[1], p[2]]
    e.translate([0, 0, 0]); e.moveToward([1, 0, 0], dt); e.lookAt([0, 0, -5])
    e.scale = [2, 2, 2]; e.rotation = [0, 0, 0, 1]
    if (e.rotation.length === 4 && e.scale[0] === 2 && e.worldPosition.length === 3) log("transform")
    if (e.id && e.name !== undefined && e.tags.length >= 0 && e.alive) log("labels")
    if (e.parent === null && e.children.length === 0) log("hierarchy")
    if (e.hasTag("player") && e.hasComponent("mesh") && e.component("mesh")?.asset === "cube") log("components")
    if (e.distanceTo(ctx.world.find("wp-1")!) > 0) log("distance")
    // world
    if (ctx.world.query({ tag: "waypoint" }).length === 2 && ctx.world.count > 0) log("query")
    if (ctx.world.query({ near: e, radius: 0.5 }).length >= 1 && ctx.world.query({ inside: "zone" }).length === 1) log("query-spatial")
    if (ctx.world.query({ component: "mesh" }).length === 1) log("query-component")
    const hit = ctx.world.raycast([0, 1, 0], [0, -1, 0], 10)
    if (hit && hit.entity.id === "floor" && hit.distance === 1) log("raycast")
    if (ctx.world.shapeCast({ sphere: 0.3 }, [0, 1, 0], [0, -1, 0], 10)?.distance === 1) log("shapecast")
    if (ctx.world.path([0, 0, 0], [1, 0, 0])?.length === 2) log("path")
    // nav / input / controller / animator
    if (ctx.nav) { ctx.nav.goTo([5, 0, 5], 2); if (ctx.nav.target && !ctx.nav.arrived && !ctx.nav.stuck) log("nav"); ctx.nav.stop() }
    if (ctx.input) {
      const [x, y] = ctx.input.axis("move")
      if (x === 1 && y === 0 && ctx.input.pressed("jump") && !ctx.input.held("jump") && !ctx.input.released("jump") && ctx.input.action("jump").pressed) log("input")
    }
    if (ctx.controller) { ctx.controller.move([1, 0, 0], 3); ctx.controller.jump(); ctx.controller.crouch(false); if (ctx.controller.grounded && ctx.controller.velocity.length === 3) log("controller") }
    if (ctx.animator) { ctx.animator.set("walk"); if (ctx.animator.state === "walk") log("animator") }
    // hud / camera / audio / particles / labels / time
    ctx.hud.objective("goal.find-key"); ctx.hud.prompt("prompt.open"); ctx.hud.prompt(null); ctx.hud.timer(30); ctx.hud.score(7); ctx.hud.set("timer", null)
    ctx.camera.set("third-person", { distance: 4 }); ctx.camera.follow(e); ctx.camera.follow(null)
    ctx.state.audio = ctx.audio.play("sfx/step", { loop: false, bus: "sfx", volume: 0.5, pitch: 1.2, at: e }); ctx.audio.setPitch(ctx.state.audio, 1.5, { rampSeconds: 0.25 }); ctx.audio.setVolume(ctx.state.audio, 0.2); ctx.audio.stop(ctx.state.audio)
    if (ctx.audio.bus("sfx").name === "sfx" && ctx.audio.bus("sfx").setVolume(0.5, 0.3) && ctx.audio.snapshot("paused")) log("audio")
    ctx.audio.music.play("tense", { crossfade: 2 })
    ctx.particles.emit("sparks", [0, 1, 0], { count: 20 })
    ctx.labels.set("hello", "label.hello", e); ctx.labels.clear("hello")
    if (ctx.strings.get("hud.timer") === "Time left" && ctx.strings.has("hud.timer") && !ctx.strings.has("nope") && ctx.strings.get("nope") === "[[nope]]") log("strings")
    ctx.particles.emit("glow", [0, 0, 0])
    if (ctx.time.frame >= 0 && ctx.time.dt > 0 && ctx.time.scale === 1 && ctx.time.now >= 0) log("time")
    ctx.events.emit("ping", { n: 1 })
    if (ctx.time.frame > 0) ctx.events.off("ping") // listeners are delivered at end of tick; off() before that drops them
    ctx.log("hits", ctx.state.hits)
  },
} satisfies Behavior<State>
```
