modelscope.cn

advanced-rendering

Advanced rendering in Decentraland scenes.

Installation

$ npx skills add https://modelscope.cn

Summary

  • Advanced rendering in Decentraland scenes.
  • Billboard (face camera), TextShape (3D world text), PBR materials (metallic, roughness, transparency, emissive glow), GltfNodeModifiers (per-node shadow/material overrides), VisibilityComponent (show/hide entities), and texture modes.
  • Use when the user wants billboards, floating labels, 3D text, material effects, glow, transparency, or model node control.
  • Do NOT use for screen-space UI (see build-ui) or loading 3D models (see add-3d-models).

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from modelscope.cn · top by installs.

npx skills add https://modelscope.cn

Browse all from modelscope.cn

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 11,763 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Advanced Rendering in Decentraland

Authoring split

Billboard, TextShape, Material, MeshRenderer, GltfContainer, VisibilityComponent, and GltfNodeModifiers are all supported in main-entities.ts — declare the visual entity (sign, label, billboard, glowing prop, model with per-node overrides) fully there with its visual components. Examples below that show engine.addEntity() followed by Transform.create + MeshRenderer / Billboard / TextShape are pre-main-entities.ts patterns — translate them by moving the entity declaration into main-entities.ts and keeping only runtime modifications (e.g., VisibilityComponent.getMutable(entity).visible = false) in src/index.ts.

// Example: floating label
// main-entities.ts
shop_label: {
  components: {
    Transform: { position: { x: 8, y: 3, z: 8 } },
    TextShape: { text: 'OPEN', fontSize: 4, textColor: { r: 1, g: 1, b: 1, a: 1 } },
    Billboard: { billboardMode: 7 }  // BM_ALL
  }
}

When to Use Which Rendering Feature

Need Component When
Entity faces the camera Billboard Name tags, signs, sprite-like objects
Text in the 3D world TextShape Labels, signs, floating text above entities
Custom material appearance Material.setPbrMaterial Metallic, rough, transparent, emissive surfaces
Show/hide without removing VisibilityComponent LOD systems, toggling objects, conditional display
Modify GLTF model nodes GltfNodeModifiers Override materials or shadow casting on specific mesh nodes

Decision flow:

  1. Need text on screen? → Use build-ui (React-ECS Label) instead
  2. Need text in 3D space? → TextShape (+ Billboard to face camera)
  3. Need glowing/transparent materials? → Material.setPbrMaterial with emissive/transparency
  4. Need to override material on a model node? → GltfNodeModifiers with modifiers array

Billboard (Face the Camera)

Make entities always rotate to face the player's camera:

import { engine, Transform, Billboard, BillboardMode, MeshRenderer } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const sign = engine.addEntity()
Transform.create(sign, { position: Vector3.create(8, 2, 8) })
MeshRenderer.setPlane(sign)

// Rotate only on Y axis (most common — stays upright)
Billboard.create(sign, {
  billboardMode: BillboardMode.BM_Y
})

Billboard Modes

BillboardMode.BM_Y      // Rotate on Y axis only (stays upright) — most common
BillboardMode.BM_ALL    // Rotate on all axes (fully faces camera)
BillboardMode.BM_X      // Rotate on X axis only
BillboardMode.BM_Z      // Rotate on Z axis only
BillboardMode.BM_NONE   // No billboard rotation
  • Prefer BMY over BMALL for most use cases — it looks more natural and is cheaper to render.
  • BM_ALL is useful for particles or effects that should always directly face the camera.

TextShape (3D Text)

Render text directly in 3D space:

import { engine, Transform, TextShape, TextAlignMode } from '@dcl/sdk/ecs'
import { Vector3, Color4 } from '@dcl/sdk/math'

const label = engine.addEntity()
Transform.create(label, { position: Vector3.create(8, 3, 8) })

TextShape.create(label, {
  text: 'Hello World!',
  fontSize: 24,
  textColor: Color4.White(),
  outlineColor: Color4.Black(),
  outlineWidth: 0.1,
  textAlign: TextAlignMode.TAM_MIDDLE_CENTER
})

Text Alignment Options

