Engine splash ("Made with Sparklight")
An optional startup screen a game turns on by data: the Sparklight mark assembles ray by ray, flares with a shock ring, sparks and
a lens streak, the wordmark rises letter by letter under a light sweep, and a short sound sting plays. 2 to 4 seconds (3.2 by
default), skippable, drawn on the GPU from the same polygons as the brand masters (assets/brand/), with no texture or font file.
Quick start
Section titled “Quick start”# Turn it on in a game: an assets file (every key optional; `{}` is enough)cat > assets/splash.json <<'JSON'{ "enabled": true, "caption": "made_with", "language": "en", "duration_s": 3.2, "skippable": true, "sound": true, "volume": 0.8 }JSON# Look at it from an agent shell: agent runs hide it unless asked, and stay mutedspark run scenes/main.space3d.json --assets assets --gw-mute --splash --frames 240 --exit-after 30The run’s summary line reports it: "splash": {"decision": "show", "frames": <drawn splash frames>, "skipped": false, "sting": false}.
When it shows
Section titled “When it shows”| run | splash | sting |
|---|---|---|
a player’s run, splash.json with "enabled": true (or {}) |
shown | plays (Ui group, volume) |
no splash.json, or "enabled": false |
not shown (no_config, disabled) |
- |
agent or test run: GAMEWAY_MUTE, --gw-mute, CLAUDECODE=1, an output-folder override, --autotest, --editor, an agent bundle id |
not shown (agent_run) |
- |
the same with --splash |
shown | never: an agent or test run is always silent |
--no-splash |
never (off) |
- |
--headless |
never (headless), even with --splash |
- |
The sting is started only when the settings want it and the run is neither muted nor an agent or test run:
splash::sting_audible checks the run’s StudioContext (mute, is_agent_run) and the process environment again (CLAUDECODE
without GAMEWAY_ALLOW_SOUND=1), so an agent shell is silent whatever the context says. Such a run never decodes the sting or calls
the audio engine for it. A skip fades the sting out over 0.25 s and stops it when the splash ends.
Settings (<assets>/splash.json)
Section titled “Settings (<assets>/splash.json)”Schema: schemas/splash.schema.json. Unknown keys and values out of range are refused before
any window opens (spark run exits 1): E_SPLASH_CONFIG (unreadable, not JSON, unknown key, wrong type), E_SPLASH_VALUE
(duration_s outside 2 to 4, volume outside 0 to 1).
| key | default | meaning |
|---|---|---|
enabled |
true |
show it at start |
caption |
made_with |
made_with (“MADE WITH” / “СДЕЛАНО НА”), powered_by (“POWERED BY” / “РАБОТАЕТ НА”) or none |
language |
en |
en or ru: the caption’s language (the wordmark is never translated) |
duration_s |
3.2 |
length in seconds, 2 to 4 |
skippable |
true |
any key, mouse button or touch skips it after the first 0.3 s (the launch key does not); a gamepad button too in a game loop that polls the gamepad (sparklight::play has no gamepad input) |
sound |
true |
play the sting |
volume |
0.8 |
sting volume, 0 to 1 |
A game that lets the player pick a language passes it before the splash (it reads splash.json once at start; write the
language into the file the game ships, or build the SplashConfig in code, below).
Timeline (seconds, default length)
Section titled “Timeline (seconds, default length)”| t | what |
|---|---|
| 0 - 0.25 | fade in from black; ambient glow |
| 0.15 - 1.15 | the four main rays grow out of the centre (N, E, S, W), then the four diagonal rays; the mark turns into place |
| 0.31 | the sting starts; its impact (0.64 s into the file, measured) lands on the hit |
| 0.95 | the hit: flare, shock ring, lens streak, sparks, a short flash |
| 1.2 - 2.1 | caption and wordmark letters rise into place, one after another |
| 1.9 - 2.5 | a light sweep runs over the wordmark |
| 2.75 - 3.2 | fade to black; the game’s first frame follows |
A skip fades to black in 0.25 s and fades the sting out with it.
Quality tiers and window size
Section titled “Quality tiers and window size”The splash follows the renderer’s QualityTier: Low draws the logo, the ambient glow and the flare only; Medium adds the
shock ring, the flash and the light sweep (10 sparks); High adds the lens streak (28 sparks); Ultra 48 sparks and a finer
ring. Its size comes from the window in logical points (mark height min(0.36 h, 0.28 w)), so it fits landscape, portrait
(phones) and ultra-wide windows with a 5 % margin.
In your own game loop
Section titled “In your own game loop”Games with their own runner (not sparklight::play) use the same pieces:
use sparklight::splash::{self, Splash, SplashConfig, SplashDecision, SplashOverride};let config = SplashConfig::load(&assets)?; // Ok(None) without the filelet decision = splash::decide(config.as_ref(), &studio, SplashOverride::from_args(&args));let mut splash = (decision == SplashDecision::Show).then(|| Splash::new(config.unwrap_or_default(), renderer.settings.tier));// every frame while `splash` is Some:let step = s.update(dt, any_key_or_button_or_touch_went_down);if step.start_sting && splash::sting_audible(s.config(), &studio) { sting = Some(audio.play(&sting_sound, Group::Ui, s.config().volume, 0.0)); }if let Some(h) = sting { audio.set_voice_volume(h, s.config().volume * step.sting_gain); }let mut canvas = Canvas::new(w, h, scale_factor);s.draw(&mut canvas);overlay.draw_cleared(&mut encoder, &view, (w, h), &canvas, splash::BACKGROUND);if step.finished { splash = None; } // draw the game from the next framesplash::STING_OGG holds the sting (Sound::from_bytes). Gamepad buttons count as input when the game polls them and passes
them to update. While the splash runs, sparklight::play keeps every press and touch from the game (releases still reach it),
and a window that gets no redraws runs the splash out on the loop’s own ticks.
Checks
Section titled “Checks”crates/sparklight-scene3d/tests/splash.rs: settings and schema (unknown keys refused), the visibility matrix above, the silent sting in every muted, agent or test run, the timeline (one sting, ends on time, skip, grace time, unskippable), a stalled frame, determinism (a frame depends only on time, size and tier), tiers, layout for seven window shapes, every glyph of every caption.gpu_splash_key_frames_match_their_goldens,gpu_splash_portrait_frame_matches_its_golden(Mac,--profile needs): key frames at 0.5, 1.05, 1.6 and 2.3 s, Low tier in Russian, a phone portrait; goldensgoldens/ui/gpu-splash-*.png.crates/sparklight-cli/tests/play3d.rs:display_spark_run_shows_the_splash_only_when_asked_and_keeps_its_sting_silent(a real muted window),display_a_stalled_window_still_ends_the_splash_and_starts_the_game(no redraws at all) andspark_run_refuses_a_bad_splash_file_without_opening_a_window; the input routing of the player is unit-tested inplay.rs(splash_input_tests).
Assets
Section titled “Assets”- Sound:
crates/sparklight-scene3d/assets/splash/sparklight-sting.ogg, Seed Audio take mastered byTools/audio/master-splash-sting.sh(4.0 s, stereo 48 kHz, -15.7 LUFS, true peak -1.3 dBFS); registry idsfx/SparklightSting/ogg. - Logo: the polygons and paths of
assets/brand/sparklight-mark.svgand the wordmark (registry idui/SparklightLogo/svg).