@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.
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Compact tool output renderers for built-in tools (write, read).
3
+ *
4
+ * Pi-coding-agent's built-in renderer shows verbose output: write shows 10 lines
5
+ * of file content, read shows 10 lines of preview. This module provides compact
6
+ * alternatives that reduce terminal noise when the agent writes/reads many files.
7
+ *
8
+ * These are wired in via a monkey-patch on InteractiveMode.getRegisteredToolDefinition
9
+ * in src/index.ts — they provide renderCall/renderResult without replacing execution logic.
10
+ */
11
+ import { Text } from "@mariozechner/pi-tui";
12
+ import type { Theme } from "@mariozechner/pi-coding-agent";
13
+ /** Partial tool definition — only the fields ToolExecutionComponent checks */
14
+ interface CompactToolDef {
15
+ name: string;
16
+ renderCall?: (args: Record<string, unknown>, theme: Theme) => Text;
17
+ renderResult?: (result: {
18
+ content: Array<{
19
+ type: string;
20
+ text?: string;
21
+ }>;
22
+ details?: unknown;
23
+ }, options: {
24
+ expanded: boolean;
25
+ isPartial: boolean;
26
+ }, theme: Theme) => Text;
27
+ }
28
+ /**
29
+ * Returns a partial tool definition with compact renderCall/renderResult
30
+ * for supported built-in tools, or undefined for tools we don't override.
31
+ */
32
+ export declare function getCompactToolDefinition(toolName: string): CompactToolDef | undefined;
33
+ export {};
34
+ //# sourceMappingURL=compact-tool-renderers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact-tool-renderers.d.ts","sourceRoot":"","sources":["../src/compact-tool-renderers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAiB3D,8EAA8E;AAC9E,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACnE,YAAY,CAAC,EAAE,CACb,MAAM,EAAE;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,EAC9E,OAAO,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,EAClD,KAAK,EAAE,KAAK,KACT,IAAI,CAAC;CACX;AA0FD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAErF"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Compact tool output renderers for built-in tools (write, read).
3
+ *
4
+ * Pi-coding-agent's built-in renderer shows verbose output: write shows 10 lines
5
+ * of file content, read shows 10 lines of preview. This module provides compact
6
+ * alternatives that reduce terminal noise when the agent writes/reads many files.
7
+ *
8
+ * These are wired in via a monkey-patch on InteractiveMode.getRegisteredToolDefinition
9
+ * in src/index.ts — they provide renderCall/renderResult without replacing execution logic.
10
+ */
11
+ import { Text } from "@mariozechner/pi-tui";
12
+ import { homedir } from "node:os";
13
+ /** Shorten absolute paths to tilde notation (mirrors pi's internal shortenPath) */
14
+ function shortenPath(path) {
15
+ const home = homedir();
16
+ if (path.startsWith(home)) {
17
+ return `~${path.slice(home.length)}`;
18
+ }
19
+ return path;
20
+ }
21
+ /** Replace tabs with spaces for consistent rendering */
22
+ function replaceTabs(text) {
23
+ return text.replace(/\t/g, " ");
24
+ }
25
+ const READ_PREVIEW_LINES = 5;
26
+ const writeRenderer = {
27
+ name: "write",
28
+ renderCall(args, theme) {
29
+ const rawPath = typeof args.path === "string" ? args.path : null;
30
+ const content = typeof args.content === "string" ? args.content : null;
31
+ const path = rawPath !== null ? shortenPath(rawPath) : null;
32
+ const invalidArg = theme.fg("error", "[invalid arg]");
33
+ let text = theme.fg("toolTitle", theme.bold("write")) +
34
+ " " +
35
+ (path === null ? invalidArg : path ? theme.fg("accent", path) : theme.fg("toolOutput", "..."));
36
+ if (content !== null) {
37
+ const lines = content.split("\n").length;
38
+ const chars = content.length;
39
+ text += theme.fg("muted", ` (${chars} chars, ${lines} lines)`);
40
+ }
41
+ return new Text(text, 0, 0);
42
+ },
43
+ };
44
+ const readRenderer = {
45
+ name: "read",
46
+ renderCall(args, theme) {
47
+ const rawPath = typeof args.path === "string" ? args.path : null;
48
+ const path = rawPath !== null ? shortenPath(rawPath) : null;
49
+ const offset = args.offset;
50
+ const limit = args.limit;
51
+ const invalidArg = theme.fg("error", "[invalid arg]");
52
+ let pathDisplay = path === null ? invalidArg : path ? theme.fg("accent", path) : theme.fg("toolOutput", "...");
53
+ if (offset !== undefined || limit !== undefined) {
54
+ const startLine = offset ?? 1;
55
+ const endLine = limit !== undefined ? startLine + limit - 1 : "";
56
+ pathDisplay += theme.fg("warning", `:${startLine}${endLine ? `-${endLine}` : ""}`);
57
+ }
58
+ return new Text(theme.fg("toolTitle", theme.bold("read")) + " " + pathDisplay, 0, 0);
59
+ },
60
+ renderResult(result, { expanded }, theme) {
61
+ const textBlocks = result.content?.filter((c) => c.type === "text") || [];
62
+ const output = textBlocks.map((c) => c.text || "").join("\n");
63
+ if (!output)
64
+ return new Text("", 0, 0);
65
+ const lines = output.split("\n");
66
+ const maxLines = expanded ? lines.length : READ_PREVIEW_LINES;
67
+ const displayLines = lines.slice(0, maxLines);
68
+ const remaining = lines.length - maxLines;
69
+ let text = displayLines.map((line) => theme.fg("toolOutput", replaceTabs(line))).join("\n");
70
+ if (remaining > 0) {
71
+ text += theme.fg("muted", `\n... (${remaining} more lines, ctrl+o to expand)`);
72
+ }
73
+ const details = result.details;
74
+ const truncation = details?.truncation;
75
+ if (truncation?.truncated) {
76
+ if (truncation.firstLineExceedsLimit) {
77
+ text += "\n" + theme.fg("warning", "[First line exceeds size limit]");
78
+ }
79
+ else if (truncation.truncatedBy === "lines") {
80
+ text +=
81
+ "\n" +
82
+ theme.fg("warning", `[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines]`);
83
+ }
84
+ else {
85
+ text += "\n" + theme.fg("warning", `[Truncated: ${truncation.outputLines} lines shown]`);
86
+ }
87
+ }
88
+ return new Text(text, 0, 0);
89
+ },
90
+ };
91
+ const renderers = new Map([
92
+ ["write", writeRenderer],
93
+ ["read", readRenderer],
94
+ ]);
95
+ /**
96
+ * Returns a partial tool definition with compact renderCall/renderResult
97
+ * for supported built-in tools, or undefined for tools we don't override.
98
+ */
99
+ export function getCompactToolDefinition(toolName) {
100
+ return renderers.get(toolName);
101
+ }
102
+ //# sourceMappingURL=compact-tool-renderers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact-tool-renderers.js","sourceRoot":"","sources":["../src/compact-tool-renderers.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { main, InteractiveMode } from "@mariozechner/pi-coding-agent";
8
8
  import { isDev } from "./utils.js";
9
+ import { getCompactToolDefinition } from "./compact-tool-renderers.js";
9
10
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
10
11
  import { homedir } from "node:os";
11
12
  import { fileURLToPath } from "node:url";
@@ -70,6 +71,17 @@ InteractiveMode.prototype.showWarning = function (msg) {
70
71
  return;
71
72
  _showWarning.call(this, msg);
72
73
  };
74
+ // Compact tool output — override built-in write/read renderers to reduce terminal noise.
75
+ // When a built-in tool has no custom renderCall/renderResult, pi shows verbose output.
76
+ // By returning compact renderers from getRegisteredToolDefinition, the ToolExecutionComponent
77
+ // uses them instead (see shouldUseBuiltInRenderer() in tool-execution.js).
78
+ const _getToolDef = InteractiveMode.prototype.getRegisteredToolDefinition;
79
+ InteractiveMode.prototype.getRegisteredToolDefinition = function (toolName) {
80
+ const original = _getToolDef.call(this, toolName);
81
+ if (original)
82
+ return original;
83
+ return getCompactToolDefinition(toolName);
84
+ };
73
85
  main(args).catch((err) => {
74
86
  console.error("OpenDCL fatal error:", err);
75
87
  process.exit(1);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -19,13 +19,13 @@ async function initScene(
19
19
  }
20
20
 
21
21
  try {
22
- const result = await pi.exec("npx", ["@dcl/sdk-commands", "init", "--skip-install"], {
22
+ const result = await pi.exec("npx", ["@dcl/sdk-commands", "init"], {
23
23
  cwd,
24
- timeout: 60000,
24
+ timeout: 180000,
25
25
  });
26
26
 
27
27
  if (result.code === 0) {
28
- return { message: "Scene initialized! Run 'npm install' to install dependencies, then use the preview tool to start." };
28
+ return { message: "Scene initialized and dependencies installed! Use the preview tool to start." };
29
29
  } else {
30
30
  return { message: `Init failed (exit code ${result.code}): ${result.stderr || result.stdout}`, isError: true };
31
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcl-regenesislabs/opendcl",
3
- "version": "0.1.0-22239132687.commit-eccf1dd",
3
+ "version": "0.1.0-22312642473.commit-ea3ce8c",
4
4
  "description": "AI coding assistant for Decentraland SDK7 scene development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -61,5 +61,5 @@
61
61
  "prompts/",
62
62
  "context/"
63
63
  ],
64
- "commit": "eccf1ddf7568056584700b927142426e95be390d"
64
+ "commit": "ea3ce8ca6234b519b29fc8e807ce51402ff3033f"
65
65
  }
package/prompts/system.md CHANGED
@@ -16,7 +16,7 @@ You are **OpenDCL**, an AI coding assistant specialized in Decentraland SDK7 sce
16
16
  ### Architecture
17
17
  - **Entity-Component System (ECS)**: Scenes are built with entities (IDs), components (data), and systems (logic).
18
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.
19
+ - **Imports**: Use `@dcl/sdk/ecs`, `@dcl/sdk/math`, `@dcl/sdk/react-ecs` for most APIs. Use `~system/RestrictedActions` for player actions (emotes, teleport, external URLs) and `~system/Runtime` for world time, realm info, and scene info.
20
20
  - **Entry point**: `export function main() {}` in `src/index.ts` — the engine calls this on scene load.
21
21
 
22
22
  ### Scene Constraints
@@ -56,18 +56,16 @@ engine.addSystem((dt: number) => {
56
56
 
57
57
  **UI with React-ECS:**
58
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
- }
59
+ import ReactEcs, { ReactEcsRenderer, UiEntity, Label, Button } from '@dcl/sdk/react-ecs'
60
+
61
+ const MyUI = () => (
62
+ <UiEntity uiTransform={{ width: 200, height: 50, positionType: 'absolute' }}>
63
+ <Label value="Hello" fontSize={18} />
64
+ </UiEntity>
65
+ )
68
66
 
69
67
  export function setupUi() {
70
- ReactEcs.setUiRenderer(MyUI)
68
+ ReactEcsRenderer.setUiRenderer(MyUI)
71
69
  }
72
70
  ```
73
71
 
@@ -97,9 +95,9 @@ scene-project/
97
95
 
98
96
  ### Empty Folder (No scene.json)
99
97
  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.
98
+ 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, and installs dependencies. Never create these files manually.
101
99
  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.
100
+ 4. Use the `preview` tool to start the preview server.
103
101
 
104
102
  ### Existing Scene
105
103
  1. Read scene.json and src/index.ts to understand the project.
@@ -110,9 +108,13 @@ scene-project/
110
108
  - Always position objects within the scene boundaries (based on parcels).
111
109
  - Use `Vector3.create()` and `Quaternion.fromEulerDegrees()` for transforms.
112
110
  - For 3D models, use `GltfContainer.create(entity, { src: 'models/myModel.glb' })`.
111
+ - `GltfContainer` only works with **local files** — never use external URLs for the `src` field. Always download models into the scene's `models/` directory first.
113
112
  - Place `.glb` files in a `models/` directory, textures in `images/`.
114
113
  - 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`.
114
+ - **Proactively suggest 3D assets**: When building a scene, always check both asset catalogs for free models that match the user's theme:
115
+ - `context/open-source-3d-assets.md` — 991 CC0 models from Polygonal Mind (nature, medieval, cyberpunk, sci-fi, etc.)
116
+ - `context/asset-packs-catalog.md` — 2,700+ models from the official Decentraland Creator Hub (furniture, structures, decorations, etc.)
117
+ - Download matching models with `curl -o models/filename.glb "URL"` before referencing them in code.
116
118
 
117
119
  ## Tools & Commands
118
120
 
@@ -93,16 +93,40 @@ GltfContainer.create(child, { src: 'models/hat.glb' })
93
93
 
94
94
  ## Free 3D Models
95
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
96
+ Always check both asset catalogs before suggesting the user create or find their own models.
99
97
 
100
- This catalog contains 991+ models organized by themed collections (Cyberpunk, Medieval, MomusPark, etc.) with direct download URLs.
98
+ ### Creator Hub Asset Packs (2,700+ models)
101
99
 
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
100
+ Read `context/asset-packs-catalog.md` for official Decentraland models across 12 themed packs (Cyberpunk, Fantasy, Gallery, Sci-fi, Western, Pirates, etc.) with furniture, structures, decorations, nature, and more.
101
+
102
+ To use a Creator Hub model:
103
+ ```bash
104
+ # Download from catalog
105
+ mkdir -p models
106
+ curl -o models/arcade_machine.glb "https://builder-items.decentraland.org/contents/bafybei..."
107
+ ```
108
+ ```typescript
109
+ // Reference in code — must be a local file path
110
+ GltfContainer.create(entity, { src: 'models/arcade_machine.glb' })
111
+ ```
112
+
113
+ ### Open Source CC0 Models (991 models)
114
+
115
+ Read `context/open-source-3d-assets.md` for free CC0-licensed models from Polygonal Mind, organized by 18 themed collections (MomusPark, Medieval Fair, Cyberpunk, Sci-fi, etc.) with direct GitHub download URLs.
116
+
117
+ ```bash
118
+ curl -o models/tree.glb "https://raw.githubusercontent.com/ToxSam/cc0-models-Polygonal-Mind/main/projects/momuspark/Tree_01_Art.glb"
119
+ ```
120
+
121
+ ### How to suggest models
122
+
123
+ 1. Read both catalog files
124
+ 2. Search for models matching the user's description/theme
125
+ 3. Suggest specific models with download commands
126
+ 4. Download selected models into the scene's `models/` directory
127
+ 5. Reference them in code with local paths
128
+
129
+ > **Important**: `GltfContainer` only works with **local files**. Never use external URLs for the model `src` field. Always download models into `models/` first.
106
130
 
107
131
  ## Model Best Practices
108
132
 
@@ -79,26 +79,46 @@ GltfContainer.create(entity, {
79
79
 
80
80
  ## Trigger Areas (Proximity Detection)
81
81
 
82
- Detect when the player enters or exits an area:
82
+ Detect when the player enters, exits, or stays inside an area:
83
83
 
84
84
  ```typescript
85
- import { engine, Transform, TriggerArea, TriggerAreaResult } from '@dcl/sdk/ecs'
85
+ import { engine, Transform, TriggerArea } from '@dcl/sdk/ecs'
86
+ import { triggerAreaEventsSystem } from '@dcl/sdk/ecs'
86
87
  import { Vector3 } from '@dcl/sdk/math'
87
88
 
88
- const trigger = engine.addEntity()
89
- Transform.create(trigger, { position: Vector3.create(8, 0, 8) })
89
+ const area = engine.addEntity()
90
+ TriggerArea.setBox(area) // or TriggerArea.setSphere(area)
91
+ Transform.create(area, {
92
+ position: Vector3.create(8, 0, 8),
93
+ scale: Vector3.create(4, 4, 4) // Size the area via Transform.scale
94
+ })
90
95
 
91
- TriggerArea.create(trigger, {
92
- area: Vector3.create(4, 4, 4) // 4x4x4 meter box
96
+ // Register enter/exit/stay events
97
+ triggerAreaEventsSystem.onTriggerEnter(area, (event) => {
98
+ console.log('Entity entered trigger:', event.trigger.entity)
93
99
  })
94
100
 
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
+ triggerAreaEventsSystem.onTriggerExit(area, () => {
102
+ console.log('Entity exited trigger')
101
103
  })
104
+
105
+ triggerAreaEventsSystem.onTriggerStay(area, () => {
106
+ // Called every frame while an entity is inside
107
+ })
108
+ ```
109
+
110
+ By default, trigger areas react to the player layer. Use `ColliderLayer` to restrict which entities activate the area:
111
+
112
+ ```typescript
113
+ import { ColliderLayer, MeshCollider } from '@dcl/sdk/ecs'
114
+
115
+ // Area that only reacts to custom layers
116
+ TriggerArea.setBox(area, ColliderLayer.CL_CUSTOM1 | ColliderLayer.CL_CUSTOM2)
117
+
118
+ // Mark a moving entity to activate the area
119
+ const mover = engine.addEntity()
120
+ Transform.create(mover, { position: Vector3.create(8, 0, 8) })
121
+ MeshCollider.setBox(mover, ColliderLayer.CL_CUSTOM1)
102
122
  ```
103
123
 
104
124
  ## Raycasting
@@ -137,10 +137,10 @@ Material.setPbrMaterial(entity, {
137
137
  ### Emissive (Glow Effects)
138
138
 
139
139
  ```typescript
140
- // Glowing material
140
+ // Glowing material (emissiveColor uses Color3, not Color4)
141
141
  Material.setPbrMaterial(entity, {
142
142
  albedoColor: Color4.create(0, 0, 0, 1),
143
- emissiveColor: Color4.create(0, 1, 0, 1), // Green glow
143
+ emissiveColor: Color3.create(0, 1, 0), // Green glow
144
144
  emissiveIntensity: 2.0
145
145
  })
146
146
 
@@ -163,33 +163,24 @@ Material.setPbrMaterial(entity, {
163
163
  })
164
164
  ```
165
165
 
166
- ## GltfNodeModifiers
166
+ ## GltfContainer Visibility Masks
167
167
 
168
- Override visibility or materials on specific nodes within a GLTF model:
168
+ Control visibility and collision of specific mesh layers within a GLTF model using collision masks:
169
169
 
170
170
  ```typescript
171
- import { engine, Transform, GltfContainer, GltfNodeModifiers, Material } from '@dcl/sdk/ecs'
172
- import { Vector3, Color4 } from '@dcl/sdk/math'
171
+ import { engine, Transform, GltfContainer, ColliderLayer } from '@dcl/sdk/ecs'
172
+ import { Vector3 } from '@dcl/sdk/math'
173
173
 
174
174
  const model = engine.addEntity()
175
- GltfContainer.create(model, { src: 'models/myModel.glb' })
176
175
  Transform.create(model, { position: Vector3.create(4, 0, 4) })
177
176
 
178
- // Override material of the entire model (empty path = whole model)
179
- GltfNodeModifiers.create(model, {
180
- modifiers: [
181
- {
182
- path: '', // empty string = all nodes
183
- materialOverride: Material.setPbrMaterial(model, {
184
- albedoColor: Color4.Red()
185
- })
186
- }
187
- ]
177
+ GltfContainer.create(model, {
178
+ src: 'models/myModel.glb',
179
+ visibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS | ColliderLayer.CL_POINTER,
180
+ invisibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS
188
181
  })
189
182
  ```
190
183
 
191
- Use node paths to target specific parts of a model for visibility or material changes.
192
-
193
184
  ## VisibilityComponent
194
185
 
195
186
  Show or hide entities without removing them:
@@ -122,16 +122,16 @@ VideoPlayer.create(screen, {
122
122
  playing: true,
123
123
  loop: true,
124
124
  volume: 0.5,
125
- playbackRate: 1.0
125
+ playbackRate: 1.0,
126
+ position: 0 // Start time in seconds
126
127
  })
127
128
 
128
- // Set material to show the video texture
129
- Material.setPbrMaterial(screen, {
130
- texture: Material.Texture.Video({ videoPlayerEntity: screen }),
131
- roughness: 1,
132
- emissiveColor: { r: 1, g: 1, b: 1 },
133
- emissiveIntensity: 1,
134
- emissiveTexture: Material.Texture.Video({ videoPlayerEntity: screen })
129
+ // Create video texture
130
+ const videoTexture = Material.Texture.Video({ videoPlayerEntity: screen })
131
+
132
+ // Basic material (recommended — better performance)
133
+ Material.setBasicMaterial(screen, {
134
+ texture: videoTexture
135
135
  })
136
136
  ```
137
137
 
@@ -150,6 +150,50 @@ VideoPlayer.getMutable(screen).volume = 0.8
150
150
  VideoPlayer.getMutable(screen).src = 'https://example.com/other.mp4'
151
151
  ```
152
152
 
153
+ ### Enhanced Video Material (PBR)
154
+
155
+ For a brighter, emissive video screen:
156
+
157
+ ```typescript
158
+ import { Color3 } from '@dcl/sdk/math'
159
+
160
+ const videoTexture = Material.Texture.Video({ videoPlayerEntity: screen })
161
+ Material.setPbrMaterial(screen, {
162
+ texture: videoTexture,
163
+ roughness: 1.0,
164
+ specularIntensity: 0,
165
+ metallic: 0,
166
+ emissiveTexture: videoTexture,
167
+ emissiveIntensity: 0.6,
168
+ emissiveColor: Color3.White()
169
+ })
170
+ ```
171
+
172
+ ### Video Events
173
+
174
+ Monitor video playback state:
175
+
176
+ ```typescript
177
+ import { videoEventsSystem, VideoState } from '@dcl/sdk/ecs'
178
+
179
+ videoEventsSystem.registerVideoEventsEntity(screen, (videoEvent) => {
180
+ switch (videoEvent.state) {
181
+ case VideoState.VS_PLAYING:
182
+ console.log('Video started playing')
183
+ break
184
+ case VideoState.VS_PAUSED:
185
+ console.log('Video paused')
186
+ break
187
+ case VideoState.VS_READY:
188
+ console.log('Video ready to play')
189
+ break
190
+ case VideoState.VS_ERROR:
191
+ console.log('Video error occurred')
192
+ break
193
+ }
194
+ })
195
+ ```
196
+
153
197
  ## Spatial Audio
154
198
 
155
199
  Audio in Decentraland is **spatial by default** — it gets louder as the player approaches the audio source entity and quieter as they move away. The position is determined by the entity's `Transform`.