TextAlignMode.TAM_TOP_LEFT
TextAlignMode.TAM_TOP_CENTER
TextAlignMode.TAM_TOP_RIGHT
TextAlignMode.TAM_MIDDLE_LEFT
TextAlignMode.TAM_MIDDLE_CENTER
TextAlignMode.TAM_MIDDLE_RIGHT
TextAlignMode.TAM_BOTTOM_LEFT
TextAlignMode.TAM_BOTTOM_CENTER
TextAlignMode.TAM_BOTTOM_RIGHT

Floating Label (Billboard + TextShape)

Combine Billboard and TextShape to create labels that always face the player:

const floatingLabel = engine.addEntity()
Transform.create(floatingLabel, { position: Vector3.create(8, 4, 8) })

TextShape.create(floatingLabel, {
  text: 'NPC Name',
  fontSize: 16,
  textColor: Color4.White(),
  outlineColor: Color4.Black(),
  outlineWidth: 0.08,
  textAlign: TextAlignMode.TAM_BOTTOM_CENTER
})

Billboard.create(floatingLabel, {
  billboardMode: BillboardMode.BM_Y
})

Advanced PBR Materials

Metallic and Roughness

import { engine, Transform, MeshRenderer, Material, MaterialTransparencyMode } from '@dcl/sdk/ecs'
import { Color4, Color3 } from '@dcl/sdk/math'

// Shiny metal
Material.setPbrMaterial(entity, {
  albedoColor: Color4.create(0.8, 0.8, 0.9, 1),
  metallic: 1.0,
  roughness: 0.1
})

// Rough stone
Material.setPbrMaterial(entity, {
  albedoColor: Color4.create(0.5, 0.5, 0.5, 1),
  metallic: 0.0,
  roughness: 0.9
})

Transparency

// Alpha blend — smooth transparency
Material.setPbrMaterial(entity, {
  albedoColor: Color4.create(1, 0, 0, 0.5), // 50% transparent red
  transparencyMode: MaterialTransparencyMode.MTM_ALPHA_BLEND
})

// Alpha test — cutout (binary visible/invisible based on threshold)
Material.setPbrMaterial(entity, {
  texture: Material.Texture.Common({ src: 'assets/cutout.png' }),
  transparencyMode: MaterialTransparencyMode.MTM_ALPHA_TEST,
  alphaTest: 0.5
})

Emissive (Glow Effects)

// Glowing material (emissiveColor uses Color3, not Color4)
Material.setPbrMaterial(entity, {
  albedoColor: Color4.create(0, 0, 0, 1),
  emissiveColor: Color3.create(0, 1, 0),  // Green glow
  emissiveIntensity: 2.0
})

// Emissive with texture
Material.setPbrMaterial(entity, {
  texture: Material.Texture.Common({ src: 'assets/diffuse.png' }),
  emissiveTexture: Material.Texture.Common({ src: 'assets/emissive.png' }),
  emissiveIntensity: 1.0,
  emissiveColor: Color3.White()
})

Texture Maps

Material.setPbrMaterial(entity, {
  texture: Material.Texture.Common({ src: 'assets/diffuse.png' }),
  bumpTexture: Material.Texture.Common({ src: 'assets/normal.png' }),
  emissiveTexture: Material.Texture.Common({ src: 'assets/emissive.png' })
})

GltfContainer Visibility Masks

Control visibility and collision of specific mesh layers within a GLTF model using collision masks:

import { engine, Transform, GltfContainer, ColliderLayer } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const model = engine.addEntity()
Transform.create(model, { position: Vector3.create(4, 0, 4) })

GltfContainer.create(model, {
  src: 'models/myModel.glb',
  visibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS | ColliderLayer.CL_POINTER,
  invisibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS
})

VisibilityComponent

Show or hide entities without removing them:

import { engine, VisibilityComponent } from '@dcl/sdk/ecs'

// Hide an entity
VisibilityComponent.create(entity, { visible: false })

// Toggle visibility
const visibility = VisibilityComponent.getMutable(entity)
visibility.visible = !visibility.visible

