BBC's guide to development
  • General

    • About
    • Tools
    • Git(hub)
    • Showpad
    • Hosting
    • Maintenance
    • Security
    • Go live checklist
  • Front-end development

    • Bundlers
    • CSS/SCSS
    • Javascript
    • Vue
    • PHP
    • Mails
    • Dev Faq
  • Functions
  • Mixins
  • General

    • OOP Structure
  • Component Classes

    • Accordion
    • App
    • Component
    • HighwayApp
    • Popup
    • PNG Sequencer
    • Tab
  • Manager Classes

    • BountListenerMgr
    • Cache
    • Configuration
    • InViewStateMgr
    • Instance Manager
    • Event dispatcher
  • Factories

    • SwiperFactory
  • PDF

    • AssetLoader
    • BasePdfDoc
    • TemplatePdfDoc
    • CustomPdfDoc
  • Utility functions

    • canvas
    • Connection Status
    • css
    • dev
    • placeholder
    • dom
    • fetch
    • json
    • object
    • scroll
    • scrollbar
    • spreadsheets
    • string
    • url
  • General

    • ComponentMgr
    • ThreeJsViewer
  • Components

    • ComponentMgr
    • GltfModel
    • Snappable
    • Socket
    • ThreeJsViewer
    • ThreeJsViewerCamera
  • Loaders

    • ConfigurationSerializer
    • GltfBlockParser
  • Utils

    • CanvasInputAdapter
    • CollisionManager
    • SocketGridExpander
    • blender
    • headless
  • General

    • Troubleshooting
    • Legacy
  • Components

    • AssetBar
    • ConfigGenerator
    • ShowpadApp
  • Managers

    • Assets
    • AppsDb
    • Config
  • Utils

    • Connection Status
    • general
    • showpad-interactive
    • showpad-upload
  • Components

    • Accordion
    • BackButton
    • Breadcrumb
    • ByltButton
    • Hamburger
    • Icon
    • Logo
    • Loader
    • Modal
    • Popup
    • Prompt
    • ProgressBar
    • TextLoader
  • Composables

    • useDebugMode
    • useConnectionStatus
  • Utils

    • dom
    • props
  • General

    • General
    • Tracking
  • Components

    • Accordion
    • ActionButton
    • AssetItem
    • AssetList
    • BackButton
    • ConfigGenButton
    • Logo
    • Media
    • Modal
    • Popup
    • Prompt
    • SPButton
    • SPRouterView
    • SPTrackedRouterLink
    • TextLoader
    • View
  • Composables

    • useConnectionStatus
  • Stores

    • useAppsDbStore
    • useBreadcrumbStore
    • useShowpadAPIStore
    • useShowpadSDKStore
    • useSpConfigStore
    • useSpStore
    • useSpTrackingStore
  • The New Kit

    • General
    • Installation & Usage
    • ACF Blocks
    • PHPCS
    • Functions
    • Vite
    • WP Config
    • Staging Deployment
  • Best Practices

    • Page Structure
    • Fonts/Typography
  • Todo
GitHub
  • General

    • About
    • Tools
    • Git(hub)
    • Showpad
    • Hosting
    • Maintenance
    • Security
    • Go live checklist
  • Front-end development

    • Bundlers
    • CSS/SCSS
    • Javascript
    • Vue
    • PHP
    • Mails
    • Dev Faq
  • Functions
  • Mixins
  • General

    • OOP Structure
  • Component Classes

    • Accordion
    • App
    • Component
    • HighwayApp
    • Popup
    • PNG Sequencer
    • Tab
  • Manager Classes

    • BountListenerMgr
    • Cache
    • Configuration
    • InViewStateMgr
    • Instance Manager
    • Event dispatcher
  • Factories

    • SwiperFactory
  • PDF

    • AssetLoader
    • BasePdfDoc
    • TemplatePdfDoc
    • CustomPdfDoc
  • Utility functions

    • canvas
    • Connection Status
    • css
    • dev
    • placeholder
    • dom
    • fetch
    • json
    • object
    • scroll
    • scrollbar
    • spreadsheets
    • string
    • url
  • General

    • ComponentMgr
    • ThreeJsViewer
  • Components

    • ComponentMgr
    • GltfModel
    • Snappable
    • Socket
    • ThreeJsViewer
    • ThreeJsViewerCamera
  • Loaders

    • ConfigurationSerializer
    • GltfBlockParser
  • Utils

    • CanvasInputAdapter
    • CollisionManager
    • SocketGridExpander
    • blender
    • headless
  • General

    • Troubleshooting
    • Legacy
  • Components

    • AssetBar
    • ConfigGenerator
    • ShowpadApp
  • Managers

    • Assets
    • AppsDb
    • Config
  • Utils

    • Connection Status
    • general
    • showpad-interactive
    • showpad-upload
  • Components

    • Accordion
    • BackButton
    • Breadcrumb
    • ByltButton
    • Hamburger
    • Icon
    • Logo
    • Loader
    • Modal
    • Popup
    • Prompt
    • ProgressBar
    • TextLoader
  • Composables

    • useDebugMode
    • useConnectionStatus
  • Utils

    • dom
    • props
  • General

    • General
    • Tracking
  • Components

    • Accordion
    • ActionButton
    • AssetItem
    • AssetList
    • BackButton
    • ConfigGenButton
    • Logo
    • Media
    • Modal
    • Popup
    • Prompt
    • SPButton
    • SPRouterView
    • SPTrackedRouterLink
    • TextLoader
    • View
  • Composables

    • useConnectionStatus
  • Stores

    • useAppsDbStore
    • useBreadcrumbStore
    • useShowpadAPIStore
    • useShowpadSDKStore
    • useSpConfigStore
    • useSpStore
    • useSpTrackingStore
  • The New Kit

    • General
    • Installation & Usage
    • ACF Blocks
    • PHPCS
    • Functions
    • Vite
    • WP Config
    • Staging Deployment
  • Best Practices

    • Page Structure
    • Fonts/Typography
  • Todo
