---
title: Registering a Reality Composer Pro custom component
framework: Reality Composer Pro
role: article
role_heading: Article
path: realitycomposerpro/registering-a-reality-composer-pro-custom-component
---

# Registering a Reality Composer Pro custom component

Expose a custom component to the Reality Composer Pro editor and RealityKit Scripting.

## Overview

Overview Reality Composer Pro’s built-in components cover common behavior, but your project’s own data — game state, gameplay parameters, or simulation values — doesn’t always map onto an existing component. You extend Reality Composer Pro by defining a custom component and registering it with Reality Composer Pro. The component then behaves like a built-in component in the editor and in the Inspector, and it becomes available to tools such as Script Graph’s Get Component, Set Component, and Has Component nodes. This article walks through defining a custom RotationComponent (the same component used in ExampleApp/ContentView.swift) and then registering the component with Reality Composer Pro’s editor. After you register the component, designers can add and edit it visually. Registering it with RealityKit Scripting also lets JavaScript scripts running via ScriptingComponent read and write it.

Review the Reality Composer Pro plugin interface The RealityComposerPro Swift package defines the plugin protocol Reality Composer Pro loads at runtime: registerComponent requires Component and Codable — Reality Composer Pro needs to serialize your component into .usda/scene files, which Inspectable (RealityKit Scripting’s requirement) doesn’t provide by itself. A component destined for both worlds needs to conform to both. Define the custom rotation component This mirrors the component from ExampleApp/ContentView.swift, with Codable added so you can also register it with Reality Composer Pro: import RealityKit import RealityKitScripting public struct RotationComponent: Component, Codable {     var rotationSpeed: Float     var rotationAxis: SIMD3<Float> = .init(0, 1, 0)     var isPaused: Bool = false     // Wobble properties (exposed via extension in Overview.md's "Extending Existing Types")     var wobbleEnabled: Bool = false     var wobbleAmplitude: Float = 0.1     var wobbleSpeed: Float = 5.0     init(rotationSpeed: Float) {         self.rotationSpeed = rotationSpeed     } } extension RotationComponent: Inspectable {} Give it a scripting schema, following the static var schema convention used throughout RealityKit Scripting (for example, CoreComponent.schema in the Hot Reload example): extension RotationComponent {     static var schema: TypeSchema<RotationComponent> {         TypeSchema<RotationComponent>("RotationComponent") {             Constructor(body: RotationComponent.init(rotationSpeed:))             StoredProperty("rotationSpeed", keyPath: \RotationComponent.rotationSpeed)             StoredProperty("rotationAxis", keyPath: \RotationComponent.rotationAxis)             StoredProperty("isPaused", keyPath: \RotationComponent.isPaused)             StoredProperty("wobbleEnabled", keyPath: \RotationComponent.wobbleEnabled)             StoredProperty("wobbleAmplitude", keyPath: \RotationComponent.wobbleAmplitude)             StoredProperty("wobbleSpeed", keyPath: \RotationComponent.wobbleSpeed)         }     } } tip: The @Scriptable macro generates the Inspectable conformance and the schema for you. The macro replaces the extension and static var schema block in the code sample above. Add import RealityKitScriptingMacros, annotate the type with @Scriptable, and mark the members you want to expose as public. The macro only exposes public members, or ones annotated with @Visible. You access generated schemas as RotationComponent.SchemaProvider.schema rather than RotationComponent.schema. See the following example: import RealityKit import RealityKitScripting import RealityKitScriptingMacros

@Scriptable public struct RotationComponent: Component, Codable {     public var rotationSpeed: Float     public var rotationAxis: SIMD3<Float> = .init(0, 1, 0)     public var isPaused: Bool = false     public var wobbleEnabled: Bool = false     public var wobbleAmplitude: Float = 0.1     public var wobbleSpeed: Float = 5.0

public init(rotationSpeed: Float) {         self.rotationSpeed = rotationSpeed     } } Register the custom component with the plugin Implement RealityComposerProPlugin and register the component twice in setup(context:): once with the Reality Composer Pro context (editor support), and once with ScriptingRuntime (RealityKit Scripting, for scripting support). In the following example, RotationComponent.schema refers to the manually-defined schema. If you use @Scriptable (shown in the previous section), substitute RotationComponent.SchemaProvider.schema. import RealityComposerPro import RealityKitScripting final class RotationPlugin: RealityComposerProPlugin {     func setup(context: any RealityComposerProContext) {         // 1. Register with Reality Composer Pro so designers can add/edit         //    RotationComponent in the Reality Composer Pro Inspector, and         //    so it round-trips through .usda/.reality scene files.         context.registerComponent(RotationComponent.self, defaultValue: RotationComponent(rotationSpeed: 1))         // 2. Register with RealityKitScripting so scripts (via ScriptingComponent)         //    can read/write RotationComponent at runtime.         let scriptingConfig = ScriptingRuntime.Configuration { _ in             let module = Module("RotationPlugin") {                 RotationComponent.schema             }             return [module]         }         do {             try ScriptingRuntime.addConfiguration(scriptingConfig)         } catch {             assertionFailure("Failed to add RealityKitScripting configuration: \(error)")         }     } } @_cdecl("createRealityComposerProPlugin") public func createRealityComposerProPlugin() -> UnsafeMutableRawPointer {     Unmanaged.passRetained(RotationPlugin()).toOpaque() } ScriptingRuntime.addConfiguration initializes ScriptingRuntime if needed and reloads immediately, so the schema is available as soon as the plugin loads — no separate startup step required. Compare what each registration provides The two registration calls serve different audiences and run at different times. See the following comparison.  |  |   |  |   |  |   |  |   |  |   |  |  note: Both registrations point at the same RotationComponent storage — they are two faces of the same RealityKit component: one for scene editing, one for JavaScript scripting at runtime.

## See Also

### Script Graph

- [Getting started with Script Graphs](realitycomposerpro/getting-started-with-script-graphs.md)
- [Building custom interactive behavior with Script Graph](realitycomposerpro/building-custom-interactive-behavior-with-script-graph.md)