// Useful for LOD (Level of Detail)
function lodSystem() {
  const playerPos = Transform.get(engine.PlayerEntity).position

  for (const [entity, transform] of engine.getEntitiesWith(Transform, MeshRenderer)) {
    const distance = Vector3.distance(playerPos, transform.position)

    if (distance > 30) {
      VisibilityComponent.createOrReplace(entity, { visible: false })
    } else {
      VisibilityComponent.createOrReplace(entity, { visible: true })
    }
  }
}

engine.addSystem(lodSystem)

Per-Node Modifiers (GltfNodeModifiers)

Override material or shadow casting on specific nodes within a GLTF model. Supported in main-entities.ts:

// main-entities.ts
armored_knight: {
  components: {
    Transform: { position: { x: 8, y: 0, z: 8 } },
    GltfContainer: { src: 'models/knight.glb' },
    GltfNodeModifiers: {
      modifiers: [
        {
          path: 'RootNode/Armor',     // GLTF hierarchy path
          castShadows: false           // disable shadows for this node
        }
      ]
    }
  }
}

Whole-model override: pass path: '' (empty string) to apply the modifier to every node in the model. Useful for re-skinning an entire model with a single material swap:

red_team_unit: {
  components: {
    Transform: { position: { x: 4, y: 0, z: 8 } },
    GltfContainer: { src: 'models/unit.glb' },
    GltfNodeModifiers: {
      modifiers: [
        {
          path: '',
          material: {
            material: {
              $case: 'pbr',
              pbr: { albedoColor: { r: 1, g: 0, b: 0, a: 1 } }
            }
          }
        }
      ]
    }
  }
}

Texture Tweens (Animate Material Textures)

Animate a material's texture offset/tiling over time — useful for water, lava, conveyor belts, scrolling backgrounds. Tween component is supported in main-entities.ts:

// main-entities.ts — continuous texture scroll
conveyor: {
  components: {
    Transform: { position: { x: 8, y: 1, z: 8 } },
    MeshRenderer: { mesh: { $case: 'plane', plane: { uvs: [] } } },
    Material: { material: { $case: 'pbr', pbr: { texture: { tex: { $case: 'texture', texture: { src: 'images/belt.png' } } } } } },
    Tween: {
      duration: 2000,
      easingFunction: 0,  // EF_LINEAR
      mode: {
        $case: 'textureMoveContinuous',
        textureMoveContinuous: { direction: { x: 1, y: 0 }, speed: 0.5 }
        // movementType defaults to 0 = TMT_OFFSET; use 1 = TMT_TILING to scale instead
      }
    }
  }
}

For a finite from-to texture move, use { $case: 'textureMove', textureMove: { start: { x: 0, y: 0 }, end: { x: 1, y: 0 }, movementType: 0 } } with a duration.

Runtime helpers (in src/index.ts): Tween.setTextureMove(entity, from, to, durationMs) and Tween.setTextureMoveContinuous(entity, direction, speed).

Avatar Texture

Generate a texture from a player's avatar:

Material.setPbrMaterial(portraitFrame, {
  texture: Material.Texture.Avatar({ userId: '0x...' })
})

Texture Modes

Control how textures are filtered and wrapped:

import { TextureFilterMode, TextureWrapMode } from '@dcl/sdk/ecs'

Material.setPbrMaterial(entity, {
  texture: Material.Texture.Common({
    src: 'images/pixel-art.png',
    filterMode: TextureFilterMode.TFM_POINT,    // crisp pixels (no smoothing)
    wrapMode: TextureWrapMode.TWM_REPEAT        // tile the texture
  })
})

Filter modes: TFMPOINT (pixelated), TFMBILINEAR (smooth), TFMTRILINEAR (smoothest). Wrap modes: TWMREPEAT (tile), TWMCLAMP (stretch edges), TWMMIRROR (mirror tile).

Best Practices

  • Use BillboardMode.BMY instead of BMALL — looks more natural and renders faster
  • Keep fontSize readable (16-32 for in-world text)
  • Add outlineColor and outlineWidth to TextShape for legibility against any background
  • Use emissiveColor with a dark albedoColor for maximum glow visibility
  • MTMALPHATEST is cheaper than MTMALPHABLEND — use cutout when smooth transparency isn't needed
  • Combine Billboard + TextShape for floating name labels above NPCs or objects
  • Use VisibilityComponent for LOD systems instead of removing/re-adding entities