GitHub
  • SocketGridExpander

SocketGridExpander

The SocketGridExpander module provides functionality to expand a socket grid definition into multiple individually placed socket instances. It takes a single socket grid group containing a base socket and a plane definition, then generates an array of cloned sockets positioned in a regular grid pattern across the plane.

This is useful for creating repetitive socket layouts (like power outlet grids on walls, connector arrays on equipment, etc.) from a compact parametric definition.

Note

This is a quick first pass at rendering multiple sockets in a grid layout with minimal overhead for both the 3D artist and the developer.

A more robust solution would use a dedicated SocketGrid class with a plane-based geometry and grid interactions rendered via ShaderMaterial—this shader-based approach would offer significantly better performance.

However, we've deferred that implementation due to time constraints and added complexity.

Warning

Meant to be used with ComponentMgr only.

Getting started

import { expandSocketGridGroup } from './SocketGridExpander.js';

// Create a grid group with proper structure
const gridGroup = new THREE.Group();
gridGroup.userData = {
    type: 'socketGrid',
    rows: 4,
    columns: 6
};
gridGroup.name = 'PowerOutletWall';

// Add plane child (defines distribution area)
const planeGeometry = new THREE.PlaneGeometry(2, 1.5); // 2m wide, 1.5m tall
const planeMesh = new THREE.Mesh(planeGeometry, material);
planeMesh.userData = { type: 'socketPlane' };
gridGroup.add(planeMesh);

// Add socket template child
const socketGroup = createSocketGeometry(); // Your socket creation logic
socketGroup.userData = { type: 'socket', voltage: 120 };
gridGroup.add(socketGroup);

// Expand the grid
const { generatedSockets, warnings } = expandSocketGridGroup(gridGroup);

if (warnings.length > 0) {
    console.warn('Grid expansion warnings:', warnings);
}

// Add all sockets to scene
generatedSockets.forEach(socket => {
    scene.add(socket);
});

Core Function

expandSocketGridGroup(gridGroup)

Purpose: Expands a socket grid group into individual socket clones positioned in a grid pattern.

Parameters:

  • gridGroup (THREE.Group): The grid group object containing socket grid definition data

Returns:

{
    generatedSockets: [],    // Array of cloned and positioned socket groups
    warnings: []             // Array of validation warning messages
}

Behavior:

  • Validates the input grid group structure
  • Extracts geometry and transformation information from child nodes
  • Calculates grid positions based on the plane bounds and row/column count
  • Scales and positions socket clones to fit grid cells
  • Returns all generated sockets regardless of warnings (partial success supported)

Input Structure

The gridGroup must be a THREE.Group with the following properties:

userData Requirements

gridGroup.userData = {
    type: 'socketGrid',          // Required: identifies as socket grid
    rows: number,                // Required: number of socket rows (≥1)
    columns: number              // Required: number of socket columns (≥1)
}

Child Nodes

The group must contain exactly two child nodes:

  1. Socket Plane Node (child with userData.type === 'socketPlane')

    • Defines the 2D plane where sockets will be distributed
    • Must contain a mesh with valid geometry
    • Geometry bounds determine the grid dimensions
    • Any shape can work as long as it has a clear bounding box
  2. Base Socket Group (child with userData.type === 'socket')

    • Template socket to be cloned and positioned
    • Must contain a mesh with valid geometry
    • Will be cloned once per grid cell
    • All userData properties are deep-cloned and preserved

Processing Pipeline

1. Validation Phase

  • Checks grid group has correct userData.type
  • Validates rows and columns are positive integers
  • Verifies required child nodes exist
  • Confirms both nodes contain valid meshes with geometry
  • Returns early with warnings if validation fails

