Dynamic 3D Models
Dynamic 3D models allow you to create your own parametric 3D geometries using React-Three-Fiber that adapt based on feature values.
Basic Structure
Dynamic models are registered in the viewer.models array:
// In Plugin.tsx
export default {
// ...
viewer: {
models: [ /* Ihre Modelle hier */ ]
}
}
If your model components use React hooks (useRef, useState, useEffect, etc.), @react-three/fiber must be explicitly imported into Plugin.tsx—otherwise, React’s singleton resolution in Module Federation will fail, and hooks will throw a runtime error:
// Plugin.tsx — zwingend erforderlich wenn Hooks genutzt werden
__PROTECTED_0__
Background: Without this import, the MF runtime resolves React lazily—too late for the first render cycle.
A single model looks like this:
__PROTECTED_1__
__PROTECTED_2__
const myModel: DynamicModel = {
type: "vendor.my-model",
label: "Mein dynamisches Modell",
description: "Ein parametrisches 3D-Modell",
screenshot: "/path/to/preview.png",
materials: ["surface", "edge"],
disabledForAR: false,
component: MyDynamicModel,
propsDialog: {
radius: {
type: "expression",
label: "Radius"
},
height: {
type: "expression",
label: "Höhe"
},
color: {
type: "basic",
label: "Farbe"
}
},
defaultProps: {
radius: { expression: "1" },
height: { expression: "2" },
color: "#ff0000"
}
};
export default myModel;
Model Descriptor
A DynamicModel consists of the following properties:
type (required)
Unique type string for the model. Should include a vendor prefix, e.g., "vendor.my-model".
label (required)
Display name for the model in the admin dialog for model selection.
description (required)
Description of the model. Can be specified as a string or LocalizedString:
description: {
de: "Ein parametrischer Ring",
en: "A parametric ring"
}
component (required)
The React Three Fiber component that renders the 3D model.
materials (required)
Array of material names used by the model. These can be replaced by other materials in K3 actions.
materials: ["surface", "border", "detail"]
disabledForAR (required)
Determines whether the model should be included in the AR export. Set this to true if the model uses shaders or features that are not supported in AR.
propsDialog (required)
Defines the properties that can be set in the admin dialog. Each property has a name (key) and a ModelProp descriptor:
propsDialog: {
width: {
type: "expression",
label: "Breite"
},
baseModel: {
type: "model",
label: "Basis-Modell",
multiple: false
},
colorVariable: {
type: "variable",
label: "Farbvariable",
allowedTypes: ["color"]
}
}
Prop Types
expression(default): Displays an expression editor. The value is calculated at runtime based on feature values.basic: Simple text/numeric input field for static values.model: Model selector. Allows selection of K3 models.multiple: trueallows multiple selections
variable: Variable selector. Allows selection of K3 characteristics.allowedTypes: Array of allowed variable types (e.g.,["color", "number"])
defaultProps (required)
Default values for all properties defined in propsDialog. For expressions, use the format { expression: "..." }:
defaultProps: {
width: { expression: "merkmal.breite * 2" },
height: { expression: "1.5" },
color: "#ff0000",
baseModel: [],
colorVariable: null,
slots: [
{ id: "base", name: "Basis", defaultModelId: null },
{ id: "subtract", name: "Subtraktion", defaultModelId: null },
]
}
Slots define placeholders into which other models can be inserted via a rule. A model with slots functions as a layout model—it arranges the passed-in models in 3D space instead of drawing geometry directly into the scene itself.
In a rule’s Model Action, you can then use the slot field to specify which slot the model should be inserted into. In this case, the model is not rendered directly into the scene, but is passed to the layout model’s component as a slots prop (see 3D Layout Components).
screenshot (optional)
URL to a preview image that is displayed in the model selection dialog.
tag (optional)
Tag for grouping or filtering models in the admin UI.
Model Component
The Model component is a standard React Three Fiber component that receives all properties defined in the descriptor as props:
__PROTECTED_3__
__PROTECTED_4__
interface MyDynamicModelProps {
radius: number;
height: number;
color: string;
// Weitere Props aus propsDialog
}
export const MyDynamicModel: React.FC<MyDynamicModelProps> = (props) => {
const meshRef = useRef<Mesh>(null);
return (
<group>
<mesh ref={meshRef}>
<cylinderGeometry args={[props.radius, props.radius, props.height, 32]} />
<meshStandardMaterial color={props.color} />
</mesh>
</group>
);
};
Context Props
In addition to the user-defined props, the component automatically receives PluginModelContext:
interface PluginModelContext {
/** Nur während Screenshot-Rendering gesetzt */
screenshotCameraName?: string;
/** Die eindeutige ID der Model-Action */
modelActionId?: string;
}
Expressions in Props
If a property is defined as an expression, it is evaluated at runtime. You can access feature values:
defaultProps: {
// Einfache Zahl
fixed: { expression: "10" },
// Merkmalswert verwenden
width: { expression: "merkmal.breite" },
// Berechnungen
height: { expression: "merkmal.hoehe * 2 + 5" },
// Komplexe Ausdrücke
total: { expression: "merkmal.breite * merkmal.hoehe * merkmal.tiefe" }
}
Accessing Other Models
If you use type: "model" in a property, you gain access to other K3 models:
propsDialog: {
childModels: {
type: "model",
label: "Kind-Modelle",
multiple: true
}
},
defaultProps: {
childModels: []
}
You can then use these models within the component (see the K3 internal documentation for details on integration).
Accessing Variables
You can use type: "variable" to reference K3 characteristics:
propsDialog: {
colorVar: {
type: "variable",
label: "Farbvariable",
allowedTypes: ["color"]
}
},
defaultProps: {
colorVar: null
}
Example: Parametric Ring
__PROTECTED_5__
interface RingModelProps {
radius: number;
thickness: number;
segmentCount: number;
}
export const RingModel: React.FC<RingModelProps> = (props) => {
const geometry = useMemo(() => {
const geo = new THREE.TorusGeometry(
props.radius,
props.thickness,
16,
props.segmentCount
);
return geo;
}, [props.radius, props.thickness, props.segmentCount]);
return (
<mesh geometry={geometry}>
<meshStandardMaterial color="#silver" metalness={0.8} roughness={0.2} />
</mesh>
);
};
3D Layout Components
A layout model defines slots and is responsible for arranging the models placed within it in 3D space. The finished <group> or mesh elements of the slot models are passed to the component as a slots prop.
Type of the slots prop
type SlotEntry = {
/** Die React-Komponente des eingesetzten Modells */
component: React.ComponentType<any>;
/** Props, die an die Komponente weitergegeben werden */
props: Record<string, any>;
};
type Slots = Record<string, SlotEntry>;
Example: Layout model with two slots
Descriptor:
__PROTECTED_6__
__PROTECTED_7__
const baseSubtractModel: DynamicModel = {
type: "vendor.base-subtract-layout",
label: "Basis + Subtraktion",
description: "Ordnet ein Basis- und ein Subtraktions-Modell übereinander an.",
materials: [],
disabledForAR: false,
slots: [
{ id: "base", name: "Basis", defaultModelId: null },
{ id: "subtract", name: "Subtraktion", defaultModelId: null },
],
propsDialog: {
offsetY: { type: "expression", label: "Y-Versatz (Subtraktion)" },
},
defaultProps: {
offsetY: { expression: "0" },
base: null,
subtract: null,
},
component: BaseSubtractLayout,
};
export default baseSubtractModel;
Component:
__PROTECTED_8__
interface BaseSubtractLayoutProps {
offsetY: number;
slots: Slots;
}
export const BaseSubtractLayout: React.FC<BaseSubtractLayoutProps> = ({ offsetY, slots }) => {
const BaseComponent = slots.base?.component;
const SubtractComponent = slots.subtract?.component;
return (
<group>
{/* Basis-Modell an Ursprung */}
{BaseComponent && <BaseComponent {...slots.base.props} />}
{/* Subtraktions-Modell mit Y-Versatz */}
<group position={[0, offsetY, 0]}>
{SubtractComponent && <SubtractComponent {...slots.subtract.props} />}
</group>
</group>
);
};
Model action with slot assignment
In a rule, the slot target is specified via the slot field of the model action.