Help Needed with TransformControls Error in Three.js

Hi everyone! :wave: I’m trying to add TransformControls to spheres in my Three.js scene, but I’m encountering the following error:

THREE.Object3D.add: object not an instance of THREE.Object3D.
TransformControls {domElement: canvas.scene, state: -1, keys: {…}, …}

Code:

import { MeshBasicMaterial, Matrix3, Mesh, SphereGeometry, Group } from 'three';
import { TransformControls } from 'three/addons/controls/TransformControls.js';

export class AddLabels {
    camera
    raycaster
    mouse
    femur
    tibia
    scene
    renderer
    orbitControls
    transformControls

    constructor(camera, raycaster, mouse, femur, tibia, scene, renderer, controls) {
        this.camera = camera;
        this.raycaster = raycaster;
        this.mouse = mouse;
        this.femur = femur;
        this.tibia = tibia;
        this.scene = scene;
        this.renderer = renderer;
        this.orbitControls = controls;
        this.transformControls = [];
        if (!this.orbitControls) {
            console.warn('OrbitControls not provided to AddLabels');
        }
        this.boundMouseMove = this.onMouseMove.bind(this);
        this.boundClick = this.onClick.bind(this);

        this.init();
    }

    init = () => {
        window.addEventListener('mousemove', this.boundMouseMove);
        window.addEventListener('click', this.boundClick);
    }

    onMouseMove = (event) => {
        this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    }

    onClick = (event) => {
        this.raycaster.setFromCamera(this.mouse, this.camera);
        const intersects = this.raycaster.intersectObjects([this.femur, this.tibia]);

        if (intersects.length > 0) {
            const intersection = intersects[0];
            const point = intersection.point;
            const normal = intersection.face.normal;

            // Create a helper position for normal visualization
            const normalMatrix = new Matrix3().getNormalMatrix(intersection.object.matrixWorld);
            const worldNormal = normal.clone().applyNormalMatrix(normalMatrix);

            console.log('Clicked on:', intersection.object === this.femur ? 'Femur' : 'Tibia');
            this.createSphere(point, worldNormal);
        }
    }

    createSphere = (position, normal) => {
        try {
            const sphereGeometry = new SphereGeometry(0.01, 32, 32);
            const sphereMaterial = new MeshBasicMaterial({
                color: 0xff00ff,
                depthTest: false,
                transparent: true,
                opacity: 0.8
            });
            const sphere = new Mesh(sphereGeometry, sphereMaterial);
            sphere.position.copy(position);
            sphere.renderOrder = 999;
            sphere.material.needsUpdate = true;

            // Create a group to hold both the sphere and controls
            const group = new Group();
            group.add(sphere);
            this.scene.add(group);

            // Create and configure transform control
            const transformControl = new TransformControls(this.camera, this.renderer.domElement);
            transformControl.setMode('translate');
            transformControl.setSize(0.5);

            // Attach control to the sphere
            transformControl.attach(sphere);

            // Add the transform control to the group
            group.add(transformControl);

            if (this.orbitControls) {
                transformControl.addEventListener('dragging-changed', (event) => {
                    this.orbitControls.enabled = !event.value;
                });
            }

            this.transformControls.push({ control: transformControl, object: sphere, group: group });

            return sphere;
        } catch (error) {
            console.error('Error in createSphere:', error);
            return null;
        }
    }

    getScreenPosition = (position) => {
        const vector = position.project(this.camera);
        const x = (vector.x * .5 + .5) * window.innerWidth;
        const y = -(vector.y * .5 + .5) * window.innerHeight;
        return { x, y };
    }

    cleanup = () => {
        window.removeEventListener('mousemove', this.boundMouseMove);
        window.removeEventListener('click', this.boundClick);

        this.transformControls.forEach(({ control, object, group }) => {
            if (object) {
                object.geometry.dispose();
                object.material.dispose();
            }
            control.dispose();
            if (group) {
                this.scene.remove(group);
            }
        });
        this.transformControls = [];
    }
}

The error occurs when I attempt to add the TransformControls to the scene.

Does anyone know what might be causing this or have suggestions for fixing it? Thanks in advance!

From the example… you don’t do scene.add(transformControls), it’s:

	control.attach( mesh );

	const gizmo = control.getHelper();
	scene.add( gizmo );

https://threejs.org/examples/#misc_controls_transform