Skip to main content

agent/orbs/
presets.rs

1//! Twelve states × four sizes — original ports plus library-native concepts.
2
3use crate::orbs::{
4    engine::{ModeOpts, base_profile, scale_counts, scale_radii},
5    types::{ModeKey, OrbSize, OrbState},
6};
7
8/// Fully resolved draw options for a (state, size) pair.
9#[derive(Clone, Debug)]
10pub struct Resolved {
11    pub mode: ModeKey,
12    pub speed: f32,
13    pub opts: ModeOpts,
14}
15
16struct Preset {
17    speed: f32,
18    count: f32,
19    size: f32,
20    // extra knobs merged after scaling
21    scan_mul: Option<f32>,
22    dim_base: Option<f32>,
23    spin: Option<f32>,
24    band_mul: Option<f32>,
25    wob_mul: Option<f32>,
26    spread: Option<f32>,
27}
28
29fn preset_for(mode: ModeKey, size: OrbSize) -> Preset {
30    use ModeKey::*;
31
32    // The large designs preserve each avatar preset's character while adding
33    // detail gradually. `scale_counts` understands each painter's topology
34    // (2-D lattices, flat lists, lane/segment pairs), so this is deliberately
35    // not a naive coordinate scale.
36    if matches!(size, OrbSize::Large | OrbSize::Hero) {
37        let mut preset = preset_for(mode, OrbSize::Avatar);
38        let (count, radius, speed) = match size {
39            OrbSize::Large => (1.15, 1.05, 0.95),
40            OrbSize::Hero => (1.30, 1.10, 0.90),
41            _ => unreachable!(),
42        };
43        preset.count *= count;
44        preset.size *= radius;
45        preset.speed *= speed;
46        return preset;
47    }
48
49    match (mode, size) {
50        (Orbits, OrbSize::Avatar) => Preset {
51            speed: 1.885,
52            count: 1.0,
53            size: 1.0,
54            scan_mul: None,
55            dim_base: None,
56            spin: None,
57            band_mul: None,
58            wob_mul: None,
59            spread: None,
60        },
61        (Orbits, OrbSize::Inline) => Preset {
62            speed: 3.9,
63            count: 0.238,
64            size: 2.4,
65            scan_mul: None,
66            dim_base: None,
67            spin: None,
68            band_mul: None,
69            wob_mul: None,
70            spread: None,
71        },
72        (Globe, OrbSize::Avatar) => Preset {
73            speed: 2.015,
74            count: 0.42,
75            size: 1.15,
76            scan_mul: Some(4.08),
77            dim_base: Some(0.45),
78            spin: None,
79            band_mul: None,
80            wob_mul: None,
81            spread: None,
82        },
83        (Globe, OrbSize::Inline) => Preset {
84            speed: 2.665,
85            count: 0.105,
86            size: 1.75,
87            scan_mul: Some(4.335),
88            dim_base: Some(0.45),
89            spin: None,
90            band_mul: None,
91            wob_mul: None,
92            spread: None,
93        },
94        (Rubik, OrbSize::Avatar) => Preset {
95            speed: 1.82,
96            count: 0.35,
97            size: 1.05,
98            scan_mul: None,
99            dim_base: None,
100            spin: None,
101            band_mul: None,
102            wob_mul: None,
103            spread: None,
104        },
105        (Rubik, OrbSize::Inline) => Preset {
106            speed: 1.95,
107            count: 0.088,
108            size: 1.9,
109            scan_mul: None,
110            dim_base: None,
111            spin: None,
112            band_mul: None,
113            wob_mul: None,
114            spread: None,
115        },
116        (Wave, OrbSize::Avatar) => Preset {
117            speed: 3.15,
118            count: 0.341,
119            size: 1.0,
120            scan_mul: None,
121            dim_base: None,
122            spin: None,
123            band_mul: None,
124            wob_mul: None,
125            spread: None,
126        },
127        (Wave, OrbSize::Inline) => Preset {
128            speed: 3.35,
129            count: 0.105,
130            size: 1.6,
131            scan_mul: None,
132            dim_base: None,
133            spin: None,
134            band_mul: None,
135            wob_mul: None,
136            spread: None,
137        },
138        (Web, OrbSize::Avatar) => Preset {
139            speed: 3.315,
140            count: 1.35,
141            size: 0.95,
142            scan_mul: None,
143            dim_base: None,
144            spin: None,
145            band_mul: None,
146            wob_mul: None,
147            spread: None,
148        },
149        (Web, OrbSize::Inline) => Preset {
150            speed: 6.63,
151            count: 0.25,
152            size: 1.52,
153            scan_mul: None,
154            dim_base: None,
155            spin: None,
156            band_mul: None,
157            wob_mul: None,
158            spread: None,
159        },
160        (Braid, OrbSize::Avatar) => Preset {
161            speed: 1.625,
162            count: 0.5,
163            size: 1.0,
164            scan_mul: None,
165            dim_base: None,
166            spin: None,
167            band_mul: None,
168            wob_mul: None,
169            spread: None,
170        },
171        (Braid, OrbSize::Inline) => Preset {
172            speed: 2.75,
173            count: 0.1125,
174            size: 1.36,
175            scan_mul: None,
176            dim_base: None,
177            spin: None,
178            band_mul: None,
179            wob_mul: None,
180            spread: None,
181        },
182        (Ribbon, OrbSize::Avatar) => Preset {
183            speed: 1.95,
184            count: 0.25,
185            size: 0.85,
186            scan_mul: None,
187            dim_base: None,
188            spin: Some(0.0),
189            band_mul: Some(2.9),
190            wob_mul: Some(1.0),
191            spread: None,
192        },
193        (Ribbon, OrbSize::Inline) => Preset {
194            speed: 2.5,
195            count: 0.051,
196            size: 1.073,
197            scan_mul: None,
198            dim_base: None,
199            spin: Some(0.0),
200            band_mul: Some(3.6),
201            wob_mul: Some(1.0),
202            spread: None,
203        },
204        (Ring, OrbSize::Avatar) => Preset {
205            speed: 1.55,
206            count: 0.25,
207            size: 0.956,
208            scan_mul: None,
209            dim_base: None,
210            spin: Some(0.0),
211            band_mul: Some(2.8),
212            wob_mul: Some(0.368),
213            spread: None,
214        },
215        (Ring, OrbSize::Inline) => Preset {
216            speed: 2.1,
217            count: 0.028,
218            size: 1.622,
219            scan_mul: None,
220            dim_base: None,
221            spin: Some(0.0),
222            band_mul: Some(3.2),
223            wob_mul: Some(0.565),
224            spread: None,
225        },
226        (Morph, OrbSize::Avatar) => Preset {
227            speed: 2.405,
228            count: 0.702,
229            size: 0.395,
230            scan_mul: None,
231            dim_base: None,
232            spin: None,
233            band_mul: None,
234            wob_mul: None,
235            spread: Some(1.45),
236        },
237        (Morph, OrbSize::Inline) => Preset {
238            speed: 2.08,
239            count: 0.53,
240            size: 1.011,
241            scan_mul: None,
242            dim_base: None,
243            spin: None,
244            band_mul: None,
245            wob_mul: None,
246            spread: Some(1.45),
247        },
248        (Focus, OrbSize::Avatar) => Preset {
249            speed: 1.72,
250            count: 1.0,
251            size: 1.0,
252            scan_mul: None,
253            dim_base: None,
254            spin: None,
255            band_mul: None,
256            wob_mul: None,
257            spread: Some(1.0),
258        },
259        (Focus, OrbSize::Inline) => Preset {
260            speed: 2.2,
261            count: 0.22,
262            size: 1.45,
263            scan_mul: None,
264            dim_base: None,
265            spin: None,
266            band_mul: None,
267            wob_mul: None,
268            spread: Some(1.0),
269        },
270        (Gyroscope, OrbSize::Avatar) => Preset {
271            speed: 1.48,
272            count: 1.0,
273            size: 1.0,
274            scan_mul: None,
275            dim_base: None,
276            spin: None,
277            band_mul: None,
278            wob_mul: None,
279            spread: Some(1.0),
280        },
281        (Gyroscope, OrbSize::Inline) => Preset {
282            speed: 2.05,
283            count: 0.25,
284            size: 1.55,
285            scan_mul: None,
286            dim_base: None,
287            spin: None,
288            band_mul: None,
289            wob_mul: None,
290            spread: Some(1.0),
291        },
292        (Echo, OrbSize::Avatar) => Preset {
293            speed: 1.85,
294            count: 1.0,
295            size: 1.0,
296            scan_mul: None,
297            dim_base: None,
298            spin: None,
299            band_mul: None,
300            wob_mul: None,
301            spread: Some(1.0),
302        },
303        (Echo, OrbSize::Inline) => Preset {
304            speed: 2.45,
305            count: 0.25,
306            size: 1.55,
307            scan_mul: None,
308            dim_base: None,
309            spin: None,
310            band_mul: None,
311            wob_mul: None,
312            spread: Some(1.0),
313        },
314        (_, OrbSize::Large | OrbSize::Hero) => unreachable!(),
315    }
316}
317
318/// Resolve a (state, size) pair to its mode + fully-scaled draw options.
319pub fn resolve_preset(state: OrbState, size: OrbSize) -> Resolved {
320    let mode = ModeKey::from_state(state);
321    let preset = preset_for(mode, size);
322    let mut opts = base_profile(mode);
323    if (preset.count - 1.0).abs() > f32::EPSILON {
324        opts = scale_counts(&opts, preset.count);
325    }
326    if (preset.size - 1.0).abs() > f32::EPSILON {
327        opts = scale_radii(&opts, preset.size);
328    }
329    if let Some(v) = preset.scan_mul {
330        opts.scan_mul = Some(v);
331    }
332    if let Some(v) = preset.dim_base {
333        opts.dim_base = Some(v);
334    }
335    if let Some(v) = preset.spin {
336        opts.spin = Some(v);
337    }
338    if let Some(v) = preset.band_mul {
339        opts.band_mul = Some(v);
340    }
341    if let Some(v) = preset.wob_mul {
342        opts.wob_mul = Some(v);
343    }
344    if let Some(v) = preset.spread {
345        opts.spread = Some(v);
346    }
347
348    Resolved {
349        mode,
350        speed: preset.speed,
351        opts,
352    }
353}