diff --git a/game/scenarios/scenario_reel_template.yaml b/game/scenarios/scenario_reel_template.yaml index 438e4c1..4ec9040 100644 --- a/game/scenarios/scenario_reel_template.yaml +++ b/game/scenarios/scenario_reel_template.yaml @@ -134,26 +134,6 @@ prompt_input: screen_json: "data/story/screens/SCENE_LOCKED.json" default_audio_pack_id: "" runtime_step_ids: [] - - scene_id: "SCENE_WIN_ETAPE" - screen_json: "data/story/screens/SCENE_WIN_ETAPE.json" - default_audio_pack_id: "PACK_WIN" - runtime_step_ids: [] - - scene_id: "SCENE_WINNER" - screen_json: "data/story/screens/SCENE_WINNER.json" - default_audio_pack_id: "PACK_WIN" - runtime_step_ids: [] - - scene_id: "SCENE_FIREWORKS" - screen_json: "data/story/screens/SCENE_FIREWORKS.json" - default_audio_pack_id: "" - runtime_step_ids: [] - - scene_id: "SCENE_BROKEN" - screen_json: "data/story/screens/SCENE_BROKEN.json" - default_audio_pack_id: "" - runtime_step_ids: [] - - scene_id: "SCENE_WIN" - screen_json: "data/story/screens/SCENE_WIN.json" - default_audio_pack_id: "PACK_WIN" - runtime_step_ids: [] - scene_id: "SCENE_REWARD" screen_json: "data/story/screens/SCENE_REWARD.json" default_audio_pack_id: "" @@ -162,22 +142,6 @@ prompt_input: screen_json: "data/story/screens/SCENE_SEARCH.json" default_audio_pack_id: "" runtime_step_ids: [] - - scene_id: "SCENE_SIGNAL_SPIKE" - screen_json: "data/story/screens/SCENE_SIGNAL_SPIKE.json" - default_audio_pack_id: "PACK_MORSE_HINT" - runtime_step_ids: [] - - scene_id: "SCENE_MEDIA_ARCHIVE" - screen_json: "data/story/screens/SCENE_MEDIA_ARCHIVE.json" - default_audio_pack_id: "" - runtime_step_ids: [] - - scene_id: "SCENE_CAMERA_SCAN" - screen_json: "data/story/screens/SCENE_CAMERA_SCAN.json" - default_audio_pack_id: "" - runtime_step_ids: [] - - scene_id: "SCENE_LA_DETECT" - screen_json: "data/story/screens/SCENE_LA_DETECT.json" - default_audio_pack_id: "PACK_SONAR_HINT" - runtime_step_ids: [] audio_pack_catalog_all: - pack_id: "PACK_BOOT_RADIO" @@ -274,31 +238,6 @@ prompt_input: default_entry_triggers: ["SCENE_GOTO SCENE_LOCKED", "scenario_reset"] default_exit_triggers: ["UNLOCK", "NEXT", "SC_EVENT button ANY"] runtime_step_ids: [] - - scene_id: "SCENE_WIN_ETAPE" - default_actions: [] - default_entry_triggers: ["SCENE_GOTO SCENE_WIN_ETAPE"] - default_exit_triggers: ["SCENE_GOTO SCENE_READY", "SCENE_GOTO SCENE_LOCKED"] - runtime_step_ids: [] - - scene_id: "SCENE_WINNER" - default_actions: [] - default_entry_triggers: ["SCENE_GOTO SCENE_WINNER"] - default_exit_triggers: ["SCENE_GOTO SCENE_READY", "SCENE_GOTO SCENE_MEDIA_MANAGER"] - runtime_step_ids: [] - - scene_id: "SCENE_FIREWORKS" - default_actions: [] - default_entry_triggers: ["SCENE_GOTO SCENE_FIREWORKS"] - default_exit_triggers: ["SCENE_GOTO SCENE_READY", "SCENE_GOTO SCENE_MEDIA_MANAGER"] - runtime_step_ids: [] - - scene_id: "SCENE_BROKEN" - default_actions: [] - default_entry_triggers: ["SCENE_GOTO SCENE_BROKEN"] - default_exit_triggers: ["SCENE_GOTO SCENE_READY", "SCENE_GOTO SCENE_LOCKED"] - runtime_step_ids: [] - - scene_id: "SCENE_WIN" - default_actions: [] - default_entry_triggers: ["SCENE_GOTO SCENE_WIN"] - default_exit_triggers: ["SCENE_GOTO SCENE_READY"] - runtime_step_ids: [] - scene_id: "SCENE_REWARD" default_actions: [] default_entry_triggers: ["SCENE_GOTO SCENE_REWARD"] @@ -309,26 +248,6 @@ prompt_input: default_entry_triggers: ["SCENE_GOTO SCENE_SEARCH"] default_exit_triggers: ["SCENE_GOTO SCENE_READY"] runtime_step_ids: [] - - scene_id: "SCENE_SIGNAL_SPIKE" - default_actions: [] - default_entry_triggers: ["SCENE_GOTO SCENE_SIGNAL_SPIKE"] - default_exit_triggers: ["SCENE_GOTO SCENE_READY"] - runtime_step_ids: [] - - scene_id: "SCENE_MEDIA_ARCHIVE" - default_actions: [] - default_entry_triggers: ["SCENE_GOTO SCENE_MEDIA_ARCHIVE"] - default_exit_triggers: ["SCENE_GOTO SCENE_MEDIA_MANAGER", "SCENE_GOTO SCENE_READY"] - runtime_step_ids: [] - - scene_id: "SCENE_CAMERA_SCAN" - default_actions: [] - default_entry_triggers: ["SCENE_GOTO SCENE_CAMERA_SCAN"] - default_exit_triggers: ["SCENE_GOTO SCENE_READY", "SCENE_GOTO SCENE_MEDIA_MANAGER"] - runtime_step_ids: [] - - scene_id: "SCENE_LA_DETECT" - default_actions: [] - default_entry_triggers: ["SCENE_GOTO SCENE_LA_DETECT"] - default_exit_triggers: ["SCENE_GOTO SCENE_READY", "SCENE_GOTO SCENE_LA_DETECTOR"] - runtime_step_ids: [] scenario: id: "DEFAULT" diff --git a/game/scenarios/scene_editor_all.yaml b/game/scenarios/scene_editor_all.yaml index adc987f..66957b3 100644 --- a/game/scenarios/scene_editor_all.yaml +++ b/game/scenarios/scene_editor_all.yaml @@ -1,35 +1,17 @@ meta: purpose: Edit LVGL/FX/audio mapping scene by scene, then sync to screen JSON. source_runtime_scenario: game/scenarios/default_unlock_win_etape2.yaml - review: - status: coherent - scope: runtime_scenes_only - checks: - - screen_json_exists - - runtime_step_ids_match_default_scenario - - effect_tokens_supported_by_ui_manager - - transition_tokens_supported_by_ui_manager - - unused_scenes_pruned scope: runtime_only - scene_order_source: game/scenarios/default_unlock_win_etape2.yaml#steps used_scene_count: 9 - removed_unused_scene_count: 15 - removed_unused_scene_ids: - - SCENE_BROKEN - - SCENE_CAMERA_SCAN - - SCENE_FIREWORKS - - SCENE_LA_DETECT + exported_scene_count: 9 + unused_scene_ids: - SCENE_LOCKED - - SCENE_MEDIA_ARCHIVE - SCENE_MP3_PLAYER - SCENE_PHOTO_MANAGER - SCENE_READY - SCENE_REWARD - SCENE_SEARCH - - SCENE_SIGNAL_SPIKE - - SCENE_WIN - - SCENE_WINNER - - SCENE_WIN_ETAPE + missing_screen_ids: [] scenes: - scene_id: SCENE_U_SON_PROTO screen_json: hardware/firmware/data/story/screens/SCENE_U_SON_PROTO.json diff --git a/hardware/firmware/data/scenarios/data/default_scenario.json b/hardware/firmware/data/scenarios/data/default_scenario.json deleted file mode 100644 index 823f59e..0000000 --- a/hardware/firmware/data/scenarios/data/default_scenario.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "id": "DEFAULT", - "scenario": "DEFAULT", - "initial_step": "SCENE_U_SON_PROTO", - "steps": [ - { - "id": "SCENE_U_SON_PROTO", - "screen_scene_id": "SCENE_U_SON_PROTO", - "audio_pack_id": "PACK_BOOT_RADIO", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT" - ] - }, - { - "id": "SCENE_LA_DETECTOR", - "screen_scene_id": "SCENE_LA_DETECTOR", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_QUEUE_SONAR" - ] - }, - { - "id": "RTC_ESP_ETAPE1", - "screen_scene_id": "SCENE_WIN_ETAPE1", - "audio_pack_id": "PACK_CONFIRM_WIN_ETAPE1", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT", - "ACTION_ESP_NOW_SEND_ETAPE1", - "ACTION_QUEUE_SONAR" - ] - }, - { - "id": "WIN_ETAPE1", - "screen_scene_id": "SCENE_WIN_ETAPE1", - "audio_pack_id": "PACK_WIN", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT" - ] - }, - { - "id": "STEP_WARNING", - "screen_scene_id": "SCENE_WARNING", - "audio_pack_id": "PACK_BOOT_RADIO", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT" - ] - }, - { - "id": "SCENE_LEFOU_DETECTOR", - "screen_scene_id": "SCENE_LEFOU_DETECTOR", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_QUEUE_SONAR" - ] - }, - { - "id": "RTC_ESP_ETAPE2", - "screen_scene_id": "SCENE_WIN_ETAPE2", - "audio_pack_id": "PACK_CONFIRM_WIN_ETAPE2", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT", - "ACTION_ESP_NOW_SEND_ETAPE2", - "ACTION_QUEUE_SONAR" - ] - }, - { - "id": "SCENE_QR_DETECTOR", - "screen_scene_id": "SCENE_QR_DETECTOR", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_QR_CODE_SCANNER_START" - ] - }, - { - "id": "SCENE_FINAL_WIN", - "screen_scene_id": "SCENE_FINAL_WIN", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_WINNER" - ] - }, - { - "id": "STEP_MEDIA_MANAGER", - "screen_scene_id": "SCENE_MEDIA_MANAGER", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_SET_BOOT_MEDIA_MANAGER" - ], - "mp3_gate_open": true - } - ], - "source": "littlefs-default-options" -} diff --git a/hardware/firmware/data/screens/la_detector.json b/hardware/firmware/data/screens/la_detector.json index 81fc02d..ca5fcce 100644 --- a/hardware/firmware/data/screens/la_detector.json +++ b/hardware/firmware/data/screens/la_detector.json @@ -1,24 +1,19 @@ { "id": "SCENE_LA_DETECTOR", - "title": "DETECTEUR DE RESONNANCE", - "subtitle": "", - "symbol": "AUDIO", - "effect": "wave", + "title": "LA DETECTOR", + "subtitle": "Trouve la bonne resonance", + "symbol": "LA", + "effect": "radar", "visual": { "show_title": true, + "show_subtitle": true, "show_symbol": true, - "effect_speed_ms": 480, - "waveform": { - "enabled": true, - "sample_count": 16, - "amplitude_pct": 100, - "jitter": true - } + "effect_speed_ms": 460 }, "theme": { - "bg": "#000000", - "accent": "#49D9FF", - "text": "#E8F6FF" + "bg": "#111B20", + "accent": "#86FFD2", + "text": "#ECFFF6" }, "timeline": { "loop": true, @@ -67,7 +62,7 @@ ] }, "transition": { - "effect": "zoom", - "duration_ms": 260 + "effect": "fade", + "duration_ms": 180 } } diff --git a/hardware/firmware/data/screens/locked.json b/hardware/firmware/data/screens/locked.json index 65e5eb4..7e7f429 100644 --- a/hardware/firmware/data/screens/locked.json +++ b/hardware/firmware/data/screens/locked.json @@ -7,7 +7,13 @@ "visual": { "show_title": true, "show_symbol": false, - "effect_speed_ms": 90 + "effect_speed_ms": 90, + "waveform": { + "enabled": true, + "sample_count": 16, + "amplitude_pct": 100, + "jitter": true + } }, "theme": { "bg": "#06060E", diff --git a/hardware/firmware/data/story/scenarios/DEFAULT.json b/hardware/firmware/data/story/scenarios/DEFAULT.json index 1d26e55..941502f 100644 --- a/hardware/firmware/data/story/scenarios/DEFAULT.json +++ b/hardware/firmware/data/story/scenarios/DEFAULT.json @@ -1,444 +1 @@ -{ - "id": "DEFAULT", - "scenario": "DEFAULT", - "version": 2, - "initial_step": "SCENE_U_SON_PROTO", - "hardware_events": { - "button_short_1": "BTN_NEXT", - "button_short_2": "BTN_NEXT", - "button_short_3": "BTN_NEXT", - "button_short_4": "BTN_NEXT", - "button_short_5": "BTN_NEXT", - "button_long_3": "FORCE_ETAPE2", - "button_long_4": "FORCE_DONE", - "espnow_event": "ESPNOW:" - }, - "app_bindings": [ - "APP_AUDIO", - "APP_SCREEN", - "APP_GATE", - "APP_WIFI", - "APP_ESPNOW", - "APP_QR_UNLOCK" - ], - "actions_catalog": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT", - "ACTION_QUEUE_SONAR", - "ACTION_ESP_NOW_SEND_ETAPE1", - "ACTION_ESP_NOW_SEND_ETAPE2", - "ACTION_QR_CODE_SCANNER_START", - "ACTION_WINNER", - "ACTION_SET_BOOT_MEDIA_MANAGER" - ], - "steps": [ - { - "id": "SCENE_U_SON_PROTO", - "screen_scene_id": "SCENE_U_SON_PROTO", - "audio_pack_id": "PACK_BOOT_RADIO", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT" - ], - "transitions": [ - { - "id": "TR_SCENE_U_SON_PROTO_1", - "trigger": "on_event", - "event_type": "audio_done", - "event_name": "AUDIO_DONE", - "target_step_id": "SCENE_U_SON_PROTO", - "after_ms": 0, - "priority": 80 - }, - { - "id": "TR_SCENE_U_SON_PROTO_2", - "trigger": "on_event", - "event_type": "button", - "event_name": "ANY", - "target_step_id": "SCENE_LA_DETECTOR", - "after_ms": 0, - "priority": 120 - }, - { - "id": "TR_SCENE_U_SON_PROTO_3", - "trigger": "on_event", - "event_type": "serial", - "event_name": "FORCE_ETAPE2", - "target_step_id": "SCENE_LA_DETECTOR", - "after_ms": 0, - "priority": 140 - } - ] - }, - { - "id": "SCENE_LA_DETECTOR", - "screen_scene_id": "SCENE_LA_DETECTOR", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_QUEUE_SONAR" - ], - "transitions": [ - { - "id": "TR_SCENE_LA_DETECTOR_1", - "trigger": "on_event", - "event_type": "timer", - "event_name": "ETAPE2_DUE", - "target_step_id": "SCENE_U_SON_PROTO", - "after_ms": 0, - "priority": 100 - }, - { - "id": "TR_SCENE_LA_DETECTOR_2", - "trigger": "on_event", - "event_type": "serial", - "event_name": "BTN_NEXT", - "target_step_id": "RTC_ESP_ETAPE1", - "after_ms": 0, - "priority": 110 - }, - { - "id": "TR_SCENE_LA_DETECTOR_3", - "trigger": "on_event", - "event_type": "unlock", - "event_name": "UNLOCK", - "target_step_id": "RTC_ESP_ETAPE1", - "after_ms": 0, - "priority": 115 - }, - { - "id": "TR_SCENE_LA_DETECTOR_4", - "trigger": "on_event", - "event_type": "action", - "event_name": "ACTION_FORCE_ETAPE2", - "target_step_id": "RTC_ESP_ETAPE1", - "after_ms": 0, - "priority": 120 - }, - { - "id": "TR_SCENE_LA_DETECTOR_5", - "trigger": "on_event", - "event_type": "serial", - "event_name": "FORCE_WIN_ETAPE1", - "target_step_id": "RTC_ESP_ETAPE1", - "after_ms": 0, - "priority": 130 - } - ] - }, - { - "id": "RTC_ESP_ETAPE1", - "screen_scene_id": "SCENE_WIN_ETAPE1", - "audio_pack_id": "PACK_CONFIRM_WIN_ETAPE1", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT", - "ACTION_ESP_NOW_SEND_ETAPE1", - "ACTION_QUEUE_SONAR" - ], - "transitions": [ - { - "id": "TR_RTC_ESP_ETAPE1_1", - "trigger": "on_event", - "event_type": "espnow", - "event_name": "ACK_WIN1", - "target_step_id": "WIN_ETAPE1", - "after_ms": 0, - "priority": 130 - }, - { - "id": "TR_RTC_ESP_ETAPE1_2", - "trigger": "on_event", - "event_type": "serial", - "event_name": "FORCE_DONE", - "target_step_id": "WIN_ETAPE1", - "after_ms": 0, - "priority": 120 - } - ] - }, - { - "id": "WIN_ETAPE1", - "screen_scene_id": "SCENE_WIN_ETAPE1", - "audio_pack_id": "PACK_WIN", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT" - ], - "transitions": [ - { - "id": "TR_WIN_ETAPE1_1", - "trigger": "on_event", - "event_type": "serial", - "event_name": "BTN_NEXT", - "target_step_id": "STEP_WARNING", - "after_ms": 0, - "priority": 110 - }, - { - "id": "TR_WIN_ETAPE1_2", - "trigger": "on_event", - "event_type": "serial", - "event_name": "FORCE_DONE", - "target_step_id": "STEP_WARNING", - "after_ms": 0, - "priority": 120 - }, - { - "id": "TR_WIN_ETAPE1_3", - "trigger": "on_event", - "event_type": "espnow", - "event_name": "ACK_WARNING", - "target_step_id": "STEP_WARNING", - "after_ms": 0, - "priority": 130 - } - ] - }, - { - "id": "STEP_WARNING", - "screen_scene_id": "SCENE_WARNING", - "audio_pack_id": "PACK_BOOT_RADIO", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT" - ], - "transitions": [ - { - "id": "TR_STEP_WARNING_1", - "trigger": "on_event", - "event_type": "audio_done", - "event_name": "AUDIO_DONE", - "target_step_id": "STEP_WARNING", - "after_ms": 0, - "priority": 80 - }, - { - "id": "TR_STEP_WARNING_2", - "trigger": "on_event", - "event_type": "button", - "event_name": "ANY", - "target_step_id": "SCENE_LEFOU_DETECTOR", - "after_ms": 0, - "priority": 120 - }, - { - "id": "TR_STEP_WARNING_3", - "trigger": "on_event", - "event_type": "serial", - "event_name": "FORCE_ETAPE2", - "target_step_id": "SCENE_LEFOU_DETECTOR", - "after_ms": 0, - "priority": 140 - } - ] - }, - { - "id": "SCENE_LEFOU_DETECTOR", - "screen_scene_id": "SCENE_LEFOU_DETECTOR", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_QUEUE_SONAR" - ], - "transitions": [ - { - "id": "TR_SCENE_LEFOU_DETECTOR_1", - "trigger": "on_event", - "event_type": "timer", - "event_name": "ETAPE2_DUE", - "target_step_id": "STEP_WARNING", - "after_ms": 0, - "priority": 100 - }, - { - "id": "TR_SCENE_LEFOU_DETECTOR_2", - "trigger": "on_event", - "event_type": "serial", - "event_name": "BTN_NEXT", - "target_step_id": "RTC_ESP_ETAPE2", - "after_ms": 0, - "priority": 110 - }, - { - "id": "TR_SCENE_LEFOU_DETECTOR_3", - "trigger": "on_event", - "event_type": "unlock", - "event_name": "UNLOCK", - "target_step_id": "RTC_ESP_ETAPE2", - "after_ms": 0, - "priority": 115 - }, - { - "id": "TR_SCENE_LEFOU_DETECTOR_4", - "trigger": "on_event", - "event_type": "action", - "event_name": "ACTION_FORCE_ETAPE2", - "target_step_id": "RTC_ESP_ETAPE2", - "after_ms": 0, - "priority": 120 - }, - { - "id": "TR_SCENE_LEFOU_DETECTOR_5", - "trigger": "on_event", - "event_type": "serial", - "event_name": "FORCE_WIN_ETAPE2", - "target_step_id": "RTC_ESP_ETAPE2", - "after_ms": 0, - "priority": 130 - } - ] - }, - { - "id": "RTC_ESP_ETAPE2", - "screen_scene_id": "SCENE_WIN_ETAPE2", - "audio_pack_id": "PACK_CONFIRM_WIN_ETAPE2", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_HW_LED_ALERT", - "ACTION_ESP_NOW_SEND_ETAPE2", - "ACTION_QUEUE_SONAR" - ], - "transitions": [ - { - "id": "TR_RTC_ESP_ETAPE2_1", - "trigger": "on_event", - "event_type": "espnow", - "event_name": "ACK_WIN2", - "target_step_id": "SCENE_QR_DETECTOR", - "after_ms": 0, - "priority": 130 - }, - { - "id": "TR_RTC_ESP_ETAPE2_2", - "trigger": "on_event", - "event_type": "serial", - "event_name": "FORCE_DONE", - "target_step_id": "SCENE_QR_DETECTOR", - "after_ms": 0, - "priority": 120 - } - ] - }, - { - "id": "SCENE_QR_DETECTOR", - "screen_scene_id": "SCENE_QR_DETECTOR", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_QR_CODE_SCANNER_START" - ], - "transitions": [ - { - "id": "TR_SCENE_QR_DETECTOR_1", - "trigger": "on_event", - "event_type": "serial", - "event_name": "QR_OK", - "target_step_id": "SCENE_FINAL_WIN", - "after_ms": 0, - "priority": 140 - }, - { - "id": "TR_SCENE_QR_DETECTOR_2", - "trigger": "on_event", - "event_type": "unlock", - "event_name": "UNLOCK_QR", - "target_step_id": "SCENE_FINAL_WIN", - "after_ms": 0, - "priority": 150 - }, - { - "id": "TR_SCENE_QR_DETECTOR_3", - "trigger": "on_event", - "event_type": "serial", - "event_name": "BTN_NEXT", - "target_step_id": "SCENE_FINAL_WIN", - "after_ms": 0, - "priority": 110 - }, - { - "id": "TR_SCENE_QR_DETECTOR_4", - "trigger": "on_event", - "event_type": "action", - "event_name": "ACTION_FORCE_ETAPE2", - "target_step_id": "SCENE_FINAL_WIN", - "after_ms": 0, - "priority": 120 - }, - { - "id": "TR_SCENE_QR_DETECTOR_5", - "trigger": "on_event", - "event_type": "serial", - "event_name": "FORCE_WIN_ETAPE2", - "target_step_id": "SCENE_FINAL_WIN", - "after_ms": 0, - "priority": 130 - } - ] - }, - { - "id": "SCENE_FINAL_WIN", - "screen_scene_id": "SCENE_FINAL_WIN", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_WINNER" - ], - "transitions": [ - { - "id": "TR_SCENE_FINAL_WIN_1", - "trigger": "on_event", - "event_type": "timer", - "event_name": "WIN_DUE", - "target_step_id": "STEP_MEDIA_MANAGER", - "after_ms": 0, - "priority": 140 - }, - { - "id": "TR_SCENE_FINAL_WIN_2", - "trigger": "on_event", - "event_type": "serial", - "event_name": "BTN_NEXT", - "target_step_id": "STEP_MEDIA_MANAGER", - "after_ms": 0, - "priority": 110 - }, - { - "id": "TR_SCENE_FINAL_WIN_3", - "trigger": "on_event", - "event_type": "unlock", - "event_name": "UNLOCK", - "target_step_id": "STEP_MEDIA_MANAGER", - "after_ms": 0, - "priority": 120 - }, - { - "id": "TR_SCENE_FINAL_WIN_4", - "trigger": "on_event", - "event_type": "action", - "event_name": "FORCE_WIN_ETAPE2", - "target_step_id": "STEP_MEDIA_MANAGER", - "after_ms": 0, - "priority": 130 - }, - { - "id": "TR_SCENE_FINAL_WIN_5", - "trigger": "on_event", - "event_type": "serial", - "event_name": "FORCE_WIN_ETAPE2", - "target_step_id": "STEP_MEDIA_MANAGER", - "after_ms": 0, - "priority": 125 - } - ] - }, - { - "id": "STEP_MEDIA_MANAGER", - "screen_scene_id": "SCENE_MEDIA_MANAGER", - "action_ids": [ - "ACTION_TRACE_STEP", - "ACTION_SET_BOOT_MEDIA_MANAGER" - ], - "mp3_gate_open": true - } - ], - "source": "story_selector", - "screen_root": "/story/screens", - "audio_root": "/story/audio" -} +{"app_bindings":[{"app":"AUDIO_PACK","config":null,"id":"APP_AUDIO"},{"app":"SCREEN_SCENE","config":null,"id":"APP_SCREEN"},{"app":"MP3_GATE","config":null,"id":"APP_GATE"},{"app":"WIFI_STACK","config":null,"id":"APP_WIFI"},{"app":"ESPNOW_STACK","config":null,"id":"APP_ESPNOW"},{"app":"QR_UNLOCK_APP","config":null,"id":"APP_QR_UNLOCK"}],"estimated_duration_s":0,"id":"DEFAULT","initial_step":"SCENE_U_SON_PROTO","steps":[{"actions":["ACTION_TRACE_STEP","ACTION_HW_LED_ALERT"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_BOOT_RADIO","mp3_gate_open":false,"screen_scene_id":"SCENE_U_SON_PROTO","step_id":"SCENE_U_SON_PROTO","transitions":[{"after_ms":0,"event_name":"AUDIO_DONE","event_type":"audio_done","id":"TR_SCENE_U_SON_PROTO_1","priority":80,"target_step_id":"SCENE_U_SON_PROTO","trigger":"on_event"},{"after_ms":0,"event_name":"ANY","event_type":"button","id":"TR_SCENE_U_SON_PROTO_2","priority":120,"target_step_id":"SCENE_LA_DETECTOR","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_ETAPE2","event_type":"serial","id":"TR_SCENE_U_SON_PROTO_3","priority":140,"target_step_id":"SCENE_LA_DETECTOR","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_QUEUE_SONAR"],"apps":["APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":false,"screen_scene_id":"SCENE_LA_DETECTOR","step_id":"SCENE_LA_DETECTOR","transitions":[{"after_ms":0,"event_name":"ETAPE2_DUE","event_type":"timer","id":"TR_SCENE_LA_DETECTOR_1","priority":100,"target_step_id":"SCENE_U_SON_PROTO","trigger":"on_event"},{"after_ms":0,"event_name":"BTN_NEXT","event_type":"serial","id":"TR_SCENE_LA_DETECTOR_2","priority":110,"target_step_id":"RTC_ESP_ETAPE1","trigger":"on_event"},{"after_ms":0,"event_name":"UNLOCK","event_type":"unlock","id":"TR_SCENE_LA_DETECTOR_3","priority":115,"target_step_id":"RTC_ESP_ETAPE1","trigger":"on_event"},{"after_ms":0,"event_name":"ACTION_FORCE_ETAPE2","event_type":"action","id":"TR_SCENE_LA_DETECTOR_4","priority":120,"target_step_id":"RTC_ESP_ETAPE1","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_WIN_ETAPE1","event_type":"serial","id":"TR_SCENE_LA_DETECTOR_5","priority":130,"target_step_id":"RTC_ESP_ETAPE1","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_HW_LED_ALERT","ACTION_ESP_NOW_SEND_ETAPE1","ACTION_QUEUE_SONAR"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_CONFIRM_WIN_ETAPE1","mp3_gate_open":false,"screen_scene_id":"SCENE_WIN_ETAPE1","step_id":"RTC_ESP_ETAPE1","transitions":[{"after_ms":0,"event_name":"ACK_WIN1","event_type":"espnow","id":"TR_RTC_ESP_ETAPE1_1","priority":130,"target_step_id":"WIN_ETAPE1","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_DONE","event_type":"serial","id":"TR_RTC_ESP_ETAPE1_2","priority":120,"target_step_id":"WIN_ETAPE1","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_HW_LED_ALERT"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_WIN","mp3_gate_open":false,"screen_scene_id":"SCENE_WIN_ETAPE1","step_id":"WIN_ETAPE1","transitions":[{"after_ms":0,"event_name":"BTN_NEXT","event_type":"serial","id":"TR_WIN_ETAPE1_1","priority":110,"target_step_id":"STEP_WARNING","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_DONE","event_type":"serial","id":"TR_WIN_ETAPE1_2","priority":120,"target_step_id":"STEP_WARNING","trigger":"on_event"},{"after_ms":0,"event_name":"ACK_WARNING","event_type":"espnow","id":"TR_WIN_ETAPE1_3","priority":130,"target_step_id":"STEP_WARNING","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_HW_LED_ALERT"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_BOOT_RADIO","mp3_gate_open":false,"screen_scene_id":"SCENE_WARNING","step_id":"STEP_WARNING","transitions":[{"after_ms":0,"event_name":"AUDIO_DONE","event_type":"audio_done","id":"TR_STEP_WARNING_1","priority":80,"target_step_id":"STEP_WARNING","trigger":"on_event"},{"after_ms":0,"event_name":"ANY","event_type":"button","id":"TR_STEP_WARNING_2","priority":120,"target_step_id":"SCENE_LEFOU_DETECTOR","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_ETAPE2","event_type":"serial","id":"TR_STEP_WARNING_3","priority":140,"target_step_id":"SCENE_LEFOU_DETECTOR","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_QUEUE_SONAR"],"apps":["APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":false,"screen_scene_id":"SCENE_LEFOU_DETECTOR","step_id":"SCENE_LEFOU_DETECTOR","transitions":[{"after_ms":0,"event_name":"ETAPE2_DUE","event_type":"timer","id":"TR_SCENE_LEFOU_DETECTOR_1","priority":100,"target_step_id":"STEP_WARNING","trigger":"on_event"},{"after_ms":0,"event_name":"BTN_NEXT","event_type":"serial","id":"TR_SCENE_LEFOU_DETECTOR_2","priority":110,"target_step_id":"RTC_ESP_ETAPE2","trigger":"on_event"},{"after_ms":0,"event_name":"UNLOCK","event_type":"unlock","id":"TR_SCENE_LEFOU_DETECTOR_3","priority":115,"target_step_id":"RTC_ESP_ETAPE2","trigger":"on_event"},{"after_ms":0,"event_name":"ACTION_FORCE_ETAPE2","event_type":"action","id":"TR_SCENE_LEFOU_DETECTOR_4","priority":120,"target_step_id":"RTC_ESP_ETAPE2","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_WIN_ETAPE2","event_type":"serial","id":"TR_SCENE_LEFOU_DETECTOR_5","priority":130,"target_step_id":"RTC_ESP_ETAPE2","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_HW_LED_ALERT","ACTION_ESP_NOW_SEND_ETAPE2","ACTION_QUEUE_SONAR"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_CONFIRM_WIN_ETAPE2","mp3_gate_open":false,"screen_scene_id":"SCENE_WIN_ETAPE2","step_id":"RTC_ESP_ETAPE2","transitions":[{"after_ms":0,"event_name":"ACK_WIN2","event_type":"espnow","id":"TR_RTC_ESP_ETAPE2_1","priority":130,"target_step_id":"SCENE_QR_DETECTOR","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_DONE","event_type":"serial","id":"TR_RTC_ESP_ETAPE2_2","priority":120,"target_step_id":"SCENE_QR_DETECTOR","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_QR_CODE_SCANNER_START"],"apps":["APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW","APP_QR_UNLOCK"],"audio_pack_id":"","mp3_gate_open":false,"screen_scene_id":"SCENE_QR_DETECTOR","step_id":"SCENE_QR_DETECTOR","transitions":[{"after_ms":0,"event_name":"QR_OK","event_type":"serial","id":"TR_SCENE_QR_DETECTOR_1","priority":140,"target_step_id":"SCENE_FINAL_WIN","trigger":"on_event"},{"after_ms":0,"event_name":"UNLOCK_QR","event_type":"unlock","id":"TR_SCENE_QR_DETECTOR_2","priority":150,"target_step_id":"SCENE_FINAL_WIN","trigger":"on_event"},{"after_ms":0,"event_name":"BTN_NEXT","event_type":"serial","id":"TR_SCENE_QR_DETECTOR_3","priority":110,"target_step_id":"SCENE_FINAL_WIN","trigger":"on_event"},{"after_ms":0,"event_name":"ACTION_FORCE_ETAPE2","event_type":"action","id":"TR_SCENE_QR_DETECTOR_4","priority":120,"target_step_id":"SCENE_FINAL_WIN","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_WIN_ETAPE2","event_type":"serial","id":"TR_SCENE_QR_DETECTOR_5","priority":130,"target_step_id":"SCENE_FINAL_WIN","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_WINNER"],"apps":["APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":false,"screen_scene_id":"SCENE_FINAL_WIN","step_id":"SCENE_FINAL_WIN","transitions":[{"after_ms":0,"event_name":"WIN_DUE","event_type":"timer","id":"TR_SCENE_FINAL_WIN_1","priority":140,"target_step_id":"STEP_MEDIA_MANAGER","trigger":"on_event"},{"after_ms":0,"event_name":"BTN_NEXT","event_type":"serial","id":"TR_SCENE_FINAL_WIN_2","priority":110,"target_step_id":"STEP_MEDIA_MANAGER","trigger":"on_event"},{"after_ms":0,"event_name":"UNLOCK","event_type":"unlock","id":"TR_SCENE_FINAL_WIN_3","priority":120,"target_step_id":"STEP_MEDIA_MANAGER","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_WIN_ETAPE2","event_type":"action","id":"TR_SCENE_FINAL_WIN_4","priority":130,"target_step_id":"STEP_MEDIA_MANAGER","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_WIN_ETAPE2","event_type":"serial","id":"TR_SCENE_FINAL_WIN_5","priority":125,"target_step_id":"STEP_MEDIA_MANAGER","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_SET_BOOT_MEDIA_MANAGER"],"apps":["APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":true,"screen_scene_id":"SCENE_MEDIA_MANAGER","step_id":"STEP_MEDIA_MANAGER","transitions":[]}],"version":2,"scenario":"DEFAULT"} diff --git a/hardware/firmware/data/story/scenarios/EXAMPLE_UNLOCK_EXPRESS.json b/hardware/firmware/data/story/scenarios/EXAMPLE_UNLOCK_EXPRESS.json index 767c65c..755633e 100644 --- a/hardware/firmware/data/story/scenarios/EXAMPLE_UNLOCK_EXPRESS.json +++ b/hardware/firmware/data/story/scenarios/EXAMPLE_UNLOCK_EXPRESS.json @@ -1,41 +1 @@ -{ - "id": "EXAMPLE_UNLOCK_EXPRESS", - "scenario": "EXAMPLE_UNLOCK_EXPRESS", - "version": 2, - "initial_step": "STEP_WAIT_UNLOCK", - "hardware_events": { - "button_short_1": "UNLOCK", - "button_short_5": "BTN_NEXT", - "button_long_4": "FORCE_DONE" - }, - "app_bindings": [ - "APP_LA", - "APP_SCREEN", - "APP_GATE", - "APP_AUDIO", - "APP_WIFI", - "APP_ESPNOW" - ], - "actions_catalog": [ - "ACTION_TRACE_STEP", - "ACTION_REFRESH_SD" - ], - "steps": [ - { - "id": "STEP_WAIT_UNLOCK", - "screen_scene_id": "SCENE_LOCKED" - }, - { - "id": "STEP_WIN", - "screen_scene_id": "SCENE_REWARD", - "audio_pack_id": "PACK_WIN" - }, - { - "id": "STEP_DONE", - "screen_scene_id": "SCENE_READY" - } - ], - "source": "story_selector", - "screen_root": "/story/screens", - "audio_root": "/story/audio" -} +{"app_bindings":[{"app":"LA_DETECTOR","config":{"hold_ms":3000,"require_listening":true,"unlock_event":"UNLOCK"},"id":"APP_LA"},{"app":"AUDIO_PACK","config":null,"id":"APP_AUDIO"},{"app":"SCREEN_SCENE","config":null,"id":"APP_SCREEN"},{"app":"MP3_GATE","config":null,"id":"APP_GATE"},{"app":"WIFI_STACK","config":null,"id":"APP_WIFI"},{"app":"ESPNOW_STACK","config":null,"id":"APP_ESPNOW"}],"estimated_duration_s":0,"id":"EXAMPLE_UNLOCK_EXPRESS","initial_step":"STEP_WAIT_UNLOCK","steps":[{"actions":["ACTION_TRACE_STEP"],"apps":["APP_LA","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":false,"screen_scene_id":"SCENE_LOCKED","step_id":"STEP_WAIT_UNLOCK","transitions":[{"after_ms":0,"event_name":"UNLOCK","event_type":"unlock","id":"TR_STEP_WAIT_UNLOCK_1","priority":100,"target_step_id":"STEP_WIN","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_WIN","mp3_gate_open":false,"screen_scene_id":"SCENE_REWARD","step_id":"STEP_WIN","transitions":[{"after_ms":0,"event_name":"AUDIO_DONE","event_type":"audio_done","id":"TR_STEP_WIN_1","priority":100,"target_step_id":"STEP_DONE","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_DONE","event_type":"serial","id":"TR_STEP_WIN_2","priority":120,"target_step_id":"STEP_DONE","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_REFRESH_SD"],"apps":["APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":true,"screen_scene_id":"SCENE_READY","step_id":"STEP_DONE","transitions":[]}],"version":2,"scenario":"EXAMPLE_UNLOCK_EXPRESS"} diff --git a/hardware/firmware/data/story/scenarios/EXEMPLE_UNLOCK_EXPRESS_DONE.json b/hardware/firmware/data/story/scenarios/EXEMPLE_UNLOCK_EXPRESS_DONE.json index 4d17820..cae5757 100644 --- a/hardware/firmware/data/story/scenarios/EXEMPLE_UNLOCK_EXPRESS_DONE.json +++ b/hardware/firmware/data/story/scenarios/EXEMPLE_UNLOCK_EXPRESS_DONE.json @@ -1,41 +1 @@ -{ - "id": "EXEMPLE_UNLOCK_EXPRESS_DONE", - "scenario": "EXEMPLE_UNLOCK_EXPRESS_DONE", - "version": 2, - "initial_step": "STEP_WAIT_UNLOCK", - "hardware_events": { - "button_short_1": "UNLOCK", - "button_short_5": "BTN_NEXT", - "button_long_4": "FORCE_DONE" - }, - "app_bindings": [ - "APP_LA", - "APP_SCREEN", - "APP_GATE", - "APP_AUDIO", - "APP_WIFI", - "APP_ESPNOW" - ], - "actions_catalog": [ - "ACTION_TRACE_STEP", - "ACTION_REFRESH_SD" - ], - "steps": [ - { - "id": "STEP_WAIT_UNLOCK", - "screen_scene_id": "SCENE_LOCKED" - }, - { - "id": "STEP_WIN", - "screen_scene_id": "SCENE_REWARD", - "audio_pack_id": "PACK_WIN" - }, - { - "id": "STEP_DONE", - "screen_scene_id": "SCENE_READY" - } - ], - "source": "story_selector", - "screen_root": "/story/screens", - "audio_root": "/story/audio" -} +{"app_bindings":[{"app":"LA_DETECTOR","config":{"hold_ms":3000,"require_listening":true,"unlock_event":"UNLOCK"},"id":"APP_LA"},{"app":"AUDIO_PACK","config":null,"id":"APP_AUDIO"},{"app":"SCREEN_SCENE","config":null,"id":"APP_SCREEN"},{"app":"MP3_GATE","config":null,"id":"APP_GATE"},{"app":"WIFI_STACK","config":null,"id":"APP_WIFI"},{"app":"ESPNOW_STACK","config":null,"id":"APP_ESPNOW"}],"estimated_duration_s":0,"id":"EXEMPLE_UNLOCK_EXPRESS_DONE","initial_step":"STEP_WAIT_UNLOCK","steps":[{"actions":["ACTION_TRACE_STEP"],"apps":["APP_LA","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":false,"screen_scene_id":"SCENE_LOCKED","step_id":"STEP_WAIT_UNLOCK","transitions":[{"after_ms":0,"event_name":"UNLOCK","event_type":"unlock","id":"TR_STEP_WAIT_UNLOCK_1","priority":100,"target_step_id":"STEP_WIN","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_WIN","mp3_gate_open":false,"screen_scene_id":"SCENE_REWARD","step_id":"STEP_WIN","transitions":[{"after_ms":0,"event_name":"AUDIO_DONE","event_type":"audio_done","id":"TR_STEP_WIN_1","priority":100,"target_step_id":"STEP_DONE","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_REFRESH_SD"],"apps":["APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":true,"screen_scene_id":"SCENE_READY","step_id":"STEP_DONE","transitions":[]}],"version":2,"scenario":"EXEMPLE_UNLOCK_EXPRESS_DONE"} diff --git a/hardware/firmware/data/story/scenarios/SPECTRE_RADIO_LAB.json b/hardware/firmware/data/story/scenarios/SPECTRE_RADIO_LAB.json index 43a6b8b..62e33be 100644 --- a/hardware/firmware/data/story/scenarios/SPECTRE_RADIO_LAB.json +++ b/hardware/firmware/data/story/scenarios/SPECTRE_RADIO_LAB.json @@ -1,53 +1 @@ -{ - "id": "SPECTRE_RADIO_LAB", - "scenario": "SPECTRE_RADIO_LAB", - "version": 2, - "initial_step": "STEP_WAIT_UNLOCK", - "hardware_events": { - "button_short_1": "UNLOCK", - "button_short_5": "BTN_NEXT", - "button_long_4": "FORCE_DONE", - "espnow_event": "SERIAL:" - }, - "app_bindings": [ - "APP_LA", - "APP_AUDIO", - "APP_SCREEN", - "APP_GATE", - "APP_WIFI", - "APP_ESPNOW" - ], - "actions_catalog": [ - "ACTION_TRACE_STEP", - "ACTION_QUEUE_SONAR", - "ACTION_REFRESH_SD" - ], - "steps": [ - { - "id": "STEP_WAIT_UNLOCK", - "screen_scene_id": "SCENE_LOCKED" - }, - { - "id": "STEP_SONAR_SEARCH", - "screen_scene_id": "SCENE_SEARCH", - "audio_pack_id": "PACK_SONAR_HINT" - }, - { - "id": "STEP_MORSE_CLUE", - "screen_scene_id": "SCENE_SEARCH", - "audio_pack_id": "PACK_MORSE_HINT" - }, - { - "id": "STEP_WIN", - "screen_scene_id": "SCENE_REWARD", - "audio_pack_id": "PACK_WIN" - }, - { - "id": "STEP_DONE", - "screen_scene_id": "SCENE_READY" - } - ], - "source": "story_selector", - "screen_root": "/story/screens", - "audio_root": "/story/audio" -} +{"app_bindings":[{"app":"LA_DETECTOR","config":{"hold_ms":3000,"require_listening":true,"unlock_event":"UNLOCK"},"id":"APP_LA"},{"app":"AUDIO_PACK","config":null,"id":"APP_AUDIO"},{"app":"SCREEN_SCENE","config":null,"id":"APP_SCREEN"},{"app":"MP3_GATE","config":null,"id":"APP_GATE"},{"app":"WIFI_STACK","config":null,"id":"APP_WIFI"},{"app":"ESPNOW_STACK","config":null,"id":"APP_ESPNOW"}],"estimated_duration_s":0,"id":"SPECTRE_RADIO_LAB","initial_step":"STEP_WAIT_UNLOCK","steps":[{"actions":["ACTION_TRACE_STEP","ACTION_QUEUE_SONAR"],"apps":["APP_LA","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":false,"screen_scene_id":"SCENE_LOCKED","step_id":"STEP_WAIT_UNLOCK","transitions":[{"after_ms":0,"event_name":"UNLOCK","event_type":"unlock","id":"TR_STEP_WAIT_UNLOCK_1","priority":100,"target_step_id":"STEP_SONAR_SEARCH","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_SONAR_HINT","mp3_gate_open":false,"screen_scene_id":"SCENE_SEARCH","step_id":"STEP_SONAR_SEARCH","transitions":[{"after_ms":0,"event_name":"AUDIO_DONE","event_type":"audio_done","id":"TR_STEP_SONAR_SEARCH_1","priority":100,"target_step_id":"STEP_MORSE_CLUE","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_DONE","event_type":"serial","id":"TR_STEP_SONAR_SEARCH_2","priority":120,"target_step_id":"STEP_DONE","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_MORSE_HINT","mp3_gate_open":false,"screen_scene_id":"SCENE_SEARCH","step_id":"STEP_MORSE_CLUE","transitions":[{"after_ms":0,"event_name":"AUDIO_DONE","event_type":"audio_done","id":"TR_STEP_MORSE_CLUE_1","priority":100,"target_step_id":"STEP_WIN","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_DONE","event_type":"serial","id":"TR_STEP_MORSE_CLUE_2","priority":120,"target_step_id":"STEP_DONE","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_WIN","mp3_gate_open":false,"screen_scene_id":"SCENE_REWARD","step_id":"STEP_WIN","transitions":[{"after_ms":0,"event_name":"AUDIO_DONE","event_type":"audio_done","id":"TR_STEP_WIN_1","priority":100,"target_step_id":"STEP_DONE","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_DONE","event_type":"serial","id":"TR_STEP_WIN_2","priority":120,"target_step_id":"STEP_DONE","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_REFRESH_SD"],"apps":["APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":true,"screen_scene_id":"SCENE_READY","step_id":"STEP_DONE","transitions":[]}],"version":2,"scenario":"SPECTRE_RADIO_LAB"} diff --git a/hardware/firmware/data/story/scenarios/ZACUS_V1_UNLOCK_ETAPE2.json b/hardware/firmware/data/story/scenarios/ZACUS_V1_UNLOCK_ETAPE2.json index 7bd2f1c..3eadbc9 100644 --- a/hardware/firmware/data/story/scenarios/ZACUS_V1_UNLOCK_ETAPE2.json +++ b/hardware/firmware/data/story/scenarios/ZACUS_V1_UNLOCK_ETAPE2.json @@ -1,52 +1 @@ -{ - "id": "ZACUS_V1_UNLOCK_ETAPE2", - "scenario": "ZACUS_V1_UNLOCK_ETAPE2", - "version": 2, - "initial_step": "STEP_BOOT_WAIT", - "hardware_events": { - "button_short_1": "UNLOCK", - "button_short_5": "BTN_NEXT", - "button_long_3": "FORCE_ETAPE2", - "button_long_4": "FORCE_DONE", - "espnow_event": "SERIAL:" - }, - "app_bindings": [ - "APP_LA", - "APP_AUDIO", - "APP_SCREEN", - "APP_GATE", - "APP_WIFI", - "APP_ESPNOW" - ], - "actions_catalog": [ - "ACTION_TRACE_STEP", - "ACTION_REFRESH_SD" - ], - "steps": [ - { - "id": "STEP_BOOT_WAIT", - "screen_scene_id": "SCENE_LOCKED" - }, - { - "id": "STEP_BOOT_USON", - "screen_scene_id": "SCENE_LOCKED", - "audio_pack_id": "PACK_BOOT_RADIO" - }, - { - "id": "STEP_LA_DETECT", - "screen_scene_id": "SCENE_SEARCH" - }, - { - "id": "STEP_WIN", - "screen_scene_id": "SCENE_REWARD", - "audio_pack_id": "PACK_WIN" - }, - { - "id": "STEP_DONE", - "screen_scene_id": "SCENE_READY" - } - ], - "source": "story_selector", - "screen_root": "/story/screens", - "audio_root": "/story/audio" -} +{"app_bindings":[{"app":"LA_DETECTOR","config":{"hold_ms":3000,"require_listening":true,"unlock_event":"UNLOCK"},"id":"APP_LA"},{"app":"AUDIO_PACK","config":null,"id":"APP_AUDIO"},{"app":"SCREEN_SCENE","config":null,"id":"APP_SCREEN"},{"app":"MP3_GATE","config":null,"id":"APP_GATE"},{"app":"WIFI_STACK","config":null,"id":"APP_WIFI"},{"app":"ESPNOW_STACK","config":null,"id":"APP_ESPNOW"}],"estimated_duration_s":0,"id":"ZACUS_V1_UNLOCK_ETAPE2","initial_step":"STEP_BOOT_WAIT","steps":[{"actions":["ACTION_TRACE_STEP"],"apps":["APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":false,"screen_scene_id":"SCENE_LOCKED","step_id":"STEP_BOOT_WAIT","transitions":[{"after_ms":0,"event_name":"BTN_NEXT","event_type":"serial","id":"TR_STEP_BOOT_WAIT_1","priority":100,"target_step_id":"STEP_BOOT_USON","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_BOOT_RADIO","mp3_gate_open":false,"screen_scene_id":"SCENE_LOCKED","step_id":"STEP_BOOT_USON","transitions":[{"after_ms":0,"event_name":"BTN_NEXT","event_type":"serial","id":"TR_STEP_BOOT_USON_1","priority":100,"target_step_id":"STEP_LA_DETECT","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP"],"apps":["APP_LA","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":false,"screen_scene_id":"SCENE_SEARCH","step_id":"STEP_LA_DETECT","transitions":[{"after_ms":0,"event_name":"UNLOCK","event_type":"unlock","id":"TR_STEP_LA_DETECT_1","priority":120,"target_step_id":"STEP_WIN","trigger":"on_event"},{"after_ms":30000,"event_name":"LA_TIMEOUT","event_type":"timer","id":"TR_STEP_LA_DETECT_2","priority":80,"target_step_id":"STEP_BOOT_USON","trigger":"after_ms"}]},{"actions":["ACTION_TRACE_STEP"],"apps":["APP_AUDIO","APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"PACK_WIN","mp3_gate_open":false,"screen_scene_id":"SCENE_REWARD","step_id":"STEP_WIN","transitions":[{"after_ms":0,"event_name":"AUDIO_DONE","event_type":"audio_done","id":"TR_STEP_WIN_1","priority":100,"target_step_id":"STEP_DONE","trigger":"on_event"},{"after_ms":0,"event_name":"FORCE_DONE","event_type":"serial","id":"TR_STEP_WIN_2","priority":120,"target_step_id":"STEP_DONE","trigger":"on_event"}]},{"actions":["ACTION_TRACE_STEP","ACTION_REFRESH_SD"],"apps":["APP_SCREEN","APP_GATE","APP_WIFI","APP_ESPNOW"],"audio_pack_id":"","mp3_gate_open":true,"screen_scene_id":"SCENE_READY","step_id":"STEP_DONE","transitions":[]}],"version":2,"scenario":"ZACUS_V1_UNLOCK_ETAPE2"} diff --git a/hardware/firmware/data/story/screens/SCENE_BROKEN.json b/hardware/firmware/data/story/screens/SCENE_BROKEN.json deleted file mode 100644 index 2ff7d16..0000000 --- a/hardware/firmware/data/story/screens/SCENE_BROKEN.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "id": "SCENE_BROKEN", - "title": "PROTO U-SON", - "subtitle": "Signal brouille", - "symbol": "ALERT", - "effect": "blink", - "visual": { - "show_title": false, - "show_symbol": true, - "effect_speed_ms": 180 - }, - "theme": { - "bg": "#2A0508", - "accent": "#FF4A45", - "text": "#FFF1F1" - }, - "timeline": { - "loop": true, - "duration_ms": 900, - "keyframes": [ - { - "at_ms": 0, - "effect": "blink", - "speed_ms": 180, - "theme": { - "bg": "#2A0508", - "accent": "#FF4A45", - "text": "#FFF1F1" - } - }, - { - "at_ms": 900, - "effect": "scan", - "speed_ms": 520, - "theme": { - "bg": "#3A0A10", - "accent": "#FF7873", - "text": "#FFF7F7" - } - } - ] - }, - "transition": { - "effect": "glitch", - "duration_ms": 160 - } -} diff --git a/hardware/firmware/data/story/screens/SCENE_CAMERA_SCAN.json b/hardware/firmware/data/story/screens/SCENE_CAMERA_SCAN.json deleted file mode 100644 index a6ad4ae..0000000 --- a/hardware/firmware/data/story/screens/SCENE_CAMERA_SCAN.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "id": "SCENE_CAMERA_SCAN", - "title": "ZACUS QR VALIDATION", - "subtitle": "Scanne le QR final", - "symbol": "QR", - "effect": "none", - "qr": { - "expected": [ - "ZACUS:MEDIA_MANAGER", - "MEDIA_MANAGER_OK" - ], - "prefix": "ZACUS:", - "contains": "MEDIA_MANAGER", - "caseInsensitive": true - }, - "visual": { - "show_title": true, - "show_subtitle": true, - "show_symbol": true, - "effect_speed_ms": 0 - }, - "theme": { - "bg": "#102040", - "accent": "#5CA3FF", - "text": "#F3F7FF" - }, - "timeline": { - "loop": true, - "duration_ms": 1400, - "keyframes": [ - { - "at_ms": 0, - "effect": "none", - "speed_ms": 0, - "theme": { - "bg": "#102040", - "accent": "#5CA3FF", - "text": "#F3F7FF" - } - }, - { - "at_ms": 700, - "effect": "pulse", - "speed_ms": 520, - "theme": { - "bg": "#162B52", - "accent": "#89BEFF", - "text": "#F7FBFF" - } - } - ] - }, - "transition": { - "effect": "fade", - "duration_ms": 180 - } -} diff --git a/hardware/firmware/data/story/screens/SCENE_FIREWORKS.json b/hardware/firmware/data/story/screens/SCENE_FIREWORKS.json deleted file mode 100644 index 10abc9f..0000000 --- a/hardware/firmware/data/story/screens/SCENE_FIREWORKS.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "id": "SCENE_FIREWORKS", - "title": "FIREWORKS", - "subtitle": "Mode celebration", - "symbol": "WIN", - "effect": "celebrate", - "visual": { - "show_title": true, - "show_symbol": true, - "effect_speed_ms": 300 - }, - "demo": { - "mode": "fireworks", - "particle_count": 4, - "strobe_level": 90 - }, - "theme": { - "bg": "#120825", - "accent": "#FFB65C", - "text": "#FFF4E6" - }, - "timeline": { - "loop": true, - "duration_ms": 1000, - "keyframes": [ - { - "at_ms": 0, - "effect": "celebrate", - "speed_ms": 300, - "theme": { - "bg": "#120825", - "accent": "#FFB65C", - "text": "#FFF4E6" - } - }, - { - "at_ms": 1000, - "effect": "blink", - "speed_ms": 220, - "theme": { - "bg": "#1C0A31", - "accent": "#FFD68D", - "text": "#FFFDF6" - } - } - ] - }, - "transition": { - "effect": "glitch", - "duration_ms": 180 - } -} diff --git a/hardware/firmware/data/story/screens/SCENE_LA_DETECT.json b/hardware/firmware/data/story/screens/SCENE_LA_DETECT.json deleted file mode 100644 index 709c8ee..0000000 --- a/hardware/firmware/data/story/screens/SCENE_LA_DETECT.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "id": "SCENE_LA_DETECT", - "title": "DETECTEUR DE RESONNANCE", - "subtitle": "", - "symbol": "AUDIO", - "effect": "wave", - "visual": { - "show_title": true, - "show_symbol": true, - "effect_speed_ms": 480, - "waveform": { - "enabled": true, - "sample_count": 16, - "amplitude_pct": 100, - "jitter": true - } - }, - "theme": { - "bg": "#000000", - "accent": "#49D9FF", - "text": "#E8F6FF" - }, - "timeline": { - "loop": true, - "duration_ms": 2400, - "keyframes": [ - { - "at_ms": 0, - "effect": "wave", - "speed_ms": 480, - "theme": { - "bg": "#000000", - "accent": "#49D9FF", - "text": "#E8F6FF" - } - }, - { - "at_ms": 800, - "effect": "radar", - "speed_ms": 620, - "theme": { - "bg": "#000000", - "accent": "#7EE8FF", - "text": "#F2FAFF" - } - }, - { - "at_ms": 1600, - "effect": "wave", - "speed_ms": 340, - "theme": { - "bg": "#000000", - "accent": "#D8FF6B", - "text": "#F9FFD8" - } - }, - { - "at_ms": 2400, - "effect": "radar", - "speed_ms": 700, - "theme": { - "bg": "#000000", - "accent": "#49D9FF", - "text": "#E8F6FF" - } - } - ] - }, - "transition": { - "effect": "zoom", - "duration_ms": 260 - } -} diff --git a/hardware/firmware/data/story/screens/SCENE_MEDIA_ARCHIVE.json b/hardware/firmware/data/story/screens/SCENE_MEDIA_ARCHIVE.json deleted file mode 100644 index 3b02737..0000000 --- a/hardware/firmware/data/story/screens/SCENE_MEDIA_ARCHIVE.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "id": "SCENE_MEDIA_ARCHIVE", - "title": "ARCHIVES MEDIA", - "subtitle": "Photos et enregistrements sauvegardes", - "symbol": "READY", - "effect": "radar", - "visual": { - "show_title": false, - "show_symbol": true, - "effect_speed_ms": 760 - }, - "theme": { - "bg": "#0D1A34", - "accent": "#7CB1FF", - "text": "#EEF4FF" - }, - "timeline": { - "loop": true, - "duration_ms": 2000, - "keyframes": [ - { - "at_ms": 0, - "effect": "radar", - "speed_ms": 760, - "theme": { - "bg": "#0D1A34", - "accent": "#7CB1FF", - "text": "#EEF4FF" - } - }, - { - "at_ms": 1000, - "effect": "pulse", - "speed_ms": 620, - "theme": { - "bg": "#132245", - "accent": "#9CC7FF", - "text": "#F7FAFF" - } - }, - { - "at_ms": 2000, - "effect": "radar", - "speed_ms": 760, - "theme": { - "bg": "#0D1A34", - "accent": "#7CB1FF", - "text": "#EEF4FF" - } - } - ] - }, - "transition": { - "effect": "fade", - "duration_ms": 240 - } -} diff --git a/hardware/firmware/data/story/screens/SCENE_SIGNAL_SPIKE.json b/hardware/firmware/data/story/screens/SCENE_SIGNAL_SPIKE.json deleted file mode 100644 index 9b3b783..0000000 --- a/hardware/firmware/data/story/screens/SCENE_SIGNAL_SPIKE.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "id": "SCENE_SIGNAL_SPIKE", - "title": "PIC DE SIGNAL", - "subtitle": "Interference soudaine detectee", - "symbol": "ALERT", - "effect": "wave", - "visual": { - "show_title": false, - "show_symbol": true, - "effect_speed_ms": 260 - }, - "theme": { - "bg": "#24090C", - "accent": "#FF6A52", - "text": "#FFF2EB" - }, - "timeline": { - "loop": true, - "duration_ms": 1400, - "keyframes": [ - { - "at_ms": 0, - "effect": "wave", - "speed_ms": 260, - "theme": { - "bg": "#24090C", - "accent": "#FF6A52", - "text": "#FFF2EB" - } - }, - { - "at_ms": 700, - "effect": "blink", - "speed_ms": 180, - "theme": { - "bg": "#2F1014", - "accent": "#FF8C73", - "text": "#FFF8F5" - } - }, - { - "at_ms": 1400, - "effect": "wave", - "speed_ms": 320, - "theme": { - "bg": "#24090C", - "accent": "#FF6A52", - "text": "#FFF2EB" - } - } - ] - }, - "transition": { - "effect": "glitch", - "duration_ms": 170 - } -} diff --git a/hardware/firmware/data/story/screens/SCENE_WIN.json b/hardware/firmware/data/story/screens/SCENE_WIN.json deleted file mode 100644 index bf8b889..0000000 --- a/hardware/firmware/data/story/screens/SCENE_WIN.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "id": "SCENE_WIN", - "title": "VICTOIRE", - "subtitle": "Etape validee", - "symbol": "WIN", - "effect": "celebrate", - "visual": { - "show_title": false, - "show_symbol": true, - "effect_speed_ms": 420 - }, - "theme": { - "bg": "#231038", - "accent": "#F4CB4A", - "text": "#FFF8E2" - }, - "timeline": { - "loop": true, - "duration_ms": 1000, - "keyframes": [ - { - "at_ms": 0, - "effect": "celebrate", - "speed_ms": 420, - "theme": { - "bg": "#231038", - "accent": "#F4CB4A", - "text": "#FFF8E2" - } - }, - { - "at_ms": 1000, - "effect": "blink", - "speed_ms": 240, - "theme": { - "bg": "#341A4D", - "accent": "#FFE083", - "text": "#FFFDF3" - } - } - ] - }, - "transition": { - "effect": "zoom", - "duration_ms": 280 - } -} diff --git a/hardware/firmware/data/story/screens/SCENE_WINNER.json b/hardware/firmware/data/story/screens/SCENE_WINNER.json deleted file mode 100644 index 74fbff4..0000000 --- a/hardware/firmware/data/story/screens/SCENE_WINNER.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "id": "SCENE_WINNER", - "title": "WINNER", - "subtitle": "Mode Winner actif", - "symbol": "WIN", - "effect": "celebrate", - "visual": { - "show_title": true, - "show_symbol": true, - "effect_speed_ms": 320 - }, - "demo": { - "mode": "arcade", - "particle_count": 3, - "strobe_level": 75 - }, - "theme": { - "bg": "#1D0E33", - "accent": "#FFD36C", - "text": "#FFF7DE" - }, - "timeline": { - "loop": true, - "duration_ms": 1200, - "keyframes": [ - { - "at_ms": 0, - "effect": "celebrate", - "speed_ms": 320, - "theme": { - "bg": "#1D0E33", - "accent": "#FFD36C", - "text": "#FFF7DE" - } - }, - { - "at_ms": 1200, - "effect": "pulse", - "speed_ms": 260, - "theme": { - "bg": "#2B1450", - "accent": "#FFE39A", - "text": "#FFFEF6" - } - } - ] - }, - "transition": { - "effect": "zoom", - "duration_ms": 220 - } -} diff --git a/hardware/firmware/data/story/screens/SCENE_WIN_ETAPE.json b/hardware/firmware/data/story/screens/SCENE_WIN_ETAPE.json deleted file mode 100644 index debef0e..0000000 --- a/hardware/firmware/data/story/screens/SCENE_WIN_ETAPE.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "id": "SCENE_WIN_ETAPE", - "title": "VICTOIRE", - "subtitle": "", - "symbol": "WIN", - "effect": "celebrate", - "visual": { - "show_title": false, - "show_symbol": true, - "effect_speed_ms": 420 - }, - "theme": { - "bg": "#231038", - "accent": "#F4CB4A", - "text": "#FFF8E2" - }, - "timeline": { - "loop": true, - "duration_ms": 1000, - "keyframes": [ - { - "at_ms": 0, - "effect": "celebrate", - "speed_ms": 420, - "theme": { - "bg": "#231038", - "accent": "#F4CB4A", - "text": "#FFF8E2" - } - }, - { - "at_ms": 1000, - "effect": "blink", - "speed_ms": 240, - "theme": { - "bg": "#341A4D", - "accent": "#FFE083", - "text": "#FFFDF3" - } - } - ] - }, - "transition": { - "effect": "zoom", - "duration_ms": 280 - } -} diff --git a/hardware/firmware/docs/AGENT_TODO.md b/hardware/firmware/docs/AGENT_TODO.md index 0dba0b4..e7a8a08 100644 --- a/hardware/firmware/docs/AGENT_TODO.md +++ b/hardware/firmware/docs/AGENT_TODO.md @@ -1,3 +1,105 @@ +## [2026-02-25] Clean ecrans - reduction du catalogue LittleFS (phase 1) + +- Checkpoint securite: + - `/tmp/zacus_checkpoint/20260225_202801_wip.patch` + - `/tmp/zacus_checkpoint/20260225_202801_status.txt` +- Scope: + - `data/story/screens/*.json` + - `game/scenarios/scene_editor_all.yaml` + - `game/scenarios/scenario_reel_template.yaml` +- Actions: + - suppression de 9 ecrans non utilises par le runtime principal: + - `SCENE_BROKEN`, `SCENE_CAMERA_SCAN`, `SCENE_FIREWORKS`, `SCENE_LA_DETECT`, + `SCENE_MEDIA_ARCHIVE`, `SCENE_SIGNAL_SPIKE`, `SCENE_WIN`, `SCENE_WINNER`, `SCENE_WIN_ETAPE`. + - regeneration workbench scenes: + - `python3 tools/dev/export_scene_editor_workbench.py` + - suppression des references YAML `screen_json` obsoletes dans `scenario_reel_template.yaml` (catalogues ecrans + triggers scenes). +- Resultat: + - `data/story/screens`: 24 -> 15 fichiers. + - `scene_editor_all.yaml`: `unused_scene_ids` reduit de 15 -> 6. +- Gates/evidence: + - `./tools/dev/story-gen validate` ✅ + - parse JSON `data/story/screens/*.json` ✅ (`json_screens_ok 15`) + - check refs `screen_json` YAML manquants ✅ (`missing_screen_json_refs 0`) + - `python3 ../../tools/scenario/validate_scenario.py ../../game/scenarios/zacus_v1.yaml` ✅ + - `python3 ../../tools/scenario/export_md.py ../../game/scenarios/zacus_v1.yaml` ✅ + - `python3 ../../tools/audio/validate_manifest.py ../../audio/manifests/zacus_v1_audio.yaml` ✅ + - `python3 ../../tools/printables/validate_manifest.py ../../printables/manifests/zacus_v1_printables.yaml` ✅ + - `pio run -e freenove_esp32s3_full_with_ui -t buildfs` ✅ + +## [2026-02-25] Clean ecrans (screens) - sync workbench + gates + +- Scope: + - `game/scenarios/scene_editor_all.yaml` + - `data/story/screens/*.json` + - `data/screens/*.json` +- Actions: + - regeneration du workbench ecrans depuis les JSON canoniques: + - `python3 tools/dev/export_scene_editor_workbench.py` + - controle coherence tokens UI (`effect`, `timeline.keyframes[].effect`, `transition.effect`) contre le parseur runtime `ui_manager.cpp`: aucun token invalide detecte. + - controle JSON des ecrans (`data/story/screens` + `data/screens`): parse OK. +- Resultat: + - `game/scenarios/scene_editor_all.yaml` resynchronise avec l'etat reel des ecrans runtime. + - aucune derive restante detectee sur les 6 mirrors legacy `data/screens/*.json` (alignes avec `data/story/screens/SCENE_*.json` correspondants). +- Gates/evidence: + - `./tools/dev/story-gen validate` ✅ + - `jq empty` sur `data/story/screens/*.json` et `data/screens/*.json` ✅ + - `pio run -e freenove_esp32s3_full_with_ui -t buildfs` ✅ + +## [2026-02-25] Clean global scenario/scene (YAML + code + assets) + +- Skills utilises (ordre): + - `firmware-story-stack` + - `firmware-littlefs-stack` +- Checkpoint securite: + - `/tmp/zacus_checkpoint/20260225_200958_wip.patch` + - `/tmp/zacus_checkpoint/20260225_200958_status.txt` +- Clean applique: + - `lib/zacus_story_gen_ai/src/zacus_story_gen_ai/generator.py` + - classification `workbench` ajoutee pour ignorer les YAML d'edition scene (`meta` + `scenes`) dans `story-gen validate`. + - resolution alias actions ajoutee pour les noms courts LittleFS: + - `ACTION_QR_CODE_SCANNER_START` -> `ACTION_QR_SCAN_START` + - `ACTION_SET_BOOT_MEDIA_MANAGER` -> `ACTION_BOOT_MEDIA_MGR` + - runtime Freenove: + - `ui_freenove_allinone/src/app/main.cpp` + - `ui_freenove_allinone/src/main.cpp` + - `executeStoryAction` charge maintenant d'abord `ACTION_ID.json`, puis fallback alias fichier court si absent. +- Gates/evidence: + - `./tools/dev/story-gen validate` ✅ (`scenarios=5`, `game_scenarios=2`) + - `./tools/dev/story-gen generate-cpp` ✅ (`spec_hash=aa9658456a0d`) + - `./tools/dev/story-gen generate-bundle --out-dir /tmp/zacus_story_bundle_clean_20260225_201347` ✅ + - verification assets actions generes: + - `/tmp/zacus_story_bundle_clean_20260225_201347/story/actions/ACTION_QR_CODE_SCANNER_START.json` (type/config presents) + - `/tmp/zacus_story_bundle_clean_20260225_201347/story/actions/ACTION_SET_BOOT_MEDIA_MANAGER.json` (type/config presents) + - `pio run -e freenove_esp32s3` ✅ + - `pio run -e freenove_esp32s3_full_with_ui -t buildfs` ✅ + +## [2026-02-25] Audit + clean dossier data (story/littlefs) + +- Skills utilises (ordre): + - `firmware-story-stack` + - `firmware-littlefs-stack` +- Checkpoint securite: + - `/tmp/zacus_checkpoint/20260225_195727_wip.patch` + - `/tmp/zacus_checkpoint/20260225_195727_status.txt` +- Audit `data/`: + - 89 fichiers, 16 dossiers, aucun fichier temporaire suspect detecte. + - derive detectee entre fallback legacy `/screens/*` et canonique `/story/screens/*` pour: + - `data/screens/la_detector.json` + - `data/screens/locked.json` + - fichier legacy non reference detecte: + - `data/scenarios/data/default_scenario.json` +- Clean applique: + - synchronisation fallback `/screens` avec les JSON canoniques: + - `data/screens/la_detector.json` -> aligne sur `data/story/screens/SCENE_LA_DETECTOR.json` + - `data/screens/locked.json` -> aligne sur `data/story/screens/SCENE_LOCKED.json` + - suppression du legacy non reference: + - `data/scenarios/data/default_scenario.json` +- Gates/evidence: + - parse JSON complet `data/**/*.json` via `jq empty` ✅ + - `pio run -e freenove_esp32s3_full_with_ui -t buildfs` ✅ + - note: `./tools/dev/story-gen validate` echoue sur `../../game/scenarios/scene_editor_all.yaml` (format workbench non reconnu), anomalie preexistante hors clean `data/`. + ## [2026-02-25] Preparation test utilisateur reel (runbook) - Carte preparee pour test terrain: @@ -2106,3 +2208,26 @@ - `~/.codex/skills/scene-verificator/scripts/run_scene_verification.sh /dev/cu.usbmodem5AB90753301 115200` ✅ - `~/.codex/skills/fx-verificator/scripts/run_fx_verification.sh /dev/cu.usbmodem5AB90753301 115200` ✅ - `~/.codex/skills/hal-verificator-status/scripts/run_hal_verification.sh /dev/cu.usbmodem5AB90753301 115200` ✅ + +## Correction SDMMC - diagnostic carte/FS/lecteur (2026-02-25) + +- Checkpoint securite: + - `/tmp/zacus_checkpoint/20260225-194217_wip.patch` + - `/tmp/zacus_checkpoint/20260225-194217_status.txt` + - scan artefacts trackes (`.pio/.platformio/logs/dist/build/node_modules/.venv`) -> aucun tracke. +- Cause identifiee: + - les lectures `/story/*` passaient par SD en priorite (`readTextFileWithOrigin`), ce qui exposait le runtime aux erreurs `diskio_sdmmc` en cas de carte instable, meme quand LittleFS contenait deja les assets. +- Correctif applique (`ui_freenove_allinone/src/storage/storage_manager.cpp`): + - fallback runtime passe en **LittleFS d'abord**, SD ensuite (sauf chemin force `/sd/...`), + - surveillance `errno` sur `SD_MMC.exists/open/read`, + - compteur d'echecs SD (`sd_failure_streak_`) + coupure SD auto apres erreurs I/O repetees, + - remount SD explicite tente dans `syncStoryFileFromSd`/`syncStoryTreeFromSd` quand SD etait degrade. +- Interface mise a jour: + - `ui_freenove_allinone/include/storage/storage_manager.h` (etat SD mutable + helpers de diagnostic). +- Build/upload: + - `pio run -e freenove_esp32s3` ✅ + - `pio run -e freenove_esp32s3 -t upload --upload-port /dev/cu.usbmodem5AB90753301` ✅ +- Validation live: + - log diagnostic: `logs/sdmmc_diag_20260225-195139.log` + - resultat: `SUMMARY sd_errors=0 panic_markers=0 ack_next_ok=10 ack_next_fail=0` + - gate smoke: `python3 tools/dev/serial_smoke.py --role esp32 --port /dev/cu.usbmodem5AB90753301 --baud 115200 --timeout 10 --wait-port 20` ✅ diff --git a/hardware/firmware/hardware/firmware/ui_freenove_allinone/include/storage/storage_manager.h b/hardware/firmware/hardware/firmware/ui_freenove_allinone/include/storage/storage_manager.h index 7f41c6a..8fa40c8 100644 --- a/hardware/firmware/hardware/firmware/ui_freenove_allinone/include/storage/storage_manager.h +++ b/hardware/firmware/hardware/firmware/ui_freenove_allinone/include/storage/storage_manager.h @@ -40,6 +40,9 @@ class StorageManager { bool copyFileFromSdToLittleFs(const char* src_path, const char* dst_path) const; bool copyStoryDirectoryFromSd(const char* relative_dir); String resolveReadableAssetPath(const String& absolute_path) const; + void noteSdAccessFailure(const char* operation, const char* path, int error_code) const; + void noteSdAccessSuccess() const; - bool sd_ready_ = false; + mutable bool sd_ready_ = false; + mutable uint8_t sd_failure_streak_ = 0U; }; diff --git a/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/app/main.cpp b/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/app/main.cpp index bff8f26..2032166 100644 --- a/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/app/main.cpp +++ b/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/app/main.cpp @@ -2611,7 +2611,22 @@ bool executeStoryAction(const char* action_id, const ScenarioSnapshot& snapshot, } const String action_path = String("/story/actions/") + action_id + ".json"; - const String payload = g_storage.loadTextFile(action_path.c_str()); + String payload = g_storage.loadTextFile(action_path.c_str()); + if (payload.isEmpty()) { + const char* alias_id = nullptr; + if (std::strcmp(action_id, "ACTION_QR_CODE_SCANNER_START") == 0) { + alias_id = "ACTION_QR_SCAN_START"; + } else if (std::strcmp(action_id, "ACTION_SET_BOOT_MEDIA_MANAGER") == 0) { + alias_id = "ACTION_BOOT_MEDIA_MGR"; + } + if (alias_id != nullptr) { + const String alias_path = String("/story/actions/") + alias_id + ".json"; + payload = g_storage.loadTextFile(alias_path.c_str()); + if (!payload.isEmpty()) { + Serial.printf("[ACTION] payload alias id=%s file=%s\n", action_id, alias_id); + } + } + } StaticJsonDocument<512> action_doc; if (!payload.isEmpty()) { deserializeJson(action_doc, payload); diff --git a/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/app/scenario_manager.cpp b/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/app/scenario_manager.cpp index c71b032..67d7cf9 100644 --- a/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/app/scenario_manager.cpp +++ b/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/app/scenario_manager.cpp @@ -635,6 +635,12 @@ void ScenarioManager::loadStepResourceOverrides(const char* scenario_file_path) } JsonObjectConst step_obj = variant.as(); const char* step_id = stringOrNull(step_obj["id"]); + if (step_id == nullptr) { + step_id = stringOrNull(step_obj["step_id"]); + } + if (step_id == nullptr) { + step_id = stringOrNull(step_obj["stepId"]); + } if (step_id == nullptr) { continue; } @@ -660,6 +666,9 @@ void ScenarioManager::loadStepResourceOverrides(const char* scenario_file_path) if (action_ids.isNull()) { action_ids = step_obj["actionIds"].as(); } + if (action_ids.isNull()) { + action_ids = step_obj["actions"].as(); + } if (action_ids.isNull()) { action_ids = step_obj["resources"]["action_ids"].as(); } diff --git a/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/main.cpp b/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/main.cpp index 02a47cc..46f6cb6 100644 --- a/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/main.cpp +++ b/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/main.cpp @@ -1534,7 +1534,22 @@ bool executeStoryAction(const char* action_id, const ScenarioSnapshot& snapshot, return false; } const String action_path = String("/story/actions/") + action_id + ".json"; - const String payload = g_storage.loadTextFile(action_path.c_str()); + String payload = g_storage.loadTextFile(action_path.c_str()); + if (payload.isEmpty()) { + const char* alias_id = nullptr; + if (std::strcmp(action_id, "ACTION_QR_CODE_SCANNER_START") == 0) { + alias_id = "ACTION_QR_SCAN_START"; + } else if (std::strcmp(action_id, "ACTION_SET_BOOT_MEDIA_MANAGER") == 0) { + alias_id = "ACTION_BOOT_MEDIA_MGR"; + } + if (alias_id != nullptr) { + const String alias_path = String("/story/actions/") + alias_id + ".json"; + payload = g_storage.loadTextFile(alias_path.c_str()); + if (!payload.isEmpty()) { + Serial.printf("[ACTION] payload alias id=%s file=%s\n", action_id, alias_id); + } + } + } StaticJsonDocument<512> action_doc; if (!payload.isEmpty()) { deserializeJson(action_doc, payload); diff --git a/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/scenario_manager.cpp b/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/scenario_manager.cpp index 945e9b7..be71012 100644 --- a/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/scenario_manager.cpp +++ b/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/scenario_manager.cpp @@ -549,6 +549,12 @@ void ScenarioManager::loadStepResourceOverrides(const char* scenario_file_path) } JsonObjectConst step_obj = variant.as(); const char* step_id = stringOrNull(step_obj["id"]); + if (step_id == nullptr) { + step_id = stringOrNull(step_obj["step_id"]); + } + if (step_id == nullptr) { + step_id = stringOrNull(step_obj["stepId"]); + } if (step_id == nullptr) { continue; } @@ -574,6 +580,9 @@ void ScenarioManager::loadStepResourceOverrides(const char* scenario_file_path) if (action_ids.isNull()) { action_ids = step_obj["actionIds"].as(); } + if (action_ids.isNull()) { + action_ids = step_obj["actions"].as(); + } if (action_ids.isNull()) { action_ids = step_obj["resources"]["action_ids"].as(); } diff --git a/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/storage/storage_manager.cpp b/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/storage/storage_manager.cpp index c6f9c29..b0eea1c 100644 --- a/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/storage/storage_manager.cpp +++ b/hardware/firmware/hardware/firmware/ui_freenove_allinone/src/storage/storage_manager.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "resources/screen_scene_registry.h" #include "scenarios/default_scenario_v2.h" @@ -49,6 +50,8 @@ constexpr EmbeddedStoryAsset kEmbeddedStoryAssets[] = { {"/story/scenarios/DEFAULT.json", R"JSON({"scenario":"DEFAULT","source":"embedded_minimal"})JSON"}, }; +constexpr uint8_t kSdFailureDisableThreshold = 3U; + uint32_t fnv1aUpdate(uint32_t hash, uint8_t value) { hash ^= value; @@ -182,6 +185,7 @@ bool StorageManager::mountSdCard() { } Serial.printf("[FS] SD_MMC mounted size=%lluMB\n", static_cast(SD_MMC.cardSize() / (1024ULL * 1024ULL))); + sd_failure_streak_ = 0U; return true; #else return false; @@ -249,7 +253,17 @@ bool StorageManager::pathExistsOnSdCard(const char* path) const { if (sd_path.isEmpty()) { return false; } - return SD_MMC.exists(sd_path.c_str()); + errno = 0; + const bool exists = SD_MMC.exists(sd_path.c_str()); + const int error_code = errno; + if (exists) { + noteSdAccessSuccess(); + return true; + } + if (error_code != 0 && error_code != ENOENT) { + noteSdAccessFailure("exists", sd_path.c_str(), error_code); + } + return false; #else (void)path; return false; @@ -285,22 +299,39 @@ bool StorageManager::readTextFromLittleFs(const char* path, String* out_payload) } bool StorageManager::readTextFromSdCard(const char* path, String* out_payload) const { - if (out_payload == nullptr || !pathExistsOnSdCard(path)) { + if (out_payload == nullptr || !sd_ready_) { return false; } #if ZACUS_HAS_SD_MMC const String sd_path = stripSdPrefix(path); + if (sd_path.isEmpty()) { + return false; + } + errno = 0; File file = SD_MMC.open(sd_path.c_str(), "r"); - if (!file) { - RuntimeMetrics::instance().noteSdError(); + const int open_error = errno; + if (!file || file.isDirectory()) { + if (file) { + file.close(); + } + if (open_error != 0 && open_error != ENOENT) { + noteSdAccessFailure("open", sd_path.c_str(), open_error); + } return false; } out_payload->remove(0); out_payload->reserve(static_cast(file.size()) + 1U); while (file.available()) { - *out_payload += static_cast(file.read()); + const int value = file.read(); + if (value < 0) { + file.close(); + noteSdAccessFailure("read", sd_path.c_str(), EIO); + return false; + } + *out_payload += static_cast(value); } file.close(); + noteSdAccessSuccess(); return !out_payload->isEmpty(); #else (void)path; @@ -317,7 +348,6 @@ bool StorageManager::readTextFileWithOrigin(const char* path, String* out_payloa return false; } const bool force_sd = startsWithIgnoreCase(normalized.c_str(), "/sd/"); - const bool prefer_sd = !force_sd && startsWithIgnoreCase(normalized.c_str(), "/story/"); String payload; if (force_sd) { @@ -332,13 +362,6 @@ bool StorageManager::readTextFileWithOrigin(const char* path, String* out_payloa return true; } - if (prefer_sd && readTextFromSdCard(normalized.c_str(), &payload)) { - *out_payload = payload; - if (out_origin != nullptr) { - *out_origin = "/sd" + stripSdPrefix(normalized.c_str()); - } - return true; - } if (readTextFromLittleFs(normalized.c_str(), &payload)) { *out_payload = payload; if (out_origin != nullptr) { @@ -576,13 +599,16 @@ bool StorageManager::copyFileFromSdToLittleFs(const char* src_path, const char* } #if ZACUS_HAS_SD_MMC if (!pathExistsOnSdCard(src_path)) { - RuntimeMetrics::instance().noteSdError(); return false; } const String sd_path = stripSdPrefix(src_path); + errno = 0; File src = SD_MMC.open(sd_path.c_str(), "r"); + const int open_error = errno; if (!src) { - RuntimeMetrics::instance().noteSdError(); + if (open_error != 0 && open_error != ENOENT) { + noteSdAccessFailure("open", sd_path.c_str(), open_error); + } return false; } if (!ensureParentDirectoriesOnLittleFs(dst_path)) { @@ -592,24 +618,26 @@ bool StorageManager::copyFileFromSdToLittleFs(const char* src_path, const char* File dst = LittleFS.open(dst_path, "w"); if (!dst) { src.close(); - RuntimeMetrics::instance().noteSdError(); return false; } uint8_t buffer[512]; while (src.available()) { const size_t read_bytes = src.read(buffer, sizeof(buffer)); if (read_bytes == 0U) { - break; + src.close(); + dst.close(); + noteSdAccessFailure("read", sd_path.c_str(), EIO); + return false; } if (dst.write(buffer, read_bytes) != read_bytes) { dst.close(); src.close(); - RuntimeMetrics::instance().noteSdError(); return false; } } dst.close(); src.close(); + noteSdAccessSuccess(); return true; #else (void)src_path; @@ -619,7 +647,10 @@ bool StorageManager::copyFileFromSdToLittleFs(const char* src_path, const char* } bool StorageManager::syncStoryFileFromSd(const char* story_path) { - if (!sd_ready_ || story_path == nullptr || story_path[0] == '\0') { + if (story_path == nullptr || story_path[0] == '\0') { + return false; + } + if (!sd_ready_ && !mountSdCard()) { return false; } const String normalized = normalizeAbsolutePath(story_path); @@ -634,7 +665,10 @@ bool StorageManager::syncStoryFileFromSd(const char* story_path) { } bool StorageManager::copyStoryDirectoryFromSd(const char* relative_dir) { - if (!sd_ready_ || relative_dir == nullptr || relative_dir[0] == '\0') { + if (relative_dir == nullptr || relative_dir[0] == '\0') { + return false; + } + if (!sd_ready_ && !mountSdCard()) { return false; } #if ZACUS_HAS_SD_MMC @@ -692,7 +726,7 @@ bool StorageManager::provisionEmbeddedAsset(const char* path, } bool StorageManager::syncStoryTreeFromSd() { - if (!sd_ready_) { + if (!sd_ready_ && !mountSdCard()) { return false; } const char* story_dirs[] = {"scenarios", "screens", "audio", "apps", "actions"}; @@ -760,6 +794,38 @@ bool StorageManager::hasSdCard() const { return sd_ready_; } +void StorageManager::noteSdAccessFailure(const char* operation, const char* path, int error_code) const { +#if ZACUS_HAS_SD_MMC + RuntimeMetrics::instance().noteSdError(); + if (error_code == 0 || error_code == ENOENT) { + return; + } + + if (sd_failure_streak_ < 255U) { + ++sd_failure_streak_; + } + Serial.printf("[FS] SD_MMC %s failed path=%s errno=%d streak=%u\n", + operation != nullptr ? operation : "op", + path != nullptr ? path : "-", + error_code, + static_cast(sd_failure_streak_)); + + if (sd_failure_streak_ >= kSdFailureDisableThreshold && sd_ready_) { + SD_MMC.end(); + sd_ready_ = false; + Serial.println("[FS] SD_MMC disabled after repeated I/O failures; fallback=LittleFS"); + } +#else + (void)operation; + (void)path; + (void)error_code; +#endif +} + +void StorageManager::noteSdAccessSuccess() const { + sd_failure_streak_ = 0U; +} + uint32_t StorageManager::checksum(const char* path) const { const String normalized = normalizeAbsolutePath(path); if (normalized.isEmpty()) { diff --git a/hardware/firmware/lib/zacus_story_gen_ai/src/zacus_story_gen_ai/generator.py b/hardware/firmware/lib/zacus_story_gen_ai/src/zacus_story_gen_ai/generator.py index c39af8a..d542d2d 100644 --- a/hardware/firmware/lib/zacus_story_gen_ai/src/zacus_story_gen_ai/generator.py +++ b/hardware/firmware/lib/zacus_story_gen_ai/src/zacus_story_gen_ai/generator.py @@ -64,6 +64,12 @@ APP_CPP = { "QR_UNLOCK_APP": "StoryAppType::kQrUnlockApp", } +ACTION_FILE_ALIASES = { + # Keep long action IDs in YAML/runtime while allowing short LittleFS filenames. + "ACTION_QR_CODE_SCANNER_START": "ACTION_QR_SCAN_START", + "ACTION_SET_BOOT_MEDIA_MANAGER": "ACTION_BOOT_MEDIA_MGR", +} + DEFAULT_SCENE_PROFILE: dict[str, Any] = { "title": "MISSION", "subtitle": "", @@ -966,6 +972,13 @@ def _classify_game_yaml(file_path: Path) -> str: has_runtime = bool(doc.get("initial_step")) and isinstance(doc.get("steps"), list) has_narrative = bool(doc.get("title")) and isinstance(doc.get("stations"), list) has_template = isinstance(doc.get("prompt_input"), dict) + has_workbench = isinstance(doc.get("meta"), dict) and isinstance(doc.get("scenes"), list) + if has_workbench and not has_runtime and not has_narrative and not has_template: + return "workbench" + if has_workbench and (has_runtime or has_narrative or has_template): + raise StoryGenerationError( + f"Ambiguous game scenario type in {file_path}: workbench mixed with runtime/narrative/template keys detected" + ) if has_template and not has_runtime and not has_narrative: return "template" if has_runtime and has_narrative: @@ -1145,6 +1158,11 @@ def _resource_candidates(resource_root: Path, resource_type: str, resource_id: s elif resource_type == "audio": slug = _resource_slug(resource_id, "PACK_") candidates.append(base / f"{slug}.json") + elif resource_type == "actions": + alias = ACTION_FILE_ALIASES.get(resource_id) + if alias: + candidates.append(base / f"{alias}.json") + candidates.append(base / f"{alias.lower()}.json") # de-duplicate while preserving order dedup: list[Path] = [] @@ -1629,6 +1647,8 @@ def load_and_validate(paths: StoryPaths, spec_dir: Path | None = None, game_dir: narrative_game_files.append(file_path) elif category == "template": template_files.append(file_path) + elif category == "workbench": + continue _validate_yamale(_schema_path("story_spec_schema.yamale"), spec_files) if runtime_game_files: