Splash Screen¶
the branded boot splash and a reusable loading screen.
▶ Run in browserTags: ui splash loading branding
Every windowed SimVX game boots with the engine’s branded splash: a fade in
from black, the SIMVX wordmark over a faint centre-lit grid, a segmented
gradient progress bar, then a fade back to black once the first frame is ready
(a one-second minimum stops sub-second flicker on fast hardware). This demo
runs with that default, then lets you re-trigger the same SplashScreen
control as an in-game loading screen driven by a real 0..1 progress source:
the pattern for heavy scene transitions.
What it demonstrates¶
The default boot splash (
App(splash=None)): automatic on windowed runs; configure viaApp(splash=..., splash_min_time=..., unbranded=...).Reusing
SplashScreenfor scene transitions: bindprogressto any() -> floator an object with a.progressattribute (an assetBatchHandleworks as-is).skippable=True: once loading completes, any key or click skips the hold.The
finishedsignal driving teardown (splash.destroy).
Controls: L / Click / Tap - Simulate loading a level behind a SplashScreen Escape - Quit
Source¶
1"""Splash Screen: the branded boot splash and a reusable loading screen.
2
3Every windowed SimVX game boots with the engine's branded splash: a fade in
4from black, the SIMVX wordmark over a faint centre-lit grid, a segmented
5gradient progress bar, then a fade back to black once the first frame is ready
6(a one-second minimum stops sub-second flicker on fast hardware). This demo
7runs with that default, then lets you re-trigger the same `SplashScreen`
8control as an in-game loading screen driven by a real 0..1 progress source:
9the pattern for heavy scene transitions.
10
11# /// simvx
12# tags = ["ui", "splash", "loading", "branding"]
13# web = { root = "SplashDemo", width = 800, height = 600, responsive = true }
14# ///
15
16## What it demonstrates
17
18- The default boot splash (`App(splash=None)`): automatic on windowed runs;
19 configure via `App(splash=..., splash_min_time=..., unbranded=...)`.
20- Reusing `SplashScreen` for scene transitions: bind `progress` to any
21 `() -> float` or an object with a `.progress` attribute (an asset
22 `BatchHandle` works as-is).
23- `skippable=True`: once loading completes, any key or click skips the hold.
24- The `finished` signal driving teardown (`splash.destroy`).
25
26Controls:
27 L / Click / Tap - Simulate loading a level behind a SplashScreen
28 Escape - Quit
29"""
30
31import math
32import sys
33
34from simvx.core import AnchorPreset, Colour, Control, Input, Key, Label, MouseButton, SplashScreen
35from simvx.graphics import App
36
37WIDTH, HEIGHT = 800, 600
38LOAD_TIME = 2.5 # seconds the simulated level load takes
39
40
41class SplashDemo(Control):
42 input_actions = {"load": [Key.L, MouseButton.LEFT], "quit": [Key.ESCAPE]}
43
44 def on_ready(self):
45 self.set_anchor_preset(AnchorPreset.FULL_RECT) # top-level Controls anchor, never absolute-size
46 self._t = 0.0
47 self._level = 1
48 self._splash: SplashScreen | None = None
49 self._load_started_at = 0.0
50 self._hint = self.add_child(
51 Label("Press L (or click) to load the next level behind a SplashScreen", font_size=18)
52 )
53 self._hint.position = (24, 24)
54
55 # ------------------------------------------------------------- loading
56
57 def _begin_load(self):
58 if self._splash is not None:
59 return
60 self._load_started_at = self.tree.now
61 # A real game passes an asset BatchHandle here; this demo fakes the
62 # same 0..1 contract off scene time.
63 self._splash = SplashScreen(
64 progress=self._load_progress,
65 min_display_time=1.0,
66 skippable=True,
67 )
68 self._splash.set_progress(0.0, f"loading level {self._level + 1}")
69 self._splash.finished.connect(self._end_load)
70 self.add_child(self._splash) # last child: draws over the scene
71
72 def _load_progress(self) -> float:
73 return min(1.0, (self.tree.now - self._load_started_at) / LOAD_TIME)
74
75 def _end_load(self):
76 self._level += 1
77 self._hint.text = f"Level {self._level} loaded. Press L to load another."
78 splash, self._splash = self._splash, None
79 splash.destroy()
80
81 # ------------------------------------------------------------- frame
82
83 def on_update(self, dt: float):
84 self._t += dt
85 if Input.is_action_just_pressed("load"):
86 self._begin_load()
87 if Input.is_action_just_pressed("quit"):
88 self.app.quit()
89 self.queue_redraw() # animated background below
90
91 def on_draw(self, renderer):
92 w, h = self.tree.screen_size
93 # A live background per level hue, so the loading screen visibly covers
94 # a running scene and the reveal fades back onto it.
95 hue = (self._level * 0.13) % 1.0
96 base = Colour.hex("#173042") if self._level % 2 else Colour.hex("#2b1a38")
97 renderer.draw_rect((0, 0), (w, h), colour=base, filled=True)
98 cx, cy = w / 2, h / 2
99 for i in range(8):
100 a = self._t * 0.8 + i * math.tau / 8
101 x = cx + math.cos(a) * (120 + 40 * math.sin(self._t + i))
102 y = cy + math.sin(a) * (90 + 30 * math.cos(self._t + i))
103 radius = 14 + 6 * math.sin(self._t * 2 + i)
104 renderer.draw_circle((x, y), radius, colour=(0.2 + hue * 0.5, 0.8, 0.7, 0.85), filled=True)
105
106
107def main():
108 if "--test" in sys.argv:
109 App(title="SimVX Splash Screen", width=WIDTH, height=HEIGHT, visible=False).run_headless(
110 SplashDemo(), frames=30
111 )
112 return
113 App(title="SimVX Splash Screen", width=WIDTH, height=HEIGHT).run(SplashDemo())
114
115
116if __name__ == "__main__":
117 main()