@dcl-regenesislabs/opendcl 0.1.0-22239132687.commit-eccf1dd → 0.1.0-22312642473.commit-ea3ce8c
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.
- package/README.md +3 -2
- package/context/asset-packs-catalog.md +2854 -0
- package/dist/compact-tool-renderers.d.ts +34 -0
- package/dist/compact-tool-renderers.d.ts.map +1 -0
- package/dist/compact-tool-renderers.js +102 -0
- package/dist/compact-tool-renderers.js.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/extensions/dcl-init.ts +3 -3
- package/package.json +2 -2
- package/prompts/system.md +16 -14
- package/skills/add-3d-models/SKILL.md +32 -8
- package/skills/add-interactivity/SKILL.md +32 -12
- package/skills/advanced-rendering/SKILL.md +10 -19
- package/skills/audio-video/SKILL.md +52 -8
- package/skills/build-ui/SKILL.md +76 -70
- package/skills/camera-control/SKILL.md +20 -9
- package/skills/create-scene/SKILL.md +21 -7
- package/skills/lighting-environment/SKILL.md +5 -3
- package/skills/multiplayer-sync/SKILL.md +15 -8
- package/skills/player-avatar/SKILL.md +27 -6
package/skills/build-ui/SKILL.md
CHANGED
|
@@ -11,25 +11,23 @@ Decentraland SDK7 uses a React-like JSX system for 2D UI overlays.
|
|
|
11
11
|
|
|
12
12
|
### File: src/ui.tsx
|
|
13
13
|
```tsx
|
|
14
|
-
import ReactEcs, { UiEntity, Label, Button } from '@dcl/sdk/react-ecs'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
}
|
|
14
|
+
import ReactEcs, { ReactEcsRenderer, UiEntity, Label, Button } from '@dcl/sdk/react-ecs'
|
|
15
|
+
|
|
16
|
+
const MyUI = () => (
|
|
17
|
+
<UiEntity
|
|
18
|
+
uiTransform={{
|
|
19
|
+
width: '100%',
|
|
20
|
+
height: '100%',
|
|
21
|
+
justifyContent: 'center',
|
|
22
|
+
alignItems: 'center'
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
25
|
+
<Label value="Hello Decentraland!" fontSize={24} />
|
|
26
|
+
</UiEntity>
|
|
27
|
+
)
|
|
30
28
|
|
|
31
29
|
export function setupUi() {
|
|
32
|
-
|
|
30
|
+
ReactEcsRenderer.setUiRenderer(MyUI)
|
|
33
31
|
}
|
|
34
32
|
```
|
|
35
33
|
|
|
@@ -56,6 +54,8 @@ export function main() {
|
|
|
56
54
|
|
|
57
55
|
### UiEntity (Container)
|
|
58
56
|
```tsx
|
|
57
|
+
import { Color4 } from '@dcl/sdk/math'
|
|
58
|
+
|
|
59
59
|
<UiEntity
|
|
60
60
|
uiTransform={{
|
|
61
61
|
width: 300, // Pixels or '50%'
|
|
@@ -70,17 +70,19 @@ export function main() {
|
|
|
70
70
|
display: 'flex' // 'flex' | 'none' (hide)
|
|
71
71
|
}}
|
|
72
72
|
uiBackground={{
|
|
73
|
-
color:
|
|
73
|
+
color: Color4.create(0, 0, 0, 0.8) // Semi-transparent black
|
|
74
74
|
}}
|
|
75
75
|
/>
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
### Label (Text)
|
|
79
79
|
```tsx
|
|
80
|
+
import { Color4 } from '@dcl/sdk/math'
|
|
81
|
+
|
|
80
82
|
<Label
|
|
81
83
|
value="Score: 100"
|
|
82
84
|
fontSize={18}
|
|
83
|
-
color={
|
|
85
|
+
color={Color4.White()}
|
|
84
86
|
textAlign="middle-center"
|
|
85
87
|
font="sans-serif"
|
|
86
88
|
uiTransform={{ width: 200, height: 30 }}
|
|
@@ -103,12 +105,16 @@ export function main() {
|
|
|
103
105
|
### Input
|
|
104
106
|
```tsx
|
|
105
107
|
import { Input } from '@dcl/sdk/react-ecs'
|
|
108
|
+
import { Color4 } from '@dcl/sdk/math'
|
|
106
109
|
|
|
107
110
|
<Input
|
|
108
111
|
placeholder="Type here..."
|
|
109
112
|
fontSize={14}
|
|
110
|
-
color={
|
|
113
|
+
color={Color4.White()}
|
|
111
114
|
uiTransform={{ width: 250, height: 35 }}
|
|
115
|
+
onChange={(value) => {
|
|
116
|
+
console.log('Value changing:', value)
|
|
117
|
+
}}
|
|
112
118
|
onSubmit={(value) => {
|
|
113
119
|
console.log('Submitted:', value)
|
|
114
120
|
}}
|
|
@@ -135,45 +141,45 @@ import { Dropdown } from '@dcl/sdk/react-ecs'
|
|
|
135
141
|
Use module-level variables for UI state (React hooks are NOT available):
|
|
136
142
|
|
|
137
143
|
```tsx
|
|
144
|
+
import { Color4 } from '@dcl/sdk/math'
|
|
145
|
+
|
|
138
146
|
let score = 0
|
|
139
147
|
let showMenu = false
|
|
140
148
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
const GameUI = () => (
|
|
150
|
+
<UiEntity uiTransform={{ width: '100%', height: '100%' }}>
|
|
151
|
+
{/* HUD - always visible */}
|
|
152
|
+
<Label
|
|
153
|
+
value={`Score: ${score}`}
|
|
154
|
+
fontSize={20}
|
|
155
|
+
uiTransform={{
|
|
156
|
+
positionType: 'absolute',
|
|
157
|
+
position: { top: 10, left: 10 }
|
|
158
|
+
}}
|
|
159
|
+
/>
|
|
160
|
+
|
|
161
|
+
{/* Menu - conditionally shown */}
|
|
162
|
+
{showMenu && (
|
|
163
|
+
<UiEntity
|
|
148
164
|
uiTransform={{
|
|
165
|
+
width: 300,
|
|
166
|
+
height: 400,
|
|
149
167
|
positionType: 'absolute',
|
|
150
|
-
position: { top:
|
|
168
|
+
position: { top: '50%', left: '50%' }
|
|
151
169
|
}}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
<Label value="Game Menu" fontSize={24} />
|
|
166
|
-
<Button
|
|
167
|
-
value="Resume"
|
|
168
|
-
variant="primary"
|
|
169
|
-
onMouseDown={() => { showMenu = false }}
|
|
170
|
-
uiTransform={{ width: 200, height: 40 }}
|
|
171
|
-
/>
|
|
172
|
-
</UiEntity>
|
|
173
|
-
)}
|
|
174
|
-
</UiEntity>
|
|
175
|
-
)
|
|
176
|
-
}
|
|
170
|
+
uiBackground={{ color: Color4.create(0.1, 0.1, 0.1, 0.9) }}
|
|
171
|
+
>
|
|
172
|
+
<Label value="Game Menu" fontSize={24} />
|
|
173
|
+
<Button
|
|
174
|
+
value="Resume"
|
|
175
|
+
variant="primary"
|
|
176
|
+
onMouseDown={() => { showMenu = false }}
|
|
177
|
+
uiTransform={{ width: 200, height: 40 }}
|
|
178
|
+
/>
|
|
179
|
+
</UiEntity>
|
|
180
|
+
)}
|
|
181
|
+
</UiEntity>
|
|
182
|
+
)
|
|
177
183
|
|
|
178
184
|
// Update state from game logic
|
|
179
185
|
export function addScore(points: number) {
|
|
@@ -189,25 +195,25 @@ export function toggleMenu() {
|
|
|
189
195
|
|
|
190
196
|
### Health Bar
|
|
191
197
|
```tsx
|
|
198
|
+
import { Color4 } from '@dcl/sdk/math'
|
|
199
|
+
|
|
192
200
|
let health = 100
|
|
193
201
|
|
|
194
|
-
|
|
195
|
-
|
|
202
|
+
const HealthBar = () => (
|
|
203
|
+
<UiEntity
|
|
204
|
+
uiTransform={{
|
|
205
|
+
width: 200, height: 20,
|
|
206
|
+
positionType: 'absolute',
|
|
207
|
+
position: { bottom: 20, left: '50%' }
|
|
208
|
+
}}
|
|
209
|
+
uiBackground={{ color: Color4.create(0.3, 0.3, 0.3, 0.8) }}
|
|
210
|
+
>
|
|
196
211
|
<UiEntity
|
|
197
|
-
uiTransform={{
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
uiBackground={{ color: { r: 0.3, g: 0.3, b: 0.3, a: 0.8 } }}
|
|
203
|
-
>
|
|
204
|
-
<UiEntity
|
|
205
|
-
uiTransform={{ width: `${health}%`, height: '100%' }}
|
|
206
|
-
uiBackground={{ color: { r: 0.2, g: 0.8, b: 0.2, a: 1 } }}
|
|
207
|
-
/>
|
|
208
|
-
</UiEntity>
|
|
209
|
-
)
|
|
210
|
-
}
|
|
212
|
+
uiTransform={{ width: `${health}%`, height: '100%' }}
|
|
213
|
+
uiBackground={{ color: Color4.create(0.2, 0.8, 0.2, 1) }}
|
|
214
|
+
/>
|
|
215
|
+
</UiEntity>
|
|
216
|
+
)
|
|
211
217
|
```
|
|
212
218
|
|
|
213
219
|
### Image Background
|
|
@@ -228,4 +234,4 @@ function HealthBar() {
|
|
|
228
234
|
- UI is rendered as a 2D overlay on top of the 3D scene
|
|
229
235
|
- Use `display: 'none'` in `uiTransform` to hide elements without removing them
|
|
230
236
|
- File extension must be `.tsx` for JSX support
|
|
231
|
-
- Only one `
|
|
237
|
+
- Only one `ReactEcsRenderer.setUiRenderer()` call per scene — combine all UI into one root component
|
|
@@ -10,7 +10,7 @@ description: Control camera behavior in Decentraland scenes. Switch between firs
|
|
|
10
10
|
Access the camera's current position and rotation via the reserved `engine.CameraEntity`:
|
|
11
11
|
|
|
12
12
|
```typescript
|
|
13
|
-
import { engine, Transform
|
|
13
|
+
import { engine, Transform } from '@dcl/sdk/ecs'
|
|
14
14
|
|
|
15
15
|
function trackCamera() {
|
|
16
16
|
if (!Transform.has(engine.CameraEntity)) return
|
|
@@ -28,6 +28,8 @@ engine.addSystem(trackCamera)
|
|
|
28
28
|
Check whether the player is in first-person or third-person:
|
|
29
29
|
|
|
30
30
|
```typescript
|
|
31
|
+
import { engine, CameraMode, CameraType } from '@dcl/sdk/ecs'
|
|
32
|
+
|
|
31
33
|
function checkCameraMode() {
|
|
32
34
|
if (!CameraMode.has(engine.CameraEntity)) return
|
|
33
35
|
|
|
@@ -73,7 +75,7 @@ When the player leaves the area, the camera reverts to their preferred mode.
|
|
|
73
75
|
Create scripted camera positions for cutscenes or special views:
|
|
74
76
|
|
|
75
77
|
```typescript
|
|
76
|
-
import { engine, Transform, VirtualCamera,
|
|
78
|
+
import { engine, Transform, VirtualCamera, MainCamera } from '@dcl/sdk/ecs'
|
|
77
79
|
import { Vector3, Quaternion } from '@dcl/sdk/math'
|
|
78
80
|
|
|
79
81
|
const cinematicCam = engine.addEntity()
|
|
@@ -84,16 +86,23 @@ Transform.create(cinematicCam, {
|
|
|
84
86
|
|
|
85
87
|
VirtualCamera.create(cinematicCam, {
|
|
86
88
|
defaultTransition: {
|
|
87
|
-
transitionMode:
|
|
88
|
-
speed: 1.0
|
|
89
|
+
transitionMode: VirtualCamera.Transition.Speed(1.0)
|
|
89
90
|
}
|
|
90
91
|
})
|
|
92
|
+
|
|
93
|
+
// Activate the virtual camera
|
|
94
|
+
MainCamera.getMutable(engine.CameraEntity).virtualCameraEntity = cinematicCam
|
|
95
|
+
|
|
96
|
+
// Return to normal camera
|
|
97
|
+
MainCamera.getMutable(engine.CameraEntity).virtualCameraEntity = undefined
|
|
91
98
|
```
|
|
92
99
|
|
|
93
100
|
### Transition Modes
|
|
94
101
|
|
|
95
|
-
|
|
96
|
-
-
|
|
102
|
+
```typescript
|
|
103
|
+
VirtualCamera.Transition.Speed(1.0) // Speed-based smooth transition
|
|
104
|
+
VirtualCamera.Transition.Time(2) // Time-based transition (2 seconds)
|
|
105
|
+
```
|
|
97
106
|
|
|
98
107
|
### Look-At Target
|
|
99
108
|
|
|
@@ -106,10 +115,12 @@ Transform.create(target, { position: Vector3.create(8, 1, 8) })
|
|
|
106
115
|
VirtualCamera.create(cinematicCam, {
|
|
107
116
|
lookAtEntity: target,
|
|
108
117
|
defaultTransition: {
|
|
109
|
-
transitionMode:
|
|
110
|
-
speed: 2.0
|
|
118
|
+
transitionMode: VirtualCamera.Transition.Speed(2.0)
|
|
111
119
|
}
|
|
112
120
|
})
|
|
121
|
+
|
|
122
|
+
// Activate
|
|
123
|
+
MainCamera.getMutable(engine.CameraEntity).virtualCameraEntity = cinematicCam
|
|
113
124
|
```
|
|
114
125
|
|
|
115
126
|
## Tracking Camera Position
|
|
@@ -117,7 +128,7 @@ VirtualCamera.create(cinematicCam, {
|
|
|
117
128
|
Poll camera position each frame for camera-triggered events:
|
|
118
129
|
|
|
119
130
|
```typescript
|
|
120
|
-
import { engine, Transform
|
|
131
|
+
import { engine, Transform } from '@dcl/sdk/ecs'
|
|
121
132
|
import { Vector3 } from '@dcl/sdk/math'
|
|
122
133
|
|
|
123
134
|
let lastNotifiedZone = ''
|
|
@@ -16,11 +16,26 @@ If the user hasn't described their scene, ask them:
|
|
|
16
16
|
|
|
17
17
|
## 2. Scaffold the Project with `/init`
|
|
18
18
|
|
|
19
|
-
**Always run `/init` first.** This uses the official `@dcl/sdk-commands init` to create scene.json, package.json, tsconfig.json, and src/index.ts with the correct, up-to-date configuration.
|
|
19
|
+
**Always run `/init` first.** This uses the official `@dcl/sdk-commands init` to create scene.json, package.json, tsconfig.json, and src/index.ts with the correct, up-to-date configuration, and installs dependencies automatically.
|
|
20
20
|
|
|
21
21
|
Never manually create scene.json, package.json, or tsconfig.json — the SDK templates may change between versions and hand-written copies will diverge.
|
|
22
22
|
|
|
23
|
-
## 3.
|
|
23
|
+
## 3. Find Matching 3D Assets
|
|
24
|
+
|
|
25
|
+
Before writing scene code, check both asset catalogs for free models that match the user's theme:
|
|
26
|
+
|
|
27
|
+
1. Read `context/asset-packs-catalog.md` (2,700+ Creator Hub models — furniture, structures, decorations, nature, etc.)
|
|
28
|
+
2. Read `context/open-source-3d-assets.md` (991 CC0 models — cyberpunk, medieval, nature, sci-fi, etc.)
|
|
29
|
+
3. Suggest matching models to the user
|
|
30
|
+
4. Download selected models into the scene's `models/` directory:
|
|
31
|
+
```bash
|
|
32
|
+
mkdir -p models
|
|
33
|
+
curl -o models/arcade_machine.glb "https://builder-items.decentraland.org/contents/bafybei..."
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
> **Important**: `GltfContainer` only works with local files. Never use external URLs for the model `src` field.
|
|
37
|
+
|
|
38
|
+
## 4. Customize the Generated Files
|
|
24
39
|
|
|
25
40
|
After `/init` completes, customize the generated files based on what the user wants:
|
|
26
41
|
|
|
@@ -51,12 +66,11 @@ export function main() {
|
|
|
51
66
|
}
|
|
52
67
|
```
|
|
53
68
|
|
|
54
|
-
##
|
|
69
|
+
## 5. Post-Creation Steps
|
|
55
70
|
|
|
56
|
-
After
|
|
57
|
-
1.
|
|
58
|
-
2.
|
|
59
|
-
3. The scene will open in a browser at http://localhost:8000
|
|
71
|
+
After customizing the files:
|
|
72
|
+
1. Use the `preview` tool to start the preview server (or run `npx @dcl/sdk-commands start --bevy-web` manually)
|
|
73
|
+
2. The scene will open in a browser at http://localhost:8000
|
|
60
74
|
|
|
61
75
|
## Important Notes
|
|
62
76
|
|
|
@@ -39,6 +39,8 @@ LightSource.create(light, {
|
|
|
39
39
|
Emit a cone of light in a direction:
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
|
+
import { Quaternion } from '@dcl/sdk/math'
|
|
43
|
+
|
|
42
44
|
const spotlight = engine.addEntity()
|
|
43
45
|
Transform.create(spotlight, {
|
|
44
46
|
position: Vector3.create(8, 4, 8),
|
|
@@ -175,10 +177,10 @@ For a visual glow without casting light on surroundings:
|
|
|
175
177
|
import { engine, Material } from '@dcl/sdk/ecs'
|
|
176
178
|
import { Color4, Color3 } from '@dcl/sdk/math'
|
|
177
179
|
|
|
178
|
-
// Self-illuminated material
|
|
180
|
+
// Self-illuminated material (emissiveColor uses Color3, not Color4)
|
|
179
181
|
Material.setPbrMaterial(entity, {
|
|
180
182
|
albedoColor: Color4.create(0, 0, 0, 1),
|
|
181
|
-
emissiveColor:
|
|
183
|
+
emissiveColor: Color3.create(0, 1, 0), // Green glow
|
|
182
184
|
emissiveIntensity: 2.0
|
|
183
185
|
})
|
|
184
186
|
```
|
|
@@ -190,7 +192,7 @@ For an object that both glows visually and casts light:
|
|
|
190
192
|
```typescript
|
|
191
193
|
// Visual glow on the mesh
|
|
192
194
|
Material.setPbrMaterial(bulb, {
|
|
193
|
-
emissiveColor:
|
|
195
|
+
emissiveColor: Color3.create(1, 0.9, 0.7),
|
|
194
196
|
emissiveIntensity: 1.5
|
|
195
197
|
})
|
|
196
198
|
|
|
@@ -9,25 +9,29 @@ Decentraland scenes are inherently multiplayer. All players in the same scene sh
|
|
|
9
9
|
|
|
10
10
|
## How Sync Works
|
|
11
11
|
|
|
12
|
-
-
|
|
12
|
+
- Entities must be explicitly synced using `syncEntity()` from `@dcl/sdk/network`.
|
|
13
13
|
- The Decentraland runtime uses CRDTs (Conflict-free Replicated Data Types) to resolve conflicts.
|
|
14
14
|
- Last-write-wins semantics for most components (Transform, Material, etc.).
|
|
15
15
|
- No server code needed — sync is built into the runtime.
|
|
16
16
|
|
|
17
17
|
## Basic Synced Entity
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Use `syncEntity()` to mark an entity and its components for multiplayer sync:
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
22
|
import { engine, Transform, MeshRenderer, Material } from '@dcl/sdk/ecs'
|
|
23
|
+
import { syncEntity } from '@dcl/sdk/network'
|
|
23
24
|
import { Vector3, Color4 } from '@dcl/sdk/math'
|
|
24
25
|
|
|
25
|
-
//
|
|
26
|
+
// Create entity
|
|
26
27
|
const sharedCube = engine.addEntity()
|
|
27
28
|
Transform.create(sharedCube, { position: Vector3.create(8, 1, 8) })
|
|
28
29
|
MeshRenderer.setBox(sharedCube)
|
|
29
30
|
Material.setPbrMaterial(sharedCube, { albedoColor: Color4.Red() })
|
|
30
31
|
|
|
32
|
+
// Sync this entity's Transform to all players
|
|
33
|
+
syncEntity(sharedCube, [Transform.componentId])
|
|
34
|
+
|
|
31
35
|
// When any player changes the transform, all players see it
|
|
32
36
|
function moveCube() {
|
|
33
37
|
const transform = Transform.getMutable(sharedCube)
|
|
@@ -37,23 +41,25 @@ function moveCube() {
|
|
|
37
41
|
|
|
38
42
|
## Custom Synced Components
|
|
39
43
|
|
|
40
|
-
Define custom components
|
|
44
|
+
Define custom components and sync them between players:
|
|
41
45
|
|
|
42
46
|
```typescript
|
|
43
47
|
import { engine, Schemas } from '@dcl/sdk/ecs'
|
|
48
|
+
import { syncEntity } from '@dcl/sdk/network'
|
|
44
49
|
|
|
45
|
-
// Define a custom
|
|
50
|
+
// Define a custom component
|
|
46
51
|
const ScoreBoard = engine.defineComponent('scoreBoard', {
|
|
47
52
|
score: Schemas.Int,
|
|
48
53
|
playerName: Schemas.String,
|
|
49
54
|
lastUpdated: Schemas.Int64
|
|
50
55
|
})
|
|
51
56
|
|
|
52
|
-
//
|
|
57
|
+
// Create and sync the entity
|
|
53
58
|
const board = engine.addEntity()
|
|
54
59
|
ScoreBoard.create(board, { score: 0, playerName: '', lastUpdated: 0 })
|
|
60
|
+
syncEntity(board, [ScoreBoard.componentId])
|
|
55
61
|
|
|
56
|
-
// Update from any player
|
|
62
|
+
// Update from any player — synced via CRDT
|
|
57
63
|
function addScore(points: number) {
|
|
58
64
|
const data = ScoreBoard.getMutable(board)
|
|
59
65
|
data.score += points
|
|
@@ -124,9 +130,10 @@ engine.addSystem(() => {
|
|
|
124
130
|
|
|
125
131
|
## Important Notes
|
|
126
132
|
|
|
127
|
-
- **
|
|
133
|
+
- **Entities must be explicitly synced** via `syncEntity(entity, [componentIds])` — pass the `componentId` of each component to sync
|
|
128
134
|
- **CRDT resolution**: If two players change the same component simultaneously, last-write-wins
|
|
129
135
|
- **No server-side code**: Decentraland scenes run entirely client-side with CRDT sync
|
|
130
136
|
- **Entity limits apply**: Each synced entity counts toward the scene's entity budget
|
|
131
137
|
- **Custom schemas must be deterministic**: Same component name = same schema across all clients
|
|
138
|
+
- **Use `Schemas.Int64` for timestamps**: `Schemas.Number` corrupts large numbers (13+ digits). Always use `Schemas.Int64` for values like `Date.now()`
|
|
132
139
|
- For server-authoritative multiplayer with validation and anti-cheat, see the `authoritative-server` skill
|
|
@@ -138,13 +138,34 @@ Transform.create(npc, { position: Vector3.create(8, 0, 8) })
|
|
|
138
138
|
AvatarShape.create(npc, {
|
|
139
139
|
id: 'npc-1',
|
|
140
140
|
name: 'Guard',
|
|
141
|
+
bodyShape: 'urn:decentraland:off-chain:base-avatars:BaseMale', // or BaseFemale
|
|
141
142
|
wearables: [
|
|
142
|
-
'urn:decentraland:off-chain:base-avatars:
|
|
143
|
-
'urn:decentraland:off-chain:base-avatars:
|
|
144
|
-
'urn:decentraland:off-chain:base-avatars:
|
|
145
|
-
'urn:decentraland:off-chain:base-avatars:
|
|
146
|
-
'urn:decentraland:off-chain:base-avatars:
|
|
147
|
-
|
|
143
|
+
'urn:decentraland:off-chain:base-avatars:eyebrows_00',
|
|
144
|
+
'urn:decentraland:off-chain:base-avatars:mouth_00',
|
|
145
|
+
'urn:decentraland:off-chain:base-avatars:eyes_00',
|
|
146
|
+
'urn:decentraland:off-chain:base-avatars:blue_tshirt',
|
|
147
|
+
'urn:decentraland:off-chain:base-avatars:brown_pants',
|
|
148
|
+
'urn:decentraland:off-chain:base-avatars:classic_shoes',
|
|
149
|
+
'urn:decentraland:off-chain:base-avatars:short_hair'
|
|
150
|
+
],
|
|
151
|
+
hairColor: { r: 0.92, g: 0.76, b: 0.62 }, // RGB values 0-1
|
|
152
|
+
skinColor: { r: 0.94, g: 0.85, b: 0.6 }, // RGB values 0-1
|
|
153
|
+
emotes: []
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Mannequin (Show Only Wearables)
|
|
158
|
+
|
|
159
|
+
Display just the wearables without a full avatar body:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
AvatarShape.create(mannequin, {
|
|
163
|
+
id: 'mannequin-1',
|
|
164
|
+
name: 'Display',
|
|
165
|
+
wearables: [
|
|
166
|
+
'urn:decentraland:matic:collections-v2:0x90e5cb2d673699be8f28d339c818a0b60144c494:0'
|
|
167
|
+
],
|
|
168
|
+
show_only_wearables: true
|
|
148
169
|
})
|
|
149
170
|
```
|
|
150
171
|
|