2. Transform Calculation Phase

  • Updates world matrices for all nodes
  • Calculates relative transformations:
    • planeToGrid: Plane mesh position relative to grid group
    • baseSocketToGrid: Base socket mesh position relative to grid group
    • baseGroupToGrid: Base socket group position relative to grid group
  • These transformations account for nested hierarchies and world-space positions

3. Plane Analysis Phase

  • Extracts bounding box from plane mesh geometry
  • Determines the two largest axes as U (width) and V (height)
  • Calculates the plane's normal axis (N)
  • Computes plane center and dimensions
  • Returns error if plane is degenerate (near-zero dimensions)

4. Socket Sizing Phase

  • Projects base socket geometry onto the grid's U, V, and N axes
  • Calculates socket extents in local grid space
  • Computes scale factors needed to fit sockets into grid cells:
    • scaleU: Cell width / socket width
    • scaleV: Cell height / socket height
  • Creates a scaling transformation that scales around the socket's center point

5. Grid Positioning Phase

  • Calculates grid cell positions using:
    • stepU: Distance between columns
    • stepV: Distance between rows
  • For each grid cell (row, column):
    • Clones the base socket group with full hierarchy
    • Deep-clones userData properties
    • Attaches metadata about the parent grid
    • Applies scaling transformation
    • Applies translation transformation to position in grid
    • Adds to results array

Key Algorithms

Plane Extraction (extractPlaneInfo)

Determines the primary 2D plane from a 3D geometry:

  1. Computes geometry bounding box
  2. Transforms bounding box axes to grid space
  3. Sorts axes by length (transformed scale)
  4. Takes the two longest axes as U and V
  5. Computes normal axis N as cross product of U and V
  6. Returns orthonormal basis and dimensions

Geometry Projection (projectGeometryExtents)

Projects a 3D geometry onto three orthogonal axes:

  1. Extracts all 8 corners of bounding box
  2. Transforms corners to target space
  3. Computes dot products along each axis
  4. Tracks min/max for each axis
  5. Returns size in each dimension

Scale-Around-Point (makeAxisScaleAroundPoint)

Creates a matrix that scales around a point in custom coordinate space:

  1. Builds basis matrix from three orthonormal axes
  2. Creates scaling matrix in basis space
  3. Transforms scale to world space
  4. Applies translation to anchor around specified point
  5. Combines all transformations: translate to origin → scale → translate back

Output

Generated Sockets

Each cloned socket receives:

  • Full geometry hierarchy from base socket
  • Deep-cloned userData with additional properties:
    • socketGridName: Name of parent grid group
    • socketGridRows: Total rows in grid
    • socketGridColumns: Total columns in grid
  • Applied transformations:
    • Scaled to fit grid cell
    • Positioned in grid layout
    • Maintains local orientation from base socket

Grid Positioning Details

  • U-axis ordering: Columns increase left to right
  • V-axis ordering: Rows increase bottom to top
  • Center reference: Grid centered at plane center, sockets scaled around their local centers
  • Cell spacing: Uniform spacing calculated as dimension / (count - 1) for count > 1

Error Handling

Validation Warnings

The function collects non-fatal warnings but continues processing:

  • Missing socketPlane or socket child nodes
  • Invalid or missing rows/columns values
  • Missing or invalid meshes in required nodes
  • Degenerate plane (near-zero dimensions)

Return Behavior

  • Always returns { generatedSockets, warnings }
  • generatedSockets may be empty if validation fails
  • warnings explains all detected issues
  • Caller can check warnings to understand partial or complete failure

Helper Functions

findFirstMesh(root)

Traverses a THREE.Object3D tree and returns the first mesh found, or null.

toPositiveInt(value)

Safely converts a value to a positive integer (≥1), returns null if invalid.

deepCloneUserData(userData)

Deep-clones userData object using JSON serialization, falls back to shallow clone if that fails.

ensureBoundingBox(geometry)

Lazy-computes and returns bounding box, computing it if not already present.

getBoundingBoxCorners(boundingBox)

Extracts all 8 corner points of a bounding box.

Performance Considerations

  • Memory: Creates N × M clones (one per grid cell), each with full geometry
  • Scale factors: Computed once per grid, not per socket
  • Transformations: Matrix operations are performed per socket (2 transformations each)
  • Large grids: For >1000 sockets, consider instancing or LOD techniques

Constraints & Limitations

  • Grid must be rectangular (even spacing in U and V)
  • Plane should be roughly planar (geometry will use bounding box axes regardless)
  • Cells are uniform-sized (no non-uniform spacing)
  • Cannot skip grid positions (always fills complete grid)
  • Scaling is uniform in U and V directions (based on cell dimensions)
  • Sockets are positioned at cell centers
Edit this page
Last Updated: 4/27/26, 12:56 PM
Contributors: Nicolas Jaenen