@dcl-regenesislabs/opendcl 0.2.1-26238928766.commit-28648d7 → 0.2.1

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 (45) hide show
  1. package/README.md +3 -5
  2. package/context/sdk7-cheat-sheet.md +0 -4
  3. package/dist/index.js +12 -0
  4. package/dist/index.js.map +1 -1
  5. package/extensions/dcl-init.ts +6 -58
  6. package/extensions/dcl-setup-ollama.ts +312 -0
  7. package/package.json +4 -3
  8. package/prompts/system.md +41 -71
  9. package/skills/add-3d-models/SKILL.md +70 -120
  10. package/skills/add-interactivity/SKILL.md +2 -74
  11. package/skills/advanced-input/SKILL.md +1 -34
  12. package/skills/advanced-rendering/SKILL.md +9 -82
  13. package/skills/animations-tweens/SKILL.md +98 -203
  14. package/skills/audio-video/SKILL.md +83 -184
  15. package/skills/build-ui/SKILL.md +2 -25
  16. package/skills/camera-control/SKILL.md +7 -78
  17. package/skills/create-scene/SKILL.md +13 -56
  18. package/skills/deploy-scene/SKILL.md +0 -12
  19. package/skills/deploy-worlds/SKILL.md +0 -35
  20. package/skills/game-design/SKILL.md +2 -1
  21. package/skills/lighting-environment/SKILL.md +56 -103
  22. package/skills/multiplayer-sync/SKILL.md +2 -31
  23. package/skills/nft-blockchain/SKILL.md +40 -45
  24. package/skills/optimize-scene/SKILL.md +2 -7
  25. package/skills/player-avatar/SKILL.md +7 -133
  26. package/skills/scene-runtime/SKILL.md +5 -9
  27. package/skills/visual-feedback/SKILL.md +0 -1
  28. package/skills/audio-analysis/SKILL.md +0 -164
  29. package/skills/editor-gizmo/.gitignore +0 -11
  30. package/skills/editor-gizmo/SKILL.md +0 -222
  31. package/skills/editor-gizmo/src/__editor/camera.ts +0 -277
  32. package/skills/editor-gizmo/src/__editor/discovery.ts +0 -186
  33. package/skills/editor-gizmo/src/__editor/drag.ts +0 -265
  34. package/skills/editor-gizmo/src/__editor/gizmo.ts +0 -496
  35. package/skills/editor-gizmo/src/__editor/history.ts +0 -72
  36. package/skills/editor-gizmo/src/__editor/index.ts +0 -137
  37. package/skills/editor-gizmo/src/__editor/input.ts +0 -55
  38. package/skills/editor-gizmo/src/__editor/math-utils.ts +0 -114
  39. package/skills/editor-gizmo/src/__editor/persistence.ts +0 -113
  40. package/skills/editor-gizmo/src/__editor/selection.ts +0 -157
  41. package/skills/editor-gizmo/src/__editor/state.ts +0 -117
  42. package/skills/editor-gizmo/src/__editor/ui.tsx +0 -697
  43. package/skills/npcs/SKILL.md +0 -180
  44. package/skills/particle-system/SKILL.md +0 -222
  45. package/skills/player-physics/SKILL.md +0 -93
@@ -5,47 +5,22 @@ description: Dynamic lighting and environment in Decentraland scenes. LightSourc
5
5
 
6
6
  # Lighting and Environment in Decentraland
7
7
 
8
- ## Authoring split
9
-
10
- `LightSource` is supported in `main-entities.ts` — declare the lamp's fixture model AND its light in the same entry. The user can drag the fixture in the editor and the light follows.
11
-
12
- ```typescript
13
- // main-entities.ts
14
- import type { Scene } from '@dcl/sdk/scene-types'
15
-
16
- export const scene = {
17
- ceiling_lamp: {
18
- components: {
19
- Transform: { position: { x: 8, y: 3, z: 8 } },
20
- GltfContainer: { src: 'models/lamp.glb' },
21
- LightSource: {
22
- type: { $case: 'point', point: {} },
23
- color: { r: 1, g: 1, b: 1 },
24
- intensity: 16000
25
- }
26
- }
27
- }
28
- } satisfies Scene
29
- ```
30
-
31
- For purely decorative lights with no mesh, declare a Transform-only entity and skip `GltfContainer`. Toggling lights at runtime still happens in `src/index.ts` via `LightSource.getMutable(getEntityOrNullByName('ceiling_lamp'))`.
32
-
33
8
  ## Point Lights
