Skip to main content

Overview

The Speckle Mesh format is different from most 3D libraries you’ve encountered. Understanding its unique structure is critical to avoid frustration when creating or consuming geometry.
Common Confusion: Speckle’s mesh format uses a packed face array with nGon support that’s fundamentally different from libraries like three.js, Babylon.js, or standard OBJ files. The faces array encodes BOTH face size AND vertex indices in a single flat list.

The Speckle Mesh Structure

Basic Properties

The Vertices Array: Simple

The vertices array is straightforward - a flat list of XYZ coordinates:
Key points:
  • Always a multiple of 3 (X, Y, Z)
  • Indexed starting from 0
  • Units apply to these coordinates

The Faces Array: The Tricky Part

This is where it gets different! The faces array is NOT a simple list of triangle indices. It’s a packed format that supports nGons (polygons with any number of sides).

Face Array Format

The faces array encodes face information as:
Structure:
  • First number = how many vertices in this face
  • Next N numbers = vertex indices for this face
  • Then repeat for next face

Example: Triangle

Example: Quad (4-sided polygon)

Example: Multiple Faces

Why This Format? nGon Support

Most mesh libraries only support triangles (or triangles + quads). Speckle supports nGons - faces with any number of vertices. Advantages:
  • Preserves design intent - Doesn’t force triangulation
  • BIM compatibility - Revit, Rhino often use quads and nGons
  • Round-trip fidelity - Original face structure preserved
  • Smaller data - No unnecessary triangulation
Trade-off:
  • More complex to parse
  • Rendering engines must triangulate

Parsing the Faces Array

Reading Faces

Accessing Face Vertices

Triangulating nGons

Most rendering engines need triangles. Here’s how to triangulate:

Vertex Colors

Colors are per-vertex ARGB integers (not per-face!):
Important:
  • Length of colors must equal number of vertices
  • Colors interpolate across faces (gradient effect)
  • If empty, viewer uses default material color

Converting RGB to ARGB

Render Materials

Render materials define the visual appearance of meshes using physically-based rendering properties. Unlike vertex colors (which are per-vertex), render materials apply to entire objects.

RenderMaterial Properties

Properties:
  • name (str, required): Material name
  • diffuse (int, required): Base color as ARGB integer (see Vertex Colors)
  • opacity (float): Transparency level (default: 1.0)
  • metalness (float): Metallic appearance (default: 0.0)
  • roughness (float): Surface roughness (default: 1.0)
  • emissive (int): Self-illumination color as ARGB integer (default: 0xFF000000)

Direct Assignment

Assign a material directly to a mesh:

RenderMaterialProxy for Collections

For efficiently sharing materials across multiple objects in a collection, use RenderMaterialProxy. This is the standard pattern used by Speckle connectors.
See the Proxification guide for detailed information on how RenderMaterialProxy works, including: - How to create and use material proxies - Resolving proxy references - Best practices for large models

Material vs Vertex Colors

Use RenderMaterial when:
  • Applying consistent appearance to entire objects
  • Using physically-based properties (metalness, roughness)
  • Need transparency or emissive effects
  • Sharing materials across multiple objects
Use vertex colors when:
  • Per-vertex color variation (gradients, heatmaps)
  • Visualizing analysis data
  • Color-coding mesh regions
Can you use both? Yes! Vertex colors and render materials can be combined, but viewer behavior may vary.

Vertex Normals

Normals control surface shading (smooth vs flat):
Important facts:
  • Length of vertexNormals must be same as vertices (3x vertex count)
  • Normals should be unit vectors (length = 1)
  • If empty, viewer auto-calculates normals
  • Per-vertex normals = smooth shading
  • Duplicated vertices with different normals = hard edges

Hard vs Soft Edges

Speckle connectors produce meshes with all hard-edged faces by default - meaning every face has its own duplicated vertices rather than sharing vertices between faces. This approach prioritizes conversion speed and ensures consistent rendering.
Understanding edge behavior:
  • Hard edges are the default - each face has its own vertices, creating sharp transitions
  • Soft edges would require shared vertices with averaged normals, but connectors don’t typically create these
  • This means most Speckle meshes have “flat” shading rather than smooth shading
If smooth shading or mixed hard/soft edges are required for your use case, mesh normalization can be performed as a server-side automation that processes the geometry and writes back properly normalized meshes with shared vertices where appropriate.

Two-Sidedness: Not Supported

Speckle doesn’t have a “two-sided” material flag. Faces have a front and back determined by winding order, but both sides render the same in the viewer.
Winding order:
  • Right-hand rule determines front face
  • Counter-clockwise = front (when viewed from front)
  • Most viewers render both sides regardless

Creating Meshes: Complete Examples

Example 1: Simple Quad

Example 2: Colored Triangle

Example 3: Box with Triangulated Faces

Example 4: Box with Quad Faces (nGons)

Common Questions

The most common issue is forgetting the vertex count in the faces array. Speckle uses a packed format where each face starts with the number of vertices.
Colors must match the number of vertices exactly. Each vertex needs one color value.
Units are crucial for proper scaling and display. Without units, your geometry might appear at the wrong size or scale.
Speckle connectors produce meshes with all hard-edged faces by default - each face has its own duplicated vertices rather than sharing vertices between faces. This creates flat shading rather than smooth shading.If you need smooth shading, you can perform mesh normalization as a server-side automation to create shared vertices where appropriate.

Debugging Tools

Validate Mesh Structure

Visualize Mesh Info

Summary

Key takeaways:
  1. Vertices = Flat list [x,y,z, x,y,z, ...]
  2. Faces = Packed format [count, i1, i2, i3, count, ...]
  3. nGons supported = Any number of vertices per face
  4. Colors = Per-vertex ARGB integers
  5. RenderMaterials = Physically-based materials with metalness, roughness, and opacity
  6. RenderMaterialProxy = Efficient material sharing across multiple objects
  7. Normals = Per-vertex, connectors produce all hard-edged faces (duplicated vertices)
  8. No two-sided flag = Must duplicate faces with reversed winding
  9. Always specify units
Common gotchas:
  • ❌ Don’t forget the vertex count in faces array
  • ❌ Colors/normals must match vertex count
  • ❌ Connectors create flat shading by default (no shared vertices)
  • ❌ No explicit two-sided support
  • ✅ nGons are supported and preserved

Next Steps

Display Values

How meshes are used in displayValue for viewer visibility

Proxification

Learn about RenderMaterialProxy and other proxy patterns

Working with Geometry

Creating and manipulating geometry objects

Simple Data Patterns

Patterns for working with geometry and properties

Objects & Base

Understanding the Base class and detachment
Last modified on July 18, 2026