APIs in every supported language
Lua 5.4, Luau, JavaScript, Python, C, C++, C#, Java, PHP, and HTML inline JavaScript use the same engine services. CSS supplies styling and executes no API calls.
Create and attach a script
- Open a project and create an Object Component Script from Programming > New Script, choosing your language.
- Select an enabled scene object and use + Add Component to attach the script.
- External languages need their toolchain on PATH: Python 3, a C17 or C++20 compiler, .NET SDK 10+, Java with javac, or PHP CLI. Lua, JavaScript and the isolated Luau host ship with Rustic.
- Generate the programming workspace from the editor before using an external editor. Include/import the engine-owned SDK shown in your language guide. PHP and HTML assets belong under ui/.
- Put tone.wav in assets/, then run the examples below from Start. Press Play. Playback is audible on Windows; other platforms currently mix without a native output device.
Shared API families
| Service | Available operations |
|---|---|
| Lifecycle and owner state | Construction, startup, enable/disable, fixed/frame updates, destroy/stop, translation, properties, built-in attributes, input, logging |
| Scene and object services | Find/list, live entity lookup, read/edit other objects, instance add/clone, current camera selection, environment/sky settings |
| Entity foundations | Tags, groups, hierarchy, destruction/lifetime, components, radius/tag queries |
| Gameplay actions | Tween/value, easing, interpolation, movement, paths, timers, sequence/timeline, effects, camera actions |
| Animation | Load/register clips, play/blend, speed/loop/pause/stop, markers, keyframes, IK and procedural actions |
| Events and time | Signals, connections, operation handles, scene clock read/pause/resume/time scale |
| Audio | Play/spatial play, reusable loaded clips, voice controls, volume/pitch/fades, device selection |
| Capture | Record game mix or microphone, hot mic, stop/read/unload script-owned PCM handles |
All these families are available in every gameplay language. Names and signatures follow each language's SDK; native bindings use typed options and handles. HTML shares the JavaScript sandbox. This does not add browser APIs or DOM access.
Load audio and record the mix
These are callback-body examples, not standalone programs. Use the callback registration from your language guide. They play the same clip, pause/resume it, stop and replay it, then release it. Recording starts before playback and stops afterward; a read returns the PCM mixed between callbacks, so stopping immediately within Start can produce an empty packet. Retain the handles across callbacks and stop/read in Update or a Timer callback when recording a longer session. The immediate stop/unload calls below run before a mixed frame, so these short snippets produce no audible output. Omit those controls until a later callback to hear playback and collect a nonempty recording.
Lua 5.4 / Luau
local rec = Game.startRecording()
local clip = Audio.load('assets/tone.wav')
clip:play({loop=true})
clip:pause(); clip:resume(); clip:stop(); clip:play()
clip:unload()
Game.stopRecording(rec)
local packet = rec:read()
rec:unload()JavaScript / HTML inline JavaScript
const rec = Game.startRecording();
const clip = Audio.load('assets/tone.wav');
clip.play({loop:true});
clip.pause(); clip.resume(); clip.stop(); clip.play();
clip.unload();
Game.stopRecording(rec);
const packet = rec.read();
rec.unload();No Lua 5.4 example is provided for this API. Documented language support for these examples: Python, C, C++, C#, Java, PHP. Choose a listed language or Show All Languages.
Python
# from rustic import Audio, Game
rec = Game.startRecording()
clip = Audio.load('assets/tone.wav')
clip.play({'loop':True})
clip.pause(); clip.resume(); clip.stop(); clip.play()
clip.unload()
Game.stopRecording(rec)
packet = rec.read()
rec.unload()C
/* #include "rustic.h" */
RusticCaptureHandle rec = Game.startRecording(NULL, NULL);
RusticLoadedAudio clip = Audio.load("assets/tone.wav");
RusticAudioOptions options = {.volume=1, .pitch=1, .loop=true};
LoadedAudio.play(clip, &options);
LoadedAudio.pause(clip); LoadedAudio.resume(clip); LoadedAudio.stop(clip);
LoadedAudio.play(clip, NULL); LoadedAudio.unload(&clip);
Game.stopRecording(&rec);
RusticCaptureData packet = Capture.read(rec);
Capture.unload(rec);C++
// #include "rustic.hpp"
auto rec = Game.startRecording();
auto clip = Audio::load("assets/tone.wav");
clip.play(1,1,true);
clip.pause(); clip.resume(); clip.stop(); clip.play();
clip.unload();
Game.stopRecording(&rec);
auto packet = rec.read();
rec.unload();C#
// using static Rustic;
var rec = Game.startRecording();
var clip = Audio.load("assets/tone.wav");
clip.play(loop:true);
clip.pause(); clip.resume(); clip.stop(); clip.play();
clip.unload();
Game.stopRecording(rec);
var packet = rec.read();
rec.unload();Java
// Inside a behavior extending Rustic.
var rec = Game.startRecording();
var clip = Audio.load("assets/tone.wav");
clip.play(1,1,true);
clip.pause(); clip.resume(); clip.stop(); clip.play();
clip.unload();
Game.stopRecording(rec);
var packet = (java.util.Map<?,?>)rec.read();
rec.unload();PHP
// Inside a callback after require_once 'rustic.php'.
global $Game;
$rec = $Game->startRecording();
$clip = Audio::load('assets/tone.wav');
$clip->play(['loop'=>true]);
$clip->pause(); $clip->resume(); $clip->stop(); $clip->play();
$clip->unload();
$Game->stopRecording($rec);
$packet = $rec->read();
$rec->unload();Audio.load decodes once. play reuses retained PCM even if the source file is removed afterward. Stop retains PCM; unload frees it and stops its playback. Unload twice is harmless. Lua/Luau, JavaScript, Python, C++, C#, Java and PHP can call clip.load() (Lua uses a colon) to load the same object again after unload. C calls Audio.load(source) to obtain a new handle. C++ copies share loaded state. A voice returned by loaded playback supports the same fades and controls as an Audio.play voice.
Microphone capture
Use Game.startHotMic() instead of startRecording() to obtain a microphone handle, then use its read, stop, and unload methods. C uses Game.startHotMic(), Capture.read(mic), Capture.stop(mic) and Capture.unload(mic). Stop all owned hot mics with Game.stopHotMic(); C passes NULL, C++ omits the pointer, and Java passes null or omits the argument.
To record microphone PCM, use Game.startRecording(null, {source:'microphone'}) in JavaScript, Game.startRecording(None, {'source':'microphone'}) in Python, Game.startRecording(nil, {source='microphone'}) in Lua/Luau, or $Game->startRecording(null, ['source'=>'microphone']) in PHP. C, C++, C# and Java pass "microphone" as the second argument. The existing rustic.game entry point also exposes the capture methods in each SDK.
Capture packets contain samples, sampleRate, channels, active, and droppedSamples. Samples are interleaved floating-point PCM. Reads advance the cursor; repeated reads do not repeat samples. C uses packet.count for the number of samples; its sample storage remains valid until the next script callback. Recording and microphone capture retain the existing platform limits: Windows supplies microphone input; other platforms report an unavailable-backend error. Device selection does not currently change capture's system-default input. See the Audio API for file paths, limits and cleanup.
Read another object's current attributes
Use rustic.get_object_attribute(source, name) in every language, with native member syntax ($rustic-> in PHP). source accepts a stable entity ID or rustic.game.Scene.Root.Child. C returns RusticValue; C++ returns RusticValue; C#/Java return ordinary scalar or vector values. JavaScript/Python/Lua return their ordinary values. Path proxies also expose GetAttribute and get_attribute; C uses rustic.game.GetAttribute(source, name).
Edits queue in JavaScript and external adapters. A live query flushes earlier commands before reading, so an edit followed by get_object_attribute in the same callback observes the new value. Owner snapshot getters such as get_translation and get_attribute retain their callback snapshot in those adapters. Lua applies writes immediately. rustic.find_entity(source) performs live lookup; scene Find/List retain their existing snapshot semantics in external adapters. List returns\none entity ID per matched object, supports a subtree path and defaults to Game.scene.
Diagnose failures
- Missing external SDK/toolchain: regenerate the workspace and check the Console's toolchain diagnostic. Do not write your own protocol loop.
- Missing clip: check the exact assets/ path and supported encoding. Playing after unload requires load first. A C handle must be replaced by Audio.load.
- Silent output or microphone unavailable: check the platform, Windows device permissions and the Console. A stopped recording still permits reading.
- Missing/stale object: use a stable entity ID or verify the scene/hierarchy path; a destroyed object cannot supply attributes.
- Capture/action lifetime: handles belong to the script and clean up on disable, destruction, successful reload or Stop.
Input remains limited to held WASD, arrows and Shift in embedded Play. Collision and touch callbacks are not dispatched. These are shared runtime limits across languages.