Skip to content
Back to skills

Sdk Component Implementation

ASecurity

End-to-end SDK7 component implementation from protocol to C# systems. Use when implementing new SDK components (PB* types, protobuf, CRDT), modifying SDK component systems, or registering in ComponentsContainer.

  • 23 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added May 27, 2026
developmenttypescriptpythongoc#node

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned September 20, 2026

npx -y skills add decentraland/unity-explorer --skill sdk-component-implementation --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sdk Component Implementation?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sdk Component Implementation
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/decentraland-sdk-component-implementation/badge)](https://www.skillsdirectory.com/skills/decentraland-sdk-component-implementation)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sdk-component-implementation
description: "End-to-end SDK7 component implementation from protocol to C# systems. Use when implementing new SDK components (PB* types, protobuf, CRDT), modifying SDK component systems, or registering in ComponentsContainer."
user-invocable: false
---

# SDK Component Implementation

## Sources

- `docs/how-to-implement-new-sdk-components.md` -- Step-by-step implementation guide
- `docs/scene-runtime.md` -- SDK7 scene execution and CRDT bridge

---

## End-to-End Workflow

### Step 1: Protocol Definition

Create protobuf definition in the `protocol` repository (branch from `main`) with a unique component ID from the `12xx` block. Take the next free ID after the highest one listed by `make list-components-ids`. The `14xx`/`16xx` experimental ranges are retired.

### Step 2: TypeScript Code Generation

In `js-sdk-toolchain`, generate serialization code and optional helper functions.

### Step 3: C# Code Generation + Unity Implementation

In `unity-explorer`:
1. Run protocol update: `npm install @dcl/protocol@next && npm run build-protocol`
   - Node/npm only — `build-protocol` runs the `protoc-gen-bitwise` plugin, a dependency-free Node script bundled in `@dcl/protocol` (no Python or extra packages required).
2. Add partial class to `IDirtyMarker.cs`
3. Register in `ComponentsContainer.cs` using `SDKComponentBuilder<T>`
4. Create feature folder under `Explorer/Assets/DCL/SDKComponents/<Feature>/`
5. Create plugin at `Explorer/Assets/DCL/SDKComponents/<Feature>/Systems/<Feature>Plugin.cs`
6. Instantiate plugin in `StaticContainer.cs` (in the `ECSWorldPlugins` array)
7. Implement systems (lifecycle, properties, cleanup)

### Step 4: Test Scene

Create example test scene in `sdk7-test-scenes`.

**SDK `getOrNull` vs `getMutableOrNull` (CRITICAL):** In scene-side TypeScript, `getMutableOrNull` marks the component dirty in the CRDT system, which triggers `IsDirty = true` on the Explorer side and causes a full property re-apply. **Only use `getMutableOrNull` when you are about to write to the component.** For read-only access (e.g., reading values to display in a UI panel), always use `getOrNull`. Calling `getMutableOrNull` every frame in a UI render function will make the component permanently dirty, causing unintended side effects like re-triggering emission bursts, restarting animations, or redundant material/texture reloads.

### PR Merge Order

Protocol first -> update both `js-sdk-toolchain` and `unity-explorer` -> merge in any order.

---

## Registration Steps

### 1. IDirtyMarker Partial Class

**File:** `Explorer/Assets/DCL/Infrastructure/ProtobufPartialClasses/IDirtyMarker.cs`

```csharp
public partial class PBMyComponent : IDirtyMarker
{
    public bool IsDirty { get; set; }
}
```

### 2. ComponentsContainer Registration

**File:** `Explorer/Assets/DCL/Infrastructure/Global/ComponentsContainer.cs`

```csharp
// Standard protobuf component (most common)
.Add(SDKComponentBuilder<PBMyComponent>.Create(ComponentID.MY_COMPONENT).AsProtobufComponent())

// Result component (explorer -> scene, LWW)
.Add(SDKComponentBuilder<PBMyResult>.Create(ComponentID.MY_RESULT).AsProtobufResult())
```

### 3. StaticContainer Plugin Instantiation

**File:** `Explorer/Assets/DCL/Infrastructure/Global/StaticContainer.cs`

Add the plugin to the `ECSWorldPlugins` array (~line 274):

```csharp
new MyFeaturePlugin(poolsRegistry, assetsProvisioner),
```

---

## Feature Folder Structure

Real example from `Explorer/Assets/DCL/SDKComponents/LightSource/`:

```
Assets/DCL/SDKComponents/<Feature>/
+-- Components/
|   +-- <Feature>Component.cs              // Internal ECS struct component
+-- Prefab/                                 // Optional: Unity prefabs for pooled objects
+-- Systems/
|   +-- DCL.<Feature>.Systems.asmref       // { "reference": "DCL.Plugins" }
|   +-- <Feature>Plugin.cs                 // Plugin lives WITH the systems it injects
|   +-- <Feature>LifecycleSystem.cs         // Create/destroy internal components
|   +-- <Feature>ApplyPropertiesSystem.cs   // Apply SDK data to Unity objects
|   +-- CleanUp<Feature>System.cs           // Cleanup on removal/destruction
|   +-- <Feature>Group.cs                  // Custom SystemGroup for execution ordering
+-- Tests/
|   +-- EditMode/
|   |   +-- <Feature>SystemShould.cs
|   |   +-- EditMode.asmref                // { "reference": "DCL.EditMode.Tests" }
```

**Assembly notes:** `.asmref` for `DCL.Plugins` goes inside `Systems/`. Tests use `DCL.EditMode.Tests`. Do not create standalone `.asmdef` for ECS systems. See **plugin-architecture** skill for full rules.

---

## Detailed Reference

For plugin code examples, system patterns (lifecycle, apply-properties, cleanup, groups), CRDT bridge usage (`IECSToCRDTWriter`, LWW vs GOVS), and test patterns, see [reference.md](reference.md).

---

## Implementation Checklist

- [ ] **IDirtyMarker** -- add partial class in `IDirtyMarker.cs`
- [ ] **ComponentsContainer** -- register with `SDKComponentBuilder<T>` in `ComponentsContainer.cs`
- [ ] **StaticContainer** -- instantiate plugin in `ECSWorldPlugins` array in `StaticContainer.cs`
- [ ] **Plugin** -- create at `DCL/SDKComponents/<Feature>/Systems/<Feature>Plugin.cs`
- [ ] **ResetDirtyFlagSystem** -- inject `ResetDirtyFlagSystem<PBComponent>.InjectToWorld(ref builder)` in plugin
- [ ] **Lifecycle system** -- `[None(typeof(InternalComponent))]` for first-occurrence detection
- [ ] **Properties system** -- `IsDirty` guard on expensive updates
- [ ] **Cleanup system** -- handle component removal, entity destruction, world finalization
- [ ] **SystemGroup** -- create custom group with `[UpdateInGroup]` and `[ThrottlingEnabled]`
- [ ] **Tests** -- `UnitySystemTestBase<T>` with NSubstitute mocks
- [ ] **Result component** (if needed) -- `IECSToCRDTWriter` PUT/APPEND in `ComponentsContainer`
- [ ] Allocation optimization (no LINQ, no closures in Update)
- [ ] Scene-current checks where needed (`ISceneStateProvider.IsCurrent`)

Files in this skill

  • SKILL.md5.6 KB
  • reference.md6.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.