KrostyMall/Landing-SENSORITY

Panneaux de contrôle visibles par le joueur pour jeux navigateur : WASD, véhicules, vol, visée souris FPS et le mode d'échec numéro 1 (A/D inversé). Tests d'auto-contrôle obligatoires et une petite interface de test pour vérifier que A tourne à gauche avant la livraison.

Qu'est-ce que Landing-SENSORITY ?

Ce skill définit la convention obligatoire de direction gauche/droite visible par le joueur pour tout jeu de mouvement, de conduite, de vol ou de véhicule utilisant WASD. Il explique comment mapper les touches A/D (et flèches) sur le lacet ou le roulis de manière cohérente avec une caméra de poursuite, en évitant l'inversion A/D qui est le problème le plus fréquent dans les démos de véhicules. Il couvre plusieurs genres (FPS/à pied, véhicules terrestres/aquatiques, avions, hélicoptères/drones, plateformes 2D) avec des extraits de code et des conventions de signes claires. Il impose un test d'auto-contrôle obligatoire (§5) avant de considérer le jeu comme terminé, avec une checklist visible par le joueur, une interface de test minimale (window.__controlsTest) et un test automatisé via l'outil agent-browser batch. Le skill est destiné aux jeux construits avec Three.js (repère direct +Y vers le haut) et s'intègre avec les skills `building-games` et `building-games/references/input.md`.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/KrostyMall/Landing-SENSORITY/tree/HEAD/.grok/skills/controls

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Contrôles (panneaux visibles par le joueur — ne pas livrer inversé)

Lisez ceci du début à la fin avant d'écrire du code de déplacement/direction/vol pour tout jeu qui utilise WASD, les flèches, une caméra de poursuite ou un engin volant. Ne sautez pas cette étape et n'ouvrez pas seulement racing-kart ou fps — ces fichiers de genre supposent que vous connaissez déjà ces panneaux. L'inversion A/D est le blocage de livraison le plus courant dans les démos de véhicules et de vol.

Associez avec building-games (boucle, caméra, orientation 3D) et building-games/references/input.md (état des touches, manette, tactile). Ce skill possède ce que gauche/droite/haut/bas signifient pour le joueur et comment vous le prouvez.


