@genex-ai/cli-demo 0.54.0-dev.122 → 0.55.0-dev.124

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,157 @@
1
+ ---
2
+ name: genex-threejs-touch-controls
3
+ description: Make a Genex Three.js game playable on phones — vendored touch primitives via `npx genex controller touch` (floating/static joystick, virtual buttons, drag zone, rotate-device overlay) plus per-genre wiring recipes (movement, camera look, taps, paddles, action buttons, touch pause). Use when wiring default touch controls into a new game, whenever someone asks to make a game playable on mobile/phone/tablet, or before shipping a game whose input is keyboard/mouse-only.
4
+ ---
5
+
6
+ # Genex Three.js Touch Controls
7
+
8
+ Game links get shared in chats, and chats get opened on phones. A game with
9
+ keyboard/mouse-only input *renders* there and then does nothing — a dead screen
10
+ at the exact moment someone was curious enough to tap the link.
11
+
12
+ **Wire touch input by default when a recipe below fits** — it's a few lines,
13
+ invisible on desktop, and never needs mobile testing. **Skip it with a one-line
14
+ reason when it doesn't fit** (typing-driven games, pointer-lock-precision aiming
15
+ with no touch equivalent, anything where touch would contort the architecture) —
16
+ it is guidance, never a requirement. Mobile *layout/HUD polish* and phone-size
17
+ testing stay ask-only either way: the kit's defaults are safe by construction,
18
+ so wiring it adds no verification work.
19
+
20
+ ## Get the kit
21
+
22
+ Games on a bundled physics controller (`genex controller character|car|drone`)
23
+ **already have the kit** — those installs ship it. Everything else:
24
+
25
+ ```bash
26
+ npx genex controller touch
27
+ ```
28
+
29
+ No extra npm install — plain DOM/CSS classes into `src/controllers/touch/`:
30
+
31
+ | File | Exports | What it is |
32
+ | --- | --- | --- |
33
+ | `touch/touch-joystick.ts` | `TouchJoystick` | movement stick — static circle, or `floating: true` (appears under the thumb, faint resting hint between touches) |
34
+ | `touch/touch-joystick.ts` | `VirtualButton` | thumb-sized action button with a label and press/release edges |
35
+ | `touch/drag-zone.ts` | `DragZone` | invisible drag surface — per-frame deltas for camera look, normalized position for paddles |
36
+ | `touch/rotate-overlay.ts` | `RotateOverlay` | "rotate your phone" screen, shown only while the device is held the wrong way |
37
+
38
+ ## The three rules that apply to every recipe
39
+
40
+ 1. **Create the widgets always, show them only on touch devices:**
41
+
42
+ ```ts
43
+ import { TouchJoystick, VirtualButton } from "./controllers/touch/touch-joystick.ts";
44
+ import { DragZone } from "./controllers/touch/drag-zone.ts";
45
+
46
+ const touch = navigator.maxTouchPoints > 0;
47
+ const joy = new TouchJoystick({ floating: true });
48
+ const btnJump = new VirtualButton({ label: "Jump" });
49
+ [joy, btnJump].forEach((w) => w.setVisible(touch));
50
+ ```
51
+
52
+ (`maxTouchPoints > 0` is also true on touch-screen laptops, so the controls
53
+ can appear on some desktops — harmless and intended; they cost nothing when
54
+ untouched.)
55
+
56
+ 2. **Give the canvas `touch-action: none`** so drags reach the game instead of
57
+ scrolling/zooming the page:
58
+
59
+ ```ts
60
+ renderer.domElement.style.touchAction = "none";
61
+ ```
62
+
63
+ 3. **Touch inputs merge with keyboard/mouse, they never replace them.** Read
64
+ both every frame and let either drive:
65
+ `jump: kb.space || btnJump.pressed`. Same intents, same code path — a touch
66
+ button and its key must run identical game logic.
67
+
68
+ ## Genre recipes
69
+
70
+ Pick what matches the game; most games need exactly one or two of these.
71
+
72
+ - **Hand-rolled WASD / character movement → joystick.** Read `joy.x`/`joy.y`
73
+ (both in [-1, 1], up-positive) wherever the key states are read and take
74
+ whichever is nonzero. Use `floating: true` for action games where the thumb
75
+ lives on the stick; the static circle is fine for slower games. On the
76
+ bundled character controller, pass it through instead — see
77
+ `$genex-threejs-character-controller` (`joystick: { x: joy.x, y: joy.y }`).
78
+ - **Camera look → drag zone on the right half.** Default `DragZone()` is
79
+ exactly that; per frame `const { dx, dy } = look.consumeDelta()` then apply
80
+ to yaw/pitch with the same sensitivity scale as the mouse path. Games on the
81
+ bundled `FollowCamera` skip this — its drag-orbit already works on touch.
82
+ - **Mouse-driven / tap games (click-to-move, tower defense, puzzles, cards) —
83
+ no widgets.** Taps already fire your click/pointer handlers. The recipe is
84
+ hit-target size: anything tappable should be ~44px+ on screen (fatten the
85
+ pick radius or the DOM button, not the art). This is the ~90%-done genre —
86
+ resist the urge to add a joystick it doesn't need.
87
+ - **Paddle / pong / slider → drag zone as an absolute axis.** Reshape the zone
88
+ over the paddle's travel area and read `zone.x` (or `.y`), normalized 0..1,
89
+ while `zone.active` — map it straight to the paddle position.
90
+ - **Discrete actions (jump / shoot / interact / brake / restart) → virtual
91
+ buttons.** One `VirtualButton` per action; first button parks bottom-right
92
+ by default, position the rest yourself
93
+ (`wrapperStyle: { right: "100px", bottom: "48px" }`). Vehicles: the
94
+ enter/exit prompt must be tappable too — `$genex-threejs-vehicle-controllers`
95
+ has that wiring.
96
+ - **Always: a tappable pause.** Escape has no key on a phone — a small pause
97
+ button (top corner, out of thumb arcs) triggering the exact same pause intent.
98
+ `$genex-threejs-game-ui` owns the pause screen itself.
99
+
100
+ ## Orientation
101
+
102
+ Declare ONE natural orientation per game (pick by genre: landscape for
103
+ racing/side-scrolling/most action, portrait for stacking/one-thumb casual) and
104
+ use the overlay **only if the wrong orientation genuinely breaks play**:
105
+
106
+ ```ts
107
+ import { RotateOverlay } from "./controllers/touch/rotate-overlay.ts";
108
+ new RotateOverlay({ orientation: "landscape" }); // optional: onChange: (b) => (physics.paused = b)
109
+ ```
110
+
111
+ If the game is merely suboptimal sideways, skip the overlay and just resize.
112
+ The web cannot force an orientation (fullscreen-only lock, none on iOS Safari)
113
+ — the overlay asks; it never traps.
114
+
115
+ ## Match the game's style
116
+
117
+ The touch controls are UI like any other — restyle them from the same style
118
+ brief `$genex-threejs-game-ui` locked for this game (the neutral translucent
119
+ defaults are a placeholder look, not art direction):
120
+
121
+ ```ts
122
+ new VirtualButton({
123
+ label: "FIRE",
124
+ capStyle: {
125
+ border: "1.5px solid rgba(255, 120, 40, 0.8)", // the brief's accent
126
+ color: "rgba(255, 210, 180, 0.95)",
127
+ fontFamily: "'Orbitron', system-ui, sans-serif", // the brief's font
128
+ },
129
+ });
130
+ ```
131
+
132
+ Whatever the restyle, keep the floors the defaults guarantee: tappable targets
133
+ stay ~44px+, labels stay readable over bright AND dark scenes (keep a text
134
+ shadow), controls never cover HUD numbers the player must read, and the
135
+ z-order stays: drag zone (5) under joystick/buttons (10) under pause menus.
136
+
137
+ ## Corner cases
138
+
139
+ - **Multi-touch is already handled** — every widget tracks its own pointer and
140
+ captures it, so stick + look-drag + a button all work simultaneously. Extra
141
+ fingers on one widget are ignored, not misread.
142
+ - **No pointer lock on touch.** Mouse-aim games need the drag-zone recipe for
143
+ aiming, or a stated opt-out; the bundled aim mode no-ops on touch by itself
144
+ (`$genex-threejs-camera-direction`).
145
+ - **Safe-area insets are built in** — default positions clear notches and the
146
+ home indicator. If you position widgets yourself near screen edges, keep
147
+ `env(safe-area-inset-*)` in the calc.
148
+ - **The drag zone swallows its touches** — taps inside it don't reach the
149
+ canvas. If the game also needs taps there (tap to shoot), read them from the
150
+ zone (`onChange` + a small-movement threshold) or shrink the zone.
151
+
152
+ ## When you skip
153
+
154
+ Say it in one plain line — *"skipped touch controls: the game is
155
+ typing-driven"* — instead of silently shipping a dead screen. Never restructure
156
+ a game's architecture to force touch in; if it doesn't fit, the one-liner is
157
+ the right outcome.
@@ -82,7 +82,8 @@ games with no on-foot character.
82
82
  touch interact button**: on phones there is no F key, so the enter prompt
83
83
  must be tappable (and an Exit button shown while driving) or the shared
84
84
  link is unenterable on mobile. Wire it whenever you wire the touch
85
- joysticks (`navigator.maxTouchPoints > 0`).
85
+ joysticks (`navigator.maxTouchPoints > 0`; the shared touch kit + genre
86
+ recipes live in `$genex-threejs-touch-controls`).
86
87
 
87
88
  ## Presets at a glance
88
89