@dcl-regenesislabs/opendcl 0.1.0-22234509684.commit-63dfd19

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.
Files changed (54) hide show
  1. package/README.md +234 -0
  2. package/context/components-reference.md +113 -0
  3. package/context/open-source-3d-assets.md +705 -0
  4. package/context/sdk7-complete-reference.md +3684 -0
  5. package/context/sdk7-examples.md +1709 -0
  6. package/dist/index.d.ts +8 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +76 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/scene-context.d.ts +97 -0
  11. package/dist/scene-context.d.ts.map +1 -0
  12. package/dist/scene-context.js +203 -0
  13. package/dist/scene-context.js.map +1 -0
  14. package/dist/utils.d.ts +2 -0
  15. package/dist/utils.d.ts.map +1 -0
  16. package/dist/utils.js +4 -0
  17. package/dist/utils.js.map +1 -0
  18. package/extensions/dcl-context.ts +123 -0
  19. package/extensions/dcl-deploy.ts +89 -0
  20. package/extensions/dcl-header.ts +162 -0
  21. package/extensions/dcl-init.ts +62 -0
  22. package/extensions/dcl-preview.ts +144 -0
  23. package/extensions/dcl-setup-ollama.ts +312 -0
  24. package/extensions/dcl-setup.ts +96 -0
  25. package/extensions/dcl-status.ts +88 -0
  26. package/extensions/dcl-tasks.ts +102 -0
  27. package/extensions/dcl-update-check.ts +79 -0
  28. package/extensions/dcl-validate.ts +80 -0
  29. package/extensions/plan-mode/index.ts +340 -0
  30. package/extensions/plan-mode/utils.ts +168 -0
  31. package/extensions/process-registry.ts +25 -0
  32. package/extensions/scene-utils.ts +31 -0
  33. package/package.json +65 -0
  34. package/prompts/explain.md +16 -0
  35. package/prompts/review.md +19 -0
  36. package/prompts/system.md +126 -0
  37. package/skills/add-3d-models/SKILL.md +115 -0
  38. package/skills/add-interactivity/SKILL.md +176 -0
  39. package/skills/advanced-input/SKILL.md +238 -0
  40. package/skills/advanced-rendering/SKILL.md +235 -0
  41. package/skills/animations-tweens/SKILL.md +173 -0
  42. package/skills/audio-video/SKILL.md +167 -0
  43. package/skills/authoritative-server/SKILL.md +329 -0
  44. package/skills/build-ui/SKILL.md +231 -0
  45. package/skills/camera-control/SKILL.md +199 -0
  46. package/skills/create-scene/SKILL.md +67 -0
  47. package/skills/deploy-scene/SKILL.md +106 -0
  48. package/skills/deploy-worlds/SKILL.md +107 -0
  49. package/skills/lighting-environment/SKILL.md +216 -0
  50. package/skills/multiplayer-sync/SKILL.md +132 -0
  51. package/skills/nft-blockchain/SKILL.md +246 -0
  52. package/skills/optimize-scene/SKILL.md +160 -0
  53. package/skills/player-avatar/SKILL.md +239 -0
  54. package/skills/smart-items/SKILL.md +181 -0
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: system
3
+ description: OpenDCL system identity and Decentraland SDK7 knowledge base
4
+ ---
5
+
6
+ You are **OpenDCL**, an AI coding assistant specialized in Decentraland SDK7 scene development.
7
+
8
+ ## Your Identity
9
+ - You help creators build interactive 3D scenes for Decentraland using SDK7.
10
+ - You are beginner-friendly: always explain what you're doing and why.
11
+ - You are precise about SDK7 APIs and never invent components or functions that don't exist.
12
+ - When unsure, read the context files in the `context/` directory for accurate SDK7 reference.
13
+
14
+ ## Decentraland SDK7 Fundamentals
15
+
16
+ ### Architecture
17
+ - **Entity-Component System (ECS)**: Scenes are built with entities (IDs), components (data), and systems (logic).
18
+ - **Runtime**: Sandboxed QuickJS — **no** Node.js APIs (`fs`, `http`, `path`, `process` are unavailable).
19
+ - **Imports**: Use `@dcl/sdk/ecs`, `@dcl/sdk/math`, `@dcl/sdk/react-ecs` — never `~system/` or internal paths.
20
+ - **Entry point**: `export function main() {}` in `src/index.ts` — the engine calls this on scene load.
21
+
22
+ ### Scene Constraints
23
+ - Each **parcel** = 16m × 16m × 20m height.
24
+ - Scenes have **entity limits**, **triangle budgets**, and **texture memory limits** based on parcel count.
25
+ - 1 parcel: ~512 entities, ~10,000 triangles. Scales with parcel count.
26
+ - All coordinates are in meters. Y is up. Scene origin (0,0,0) is the southwest corner of the base parcel at ground level.
27
+
28
+ ### Key Patterns
29
+
30
+ **Creating an entity with components:**
31
+ ```typescript
32
+ import { engine, Transform, MeshRenderer, Material } from '@dcl/sdk/ecs'
33
+ import { Vector3, Color4 } from '@dcl/sdk/math'
34
+
35
+ const cube = engine.addEntity()
36
+ Transform.create(cube, { position: Vector3.create(8, 1, 8) })
37
+ MeshRenderer.setBox(cube)
38
+ Material.setPbrMaterial(cube, { albedoColor: Color4.Red() })
39
+ ```
40
+
41
+ **Adding interactivity:**
42
+ ```typescript
43
+ import { pointerEventsSystem, InputAction } from '@dcl/sdk/ecs'
44
+
45
+ pointerEventsSystem.onPointerDown({ entity: cube, opts: { button: InputAction.IA_POINTER, hoverText: 'Click me' } }, () => {
46
+ // Handle click
47
+ })
48
+ ```
49
+
50
+ **Systems (per-frame logic):**
51
+ ```typescript
52
+ engine.addSystem((dt: number) => {
53
+ // Runs every frame, dt = delta time in seconds
54
+ })
55
+ ```
56
+
57
+ **UI with React-ECS:**
58
+ ```tsx
59
+ import ReactEcs, { UiEntity, Label, Button } from '@dcl/sdk/react-ecs'
60
+
61
+ function MyUI() {
62
+ return (
63
+ <UiEntity uiTransform={{ width: 200, height: 50, positionType: 'absolute' }}>
64
+ <Label value="Hello" fontSize={18} />
65
+ </UiEntity>
66
+ )
67
+ }
68
+
69
+ export function setupUi() {
70
+ ReactEcs.setUiRenderer(MyUI)
71
+ }
72
+ ```
73
+
74
+ ### Project Structure
75
+ ```
76
+ scene-project/
77
+ ├── scene.json # Scene metadata (parcels, title, main entry)
78
+ ├── package.json # Dependencies (@dcl/sdk)
79
+ ├── tsconfig.json # TypeScript config
80
+ └── src/
81
+ ├── index.ts # Main entry point (export function main)
82
+ └── ui.tsx # UI components (optional)
83
+ ```
84
+
85
+ ### scene.json Required Fields
86
+ ```json
87
+ {
88
+ "ecs7": true,
89
+ "runtimeVersion": "7",
90
+ "display": { "title": "My Scene" },
91
+ "scene": { "parcels": ["0,0"], "base": "0,0" },
92
+ "main": "bin/index.js"
93
+ }
94
+ ```
95
+
96
+ ## How to Help Users
97
+
98
+ ### Empty Folder (No scene.json)
99
+ 1. Ask the user what they want to build.
100
+ 2. **Use the `init` tool first** — this uses the official SDK scaffolding to create scene.json, package.json, tsconfig.json, and src/index.ts with the correct, up-to-date configuration. Never create these files manually.
101
+ 3. After init completes, customize `scene.json` (title, description, parcels) and `src/index.ts` (scene code) based on what the user wants.
102
+ 4. Run `npm install`, then use the `preview` tool to start the preview server.
103
+
104
+ ### Existing Scene
105
+ 1. Read scene.json and src/index.ts to understand the project.
106
+ 2. Offer contextual help — adding features, fixing bugs, optimizing.
107
+ 3. Always preserve existing code when making edits.
108
+
109
+ ### Best Practices
110
+ - Always position objects within the scene boundaries (based on parcels).
111
+ - Use `Vector3.create()` and `Quaternion.fromEulerDegrees()` for transforms.
112
+ - For 3D models, use `GltfContainer.create(entity, { src: 'models/myModel.glb' })`.
113
+ - Place `.glb` files in a `models/` directory, textures in `images/`.
114
+ - After writing TypeScript, use the `preview` tool to start the preview server.
115
+ - If the user asks about 3D models, reference the open-source-3D-assets catalog in `context/open-source-3d-assets.md`.
116
+
117
+ ## Tools & Commands
118
+
119
+ You have these Decentraland-specific tools — **use them directly** when the user's request matches:
120
+ - `init` — Scaffold a new scene (**always use this first** in an empty folder)
121
+ - `preview` — Start the Bevy-web preview server
122
+ - `deploy` — Deploy to Genesis City or a World (auto-detects from scene.json)
123
+ - `tasks` — List or stop running background processes
124
+
125
+ The user can also type these as `/init`, `/preview`, `/deploy`, `/tasks` slash commands directly.
126
+ Additional user-only commands: `/review`, `/explain`, `/setup`, `/setup-ollama`
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: add-3d-models
3
+ description: Add 3D models (.glb/.gltf) to a Decentraland scene using GltfContainer. Covers loading models, positioning, scaling, colliders, and browsing the open-source 3D assets catalog for free CC0 models. Use when user wants to add models, import GLB files, or find free 3D assets.
4
+ ---
5
+
6
+ # Adding 3D Models to Decentraland Scenes
7
+
8
+ ## Loading a 3D Model
9
+
10
+ Use `GltfContainer` to load `.glb` or `.gltf` files:
11
+
12
+ ```typescript
13
+ import { engine, Transform, GltfContainer } from '@dcl/sdk/ecs'
14
+ import { Vector3, Quaternion } from '@dcl/sdk/math'
15
+
16
+ const model = engine.addEntity()
17
+ Transform.create(model, {
18
+ position: Vector3.create(8, 0, 8),
19
+ rotation: Quaternion.fromEulerDegrees(0, 0, 0),
20
+ scale: Vector3.create(1, 1, 1)
21
+ })
22
+ GltfContainer.create(model, {
23
+ src: 'models/myModel.glb'
24
+ })
25
+ ```
26
+
27
+ ## File Organization
28
+
29
+ Place model files in a `models/` directory at the project root:
30
+ ```
31
+ project/
32
+ ├── models/
33
+ │ ├── building.glb
34
+ │ ├── tree.glb
35
+ │ └── furniture/
36
+ │ ├── chair.glb
37
+ │ └── table.glb
38
+ ├── src/
39
+ │ └── index.ts
40
+ └── scene.json
41
+ ```
42
+
43
+ ## Colliders
44
+
45
+ ### Using Model's Built-in Colliders
46
+ Models exported with collision meshes work automatically. Set the collision mask:
47
+ ```typescript
48
+ GltfContainer.create(model, {
49
+ src: 'models/building.glb',
50
+ visibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS | ColliderLayer.CL_POINTER,
51
+ invisibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS
52
+ })
53
+ ```
54
+
55
+ ### Adding Simple Colliders
56
+ For basic shapes, add `MeshCollider`:
57
+ ```typescript
58
+ import { MeshCollider } from '@dcl/sdk/ecs'
59
+ MeshCollider.setBox(model) // Box collider
60
+ MeshCollider.setSphere(model) // Sphere collider
61
+ ```
62
+
63
+ ## Common Model Operations
64
+
65
+ ### Scaling
66
+ ```typescript
67
+ Transform.create(model, {
68
+ position: Vector3.create(8, 0, 8),
69
+ scale: Vector3.create(2, 2, 2) // 2x size
70
+ })
71
+ ```
72
+
73
+ ### Rotation
74
+ ```typescript
75
+ Transform.create(model, {
76
+ position: Vector3.create(8, 0, 8),
77
+ rotation: Quaternion.fromEulerDegrees(0, 90, 0) // Rotate 90° on Y axis
78
+ })
79
+ ```
80
+
81
+ ### Parenting (Attach to Another Entity)
82
+ ```typescript
83
+ const parent = engine.addEntity()
84
+ Transform.create(parent, { position: Vector3.create(8, 0, 8) })
85
+
86
+ const child = engine.addEntity()
87
+ Transform.create(child, {
88
+ position: Vector3.create(0, 2, 0), // 2m above parent
89
+ parent: parent
90
+ })
91
+ GltfContainer.create(child, { src: 'models/hat.glb' })
92
+ ```
93
+
94
+ ## Free 3D Models
95
+
96
+ For free CC0-licensed 3D models suitable for Decentraland, read the catalog at:
97
+ `context/open-source-3d-assets.md` (in the opendcl repo root). If unavailable locally, fetch from:
98
+ https://raw.githubusercontent.com/dcl-regenesislabs/opendcl/main/context/open-source-3d-assets.md
99
+
100
+ This catalog contains 991+ models organized by themed collections (Cyberpunk, Medieval, MomusPark, etc.) with direct download URLs.
101
+
102
+ When the user asks for 3D models:
103
+ 1. Read the open-source-3d-assets.md file
104
+ 2. Suggest models that match their description
105
+ 3. Show them how to download and add the model to their scene
106
+
107
+ ## Model Best Practices
108
+
109
+ - Keep models under 50MB per file for good loading times
110
+ - Use `.glb` format (binary GLTF) — smaller than `.gltf`
111
+ - Optimize triangle count: aim for under 1,500 triangles per model for small props
112
+ - Use texture atlases when possible to reduce draw calls
113
+ - Models with embedded animations can be played with the `Animator` component
114
+ - Test model orientation — Decentraland uses Y-up coordinate system
115
+ - Materials in models should use PBR (physically-based rendering) for best results
@@ -0,0 +1,176 @@
1
+ ---
2
+ name: add-interactivity
3
+ description: Add click handlers, hover effects, pointer events, triggers, and raycasting to Decentraland scene entities. Use when user wants to make objects clickable, add interactions, detect player proximity, or handle user input.
4
+ ---
5
+
6
+ # Adding Interactivity to Decentraland Scenes
7
+
8
+ ## Pointer Events (Click / Hover)
9
+
10
+ ### Using the Helper System (Recommended)
11
+ ```typescript
12
+ import { engine, Transform, MeshRenderer, pointerEventsSystem, InputAction } from '@dcl/sdk/ecs'
13
+ import { Vector3 } from '@dcl/sdk/math'
14
+
15
+ const cube = engine.addEntity()
16
+ Transform.create(cube, { position: Vector3.create(8, 1, 8) })
17
+ MeshRenderer.setBox(cube)
18
+
19
+ // Add click handler
20
+ pointerEventsSystem.onPointerDown(
21
+ {
22
+ entity: cube,
23
+ opts: {
24
+ button: InputAction.IA_POINTER, // Left click
25
+ hoverText: 'Click me!',
26
+ maxDistance: 10
27
+ }
28
+ },
29
+ (event) => {
30
+ console.log('Cube clicked!', event.hit?.position)
31
+ }
32
+ )
33
+ ```
34
+
35
+ ### Available Input Actions
36
+ ```typescript
37
+ InputAction.IA_POINTER // Left click / primary
38
+ InputAction.IA_PRIMARY // E key
39
+ InputAction.IA_SECONDARY // F key
40
+ InputAction.IA_ACTION_3 // Key 1
41
+ InputAction.IA_ACTION_4 // Key 2
42
+ InputAction.IA_ACTION_5 // Key 3
43
+ InputAction.IA_ACTION_6 // Key 4
44
+ ```
45
+
46
+ ### Pointer Up (Release)
47
+ ```typescript
48
+ pointerEventsSystem.onPointerDown(
49
+ { entity: cube, opts: { button: InputAction.IA_POINTER, hoverText: 'Hold me' } },
50
+ () => { console.log('Pressed!') }
51
+ )
52
+
53
+ pointerEventsSystem.onPointerUp(
54
+ { entity: cube, opts: { button: InputAction.IA_POINTER } },
55
+ () => { console.log('Released!') }
56
+ )
57
+ ```
58
+
59
+ ### Removing Handlers
60
+ ```typescript
61
+ pointerEventsSystem.removeOnPointerDown(cube)
62
+ pointerEventsSystem.removeOnPointerUp(cube)
63
+ ```
64
+
65
+ ### Important: Colliders Required
66
+ Pointer events only work on entities with a **collider**. Add one if your entity doesn't have a mesh:
67
+ ```typescript
68
+ import { MeshCollider } from '@dcl/sdk/ecs'
69
+ MeshCollider.setBox(entity) // Invisible box collider
70
+ ```
71
+
72
+ For GLTF models, set the collision mask:
73
+ ```typescript
74
+ GltfContainer.create(entity, {
75
+ src: 'models/button.glb',
76
+ visibleMeshesCollisionMask: ColliderLayer.CL_POINTER
77
+ })
78
+ ```
79
+
80
+ ## Trigger Areas (Proximity Detection)
81
+
82
+ Detect when the player enters or exits an area:
83
+
84
+ ```typescript
85
+ import { engine, Transform, TriggerArea, TriggerAreaResult } from '@dcl/sdk/ecs'
86
+ import { Vector3 } from '@dcl/sdk/math'
87
+
88
+ const trigger = engine.addEntity()
89
+ Transform.create(trigger, { position: Vector3.create(8, 0, 8) })
90
+
91
+ TriggerArea.create(trigger, {
92
+ area: Vector3.create(4, 4, 4) // 4x4x4 meter box
93
+ })
94
+
95
+ // System to check trigger
96
+ engine.addSystem(() => {
97
+ const result = TriggerAreaResult.getOrNull(trigger)
98
+ if (result && result.isTriggered) {
99
+ // Player is inside the trigger area
100
+ }
101
+ })
102
+ ```
103
+
104
+ ## Raycasting
105
+
106
+ Cast rays to detect objects in a direction:
107
+
108
+ ```typescript
109
+ import { engine, Raycast, RaycastResult, RaycastQueryType } from '@dcl/sdk/ecs'
110
+ import { Vector3 } from '@dcl/sdk/math'
111
+
112
+ const rayEntity = engine.addEntity()
113
+ Raycast.create(rayEntity, {
114
+ direction: { $case: 'localDirection', localDirection: Vector3.Forward() },
115
+ maxDistance: 16,
116
+ queryType: RaycastQueryType.RQT_HIT_FIRST,
117
+ continuous: false // Set true for continuous raycasting
118
+ })
119
+
120
+ // Check results
121
+ engine.addSystem(() => {
122
+ const result = RaycastResult.getOrNull(rayEntity)
123
+ if (result && result.hits.length > 0) {
124
+ const hit = result.hits[0]
125
+ console.log('Hit entity:', hit.entityId, 'at', hit.position)
126
+ }
127
+ })
128
+ ```
129
+
130
+ ## Global Input Handling
131
+
132
+ Listen for key presses anywhere (not entity-specific):
133
+
134
+ ```typescript
135
+ import { inputSystem, InputAction, PointerEventType } from '@dcl/sdk/ecs'
136
+
137
+ engine.addSystem(() => {
138
+ // Check if E key was just pressed this frame
139
+ if (inputSystem.isTriggered(InputAction.IA_PRIMARY, PointerEventType.PET_DOWN)) {
140
+ console.log('E key pressed!')
141
+ }
142
+
143
+ // Check if a key is currently held down
144
+ if (inputSystem.isPressed(InputAction.IA_SECONDARY)) {
145
+ console.log('F key is held!')
146
+ }
147
+ })
148
+ ```
149
+
150
+ ## Toggle Pattern (Click to Switch States)
151
+
152
+ Common pattern for toggleable objects:
153
+
154
+ ```typescript
155
+ let doorOpen = false
156
+
157
+ pointerEventsSystem.onPointerDown(
158
+ { entity: door, opts: { button: InputAction.IA_POINTER, hoverText: 'Toggle door' } },
159
+ () => {
160
+ doorOpen = !doorOpen
161
+ const mutableTransform = Transform.getMutable(door)
162
+ mutableTransform.rotation = doorOpen
163
+ ? Quaternion.fromEulerDegrees(0, 90, 0)
164
+ : Quaternion.fromEulerDegrees(0, 0, 0)
165
+ }
166
+ )
167
+ ```
168
+
169
+ ## Best Practices
170
+
171
+ - Always set `maxDistance` on pointer events (8-16m is typical)
172
+ - Always set `hoverText` so users know they can interact
173
+ - Clean up handlers when entities are removed
174
+ - Use `MeshCollider` for invisible trigger surfaces
175
+ - For complex interactions, use a system with state tracking
176
+ - Test interactions in preview — hover text should be visible and clear
@@ -0,0 +1,238 @@
1
+ ---
2
+ name: advanced-input
3
+ description: Advanced input handling in Decentraland scenes. Use PointerLock to detect cursor capture state, InputModifier to freeze or restrict player movement, PrimaryPointerInfo for cursor position and world ray, inputSystem.getInputCommand for per-entity input polling, and keyboard patterns for WASD movement controls. Use when user wants custom input, cursor control, movement restriction, keyboard handling, FPS controls, or input polling.
4
+ ---
5
+
6
+ # Advanced Input Handling in Decentraland
7
+
8
+ For basic click/hover events, see the `add-interactivity` skill. This skill covers advanced input patterns.
9
+
10
+ ## Pointer Lock State
11
+
12
+ Detect whether the cursor is captured (first-person mode) or free:
13
+
14
+ ```typescript
15
+ import { engine, PointerLock } from '@dcl/sdk/ecs'
16
+
17
+ function checkPointerLock() {
18
+ const isLocked = PointerLock.get(engine.CameraEntity).isPointerLocked
19
+
20
+ if (isLocked) {
21
+ // Cursor is captured — player is in first-person control
22
+ } else {
23
+ // Cursor is free — player can click UI elements
24
+ }
25
+ }
26
+
27
+ engine.addSystem(checkPointerLock)
28
+ ```
29
+
30
+ ### Pointer Lock Change Detection
31
+
32
+ ```typescript
33
+ PointerLock.onChange(engine.CameraEntity, (pointerLock) => {
34
+ if (pointerLock?.isPointerLocked) {
35
+ console.log('Cursor locked')
36
+ } else {
37
+ console.log('Cursor unlocked')
38
+ }
39
+ })
40
+ ```
41
+
42
+ ## Cursor Position and World Ray
43
+
44
+ Get the cursor's screen position and the ray it casts into the 3D world:
45
+
46
+ ```typescript
47
+ import { engine, PrimaryPointerInfo } from '@dcl/sdk/ecs'
48
+
49
+ function readPointer() {
50
+ const pointerInfo = PrimaryPointerInfo.get(engine.RootEntity)
51
+ console.log('Cursor position:', pointerInfo.screenCoordinates)
52
+ console.log('Cursor delta:', pointerInfo.screenDelta)
53
+ console.log('World ray direction:', pointerInfo.worldRayDirection)
54
+ }
55
+
56
+ engine.addSystem(readPointer)
57
+ ```
58
+
59
+ ## Input Polling with inputSystem
60
+
61
+ ### Per-Entity Input Commands
62
+
63
+ Check if a specific input action occurred on a specific entity:
64
+
65
+ ```typescript
66
+ import { engine, inputSystem, InputAction, PointerEventType } from '@dcl/sdk/ecs'
67
+
68
+ function myInputSystem() {
69
+ // Check for click on a specific entity
70
+ const clickData = inputSystem.getInputCommand(
71
+ InputAction.IA_POINTER,
72
+ PointerEventType.PET_DOWN,
73
+ myEntity
74
+ )
75
+
76
+ if (clickData) {
77
+ console.log('Entity clicked via system:', clickData.hit.entityId)
78
+ }
79
+ }
80
+
81
+ engine.addSystem(myInputSystem)
82
+ ```
83
+
84
+ ### Global Input Checks
85
+
86
+ ```typescript
87
+ function globalInputSystem() {
88
+ // Was the key just pressed this frame?
89
+ if (inputSystem.isTriggered(InputAction.IA_PRIMARY, PointerEventType.PET_DOWN)) {
90
+ console.log('E key pressed!')
91
+ }
92
+
93
+ // Is the key currently held down?
94
+ if (inputSystem.isPressed(InputAction.IA_SECONDARY)) {
95
+ console.log('F key is held!')
96
+ }
97
+ }
98
+
99
+ engine.addSystem(globalInputSystem)
100
+ ```
101
+
102
+ ## All InputAction Values
103
+
104
+ | InputAction | Key/Button |
105
+ |-------------|-----------|
106
+ | `IA_POINTER` | Left mouse button |
107
+ | `IA_PRIMARY` | E key |
108
+ | `IA_SECONDARY` | F key |
109
+ | `IA_ACTION_3` | 1 key |
110
+ | `IA_ACTION_4` | 2 key |
111
+ | `IA_ACTION_5` | 3 key |
112
+ | `IA_ACTION_6` | 4 key |
113
+ | `IA_JUMP` | Space key |
114
+ | `IA_FORWARD` | W key |
115
+ | `IA_BACKWARD` | S key |
116
+ | `IA_LEFT` | A key |
117
+ | `IA_RIGHT` | D key |
118
+ | `IA_WALK` | Shift key |
119
+
120
+ ## Event Types
121
+
122
+ ```typescript
123
+ PointerEventType.PET_DOWN // Button/key pressed
124
+ PointerEventType.PET_UP // Button/key released
125
+ PointerEventType.PET_HOVER_ENTER // Cursor enters entity
126
+ PointerEventType.PET_HOVER_LEAVE // Cursor leaves entity
127
+ ```
128
+
129
+ ## InputModifier (Movement Restriction)
130
+
131
+ Restrict or freeze the player's movement:
132
+
133
+ ```typescript
134
+ import { engine, InputModifier } from '@dcl/sdk/ecs'
135
+
136
+ // Freeze player completely
137
+ InputModifier.create(engine.PlayerEntity, {
138
+ mode: InputModifier.Mode.Standard({ disableAll: true })
139
+ })
140
+
141
+ // Restrict specific movement
142
+ InputModifier.createOrReplace(engine.PlayerEntity, {
143
+ mode: InputModifier.Mode.Standard({
144
+ disableRun: true,
145
+ disableJump: true,
146
+ disableEmote: true
147
+ })
148
+ })
149
+
150
+ // Restore normal movement
151
+ InputModifier.deleteFrom(engine.PlayerEntity)
152
+ ```
153
+
154
+ **Important:** InputModifier only works in the DCL 2.0 desktop client. It has no effect in the web browser explorer.
155
+
156
+ ### Cutscene Pattern
157
+
158
+ Freeze the player during a cinematic sequence:
159
+
160
+ ```typescript
161
+ function startCutscene() {
162
+ // Freeze player
163
+ InputModifier.create(engine.PlayerEntity, {
164
+ mode: InputModifier.Mode.Standard({ disableAll: true })
165
+ })
166
+
167
+ // ... play cinematic with VirtualCamera ...
168
+
169
+ // After cutscene ends, restore movement
170
+ // InputModifier.deleteFrom(engine.PlayerEntity)
171
+ }
172
+ ```
173
+
174
+ ## WASD Movement Pattern
175
+
176
+ Poll movement keys to control custom entities:
177
+
178
+ ```typescript
179
+ import { engine, inputSystem, InputAction, PointerEventType, Transform } from '@dcl/sdk/ecs'
180
+ import { Vector3 } from '@dcl/sdk/math'
181
+
182
+ const MOVE_SPEED = 5
183
+
184
+ function customMovementSystem(dt: number) {
185
+ const transform = Transform.getMutable(controllableEntity)
186
+ let moveX = 0
187
+ let moveZ = 0
188
+
189
+ if (inputSystem.isPressed(InputAction.IA_FORWARD)) moveZ += 1
190
+ if (inputSystem.isPressed(InputAction.IA_BACKWARD)) moveZ -= 1
191
+ if (inputSystem.isPressed(InputAction.IA_LEFT)) moveX -= 1
192
+ if (inputSystem.isPressed(InputAction.IA_RIGHT)) moveX += 1
193
+
194
+ transform.position.x += moveX * MOVE_SPEED * dt
195
+ transform.position.z += moveZ * MOVE_SPEED * dt
196
+ }
197
+
198
+ engine.addSystem(customMovementSystem)
199
+ ```
200
+
201
+ ## Combining Input Patterns
202
+
203
+ ### Action Bar with Number Keys
204
+
205
+ ```typescript
206
+ function actionBarSystem() {
207
+ if (inputSystem.isTriggered(InputAction.IA_ACTION_3, PointerEventType.PET_DOWN)) {
208
+ console.log('Slot 1 activated')
209
+ useAbility(1)
210
+ }
211
+ if (inputSystem.isTriggered(InputAction.IA_ACTION_4, PointerEventType.PET_DOWN)) {
212
+ console.log('Slot 2 activated')
213
+ useAbility(2)
214
+ }
215
+ if (inputSystem.isTriggered(InputAction.IA_ACTION_5, PointerEventType.PET_DOWN)) {
216
+ console.log('Slot 3 activated')
217
+ useAbility(3)
218
+ }
219
+ if (inputSystem.isTriggered(InputAction.IA_ACTION_6, PointerEventType.PET_DOWN)) {
220
+ console.log('Slot 4 activated')
221
+ useAbility(4)
222
+ }
223
+ }
224
+
225
+ engine.addSystem(actionBarSystem)
226
+ ```
227
+
228
+ ## Best Practices
229
+
230
+ - Use `isTriggered()` for one-shot actions (fire weapon, open door) — it returns true only on the frame the key is first pressed
231
+ - Use `isPressed()` for continuous actions (movement, holding a shield) — it returns true every frame while held
232
+ - `getInputCommand()` gives hit data (position, entity) — use it when you need to know what was clicked
233
+ - Prefer `pointerEventsSystem.onPointerDown()` for simple entity clicks — use `inputSystem` for complex multi-key or polling patterns
234
+ - InputModifier only works in the DCL 2.0 desktop client — test with the desktop client if your scene relies on it
235
+ - WASD keys (`IA_FORWARD`, etc.) also control player movement — polling them reads the movement state but doesn't override it
236
+
237
+ For basic pointer events and click handlers, see the `add-interactivity` skill.
238
+ For component field details, see `context/components-reference.md`.