34
9
 
35
10
  Emit light in all directions from a position:
36
11
 
37
12
  ```typescript
38
- // main-entities.ts entry
39
- ambient_point: {
40
- components: {
41
- Transform: { position: { x: 8, y: 3, z: 8 } },
42
- LightSource: {
43
- type: { $case: 'point', point: {} },
44
- color: { r: 1, g: 1, b: 1 },
45
- intensity: 16000 // candela — point lights typically need 8000–32000 to be visible
46
- }
47
- }
48
- }
13
+ import { engine, Transform, LightSource } from '@dcl/sdk/ecs'
14
+ import { Vector3, Color3 } from '@dcl/sdk/math'
15
+
16
+ const light = engine.addEntity()
17
+ Transform.create(light, { position: Vector3.create(8, 3, 8) })
18
+
19
+ LightSource.create(light, {
20
+ type: LightSource.Type.Point({}),
21
+ color: Color3.White(),
22
+ intensity: 300 // candela
23
+ })
49
24
  ```
50
25
 
51
26
  ### Colored Point Light
@@ -54,31 +29,29 @@ ambient_point: {
54
29
  LightSource.create(light, {
55
30
  type: LightSource.Type.Point({}),
56
31
  color: Color3.create(1, 0.5, 0), // Warm orange
57
- intensity: 12000,
32
+ intensity: 200,
58
33
  range: 15 // Maximum distance in meters
59
34
  })
60
35
  ```
61
36
 
62
37
  ## Spot Lights
63
38
 
64
- Emit a cone of light in a direction. The cone's orientation comes from the entity's Transform rotation.
39
+ Emit a cone of light in a direction:
65
40
 
66
41
  ```typescript
67
- // main-entities.ts
68
- stage_spot: {
69
- components: {
70
- Transform: {
71
- position: { x: 8, y: 4, z: 8 },
72
- rotation: { x: -0.7071, y: 0, z: 0, w: 0.7071 } // pitch -90° (down)
73
- },
74
- GltfContainer: { src: 'models/spotlight.glb' },
75
- LightSource: {
76
- type: { $case: 'spot', spot: { innerAngle: 25, outerAngle: 45 } },
77
- color: { r: 1, g: 1, b: 1 },
78
- intensity: 16000
79
- }
80
- }
81
- }
42
+ import { Quaternion } from '@dcl/sdk/math'
43
+
44
+ const spotlight = engine.addEntity()
45
+ Transform.create(spotlight, {
46
+ position: Vector3.create(8, 4, 8),
47
+ rotation: Quaternion.fromEulerDegrees(-90, 0, 0) // Point downward
48
+ })
49
+
50
+ LightSource.create(spotlight, {
51
+ type: LightSource.Type.Spot({ innerAngle: 25, outerAngle: 45 }),
52
+ color: Color3.White(),
53
+ intensity: 800
54
+ })
82
55
  ```
83
56
 
84
57
  - `innerAngle` — full-brightness cone angle (degrees)
@@ -93,12 +66,10 @@ Enable shadows on point or spot lights:
93
66
  LightSource.create(spotlight, {
94
67
  type: LightSource.Type.Spot({ innerAngle: 25, outerAngle: 45 }),
95
68
  shadow: true,
96
- intensity: 16000
69
+ intensity: 800
97
70
  })
98
71
  ```
99
72
 
100
- > Shadows are only available on **spot lights**, not point lights.
101
-
102
73
  ### Shadow Mask Textures (Gobos)
103
74
 
104
75
  Project a pattern through the light:
@@ -120,11 +91,10 @@ lightData.active = !lightData.active
120
91
 
121
92
  ## Light Limits
122
93
 
123
- - Maximum **one active light per parcel** (16m x 16m) — multi-parcel scenes can group lights close together when needed.
124
- - The renderer auto-culls lights based on quality settings and proximity. Quality range allows **4–10 lights visible simultaneously**.
125
- - Shadows are only available on spot lights; up to ~3 shadowed lights visible at once.
126
- - Intensity is in candela. Practical visible range: point lights ~8000–32000, spot lights ~10000–24000. Values below ~1000 are usually invisible.
127
- - Emissive materials **don't illuminate surrounding entities** — they only have a glow effect on themselves. Combine an emissive material with a `LightSource` for both.
94
+ - Maximum **one active light per parcel** (16m x 16m)
95
+ - The renderer auto-culls lights based on quality settings and proximity
96
+ - Up to ~3 shadowed lights visible at once
97
+ - Intensity is in candela visible distance grows roughly with `sqrt(intensity)`
128
98
 
129
99
  ## SkyboxTime (Day/Night Cycle)
130
100
 
@@ -201,55 +171,38 @@ executeTask(async () => {
201
171
 
202
172
  ## Emissive Materials (Glow Effects)
203
173
 
204
- `Material` is supported in `main-entities.ts`, so a glow that doesn't need to cast light on surroundings can be declared inline:
174
+ For a visual glow without casting light on surroundings:
205
175
 
206
176
  ```typescript
207
- // main-entities.ts
208
- glowing_orb: {
209
- components: {
210
- Transform: { position: { x: 8, y: 1, z: 8 } },
211
- MeshRenderer: { mesh: { $case: 'sphere', sphere: {} } },
212
- Material: {
213
- material: {
214
- $case: 'pbr',
215
- pbr: {
216
- albedoColor: { r: 0, g: 0, b: 0, a: 1 },
217
- emissiveColor: { r: 0, g: 1, b: 0 },
218
- emissiveIntensity: 2.0
219
- }
220
- }
221
- }
222
- }
223
- }
177
+ import { engine, Material } from '@dcl/sdk/ecs'
178
+ import { Color4, Color3 } from '@dcl/sdk/math'
179
+
180
+ // Self-illuminated material (emissiveColor uses Color3, not Color4)
181
+ Material.setPbrMaterial(entity, {
182
+ albedoColor: Color4.create(0, 0, 0, 1),
183
+ emissiveColor: Color3.create(0, 1, 0), // Green glow
184
+ emissiveIntensity: 2.0
185
+ })
224
186
  ```
225
187
 
226
188
  ### Combining Emissive + LightSource
227
189
 
228
- A single entity can carry both emissive glow on the material AND light emission.
190
+ For an object that both glows visually and casts light:
229
191
 
230
192
  ```typescript
231
- // main-entities.ts
232
- bulb: {
233
- components: {
234
- Transform: { position: { x: 8, y: 3, z: 8 } },
235
- GltfContainer: { src: 'models/bulb.glb' },
236
- Material: {
237
- material: {
238
- $case: 'pbr',
239
- pbr: {
240
- emissiveColor: { r: 1, g: 0.9, b: 0.7 },
241
- emissiveIntensity: 1.5
242
- }
243
- }
244
- },
245
- LightSource: {
246
- type: { $case: 'point', point: {} },
247
- color: { r: 1, g: 0.9, b: 0.7 },
248
- intensity: 12000,
249
- range: 10
250
- }
251
- }
252
- }
193
+ // Visual glow on the mesh
194
+ Material.setPbrMaterial(bulb, {
195
+ emissiveColor: Color3.create(1, 0.9, 0.7),
196
+ emissiveIntensity: 1.5
197
+ })
198
+
199
+ // Actual light emission
200
+ LightSource.create(bulb, {
201
+ type: LightSource.Type.Point({}),
202
+ color: Color3.create(1, 0.9, 0.7),
203
+ intensity: 200,
204
+ range: 10
205
+ })
253
206
  ```
254
207
 
255
208
  ### Shadow Types
@@ -267,7 +220,7 @@ LightSource.create(spotEntity, {
267
220
  shadow: PBLightSource_ShadowType.ST_SOFT
268
221
  }),
269
222
  shadow: true,
270
- intensity: 16000
223
+ intensity: 800
271
224
  })
272
225
  ```
273
226
 
@@ -5,36 +5,7 @@ description: Synchronize state between players in Decentraland using CRDT networ
5
5
 
6
6
  # Multiplayer Synchronization in Decentraland
7
7
 
8
- ## Authoring split
9
-
10
- `syncEntity()` adds a `NetworkEntity` component at runtime — and `NetworkEntity` is **not** in `main-entities.ts`'s supported component list. The pattern is:
11
-
12
- - **Predefined synced entities** (a door, a switch, a scoreboard — known at author time): declare them in `main-entities.ts` with their visual components. Look them up in `src/index.ts` and call `syncEntity(entity, [...componentIds], SyncIds.NAME)` there.
13
- - **Dynamically-spawned synced entities** (projectiles, drops, runtime-created game objects): create with `engine.addEntity()` in `src/index.ts` and `syncEntity` immediately.
14
-
15
- ```typescript
16
- // main-entities.ts
17
- door: {
18
- components: {
19
- Transform: { position: { x: 8, y: 1, z: 8 } },
20
- MeshRenderer: { mesh: { $case: 'box', box: { uvs: [] } } }
21
- }
22
- }
23
- ```
24
-
25
- ```typescript
26
- // src/index.ts
27
- import { engine, Transform, syncEntity } from '@dcl/sdk/network'
28
-
29
- export function main() {
30
- const door = engine.getEntityOrNullByName('door')
31
- if (door) syncEntity(door, [Transform.componentId], SyncIds.DOOR)
32
- }
33
- ```
34
-
35
- Decentraland scenes are inherently multiplayer — every player in the same scene shares the same space. **By default, however, players interact with the environment independently — changes one player makes are NOT shared with others.** Opt in to sharing by wrapping mutable state in `syncEntity`, broadcasting events through `MessageBus`, or persisting through your own backend.
36
-
37
- `syncEntity` state persists only as long as **at least one player remains in the scene**. The state resets as soon as the scene is empty. For durable state across scene resets, persist to your own server.
8
+ Decentraland scenes are inherently multiplayer. All players in the same scene share the same space. SDK7 uses CRDT-based synchronization.
38
9
 
39
10
  > **Runtime constraint:** Decentraland runs in a QuickJS sandbox. No Node.js APIs (`fs`, `http`, `path`, `process`). Use `fetch()` and `WebSocket` for network communication. See the **scene-runtime** skill for async patterns.
40
11
 
@@ -53,7 +24,7 @@ Choose the right networking approach based on what you need:
53
24
  **Decision flow:**
54
25
  1. Does every player need to see the same state, including late joiners? --> `syncEntity`
55
26
  2. Is it a fire-and-forget event only for players currently in the scene? --> `MessageBus`
56
- 3. Do you need state persisted after all players leave, or server-side validation? --> external server via `fetch` or `signedFetch`
27
+ 3. Do you need to talk to an external server? --> `fetch` or `signedFetch`
57
28
  4. Do you need continuous real-time server communication? --> `WebSocket`
58
29
  5. Combine approaches freely: use `syncEntity` for world state, `MessageBus` for effects, and `fetch` for persistence.
59
30
 
@@ -7,27 +7,24 @@ description: NFT display and blockchain interaction in Decentraland. NftShape (f
7
7
 
8
8
  ## Display NFT Artwork
9
9
 
10
- `NftShape` is supported in `main-entities.ts` — declare the framed NFT directly. The user can drag it around in the visual editor.
10
+ Show an NFT from Ethereum in a decorative frame:
11
11
 
12
12
  ```typescript
13
- // main-entities.ts
14
- import type { Scene } from '@dcl/sdk/scene-types'
15
-
16
- export const scene = {
17
- hero_nft: {
18
- components: {
19
- Transform: { position: { x: 8, y: 2, z: 8 } },
20
- NftShape: {
21
- urn: 'urn:decentraland:ethereum:erc721:0x06012c8cf97bead5deae237070f9587f8e7a266d:558536',
22
- color: { r: 1, g: 1, b: 1, a: 1 },
23
- style: 0 // NftFrameType.NFT_CLASSIC — enum values are integers in the literal
24
- }
25
- }
26
- }
27
- } satisfies Scene
28
- ```
13
+ import { engine, Transform, NftShape, NftFrameType } from '@dcl/sdk/ecs'
14
+ import { Vector3, Quaternion, Color4 } from '@dcl/sdk/math'
15
+
16
+ const nftFrame = engine.addEntity()
17
+ Transform.create(nftFrame, {
18
+ position: Vector3.create(8, 2, 8),
19
+ rotation: Quaternion.fromEulerDegrees(0, 0, 0)
20
+ })
29
21
 
30
- The `style` field is a numeric enum — the literal cannot reference `NftFrameType.NFT_CLASSIC` directly because the AST walker only accepts JSON-compatible expressions. Use the integer value (table below) and leave a comment.
22
+ NftShape.create(nftFrame, {
23
+ urn: 'urn:decentraland:ethereum:erc721:0x06012c8cf97bead5deae237070f9587f8e7a266d:558536',
24
+ color: Color4.White(),
25
+ style: NftFrameType.NFT_CLASSIC
26
+ })
27
+ ```
31
28
 
32
29
  ### NFT URN Format
33
30
 
@@ -40,33 +37,31 @@ urn:decentraland:ethereum:erc721:<contractAddress>:<tokenId>
40
37
 
41
38
  ### Available Frame Styles
42
39
 
43
- | value | enum name | description |
44
- |---|---|---|
45
- | 0 | NFT_CLASSIC | Simple classic frame |
46
- | 1 | NFT_BAROQUE_ORNAMENT | Ornate baroque |
47
- | 2 | NFT_DIAMOND_ORNAMENT | Diamond pattern |
48
- | 3 | NFT_MINIMAL_WIDE | Minimal wide border |
49
- | 4 | NFT_MINIMAL_GREY | Minimal grey border |
50
- | 5 | NFT_BLOCKY | Pixelated/blocky |
51
- | 6 | NFT_GOLD_EDGES | Gold edge trim |
52
- | 7 | NFT_GOLD_CARVED | Carved gold |
53
- | 8 | NFT_GOLD_WIDE | Wide gold border |
54
- | 9 | NFT_GOLD_ROUNDED | Rounded gold |
55
- | 10 | NFT_METAL_MEDIUM | Medium metal |
56
- | 11 | NFT_METAL_WIDE | Wide metal |
57
- | 12 | NFT_METAL_SLIM | Slim metal |
58
- | 13 | NFT_METAL_ROUNDED | Rounded metal |
59
- | 14 | NFT_PINS | Pinned to wall |
60
- | 15 | NFT_MINIMAL_BLACK | Minimal black |
61
- | 16 | NFT_MINIMAL_WHITE | Minimal white |
62
- | 17 | NFT_TAPE | Taped to wall |
63
- | 18 | NFT_WOOD_SLIM | Slim wood |
64
- | 19 | NFT_WOOD_WIDE | Wide wood |
65
- | 20 | NFT_WOOD_TWIGS | Twig/branch wood |
66
- | 21 | NFT_CANVAS | Canvas style |
67
- | 22 | NFT_NONE | No frame |
68
-
69
- In `src/index.ts` where enum identifiers are allowed, use `NftFrameType.NFT_CLASSIC` etc. directly.
40
+ ```typescript
41
+ NftFrameType.NFT_CLASSIC // Simple classic frame
42
+ NftFrameType.NFT_BAROQUE_ORNAMENT // Ornate baroque
43
+ NftFrameType.NFT_DIAMOND_ORNAMENT // Diamond pattern
44
+ NftFrameType.NFT_MINIMAL_WIDE // Minimal wide border
45
+ NftFrameType.NFT_MINIMAL_GREY // Minimal grey border
46
+ NftFrameType.NFT_BLOCKY // Pixelated/blocky
47
+ NftFrameType.NFT_GOLD_EDGES // Gold edge trim
48
+ NftFrameType.NFT_GOLD_CARVED // Carved gold
49
+ NftFrameType.NFT_GOLD_WIDE // Wide gold border
50
+ NftFrameType.NFT_GOLD_ROUNDED // Rounded gold
51
+ NftFrameType.NFT_METAL_MEDIUM // Medium metal
52
+ NftFrameType.NFT_METAL_WIDE // Wide metal
53
+ NftFrameType.NFT_METAL_SLIM // Slim metal
54
+ NftFrameType.NFT_METAL_ROUNDED // Rounded metal
55
+ NftFrameType.NFT_PINS // Pinned to wall
56
+ NftFrameType.NFT_MINIMAL_BLACK // Minimal black
57
+ NftFrameType.NFT_MINIMAL_WHITE // Minimal white
58
+ NftFrameType.NFT_TAPE // Taped to wall
59
+ NftFrameType.NFT_WOOD_SLIM // Slim wood
60
+ NftFrameType.NFT_WOOD_WIDE // Wide wood
61
+ NftFrameType.NFT_WOOD_TWIGS // Twig/branch wood
62
+ NftFrameType.NFT_CANVAS // Canvas style
63
+ NftFrameType.NFT_NONE // No frame
64
+ ```
70
65
 
71
66
  ## Check Player Wallet
72
67
 
@@ -5,15 +5,9 @@ description: Optimize Decentraland scene performance. Scene limit formulas (tria
5
5
 
6
6
  # Optimizing Decentraland Scenes
7
7
 
8
- ## Authoring split
9
-
10
- The patterns in this skill — object pools, LOD, asset preloading, system throttling — are all **runtime mechanics** and live in `src/index.ts`. The static layout (chairs, walls, lamps, the props that get LOD'd) should still be declared in `main-entities.ts`; the optimization code reads those entities by name (`engine.getEntityOrNullByName`) or by component query (`engine.getEntitiesWith(Transform)`).
11
-
12
- The parenting optimization (a static container with many children) is best expressed in `main-entities.ts` using `Transform.parent: 'parent_name'` — that way the editor can move the entire group as a unit.
13
-
14
8
  ## Scene Limits (Per Parcel Count)
15
9
 
16
- All limits scale with parcel count `n`. Triangles, entities, and bodies scale linearly. Materials, textures, and height scale logarithmically. **Except for hard MB size limits on deploy, all other limits CAN be exceeded** — scenes won't crash, but performance degrades and the scene may become unusable on lower-end devices. Treat the numbers as guidelines, not enforcement.
10
+ All limits scale with parcel count `n`. Triangles, entities, and bodies scale linearly. Materials, textures, and height scale logarithmically.
17
11
 
18
12
  | Resource | Formula | 1 parcel | 2 parcels | 4 parcels | 9 parcels | 16 parcels |
19
13
  |---|---|---|---|---|---|---|
@@ -106,6 +100,7 @@ MeshRenderer.setPlane(entity) // Very cheap
106
100
 
107
101
  - **Dimensions must be power-of-two**: 256, 512, 1024, 2048
108
102
  - **Recommended sizes**: 512x512 for most objects, 1024x1024 max for hero pieces
103
+ - **Avoid textures over 2048x2048** — they consume excessive memory and often exceed limits
109
104
  - Use `.png` for UI/sprites with transparency
110
105
  - Use `.jpg` for photos and textures without transparency
111
106
  - Prefer compressed formats (WebP) over raw PNG where possible
@@ -5,30 +5,6 @@ description: Player and avatar system in Decentraland. Read player position/prof
5
5
 
6
6
  # Player and Avatar System in Decentraland
7
7
 
8
- ## Authoring split
9
-
10
- `AvatarShape` (the component used for NPCs and pre-placed avatars) is supported in `main-entities.ts` — declare the NPC fully there with id, name, wearables, etc.:
11
-
12
- ```typescript
13
- // main-entities.ts
14
- shopkeeper: {
15
- components: {
16
- Transform: { position: { x: 8, y: 0, z: 8 } },
17
- AvatarShape: {
18
- id: 'shopkeeper-1',
19
- name: 'Shopkeeper',
20
- bodyShape: 'urn:decentraland:off-chain:base-avatars:BaseMale',
21
- wearables: [],
22
- emotes: []
23
- }
24
- }
25
- }
26
- ```
27
-
28
- `AvatarAttach`, `AvatarModifierArea`, `AvatarBase`, `AvatarEquippedData` are **not** in the supported list — they're runtime by design (they bind to the live player, or apply to entities you create on-the-fly). Add them in `src/index.ts` and attach to entities looked up via `getEntityOrNullByName` (for static placement) or runtime-created entities (for player-bound effects).
29
-
30
- The reserved `engine.PlayerEntity` is engine-managed and has no representation in `main-entities.ts`.
31
-
32
8
  ## Player Position and Movement
33
9
 
34
10
  Access the player's position via the reserved `engine.PlayerEntity`:
@@ -85,36 +61,6 @@ function main() {
85
61
  - `userId` — the player's Ethereum wallet address (or guest ID)
86
62
  - `isGuest` — `true` if the player hasn't connected a wallet
87
63
 
88
- ### Fetch Full Avatar Profile from the Catalyst
89
-
90
- `getPlayer()` returns the local view of the player. For full avatar data (wearables list, body shape, skin/hair/eye colors), fetch from the Catalyst:
91
-
92
- ```typescript
93
- import { executeTask, signedFetch } from '@dcl/sdk/network'
94
- import { getPlayer } from '@dcl/sdk/players'
95
-
96
- executeTask(async () => {
97
- const player = getPlayer()
98
- if (!player || player.isGuest) return
99
-
100
- const res = await fetch(`https://peer.decentraland.org/lambdas/profiles/${player.userId}`)
101
- const body = await res.json()
102
-
103
- // Response is an array of profiles; the first entry holds the active avatar.
104
- const profile = body?.avatars?.[0]
105
- if (!profile) return
106
-
107
- console.log('name:', profile.name)
108
- console.log('wearables:', profile.avatar.wearables)
109
- console.log('skin color:', profile.avatar.skin.color) // { r, g, b } — already unwrapped, NOT { color: { r,g,b } }
110
- })
111
- ```
112
-
113
- **Gotchas:**
114
- - The response is `{ avatars: [...] }`, not a flat profile object. Always read `body.avatars[0]`.
115
- - Color fields (`skin.color`, `hair.color`, `eyes.color`) are already `{ r, g, b }` objects — don't unwrap one more level.
116
- - The fetch is unauthenticated; for endpoints that need the player's signed identity, use `signedFetch` from `@dcl/sdk/network` instead of plain `fetch`.
117
-
118
64
  ## Avatar Attachments
119
65
 
120
66
  Attach 3D objects to a player's avatar:
@@ -133,36 +79,12 @@ AvatarAttach.create(hat, {
133
79
 
134
80
  ### Anchor Points
135
81
 
136
- Full enum of bones / positions an attachment can track. Inside `main-entities.ts` use the integer value (left). In `src/index.ts` use `AvatarAnchorPointType.<NAME>`.
137
-
138
- | value | enum | location |
139
- |---|---|---|
140
- | 0 | AAPT_POSITION | avatar feet (deprecated — prefer `parent: engine.PlayerEntity`) |
141
- | 1 | AAPT_NAME_TAG | above the name tag |
142
- | 2 | AAPT_LEFT_HAND | left hand |
143
- | 3 | AAPT_RIGHT_HAND | right hand |
144
- | 4 | AAPT_HEAD | head bone |
145
- | 5 | AAPT_NECK | neck |
146
- | 6 | AAPT_SPINE | spine root |
147
- | 7 | AAPT_SPINE1 | spine mid |
148
- | 8 | AAPT_SPINE2 | spine top |
149
- | 9 | AAPT_HIP | hip |
150
- | 10 | AAPT_LEFT_SHOULDER | left shoulder |
151
- | 11 | AAPT_LEFT_ARM | left upper arm |
152
- | 12 | AAPT_LEFT_FOREARM | left forearm |
153
- | 13 | AAPT_LEFT_HAND_INDEX | left index finger |
154
- | 14 | AAPT_RIGHT_SHOULDER | right shoulder |
155
- | 15 | AAPT_RIGHT_ARM | right upper arm |
156
- | 16 | AAPT_RIGHT_FOREARM | right forearm |
157
- | 17 | AAPT_RIGHT_HAND_INDEX | right index finger |
158
- | 18 | AAPT_LEFT_UP_LEG | left thigh |
159
- | 19 | AAPT_LEFT_LEG | left calf |
160
- | 20 | AAPT_LEFT_FOOT | left foot |
161
- | 21 | AAPT_LEFT_TOE_BASE | left toes |
162
- | 22 | AAPT_RIGHT_UP_LEG | right thigh |
163
- | 23 | AAPT_RIGHT_LEG | right calf |
164
- | 24 | AAPT_RIGHT_FOOT | right foot |
165
- | 25 | AAPT_RIGHT_TOE_BASE | right toes |
82
+ ```typescript
83
+ AvatarAnchorPointType.AAPT_NAME_TAG // Above the head
84
+ AvatarAnchorPointType.AAPT_RIGHT_HAND // Right hand
85
+ AvatarAnchorPointType.AAPT_LEFT_HAND // Left hand
86
+ AvatarAnchorPointType.AAPT_POSITION // Avatar root position
87
+ ```
166
88
 
167
89
  ### Attach to a Specific Player
168
90
 
@@ -308,46 +230,9 @@ AvatarLocomotionSettings.createOrReplace(engine.PlayerEntity, {
308
230
  })
309
231
  ```
310
232
 
311
- ## InputModifier — Restrict Player Movement
312
-
313
- Disable specific movement modes for the local player. Useful for cutscenes, dialogue freezes, traversal puzzles. Applies to `engine.PlayerEntity`.
314
-
315
- ```typescript
316
- import { engine, InputModifier } from '@dcl/sdk/ecs'
317
-
318
- InputModifier.createOrReplace(engine.PlayerEntity, {
319
- mode: InputModifier.Mode.Standard({
320
- disableWalk: false,
321
- disableJog: false,
322
- disableRun: false,
323
- disableJump: false,
324
- disableDoubleJump: false,
325
- disableGliding: false
326
- })
327
- })
328
- ```
329
-
330
- Set any field to `true` to disable that mode. While disabled:
331
- - Gravity still applies (the player still falls).
332
- - The camera can still rotate freely.
333
- - The player can still trigger pointer / proximity events.
334
- - All restrictions are auto-lifted when the player leaves the scene.
335
-
336
- ### Freeze All Movement
337
-
338
- ```typescript
339
- InputModifier.createOrReplace(engine.PlayerEntity, {
340
- mode: InputModifier.Mode.Standard({ disableAll: true })
341
- })
342
- ```
343
-
344
- To release: `InputModifier.deleteFrom(engine.PlayerEntity)` — or `createOrReplace` with all flags `false`.
345
-
346
233
  ## Teleporting the Player
347
234
 
348
- **You MUST use `movePlayerTo` from `~system/RestrictedActions` to move or teleport the player.** Setting `Transform.getMutable(engine.PlayerEntity).position` does NOT work — the runtime ignores direct writes to the player transform. `Transform` on `engine.PlayerEntity` is **read-only**; the same applies to `engine.CameraEntity`.
349
-
350
- `movePlayerTo` only teleports the player **within the same scene**. Cross-scene teleports require explicit player consent and a different API.
235
+ **You MUST use `movePlayerTo` from `~system/RestrictedActions` to move or teleport the player.** Setting `Transform.getMutable(engine.PlayerEntity).position` does NOT work — the runtime ignores direct writes to the player transform.
351
236
 
352
237
  ```typescript
353
238
  import { movePlayerTo } from '~system/RestrictedActions'
@@ -364,17 +249,6 @@ void movePlayerTo({
364
249
  })
365
250
  ```
366
251
 
367
- `movePlayerTo` returns a Promise — `await` it if you need to chain actions:
368
-
369
- ```typescript
370
- import { executeTask } from '@dcl/sdk/ecs'
371
-
372
- executeTask(async () => {
373
- await movePlayerTo({ newRelativePosition: Vector3.create(8, 0, 8) })
374
- console.log('teleported, continuing flow')
375
- })
376
- ```
377
-
378
252
  ### Avatar Change Listeners
379
253
 
380
254
  React to avatar changes in real-time:
@@ -153,16 +153,12 @@ changeRealm({ realm: 'other-realm.dcl.eth', message: 'Join this realm?' })
153
153
 
154
154
  ## Timers
155
155
 
156
- **Use the `timers` API from `@dcl/sdk/ecs`**, not the global `setTimeout`/`setInterval`. The globals are not reliable in the QuickJS runtime.
156
+ **setTimeout / setInterval** are supported via the QuickJS runtime polyfill:
157
157
 
158
158
  ```typescript
159
- import { timers } from '@dcl/sdk/ecs'
160
-
161
- const t = timers.setTimeout(() => console.log('delayed'), 2000)
162
- timers.clearTimeout(t)
163
-
164
- const id = timers.setInterval(() => console.log('tick'), 1000)
165
- timers.clearInterval(id)
159
+ setTimeout(() => console.log('delayed'), 2000)
160
+ const id = setInterval(() => console.log('tick'), 1000)
161
+ clearInterval(id)
166
162
  ```
167
163
 
168
164
  **System-based timers** (recommended for game logic — synchronized with the frame loop):
@@ -255,7 +251,7 @@ npx @dcl/sdk-commands test
255
251
 
256
252
  - Always wrap async code in `executeTask()` — bare promises will be silently dropped
257
253
  - Use `signedFetch` (not plain `fetch`) when your backend needs to verify the player's identity
258
- - Prefer system-based timers over `timers.setTimeout`/`timers.setInterval` for game logic — they stay in sync with the frame loop. Use `timers.*` for one-shot scheduled actions (auto-close door, delayed sound, etc.).
254
+ - Prefer system-based timers over `setTimeout`/`setInterval` for game logic — they stay in sync with the frame loop
259
255
  - Check `realm.realmInfo?.isPreview` to detect preview mode and enable debug features
260
256
  - Use `readFile()` for data files (JSON configs, level data) deployed alongside the scene
261
257
  - `removeEntityWithChildren()` is essential when cleaning up complex entity hierarchies
@@ -106,7 +106,6 @@ Keep it to 1-2 screenshots per task. Each screenshot consumes significant tokens
106
106
  | Missing textures (pink/magenta) | Texture file not found or wrong path | Verify file exists in project and path matches code |
107
107
  | Objects appear wrong scale | Scale values off or model exported at wrong scale | Check Transform.scale values; 1,1,1 is original model size |
108
108
  | Lighting looks flat | No LightSource components in scene | Add point or spot lights — see **lighting-environment** skill |
109
- | Custom lights look too dim or invisible | Intensity value too low | Point/spot lights typically need `intensity: 8000–32000` candela. Values below ~1000 are usually invisible |
110
109
 
111
110
  ## What to Look For in Screenshots
112
111