feat(box): celebratory spinning star on bravo
Make the end-of-routine "Bravo !" lively: the star now spins
(continuous full turn via lv_image_set_rotation) and bounces
(translate_y ping-pong). Both use layer-free paths — image
rotation transforms against the flush band, translate is not a
layer-forcing style — so the render task stays light (no repeat
of the full-screen-layer task_wdt). Auto-return stretched to
3.6 s so the spin shows and the festive cue finishes.
Tower: seed a more festive bravo.mp3 line ("Youpi, tu as
réussi ! Tu es super !").
This commit is contained in:
+48
-10
@@ -385,6 +385,24 @@ static void bravo_auto_return_cb(lv_timer_t *t)
|
||||
bravo_go_home();
|
||||
}
|
||||
|
||||
// 3D-ish spin: rotate the star image about its centre. Uses the IMAGE
|
||||
// rotation property (lv_image_set_rotation), NOT the style transform_rotation:
|
||||
// the image path transforms inside the draw against the flush band and does
|
||||
// not allocate a full-screen object layer (that full-screen layer is what
|
||||
// wedged the render task with FADE_IN / style transform_scale). The source is
|
||||
// 44x44 in flash; scaled up ~2.5x for a big celebratory star.
|
||||
static void bravo_spin_cb(void *var, int32_t v)
|
||||
{
|
||||
lv_image_set_rotation((lv_obj_t *)var, v); // v in 0.1 degree units
|
||||
}
|
||||
|
||||
// Vertical bounce via translate_y — a pure position offset, layer-free
|
||||
// (translate is not in LVGL's layer-forcing style set, unlike scale/rotation).
|
||||
static void bravo_bounce_cb(void *var, int32_t v)
|
||||
{
|
||||
lv_obj_set_style_translate_y((lv_obj_t *)var, v, 0);
|
||||
}
|
||||
|
||||
static void show_bravo(void)
|
||||
{
|
||||
lv_obj_t *scr = lv_obj_create(NULL);
|
||||
@@ -392,17 +410,36 @@ static void show_bravo(void)
|
||||
lv_obj_set_style_bg_grad_color(scr, lv_color_hex(0xFFFFFF), 0);
|
||||
lv_obj_set_style_bg_grad_dir(scr, LV_GRAD_DIR_VER, 0);
|
||||
|
||||
// Star image: pop-in from 0.33x to 1x with overshoot (bouncy feel).
|
||||
// Spinning, bouncing star (44px source scaled ~2.5x -> ~110px on screen).
|
||||
lv_obj_t *star = lv_image_create(scr);
|
||||
lv_image_set_src(star, &lisael_ic_star);
|
||||
lv_obj_set_size(star, 140, 140);
|
||||
lv_image_set_inner_align(star, LV_IMAGE_ALIGN_CONTAIN);
|
||||
lv_image_set_scale(star, 256 * 5 / 2); // 2.5x
|
||||
lv_image_set_pivot(star, 22, 22); // centre of the 44px source
|
||||
lv_obj_align(star, LV_ALIGN_CENTER, 0, -40);
|
||||
// NB: deliberately NO transform/scale animation. A style transform_scale
|
||||
// forces LVGL to render the star into an intermediate layer; on this
|
||||
// RAM-tight BOX-3 (16-line flush buffer) that layer allocation wedges the
|
||||
// render task → task_wdt (the "crash at end of routine"). The screen-load
|
||||
// slide is the entrance instead.
|
||||
|
||||
// Continuous 3D-feel spin (full turn every 2 s, forever).
|
||||
lv_anim_t spin;
|
||||
lv_anim_init(&spin);
|
||||
lv_anim_set_var(&spin, star);
|
||||
lv_anim_set_exec_cb(&spin, bravo_spin_cb);
|
||||
lv_anim_set_values(&spin, 0, 3600); // 0 -> 360.0 deg
|
||||
lv_anim_set_duration(&spin, 2000);
|
||||
lv_anim_set_repeat_count(&spin, LV_ANIM_REPEAT_INFINITE);
|
||||
lv_anim_start(&spin);
|
||||
|
||||
// Gentle bounce (down then up, bouncy easing, ping-pong forever).
|
||||
lv_anim_t bounce;
|
||||
lv_anim_init(&bounce);
|
||||
lv_anim_set_var(&bounce, star);
|
||||
lv_anim_set_exec_cb(&bounce, bravo_bounce_cb);
|
||||
lv_anim_set_values(&bounce, -18, 14);
|
||||
lv_anim_set_duration(&bounce, 650);
|
||||
lv_anim_set_reverse_duration(&bounce, 650);
|
||||
lv_anim_set_repeat_count(&bounce, LV_ANIM_REPEAT_INFINITE);
|
||||
lv_anim_set_path_cb(&bounce, lv_anim_path_ease_in_out);
|
||||
lv_anim_start(&bounce);
|
||||
// NB: both anims target `star`; LVGL removes them automatically when the
|
||||
// bravo screen (and its star child) is deleted on return Home.
|
||||
|
||||
// "Bravo !" label (Fredoka large, centred below the star).
|
||||
lv_obj_t *txt = lv_label_create(scr);
|
||||
@@ -434,7 +471,8 @@ static void show_bravo(void)
|
||||
lv_screen_load_anim(scr, LV_SCR_LOAD_ANIM_MOVE_LEFT, 250, 0, true);
|
||||
s_step_screen = scr; // track the bravo screen for explicit cleanup on return
|
||||
|
||||
// Auto-return after 2.2 s (one-shot timer). The tap handler deletes it.
|
||||
s_bravo_timer = lv_timer_create(bravo_auto_return_cb, 2200, NULL);
|
||||
// Auto-return after 3.6 s (lets the festive bravo.mp3 ~3.5 s finish and the
|
||||
// star spin a couple of turns). One-shot; the tap handler deletes it early.
|
||||
s_bravo_timer = lv_timer_create(bravo_auto_return_cb, 3600, NULL);
|
||||
lv_timer_set_repeat_count(s_bravo_timer, 1);
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ def build_routine_manifest(gen_bin=None, gen_audio=None):
|
||||
# Seed fixed firmware sound cues (only on the real TTS path, not in test fakes)
|
||||
if _real_audio:
|
||||
_seed_fixed_sound("ok.mp3", "Et hop !")
|
||||
_seed_fixed_sound("bravo.mp3", "Bravo ! Tu as fini.")
|
||||
_seed_fixed_sound("bravo.mp3", "Bravo ! Youpi, tu as réussi ! Tu es super !")
|
||||
return {"generated": generated, "skipped": skipped, "routines": manifest}
|
||||
|
||||
def _gen_step_audio(text, key):
|
||||
|
||||
Reference in New Issue
Block a user