Community编程与开发github.com

KrostyMall/Landing-SENSORITY

面向玩家的输入标志,用于浏览器游戏:WASD、车辆、飞行、FPS 鼠标视角,以及 #1 故障模式(反转 A/D)。强制控制自检和一个小型测试界面,以便在发布前验证 A 键是否向左转。适用于任何包含移动、转向、飞行、驾驶、坦克、船只、机甲、无人机、飞机、卡丁车、第三人称跟随摄像机的游戏——不仅仅是赛车。触发器关键词:“controls”、“WASD”、“inverted”、“steer”、“flight”、“airplane”、“kart”、“vehicle”、“yaw”、“roll”、“pitch”、“mouse look”、“A/D”。

Landing-SENSORITY 是什么?

该技能为浏览器游戏开发者提供了一套严格的控制规范,专注于确保 WASD 和方向键的玩家可见方向正确,特别是防止最常见的“A/D 反转”错误。它定义了一个共享的 3D 坐标系(three.js 右手系,+Y 向上)和多种游戏类型的键位映射,包括 FPS(平移)、地面/水上车辆(偏航转向)、固定翼飞行(滚转+俯仰)、直升机/无人机以及 2D 平台游戏。技能的核心是强制性的“控制自检”流程,要求开发者通过一个暴露的 `window.__controlsTest` 接口来验证 A 键是否导致画面左转,并提供了一个可以直接在浏览器中运行的自动化烟雾测试脚本(使用 `agent-browser`)。技能适用于任何需要移动、转向或飞行控制机制的游戏,并强调在编写任何移动/转向/飞行代码之前必须完整阅读此文档。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/KrostyMall/Landing-SENSORITY/tree/HEAD/.grok/skills/controls

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Controls(玩家可见的标志——切勿反转发布)

在编写任何使用 WASD、方向键、追逐摄像机或飞行器的游戏移动/转向/飞行代码之前,完整阅读本文档。 不要跳过此项而只打开 racing-kart 或 fps 类型文件——那些类型文件假定你已经知道这些标志。A/D 反转是车辆和飞行演示中最常见的阻塞发布问题。

与 building-games(循环、摄像机、3D 方向)和 building-games/references/input.md(按键状态、游戏手柄、触控)配合使用。本技能负责左/右/上对玩家意味着什么以及你如何证明它。


0. 硬性规则(违反则构建失败)

  1. 玩家可见的左/右是法律。 从追逐/后方摄像机视角,且载具向前移动时:
    • A / ← → 机头(或倾斜)在屏幕上向左转
    • D / → → 机头(或倾斜)在屏幕上向右转
  2. 切勿将 FPS 横向平移用作车辆转向。 FPS 的“D → +right 向量”是地面平面上的位置。车辆 A/D 是偏航(或滚转)速率,而不是横向平移偏移。混淆它们是 A/D 反转的头号原因。
  3. 在声明完成之前,必须运行控制自检(第5节)。 仅截图 QA 是不够的。如果 A 向右转,翻转转向/滚转符号,重新测试,然后发布——不要发明新的坐标故事。

1. 共享 3D 基础(到处使用此基础)

three.js:右手系,+Y 向上,网格面向 +Z,摄像机看向 −Z。

XZ 平面上的纯偏航航向(地面车辆、步行者、大多数街机关卡载具):

// 偏航 = 0 面向世界 −Z;+偏航 绕 +Y 逆时针(机头移向 −X)
forward = (-sin(yaw), 0, -cos(yaw))
right   = ( cos(yaw), 0, -sin(yaw))   // = normalize(cross(forward, worldUp))

使用后方的追逐摄像机(摄像机位于 position - forward * dist 附近):

玩家所见世界(此基础)输入
机头向左+偏航A / ← 必须产生 +偏航(或对飞机等效的向左倾斜)
机头向右−偏航D / → 必须产生 −偏航

如果你的基础不同,请保持一个一致的配对——但上方的玩家可见行是强制性的。


2. 类型映射

2a. FPS / 步行(平移,非转向)

W = +向前, S = −向前, D = +向右, A = −向右   // 位置,非偏航
鼠标:偏航 -= movementX * sens; 俯仰 -= movementY * sens; 限制俯仰

身体偏航用于视角;移动仅使用偏航(不要将俯仰应用于行走)。

2b. 地面 / 水上车辆(卡丁车、摩托车、摩托艇、船、坦克、火星车、雪地摩托)