0. Règles strictes (échec de la build si cassé)

  1. La gauche/droite visible par le joueur est la loi. Depuis une caméra de poursuite / derrière pendant que l'engin avance vers l'avant :
    • A / ← → le nez (ou l'inclinaison) tourne à gauche sur l'écran
    • D / → → le nez (ou l'inclinaison) tourne à droite sur l'écran
  2. Ne réutilisez jamais le strafe FPS comme direction de véhicule. Le “D → +vecteur droit” FPS est une position sur le plan du sol. Le A/D du véhicule est un taux de lacet (ou de roulis), pas un décalage de strafe. Les mélanger est la cause numéro 1 de l'inversion A/D.
  3. Vous devez exécuter un auto-test de contrôle (§5) avant de dire terminé. Une QA uniquement par capture d'écran ne suffit pas. Si A tourne à droite, inversez le signe de direction/roulis, testez à nouveau, puis livrez — n'inventez pas une nouvelle histoire de coordonnées.

1. Base 3D partagée (utilisez-la partout)

Three.js : main droite, +Y vers le haut, les maillages font face à +Z, les caméras regardent −Z.

Cap uniquement par lacet sur XZ (véhicules terrestres, marcheurs, la plupart des engins arcade) :

// yaw = 0 fait face à −Z monde; +yaw est antihoraire autour de +Y (le nez se déplace vers −X)
forward = (-sin(yaw), 0, -cos(yaw))
right   = ( cos(yaw), 0, -sin(yaw))   // = normalize(cross(forward, worldUp))

Avec une caméra de poursuite derrière l'engin (caméra près de position - forward * dist) :

Le joueur voitMonde (cette base)Entrée
Nez à gauche+yawA / ← doit produire +yaw (ou l'inclinaison à gauche équivalente pour les avions)
Nez à droite−yawD / → doit produire −yaw

Si votre base diffère, gardez une paire cohérente — mais la ligne visible par le joueur ci-dessus est obligatoire.


2. Cartes par genre

2a. FPS / à pied (strafe, pas de direction)

W = +avant, S = −avant, D = +droite, A = −gauche   // position, pas lacet
souris : yaw -= movementX * sens; pitch -= movementY * sens; clamp pitch

Lacet du corps pour le regard; le mouvement utilise uniquement le lacet (n'appliquez pas le tangage à la marche).

2b. Véhicule terrestre / aquatique (kart, vélo, jet-ski, bateau, char, rover, motoneige)

Corps arcade avec heading/yaw et vitesse avant speed :

// Entrée (touches maintenues → actions une fois par frame)
let steer = 0; // -1..+1, visible par le joueur
if (keys.has('KeyA') || keys.has('ArrowLeft'))  steer += 1;  // GAUCHE
if (keys.has('KeyD') || keys.has('ArrowRight')) steer -= 1;  // DROITE
// Optionnel : steer = clamp(steer + gamepadX, -1, 1) avec la même convention de signe

// Intégration (speedFactor ~ 0..1 selon |speed|)
const reverse = speed >= 0 ? 1 : -1; // roue gauche reste à gauche en marche arrière
yaw += steer * turnRate * speedFactor * reverse * dt;

// Déplacement selon le cap
const fx = -Math.sin(yaw), fz = -Math.cos(yaw);
position.x += fx * speed * dt;
position.z += fz * speed * dt;

Bogue canonique (ne pas copier) :

// FAUX — c'est ce qui livre A/D inversé dans la nature
if (KeyA) steer -= 1;
if (KeyD) steer += 1;
yaw += steer * turnRate * dt;  // A → −yaw → nez à DROITE sur caméra de poursuite

Si vous avez déjà écrit KeyA → steer--, soit échangez le mappage des touches soit niez une fois à l'intégration (yaw += -steer * …) — puis exécutez §5. Ne faites pas deux inversions (touches + intégration + inclinaison du maillage).

2c. Vol à voilure fixe (avion, planeur, RC)

EntréeActionAttente du joueur
A / ←Roulis à gauche (aileron)Aile gauche vers le bas / inclinaison à gauche
D / →Roulis à droiteAile droite vers le bas / inclinaison à droite
W / ↑Tangage (choisir un schéma et étiqueter le HUD)Généralement piquer ou cabrer — soyez cohérent
S / ↓Tangage opposé
Q / ELacet / gouverne de direction (optionnel)Q à gauche, E à droite
  • A/D ne sont pas du strafe et pas “direction terrestre avec signes FPS.”
  • Appliquez le roulis dans l’axe avant local de l’engin avec un signe qui correspond à inclinaison à gauche sur A. Si le maillage s’incline dans le mauvais sens, inversez un signe sur l’application du roulis (ou sur le mappage A/D → roulis), pas toute la base.
  • Virage coordonné : une inclinaison positive doit produire un virage qui correspond à la direction de l’inclinaison sous la caméra de poursuite/externe.

2d. Hélicoptère / drone / 6DOF

Documentez le schéma sur une superposition de départ. Minimum :

  • Les gaz/altitude sur touches discrètes ne doivent pas rester “toujours en haut” après une pression (utilisez l’état maintenu ou des touches haut/bas explicites).
  • Strafe/lacet : A gauche, D droite dans le cadre horizontal de l’engin (visible par le joueur).

2e. Side-scroller / plateforme 2D

D / → se déplace à droite sur l’écran ; A / ← se déplace à gauche. La gravité n’est inversée que si le genre est explicitement tête en bas.


3. La caméra doit être d’accord

  • Caméra de poursuite : desired = craftPos + up*height + forward*(-followDist) ; lerp ; lookAt(craft).
  • Calculez forward une fois pour le mouvement et la caméra — ne le reconstruisez pas avec un signe de lacet opposé dans le chemin de la caméra.
  • Ordre de débogage : (1) les touches s’enregistrent → (2) les signes sont corrects (§5) → (3) la caméra est d’accord.

4. Plomberie d’entrée (bref)

  • Suivez les touches avec un Set sur keydown/keyup en utilisant event.code ; effacez sur blur / visibilitychange. Bougez dans la boucle de jeu avec dt, pas dans le gestionnaire de touches.
  • Unifiez clavier + tactile + manette en actions (throttle, steer, pitch, roll, …). Voir building-games/references/input.md.
  • Tactile : stick gauche = déplacement/direction, droite = actions ; cibles ≥44px.

5. Auto-test de contrôle obligatoire (avant “terminé”)

Une capture d’écran seule ne suffit pas pour tout engin avec A/D.

5a. Checklist visible par le joueur (chaque build véhicule / vol)

Pendant que vous avancez vers l’avant (vitesse > petit epsilon), caméra de poursuite derrière :

MaintenezDoit être observé dans ~0,5s
ALe nez ou l’inclinaison se déplace à gauche sur l’écran
DLe nez ou l’inclinaison se déplace à droite sur l’écran
W (sol)La vitesse augmente / se déplace dans la direction face
S (sol)Freine ou recule (comme conçu)

Si A échoue : inversez le signe de direction/roulis une fois, testez à nouveau A et D.

5b. Interface de test minimale (implémentez-la)

Exposez un petit hook pour que vous (et la QA automatisée) puissiez prouver les signes sans deviner les fermetures privées :

// par ex. src/game/controlsTest.ts — dev/QA seulement, c’est bien
export type ControlsProbe = {
  getYaw: () => number;       // radians ; ou getHeading()
  getSpeed: () => number;
  /** Injecte les actions maintenues au lieu des vraies touches ; les deux restent
   *  appliquées jusqu’à ce que vous les changiez, donc §5c peut maintenir une
   *  touche sur plusieurs frames et la libérer à la fin. */
  setSteer?: (v: number) => void; // -1..1, même signe qu’en production
  setKeys?: (codes: string[]) => void; // maintenu jusqu’au prochain appel ; `[]` libère
};

declare global {
  interface Window {
    __controlsTest?: ControlsProbe;
  }
}

Câblez window.__controlsTest depuis la boucle de jeu quand import.meta.env.DEV ou un indicateur ?qa=1 est défini.

5c. Test de fumée automatisé (exécutez-le)

Pilotez la sonde §5b avec le CLI agent-browser préinstallé — c’est le premier geste, pas un script écrit à la main. Un eval qui lève une exception sort avec un code non nul ; un simple falsy ne le fait pas, donc affirmez en levant une exception. Exécutez-le en un seul batch — un seul appel CLI, pas un par verbe — en prenant du JSON sur stdin ; --bail s’arrête à la première étape en échec et sort avec un code non nul.

agent-browser batch --bail <<'JSON'   # le libellé de find est sensible à la casse : copiez-le depuis `snapshot -i`
[["open","http://127.0.0.1:8080/"],
 ["find","text","Start","click"],
 ["eval","if (!window.__controlsTest?.setKeys) throw Error('pas de sonde §5b : ajoutez setKeys')"],
 ["eval","__controlsTest.setKeys(['KeyW'])"],
 ["wait","600"],
 ["eval","if (__controlsTest.getSpeed() <= 0.1) throw Error('W : pas de mouvement')"],
 ["eval","(async () => { const t = __controlsTest, y0 = t.getYaw(); t.setKeys(['KeyW','KeyA']); await new Promise(r => setTimeout(r, 300)); t.setKeys(['KeyW']); const d = t.getYaw() - y0, w = Math.atan2(Math.sin(d), Math.cos(d)); if (w < -0.05) throw Error('A tourne à DROITE — inversé, obtenu ' + w.toFixed(2)); if (w <= 0.05) throw Error('A a à peine tourné (' + w.toFixed(2) + ') — maintenez plus longtemps ou vérifiez que la sim tourne'); return 'A ok' })()"],
 ["eval","__controlsTest.setKeys([])"],
 ["screenshot","/workspace/screenshots/controls.png"],
 ["close"]]
JSON

Maintenez les touches via la sonde, pas avec keydown — agent-browser keydown n’atteint pas le Set de §4, donc un jeu correct sera lu comme cassé. Pas de setKeys sur votre sonde ? Ajoutez-la (§5b), ou distribuez vous-même l’événement clavier — la note Keys de la référence browser-QA contient le mécanisme et le formulaire.

Le maintien se trouve à l’intérieur d’un seul eval : réparti sur des commandes, il dure aussi longtemps qu’elles prennent, et l’enveloppement ±π dans Math.atan2(Math.sin(d), Math.cos(d)) lit un engin qui a tourné de plus de π comme tournant dans l’autre sens. L’IIFE est ce qui rend l’étape ré-exécutable — un const d = … nu échoue la deuxième fois avec “déjà déclaré” — et async est ce qui permet au maintien de s’exécuter dans le temps de la page. Répétez pour D avec 'KeyD' et les deux comparaisons inversées (w > 0.05 est inversé, w >= -0.05 est à peine), entre guillemets simples pour que le JSON n’ait pas besoin d’échappements ; pour les avions, affirmez roll : A ⇒ inclinaison à gauche.

A tourne à DROITE est l’erreur de signe : inversez un signe et ré-exécutez. A a à peine tourné ne l’est pas — l’engin a bougé dans la bonne direction, juste moins de 0,05 rad en 300 ms, ce qu’un bateau ou un rover lourd fera ; augmentez le maintien, ou vérifiez que la simulation tourne, et n’inversez rien. Tout autre code de sortie non nul — pas de sonde, un démon bloqué — signifie que la vérification n’a jamais été exécutée : lisez d’abord le message. Lisez les liens AGENTS.md de la référence browser-QA avant votre premier flux — les verbes, les formes des arguments et le repli sont là.

5d. Ce qu’il ne faut pas faire

  • Ne testez pas seulement “D augmente une variable interne.”
  • N’utilisez pas le “D → +X quand on fait face à −Z” du FPS comme condition de validation du véhicule.
  • N’inversez pas l’inclinaison du maillage, la caméra et la direction en même temps pour corriger — changez un signe, testez à nouveau.

6. Critères de finition (contrôles)

  • A ouvert ce skill avant d’écrire le mouvement/la direction/le vol.
  • Carte de genre choisie (§2) et les étiquettes de l’écran d’accueil / HUD correspondent.
  • Test visible par le joueur caméra de poursuite A/D passé (§5a).
  • window.__controlsTest (ou équivalent) disponible en dev/QA et utilisé une fois.
  • Aucun maillage d’inclinaison inversé par rapport à l’entrée de roulis/direction.
  • Les touches sont en état maintenu + échelonné par dt ; pas de poussée collante d’une seule pression Espace sauf si intentionnelle et étiquetée.

Si une case n’est pas cochée, le jeu n’est pas terminé.

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

KrostyMall/Landing-SENSORITY

Add user accounts and sign-in to this TanStack Start app. Use when the app needs authentication, sign-in, user accounts, protected routes, or per-user data. Triggers on "auth", "login", "log in", "sign in", "sign up", "account", "users", "authentication", "protected", "who is logged in", "current user", "per-user".

KrostyMall/Landing-SENSORITY

Build browser games and interactive/canvas/3D experiences in this TanStack Start + React app. Use for any game, simulation, or WebGL/Canvas experience — 2D or 3D, single-player. Covers the game loop & timing, 3D orientation/camera conventions, collision, performance, assets, audio, save, game feel, and per-genre playbooks. For WASD / vehicle / flight **input signs and inverted A/D**, open the **`controls`** skill — do not rely on this file or racing-kart alone. Triggers on "game", "minecraft", "fps", "platformer", "racing", "tetris", "snake", "shooter", "3d", "three.js", "canvas", "voxel", "physics".

KrostyMall/Landing-SENSORITY

Design and build polished, non-generic UI for this TanStack Start + React + Tailwind v4 + shadcn/Radix app. Use whenever you create or restyle any interface surface — pages, landing pages, dashboards, forms, modals, nav, and game overlays (start screens, HUD, menus). Covers design tokens, layout, typography, color, spacing, motion, and the anti-"AI-slop" rules that keep output from looking generic. Triggers on "design", "UI", "make it look good", "polish", "landing page", "theme", "style", "redesign", "ugly", "clean up".

KrostyMall/Landing-SENSORITY

Deep guide for game ANIMATION assets: motion cycles, action keyframes, effect sequences, and animation sprite sheets — built around a video-first pipeline. In this app-builder sandbox, execute via the video2dsprite / generate2dsprite skills (magenta + scripts), not ad-hoc ffmpeg. Use whenever generating anything that moves: walk/run cycles, attacks, idles, FX, flags, fire, animation sheets. Complements game-asset-core.

Skills associés