diff --git a/AI/CHANGELOG.md b/AI/CHANGELOG.md
index 046661e..6571de5 100644
--- a/AI/CHANGELOG.md
+++ b/AI/CHANGELOG.md
@@ -29,6 +29,13 @@
## [Unreleased]
+### Changed — Tutorial prompts are pad arrows in one centered cue
+- **Scope:** component:Tutorial
+- **What:** `TutorialInputLabels` returns fixed pad glyphs (`←`, `→`, `↓`) instead of binding display strings, and `SetContinueVisible` shows the `↓` cue in the large centered `BindingLabel` rather than the small bottom-right `ContinuePrompt` chip, which is now always hidden. Wrong-direction hints follow the same glyphs ("Try →", "Press ↓").
+- **Why:** The cabinet input is a dance pad, so a key name like "A" or "J" describes something no player can see, and the same lesson looked different depending on which player took it. The advance chip was also unreadable at cabinet distance while the move cue next to it was large.
+- **Impact:** Every prompt in the lesson now appears in one place at one size. This intentionally supersedes part of the per-player key hints below: cues are pad arrows for both players. Input routing and remapping are untouched, so P2 still plays on the Player2 map.
+- **Refs:** `TutorialInputLabels.cs`, `TutorialController.cs`, `TutorialLessonConfig.cs`, `DefaultTutorialLesson.asset`, `Tutorial.md` (0.6.0 -> 0.6.1)
+
### Fixed — 2P tutorial shows Player 2's control hints on P2's turn
- **Scope:** component:Tutorial
- **What:** `TutorialInputLabels` now resolves binding display strings from the active tutorial player's map (`Player2` = arrow keys when `ActiveTutorialPlayerIndex == 1`) instead of always Player1 (A / D / X). Gameplay + dialogue input were already routed to the Player2 map for P2's turn; only the on-screen LEFT / RIGHT / PLACE hints were stuck on P1 keys.
diff --git a/AI/COMPONENT_INDEX.md b/AI/COMPONENT_INDEX.md
index e4e1acf..c8edf5c 100644
--- a/AI/COMPONENT_INDEX.md
+++ b/AI/COMPONENT_INDEX.md
@@ -19,7 +19,7 @@ Each component has a self-contained doc that lists its own files, tokens, animat
| Song Carousel | [components/SongCarousel.md](./components/SongCarousel.md) | Component | `Assets/UI/Style1/SongCarousel/` | Stable | 1.0.0 | carousel, songs, selection, scroll |
| **Title Screen** | [components/TitleScreen.md](./components/TitleScreen.md) | Component | `Assets/Menu/TitleScreen/` | Beta | 0.2.2 | title, menu, 1P, 2P, vs-bot, tutorial, pushdown-automata |
| **Player vs Bot** | [components/PlayerVsBot.md](./components/PlayerVsBot.md) | Integration | `Assets/Bot/` | Beta | 0.2.0 | bot, difficulty, two-player, session, tier-names |
-| **Tutorial** | [components/Tutorial.md](./components/Tutorial.md) | Integration | `Assets/Tutorial/` | Beta | 0.6.0 | tutorial, bst, tree, style1, menu-flow, metronome, sample-play, authored-scene, guide-style |
+| **Tutorial** | [components/Tutorial.md](./components/Tutorial.md) | Integration | `Assets/Tutorial/` | Beta | 0.6.1 | tutorial, bst, tree, style1, menu-flow, metronome, sample-play, authored-scene, guide-style |
| **Song Select** | [components/SongSelect.md](./components/SongSelect.md) | Component | `Assets/Menu/SongSelect/` | Beta | 0.1.0 | song-select, carousel, difficulty, 2P, transition |
| Style 1 Button *(primitive)* | [components/Style1Button.md](./components/Style1Button.md) | Primitive | `Assets/UI/Style1/` | Stable | 1.0.0 | button, nav, press, hover |
| UI Component Gallery *(tool / board)* | [components/ComponentGallery.md](./components/ComponentGallery.md) | Tool | `Assets/UI/Style1/ComponentGallery/` | Stable | 1.1.0 | board, gallery, showcase, catalog |
diff --git a/AI/components/Tutorial.md b/AI/components/Tutorial.md
index c1a882f..0a5eb4d 100644
--- a/AI/components/Tutorial.md
+++ b/AI/components/Tutorial.md
@@ -1,6 +1,6 @@
# Tutorial — BST insertion lesson
-> **Category:** Integration · **Folder:** `Assets/Tutorial/` · **Status:** Beta · **Version:** 0.6.0
+> **Category:** Integration · **Folder:** `Assets/Tutorial/` · **Status:** Beta · **Version:** 0.6.1
Uses the **real GameScene level stack** (`TreeRhythmController`, Score HUD, falling notes on `NotePathBehaviour`). Metronome ticks instead of song audio; side guide panels during the lesson.
@@ -40,11 +40,13 @@ GameScene-identical world: tree, LeftNotePath (+ NoteHitSpot timing bar), NoteCo
Synthwave floor (+ mountains); sky disabled for tutorial
TutorialGuideCanvas (sort 30)
├── LeftGuidePanel — headline + hint (left margin)
-└── RightGuidePanel — binding + continue prompt (right margin)
+└── RightGuidePanel — binding (right margin; ContinuePrompt kept hidden)
```
Center stays clear for gameplay. Side panels sit in the left/right margins. Score HUD is Overlay, top-left only (not full-screen).
+The right panel shows **one** large centered cue in `BindingLabel`: the pad arrow for a move step (`←` / `→` / `↓` from `TutorialInputLabels`), and the same `↓` when a dialogue step is waiting to be advanced. The small bottom-right `ContinuePrompt` chip still exists in the hierarchy but is always hidden, since it was unreadable at cabinet distance.
+
---
## Files
diff --git a/Assets/ScriptableObjects/Tutorial/DefaultTutorialLesson.asset b/Assets/ScriptableObjects/Tutorial/DefaultTutorialLesson.asset
index c734bc2..dee982e 100644
--- a/Assets/ScriptableObjects/Tutorial/DefaultTutorialLesson.asset
+++ b/Assets/ScriptableObjects/Tutorial/DefaultTutorialLesson.asset
@@ -31,17 +31,17 @@ MonoBehaviour:
Headline: GO RIGHT
Hint: 6 is greater than 4.
RequiredAction: 1
- WrongHint: Try RIGHT
+ WrongHint: Try →
- Kind: 1
Headline: GO LEFT
Hint: 6 is less than 8.
RequiredAction: 0
- WrongHint: Try LEFT
+ WrongHint: Try ←
- Kind: 1
Headline: PLACE IT
Hint: Empty slot — lock it in.
RequiredAction: 2
- WrongHint: Press PLACE
+ WrongHint: Press ↓
- Kind: 2
Headline: COMPLETE
Hint: Starting your song.
diff --git a/Assets/Tutorial/TutorialController.cs b/Assets/Tutorial/TutorialController.cs
index c8b5368..e45a17d 100644
--- a/Assets/Tutorial/TutorialController.cs
+++ b/Assets/Tutorial/TutorialController.cs
@@ -418,15 +418,19 @@ private void SetBinding(string binding)
_ui.BindingLabel.gameObject.SetActive(!string.IsNullOrWhiteSpace(binding));
}
+ /**
+ * Shows or hides the cue for advancing dialogue. It reuses the large centered
+ * binding label, so the prompt to advance appears in the same place and at the
+ * same size as the prompt to move or place. The old bottom-right chip is kept
+ * hidden: at cabinet distance it was too small to read.
+ *
+ */
private void SetContinueVisible(bool visible)
{
- if (_ui.ContinuePromptLabel == null) return;
- _ui.ContinuePromptLabel.gameObject.SetActive(visible);
- if (visible)
- {
- _ui.ContinuePromptLabel.fontSize = GuideStyle.ContinueFontSize;
- _ui.ContinuePromptLabel.text = $"{TutorialInputLabels.Place}{GuideStyle.ContinueSuffix}";
- }
+ if (_ui.ContinuePromptLabel != null)
+ _ui.ContinuePromptLabel.gameObject.SetActive(false);
+
+ SetBinding(visible ? TutorialInputLabels.Place : "");
}
private void ShowActionBinding(NavigationAction action)
diff --git a/Assets/Tutorial/TutorialInputLabels.cs b/Assets/Tutorial/TutorialInputLabels.cs
index cdfc293..07d8201 100644
--- a/Assets/Tutorial/TutorialInputLabels.cs
+++ b/Assets/Tutorial/TutorialInputLabels.cs
@@ -1,65 +1,25 @@
-using UnityEngine.InputSystem;
-
/**
- * Resolves remappable binding display strings for tutorial prompts from the same
- * action maps gameplay uses. Remap keys in and
- * these hints update automatically — nothing here names a physical key.
+ * Direction cues shown in the tutorial guide panel.
+ *
+ * The cabinet input is a dance pad, so every prompt is the arrow the player
+ * physically steps on. The pad panels are fixed hardware and read identically
+ * for Player 1 and Player 2, which is why these are glyphs rather than binding
+ * display strings: a keyboard name such as "A" or "J" describes a key nobody at
+ * the cabinet can see, and a per-player name makes the same lesson look
+ * different depending on who is taking it.
*
- * For P1, if a DPad binding exists on the action, the display shows both the
- * keyboard key and the DPad arrow (e.g. "A ←") so DDR-pad players know what to press.
- * P2 shows only binding[0] (the keyboard key: J/I/K/L cluster).
+ * This is display only. Bindings and remapping still live in
+ * InputSystem_Actions, and the tutorial keeps routing input through the
+ * active player's map.
* */
public static class TutorialInputLabels
{
- private static InputSystem_Actions _actions;
-
- private static InputSystem_Actions Actions => _actions ??= new InputSystem_Actions();
-
- /** Action map for whoever is taking the lesson right now. */
- private static InputActionMap ActiveMap
- {
- get
- {
- int playerIndex = GameSession.Instance?.ActiveTutorialPlayerIndex ?? 0;
- return playerIndex == 1 ? (InputActionMap)Actions.Player2 : Actions.Player1;
- }
- }
-
- private static bool IsP1 => (GameSession.Instance?.ActiveTutorialPlayerIndex ?? 0) == 0;
-
- private static string FromAction(string actionName, string fallback)
- {
- InputAction action = ActiveMap?.FindAction(actionName);
- if (action == null) return fallback;
-
- string keyboard = action.GetBindingDisplayString(0);
- if (string.IsNullOrWhiteSpace(keyboard)) keyboard = fallback;
-
- if (IsP1)
- {
- string dpad = DPadSymbol(action);
- if (dpad != null)
- return $"{keyboard} {dpad}";
- }
-
- return keyboard;
- }
+ /** Cue for moving to the left child. */
+ public const string NavLeft = "\u2190";
- private static string DPadSymbol(InputAction action)
- {
- foreach (var b in action.bindings)
- {
- if (b.isComposite || b.isPartOfComposite) continue;
- string path = b.effectivePath?.ToLowerInvariant() ?? "";
- if (path.Contains("dpad/left")) return "←";
- if (path.Contains("dpad/right")) return "→";
- if (path.Contains("dpad/down")) return "↓";
- if (path.Contains("dpad/up")) return "↑";
- }
- return null;
- }
+ /** Cue for moving to the right child. */
+ public const string NavRight = "\u2192";
- public static string NavLeft => FromAction("NavLeft", "LEFT");
- public static string NavRight => FromAction("NavRight", "RIGHT");
- public static string Place => FromAction("Submit", "PLACE");
+ /** Cue for placing the held value, and for advancing dialogue. */
+ public const string Place = "\u2193";
}
diff --git a/Assets/Tutorial/TutorialLessonConfig.cs b/Assets/Tutorial/TutorialLessonConfig.cs
index 238fbcd..d80e530 100644
--- a/Assets/Tutorial/TutorialLessonConfig.cs
+++ b/Assets/Tutorial/TutorialLessonConfig.cs
@@ -58,7 +58,7 @@ public class TutorialLessonConfig : ScriptableObject
RequiredAction = NavigationAction.Right,
Headline = "GO RIGHT",
Hint = "6 is greater than 4.",
- WrongHint = "Try RIGHT"
+ WrongHint = "Try " + TutorialInputLabels.NavRight
},
new TutorialStep
{
@@ -66,7 +66,7 @@ public class TutorialLessonConfig : ScriptableObject
RequiredAction = NavigationAction.Left,
Headline = "GO LEFT",
Hint = "6 is less than 8.",
- WrongHint = "Try LEFT"
+ WrongHint = "Try " + TutorialInputLabels.NavLeft
},
new TutorialStep
{
@@ -74,7 +74,7 @@ public class TutorialLessonConfig : ScriptableObject
RequiredAction = NavigationAction.Place,
Headline = "PLACE IT",
Hint = "Empty slot — lock it in.",
- WrongHint = "Press PLACE"
+ WrongHint = "Press " + TutorialInputLabels.Place
},
new TutorialStep
{