具有 heading/yaw 和向前 speed 的街机主体:

// 输入(按住键 → 每帧执行一次动作)
let steer = 0; // -1..+1,玩家可见
if (keys.has('KeyA') || keys.has('ArrowLeft'))  steer += 1;  // 向左
if (keys.has('KeyD') || keys.has('ArrowRight')) steer -= 1;  // 向右
// 可选:steer = clamp(steer + gamepadX, -1, 1) 使用相同的符号约定

// 积分(speedFactor ~ 0..1 来自 |speed|)
const reverse = speed >= 0 ? 1 : -1; // 倒车时左轮仍然向左感觉
偏航 += steer * turnRate * speedFactor * reverse * dt;

// 沿航向移动
const fx = -Math.sin(yaw), fz = -Math.cos(yaw);
position.x += fx * speed * dt;
position.z += fz * speed * dt;

经典错误(请勿复制):

// 错误——这就是导致 A/D 反转发布的实际代码
if (KeyA) steer -= 1;
if (KeyD) steer += 1;
偏航 += steer * turnRate * dt;  // A → −偏航 → 追逐摄像机下机头向右

如果你已经写了 KeyA → steer--,要么交换键位映射,要么在积分时取反一次(偏航 += -steer * …)——然后运行第5节。不要翻转两次(键位 + 积分 + 网格倾斜)。

2c. 固定翼飞行(飞机、滑翔机、遥控飞机)

输入动作玩家预期
A / ←向左滚转(副翼)左翼向下/向左倾斜
D / →向右滚转右翼向下/向右倾斜
W / ↑俯仰(选择一种方案并标注 HUD)通常是机头向下或拉起——保持一致
S / ↓相反俯仰
Q / E偏航/方向舵(可选)Q 向左,E 向右
  • A/D 不是横向平移,也不是“带有 FPS 标志的地面转向”。
  • 在载具的局部向前轴上应用滚转,并使用与A 键向左倾斜匹配的符号。如果网格倾斜方向错误,则翻转一个滚转应用上的符号(或 A/D → 滚转映射上的符号),而不是整个基础。
  • 协调转弯:正倾斜应产生一个与倾斜方向匹配的转弯,在追逐/外部摄像机视角下。

2d. 直升机 / 无人机 / 6自由度

在开始覆盖层上记录方案。最低要求:

  • 离散键上的油门/高度不能在按一次后锁定为“始终向上”(使用按住状态或明确的上下)。
  • 横向平移/偏航:在载具的水平框架中(玩家可见),A 向左,D 向右。

2e. 2D 横向卷轴 / 平台游戏

D / → 在屏幕上向右移动;A / ← 在屏幕上向左移动。只有当游戏类型明确为倒置时才反转重力。


3. 摄像机必须一致

  • 追逐摄像机:desired = craftPos + up*height + forward*(-followDist);线性插值;lookAt(craft)。
  • 为移动和摄像机一次性计算 forward——不要在摄像机路径中使用相反偏航符号重建。
  • 调试顺序:(1) 键位注册 → (2) 符号正确(第5节)→ (3) 摄像机一致。

4. 输入管道(简要)

  • 使用 Set 在 keydown/keyup 上跟踪键位,使用 event.code;在 blur/visibilitychange 时清除。在游戏循环中使用 dt 移动,而不是在按键处理程序中。
  • 将键盘 + 触控 + 游戏手柄统一为动作(throttle、steer、pitch、roll……)。参见 building-games/references/input.md。
  • 触控:左摇杆 = 移动/转向,右摇杆 = 动作;目标区域 ≥ 44px。

5. 强制性控制自检(在“完成”之前)

对于任何使用 A/D 的载具,仅截图不足以验证。

5a. 玩家可见检查清单(每个车辆/飞行构建)

在向前移动(速度 > 小 epsilon)且追逐摄像机在后方时:

按住必须在约 0.5 秒内观察到
A机头或倾斜在屏幕上向左移动
D机头或倾斜在屏幕上向右移动
W(地面)速度增加 / 沿面向方向移动
S(地面)刹车或倒车(按设计)

如果 A 失败:翻转转向/滚转符号一次,同时重新测试 A 和 D。

5b. 最小测试接口(实现此接口)

公开一个小钩子,以便你(和自动化 QA)无需猜测私有闭包即可证明符号:

// 例如 src/game/controlsTest.ts —— 仅用于开发/QA 即可
export type ControlsProbe = {
  getYaw: () => number;       // 弧度;或 getHeading()
  getSpeed: () => number;
  /** 注入按住的动作以代替真实键位;两者都会保持已应用状态,直到你
   *  更改它们,因此第5c节可以跨帧保持一个键位并在最后清除。 */
  setSteer?: (v: number) => void; // -1..1,与生产代码符号相同
  setKeys?: (codes: string[]) => void; // 保持按住直到下次调用;`[]` 清除
};

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

当 import.meta.env.DEV 或设置了 ?qa=1 标志时,从游戏循环连接 window.__controlsTest。

5c. 自动化烟雾测试(运行它)

使用预装的 agent-browser CLI 驱动第5b节的探针——这是第一步,而不是手写脚本。抛出的 eval 以非零退出;仅仅为假值的不会,因此通过抛出来断言。将其作为一个 batch 运行——一次 CLI 调用,而不是每个动词一次——从 stdin 接收 JSON;--bail 在第一个失败步骤处停止并以非零退出。

agent-browser batch --bail <<'JSON'   # find 的标签区分大小写:从 `snapshot -i` 复制
[["open","http://127.0.0.1:8080/"],
 ["find","text","Start","click"],
 ["eval","if (!window.__controlsTest?.setKeys) throw Error('缺少第5b节探针:添加 setKeys')"],
 ["eval","__controlsTest.setKeys(['KeyW'])"],
 ["wait","600"],
 ["eval","if (__controlsTest.getSpeed() <= 0.1) throw Error('W:没有移动')"],
 ["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 向右转——反转了,得到 ' + w.toFixed(2)); if (w <= 0.05) throw Error('A 几乎没有转动(' + w.toFixed(2) + ')——保持更长时间或检查模拟是否正在运行'); return 'A ok' })()"],
 ["eval","__controlsTest.setKeys([])"],
 ["screenshot","/workspace/screenshots/controls.png"],
 ["close"]]
JSON

通过探针保持键位,而不是用 keydown —— agent-browser keydown 无法到达第4节的 Set,因此正确的游戏会被读作损坏。你的探针没有 setKeys?添加它(第5b节),或者自己分发按键事件——浏览器 QA 参考的 Keys 说明有机制和表单。

保持位于一个 eval 内部:分布在多个命令中时,它会持续命令执行所需的时间,并且 Math.atan2(Math.sin(d), Math.cos(d)) 中的 ±π 环绕会将转动超过 π 的载具读作向另一方向转动。IIFE 使得步骤可重运行——裸的 const d = … 第二次会因“已声明”而失败——而 async 使得保持能在页面时间内运行。对 D 重复测试,使用 'KeyD' 并镜像两个比较(w > 0.05 是反转,w >= -0.05 是几乎没有转动),使用单引号以便 JSON 无需转义;对于飞机,断言 roll:A ⇒ 向左倾斜。

A 向右转 是符号错误:翻转一个符号并重新运行。 A 几乎没有转动 则不是——载具移动方向正确,只是在 300 毫秒内小于 0.05 弧度,这对于船或重型火星车来说会发生;增加保持时间,或检查模拟是否正在运行,且不要翻转任何内容。任何其他非零退出——没有探针、守护进程挂起——意味着检查从未运行:首先阅读消息。在第一个流程之前阅读浏览器 QA 参考的 AGENTS.md 链接——动词、参数形状和回退都在那里。

5d. 不该做什么

  • 不要只测试“D 增加了某个内部变量”。
  • 不要将 FPS 的“D → 当面向 −Z 时 +X”用作车辆通过条件。
  • 不要在修复时同时翻转网格倾斜、摄像机和转向——更改一个符号,重新测试。

6. 完成标准(控制)

  • 在编写移动/转向/飞行代码之前打开了本技能。
  • 选择了类型映射(第2节),并且开始画面/HUD 标签与之匹配。
  • 追逐摄像机 A/D 玩家可见测试通过(第5a节)。
  • window.__controlsTest(或等效项)在开发/QA 中可用并已使用一次。
  • 相对于滚转/转向输入,没有反转的倾斜网格。
  • 键位为按住状态 + dt 缩放;没有来自单次空格点击的粘性推力,除非有意识且已标注。

如果任何框未选中,则游戏未完成。

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.

相关技能