Candy Logo Copyright © 2025-2026 Candy Arts

Media Players
Media players play the media Dialogues control: audio, video, images (with the Media commands) and animation effects (with the Effect commands). Controlling media from a Dialogue is covered in Media.
PlayerPlays
Audio PlayersMusic, sounds, ambience, recorded speech...
Video PlayersVideos.
Image PlayersImages and frame-folder animations.
Effect PlayersAnimations from AnimationLibraries, to animate any part of your UI.
Voice Players are a separate case: they speak Spoken Lines, and aren't controlled by commands. Names Each media player is listed in the Engine's media_players_paths dictionary (see UI Elements). Its key is the player's name: the name Dialogues use to address it (e.g. "Music"), and the name of its media folder (see Media Files). Keys can be renamed or removed, and any number of players added. The Player Node A media player is a single node of the right type, with the matching script attached. Each script has one required variable, the node it plays through (audio_player, video_player, image_player or effect_player). It defaults to the node the script is attached to, so it rarely needs changing. Access Several Engines can share a media player, such as a music player shared by every Dialogue in your game. The Access settings decide which Engines may control it. Background Scenes and VN Scenes use the same settings. Private and Public
  • Private (default): the player only obeys the Engine that owns it (see "Owning or naming" in UI Elements). A Private player that no Engine owns obeys none.
  • Public: any Engine may control it, as its Public Mode allows.
The owner of a Private player always pauses it when its Dialogue is suspended, and stops it when its Dialogue ends. Holding a Public player When an Engine starts playback on a Public player, it becomes the player's holder until that playback ends or is stopped. While a player is held, its public_mode decides what other Engines may do:
Public ModeOther Engines
ExclusiveTheir commands are rejected.
Semi-ExclusiveThey may only send the commands in semi_exclusive_commands (by default: pause, resume, stop, volume, skip).
FreeThey may send any command. One that takes hold becomes the holder.
A rejected command is reported in the Output panel, and the Dialogue carries on. Command lists Commands are listed by name, as written in Dialogues (e.g. "Media_Play"); case doesn't matter. Add your own commands to these lists if they act on media players.
SettingPurpose
hold_commandsCommands whose sender becomes the player's holder. A Line can override this with its Take_Hold key.
semi_exclusive_commandsCommands other Engines may still send while the player is held in Semi-Exclusive mode.
unrestricted_commandsCommands accepted from any Engine, Private or Public, held or not. They only affect the Engine's own Dialogue (e.g. waiting for the player to finish), never the player itself.
Held players and Dialogue end or suspension Whether the holder also pauses a Public player when its Dialogue is suspended, and stops it when its Dialogue ends, is decided in this order, each overriding the previous:
  • suspend_held_media / end_held_media in Candy_Properties.gd.
  • The same settings on the Engine, when enable_suspend_held_media / enable_end_held_media is on.
  • The same settings on the player (under Held Player Overrides), when its enable_ switch is on.
When the holder doesn't stop a player at the end of its Dialogue, the player continues to play and is released. Hook Functions The hook functions of a media player are in its script, an 'unsafe' file. Write yours in a copy of the script, attached to your own nodes, or updates will overwrite them (see Customizing UI Elements, on the UI page). Every media player has these hook functions:
HookCalled
x_playback_starting()Right before the player starts playback.
x_playback_started()Right after playback has started.
x_playback_finished()Once the playback is over.
The first two are called when a Media_Play or Effect_Play command starts playback. A playback started with a Loops of 0 only holds its first frame: its hooks run later, when a Resume command starts it. A static image shown without a Duration is held in the same way, and none of the three hooks is called for it. candy_args contains "caller" (the Engine) and "node" (the player). custom_data is [[command values], [player values]]: the Line's Custom Data, then that of the Line's entry for this player. See UI Elements for how hook functions work. When playback is over x_playback_finished() is called once for each playback the first two hooks announced, when the player stops playing it. Use it to react to the end of a media, such as hiding the frame around a video or restoring your game's music after a jingle.
  • The media reached its end by itself: all its loops are done, or its Duration ran out.
  • The media was stopped, by a Media_Stop or Effect_Stop command (at once, or where its Loops and Duration said) or by the end of the Dialogue.
candy_args contains "caller" (the Engine that started the playback), "node" (the player) and "ended", which is true in the first case and false in the second. custom_data is that of the Line that started the playback.
  • It isn't called when another Media_Play or Effect_Play starts a new playback on a player that is still playing. The player continues to play, and the hook is called when that new playback is over.
  • It isn't called for a Pause or for a Dialogue suspension. The playback isn't over.
  • The Engine doesn't wait for it: an await inside it delays nothing.