diff --git a/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.cxx b/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.cxx
index f1127874a16297ef81d291bbe7c573889baf710a..310df6fbe3763418c49b7b2541bafda67361b76d 100644
--- a/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.cxx
+++ b/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.cxx
@@ -206,37 +206,51 @@ void vtkWebGPUBatchedPolyDataMapper::RenderPiece(vtkRenderer* renderer, vtkActor
   {
     if (useNanColor)
     {
-      this->WriteOverrideColorBuffer(wgpuConfiguration, true, batchElement.Opacity,
-        vtkColor3d{ nanColor }, vtkColor3d{ nanColor });
+      this->UpdateMeshDescriptor(wgpuConfiguration, true, batchElement.Opacity,
+        vtkColor3d{ nanColor }, vtkColor3d{ nanColor }, batchElement.FlatIndex);
     }
     else
     {
-      this->WriteOverrideColorBuffer(wgpuConfiguration, batchElement.OverridesColor,
-        batchElement.Opacity, batchElement.AmbientColor, batchElement.DiffuseColor);
+      this->UpdateMeshDescriptor(wgpuConfiguration, batchElement.OverridesColor,
+        batchElement.Opacity, batchElement.AmbientColor, batchElement.DiffuseColor,
+        batchElement.FlatIndex);
     }
   }
   this->LastUseNanColor = useNanColor;
 }
 
 //------------------------------------------------------------------------------
-void vtkWebGPUBatchedPolyDataMapper::WriteOverrideColorBuffer(
+void vtkWebGPUBatchedPolyDataMapper::UpdateMeshDescriptor(
   vtkSmartPointer<vtkWebGPUConfiguration> wgpuConfiguration, bool applyOverrides,
   double overrideOpacity, const vtkColor3d& overrideAmbientColor,
-  const vtkColor3d& overrideDiffuseColor)
+  const vtkColor3d& overrideDiffuseColor, vtkTypeUInt32 compositeId)
 {
-  OverrideColorDescriptor overrideColorDescriptor = {};
-  overrideColorDescriptor.ApplyOverrideColors = applyOverrides ? 1 : 0;
-  overrideColorDescriptor.Opacity = overrideOpacity;
-  for (int i = 0; i < 3; ++i)
-  {
-    overrideColorDescriptor.Ambient[i] = overrideAmbientColor[i];
-    overrideColorDescriptor.Diffuse[i] = overrideDiffuseColor[i];
-  }
   if (this->AttributeDescriptorBuffer != nullptr)
   {
+    vtkTypeUInt32 applyOverrideColors = applyOverrides ? 1 : 0;
+    vtkTypeFloat32 opacity = overrideOpacity;
+    vtkTypeFloat32 ambientColor[3];
+    vtkTypeFloat32 diffuseColor[3];
+    for (int i = 0; i < 3; ++i)
+    {
+      ambientColor[i] = overrideAmbientColor[i];
+      diffuseColor[i] = overrideDiffuseColor[i];
+    }
+    wgpuConfiguration->WriteBuffer(this->AttributeDescriptorBuffer,
+      offsetof(MeshAttributeDescriptor, ApplyOverrideColors), &applyOverrideColors,
+      sizeof(vtkTypeUInt32));
+
+    wgpuConfiguration->WriteBuffer(this->AttributeDescriptorBuffer,
+      offsetof(MeshAttributeDescriptor, Opacity), &opacity, sizeof(vtkTypeFloat32));
+
+    wgpuConfiguration->WriteBuffer(this->AttributeDescriptorBuffer,
+      offsetof(MeshAttributeDescriptor, CompositeId), &compositeId, sizeof(vtkTypeUInt32));
+
+    wgpuConfiguration->WriteBuffer(this->AttributeDescriptorBuffer,
+      offsetof(MeshAttributeDescriptor, Ambient), &ambientColor, sizeof(ambientColor));
+
     wgpuConfiguration->WriteBuffer(this->AttributeDescriptorBuffer,
-      offsetof(MeshAttributeDescriptor, OverrideColors), &overrideColorDescriptor,
-      sizeof(overrideColorDescriptor));
+      offsetof(MeshAttributeDescriptor, Diffuse), &diffuseColor, sizeof(diffuseColor));
   }
   this->OverrideColorUploadTimestamp.Modified();
 }
diff --git a/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.h b/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.h
index a3b48c03bc334042fe35609aebed0b6461750f2d..5b5d52ffbf6c9818d1a5ca69a3a1fe07fba2bdb1 100644
--- a/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.h
+++ b/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.h
@@ -73,9 +73,9 @@ protected:
   bool LastBlockVisibility = true;
   bool LastUseNanColor = false;
 
-  void WriteOverrideColorBuffer(vtkSmartPointer<vtkWebGPUConfiguration> wgpuConfiguration,
+  void UpdateMeshDescriptor(vtkSmartPointer<vtkWebGPUConfiguration> wgpuConfiguration,
     bool applyOverrides, double overrideOpacity, const vtkColor3d& overrideAmbientColor,
-    const vtkColor3d& overrideDiffuseColor);
+    const vtkColor3d& overrideDiffuseColor, vtkTypeUInt32 compositeId);
 
 private:
   vtkWebGPUBatchedPolyDataMapper(const vtkWebGPUBatchedPolyDataMapper&) = delete;
diff --git a/Rendering/WebGPU/vtkWebGPUPolyDataMapper.cxx b/Rendering/WebGPU/vtkWebGPUPolyDataMapper.cxx
index 8fe632b4a1a6a417dfefb3ffe347086a2753c11e..980b075e6e2840fb6a28b696f2c7151ff8ec041e 100644
--- a/Rendering/WebGPU/vtkWebGPUPolyDataMapper.cxx
+++ b/Rendering/WebGPU/vtkWebGPUPolyDataMapper.cxx
@@ -962,7 +962,7 @@ void vtkWebGPUPolyDataMapper::UpdateMeshGeometryBuffers(vtkWebGPURenderWindow* w
   this->MapScalars(this->CurrentInput, 1.0, cellFlag);
   this->DeducePointCellAttributeAvailability(this->CurrentInput);
 
-  MeshAttributeDescriptor meshAttrDescriptor;
+  MeshAttributeDescriptor meshAttrDescriptor = {};
 
   vtkPointData* pointData = this->CurrentInput->GetPointData();
   vtkDataArray* pointPositions = this->CurrentInput->GetPoints()->GetData();
@@ -1317,6 +1317,10 @@ void vtkWebGPUPolyDataMapper::SetupGraphicsPipelines(
   depthState->depthWriteEnabled = true;
   depthState->depthCompare = wgpu::CompareFunction::Less;
   ///@}
+  // Prepare selection ids output.
+  descriptor.cTargets[1].format = wgpuRenderWindow->GetPreferredSelectorIdsTextureFormat();
+  descriptor.cFragment.targetCount++;
+  descriptor.DisableBlending(1);
 
   // Update local parameters that decide whether a pipeline must be rebuilt.
   this->RebuildGraphicsPipelines = false;
diff --git a/Rendering/WebGPU/vtkWebGPUPolyDataMapper.h b/Rendering/WebGPU/vtkWebGPUPolyDataMapper.h
index b0d5eb5bddadc8c459afe4b9b771fa33d75177b9..de37be7a7e14d0b2d6f7ecccc24a0d0473a6e550 100644
--- a/Rendering/WebGPU/vtkWebGPUPolyDataMapper.h
+++ b/Rendering/WebGPU/vtkWebGPUPolyDataMapper.h
@@ -358,14 +358,6 @@ protected:
     vtkTypeUInt32 NumTuples = 0;
     vtkTypeUInt32 NumComponents = 0;
   };
-  struct OverrideColorDescriptor
-  {
-    vtkTypeUInt32 ApplyOverrideColors = 0;
-    vtkTypeFloat32 Opacity = 0;
-    vtkTypeUInt8 Padding1[8];
-    vtkTypeFloat32 Ambient[4] = {}; // last component is padding for 16-byte alignment
-    vtkTypeFloat32 Diffuse[4] = {}; // last component is padding for 16-byte alignment
-  };
   struct MeshAttributeDescriptor
   {
     AttributeDescriptor Positions;
@@ -375,8 +367,13 @@ protected:
     AttributeDescriptor UVs;
     AttributeDescriptor CellColors;
     AttributeDescriptor CellNormals;
-    vtkTypeUInt8 Padding[12];
-    OverrideColorDescriptor OverrideColors;
+    vtkTypeUInt32 ApplyOverrideColors = 0;
+    vtkTypeFloat32 Opacity = 0;
+    vtkTypeUInt32 CompositeId = 0;
+    vtkTypeFloat32 Ambient[3] = {};
+    vtkTypeUInt32 ProcessId = 0;
+    vtkTypeFloat32 Diffuse[3] = {};
+    vtkTypeUInt8 Padding[4];
   };
   wgpu::Buffer AttributeDescriptorBuffer;
 
diff --git a/Rendering/WebGPU/wgsl/LineFragmentShader.wgsl b/Rendering/WebGPU/wgsl/LineFragmentShader.wgsl
index d1c307534e9a4771708e99c0e43570cac7da73b1..94eb6a34b886f195ef5bcfbbf71fa0964f3622af 100644
--- a/Rendering/WebGPU/wgsl/LineFragmentShader.wgsl
+++ b/Rendering/WebGPU/wgsl/LineFragmentShader.wgsl
@@ -1,7 +1,7 @@
 //-------------------------------------------------------------------
 struct FragmentOutput {
   @location(0) color: vec4<f32>,
-  @location(1) cell_id: u32
+  @location(1) ids: vec4<u32>, // cell_id, prop_id, composite_id, process_id
 }
 
 //-------------------------------------------------------------------
@@ -14,6 +14,11 @@ fn fragmentMain(vertex: VertexOutput) -> FragmentOutput {
 
   var opacity: f32;
 
+  output.ids.x = vertex.cell_id + 1;
+  output.ids.y = vertex.prop_id + 1;
+  output.ids.z = vertex.composite_id + 1;
+  output.ids.w = vertex.process_id + 1;
+
   let distance_from_centerline = abs(vertex.distance_from_centerline);
 
   // adjust z component of normal in order to emulate a tube if necessary.
@@ -27,10 +32,10 @@ fn fragmentMain(vertex: VertexOutput) -> FragmentOutput {
   // Colors are acquired either from a global per-actor color, or from per-vertex colors, or from cell colors.
   ///------------------------///
   let has_mapped_colors: bool = mesh.point_color.num_tuples > 0u || mesh.cell_color.num_tuples > 0u;
-  if (mesh.override_colors.apply_override_colors == 1u) {
-    ambient_color = mesh.override_colors.ambient_color.rgb;
-    diffuse_color = mesh.override_colors.diffuse_color.rgb;
-    opacity = mesh.override_colors.opacity;
+  if (mesh.apply_override_colors == 1u) {
+    ambient_color = mesh.ambient_color.rgb;
+    diffuse_color = mesh.diffuse_color.rgb;
+    opacity = mesh.opacity;
   } else if (has_mapped_colors) {
     ambient_color = vertex.color.rgb;
     diffuse_color = vertex.color.rgb;
@@ -86,6 +91,5 @@ fn fragmentMain(vertex: VertexOutput) -> FragmentOutput {
   }
   // pre-multiply colors
   output.color = vec4(output.color.rgb * opacity, opacity);
-  output.cell_id = vertex.cell_id;
   return output;
 }
diff --git a/Rendering/WebGPU/wgsl/LineMiterJoinVertexShader.wgsl b/Rendering/WebGPU/wgsl/LineMiterJoinVertexShader.wgsl
index 2e17120cad89d21dda5280d151cc55e9413b8a65..e42a34b64d6648b9146e0fba7e2746cd8b6ed017 100644
--- a/Rendering/WebGPU/wgsl/LineMiterJoinVertexShader.wgsl
+++ b/Rendering/WebGPU/wgsl/LineMiterJoinVertexShader.wgsl
@@ -49,14 +49,6 @@ struct MeshAttributeArrayDescriptor {
   num_components: u32
 }
 
-//-------------------------------------------------------------------
-struct OverrideColorDescriptor {
-  apply_override_colors: u32,
-  opacity: f32,
-  ambient_color: vec3<f32>,
-  diffuse_color: vec3<f32>
-}
-
 //-------------------------------------------------------------------
 struct MeshDescriptor {
   position: MeshAttributeArrayDescriptor,
@@ -66,7 +58,12 @@ struct MeshDescriptor {
   point_uv: MeshAttributeArrayDescriptor,
   cell_color: MeshAttributeArrayDescriptor,
   cell_normal: MeshAttributeArrayDescriptor,
-  override_colors: OverrideColorDescriptor
+  apply_override_colors: u32,
+  opacity: f32,
+  composite_id: u32,
+  ambient_color: vec3<f32>,
+  process_id: u32,
+  diffuse_color: vec3<f32>,
 }
 
 //-------------------------------------------------------------------
@@ -113,8 +110,11 @@ struct VertexOutput {
   @location(1) position_vc: vec4<f32>,
   @location(2) normal_vc: vec3<f32>,
   @location(3) tangent_vc: vec3<f32>,
-  @location(4) @interpolate(flat) cell_id: u32,
-  @location(5) distance_from_centerline: f32,
+  @location(4) distance_from_centerline: f32,
+  @location(5) @interpolate(flat) cell_id: u32,
+  @location(6) @interpolate(flat) prop_id: u32,
+  @location(7) @interpolate(flat) composite_id: u32,
+  @location(8) @interpolate(flat) process_id: u32,
 }
 
 
@@ -137,7 +137,13 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
   // pull the point id
   let point_id = topology[p].point_id;
   // get CellID from vertex ID -> VTK cell map.
-  output.cell_id = topology[p].cell_id;
+  let cell_id = topology[p].cell_id;
+
+  // Write indices
+  output.cell_id = cell_id;
+  output.prop_id = actor.id;
+  output.composite_id = mesh.composite_id;
+  output.process_id = 2u;
 
   var is_polyline_rl: bool = false; // whether polyline is going from right -> left in the topology buffer.
   var is_polyline_lr: bool = false; // whether polyline is going from left -> right in the topology buffer.
@@ -241,7 +247,7 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
     output.color = getTuple4F32(point_id, mesh.point_color.start, &point_data.values);
   } else if mesh.cell_color.num_tuples > 0u {
     // Flat shading
-    output.color = getTuple4F32(output.cell_id, mesh.cell_color.start, &cell_data.values);
+    output.color = getTuple4F32(cell_id, mesh.cell_color.start, &cell_data.values);
   }
 
   ///------------------------///
@@ -250,7 +256,7 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
   ///------------------------///
   if mesh.cell_normal.num_tuples > 0u {
     // pull normal of this vertex from cell normals
-    let normal_mc = getTuple3F32(output.cell_id, mesh.cell_normal.start, &cell_data.values);
+    let normal_mc = getTuple3F32(cell_id, mesh.cell_normal.start, &cell_data.values);
     output.normal_vc = scene_transform.normal * actor.transform.normal * normal_mc;
   } else if mesh.point_tangent.num_tuples > 0u {
     // pull tangent of this vertex from point tangents
diff --git a/Rendering/WebGPU/wgsl/LineRoundJoinVertexShader.wgsl b/Rendering/WebGPU/wgsl/LineRoundJoinVertexShader.wgsl
index 98da5789efbec6b8dc1aea6bd340bf8c829c5970..c54bda3d45dd88336c839a4a0a3b52630ccc7bac 100644
--- a/Rendering/WebGPU/wgsl/LineRoundJoinVertexShader.wgsl
+++ b/Rendering/WebGPU/wgsl/LineRoundJoinVertexShader.wgsl
@@ -102,14 +102,6 @@ struct MeshAttributeArrayDescriptor {
   num_components: u32
 }
 
-//-------------------------------------------------------------------
-struct OverrideColorDescriptor {
-  apply_override_colors: u32,
-  opacity: f32,
-  ambient_color: vec3<f32>,
-  diffuse_color: vec3<f32>
-}
-
 //-------------------------------------------------------------------
 struct MeshDescriptor {
   position: MeshAttributeArrayDescriptor,
@@ -119,7 +111,12 @@ struct MeshDescriptor {
   point_uv: MeshAttributeArrayDescriptor,
   cell_color: MeshAttributeArrayDescriptor,
   cell_normal: MeshAttributeArrayDescriptor,
-  override_colors: OverrideColorDescriptor
+  apply_override_colors: u32,
+  opacity: f32,
+  composite_id: u32,
+  ambient_color: vec3<f32>,
+  process_id: u32,
+  diffuse_color: vec3<f32>,
 }
 
 //-------------------------------------------------------------------
@@ -166,8 +163,11 @@ struct VertexOutput {
   @location(1) position_vc: vec4<f32>,
   @location(2) normal_vc: vec3<f32>,
   @location(3) tangent_vc: vec3<f32>,
-  @location(4) @interpolate(flat) cell_id: u32,
-  @location(5) distance_from_centerline: f32,
+  @location(4) distance_from_centerline: f32,
+  @location(5) @interpolate(flat) cell_id: u32,
+  @location(6) @interpolate(flat) prop_id: u32,
+  @location(7) @interpolate(flat) composite_id: u32,
+  @location(8) @interpolate(flat) process_id: u32,
 }
 
 
@@ -221,7 +221,13 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
   // pull the point id
   let point_id = topology[vertex_id].point_id;
   // get CellID from vertex ID -> VTK cell map.
-  output.cell_id = topology[vertex_id].cell_id;
+  let cell_id = topology[vertex_id].cell_id;
+
+  // Write indices
+  output.cell_id = cell_id;
+  output.prop_id = actor.id;
+  output.composite_id = mesh.composite_id;
+  output.process_id = 2u;
 
   ///------------------------///
   // Smooth/Flag shading
@@ -231,7 +237,7 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
     output.color = getTuple4F32(point_id, mesh.point_color.start, &point_data.values);
   } else if mesh.cell_color.num_tuples > 0u {
     // Flat shading
-    output.color = getTuple4F32(output.cell_id, mesh.cell_color.start, &cell_data.values);
+    output.color = getTuple4F32(cell_id, mesh.cell_color.start, &cell_data.values);
   }
 
   ///------------------------///
@@ -240,7 +246,7 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
   ///------------------------///
   if mesh.cell_normal.num_tuples > 0u {
     // pull normal of this vertex from cell normals
-    let normal_mc = getTuple3F32(output.cell_id, mesh.cell_normal.start, &cell_data.values);
+    let normal_mc = getTuple3F32(cell_id, mesh.cell_normal.start, &cell_data.values);
     output.normal_vc = scene_transform.normal * actor.transform.normal * normal_mc;
   } else if mesh.point_tangent.num_tuples > 0u {
     // pull tangent of this vertex from point tangents
diff --git a/Rendering/WebGPU/wgsl/PointShader.wgsl b/Rendering/WebGPU/wgsl/PointShader.wgsl
index 768d917cdb384869579bcf6ea13737e993a3146e..118081e8ec1d4802f3b72529b7c0bca04b27210e 100644
--- a/Rendering/WebGPU/wgsl/PointShader.wgsl
+++ b/Rendering/WebGPU/wgsl/PointShader.wgsl
@@ -53,14 +53,6 @@ struct MeshAttributeArrayDescriptor {
   num_components: u32
 }
 
-//-------------------------------------------------------------------
-struct OverrideColorDescriptor {
-  apply_override_colors: u32,
-  opacity: f32,
-  ambient_color: vec3<f32>,
-  diffuse_color: vec3<f32>
-}
-
 //-------------------------------------------------------------------
 struct MeshDescriptor {
   position: MeshAttributeArrayDescriptor,
@@ -70,7 +62,12 @@ struct MeshDescriptor {
   point_uv: MeshAttributeArrayDescriptor,
   cell_color: MeshAttributeArrayDescriptor,
   cell_normal: MeshAttributeArrayDescriptor,
-  override_colors: OverrideColorDescriptor
+  apply_override_colors: u32,
+  opacity: f32,
+  composite_id: u32,
+  ambient_color: vec3<f32>,
+  process_id: u32,
+  diffuse_color: vec3<f32>,
 }
 
 //-------------------------------------------------------------------
@@ -117,8 +114,11 @@ struct VertexOutput {
   @location(1) position_vc: vec4<f32>,
   @location(2) normal_vc: vec3<f32>,
   @location(3) tangent_vc: vec3<f32>,
-  @location(4) @interpolate(flat) cell_id: u32,
-  @location(5) local_position: vec2<f32>,
+  @location(4) local_position: vec2<f32>,
+  @location(5) @interpolate(flat) cell_id: u32,
+  @location(6) @interpolate(flat) prop_id: u32,
+  @location(7) @interpolate(flat) composite_id: u32,
+  @location(8) @interpolate(flat) process_id: u32,
 }
 
 //-------------------------------------------------------------------
@@ -130,12 +130,18 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
   ///------------------------///
   let pull_vertex_id: u32 = vertex.instance_id;
   // get CellID from vertex ID -> VTK cell map.
-  output.cell_id = topology[pull_vertex_id].cell_id;
+  let cell_id = topology[pull_vertex_id].cell_id;
   // pull the point id
   let point_id = topology[pull_vertex_id].point_id;
   // pull the position for this vertex.
   let p_mc = vec4<f32>(getTuple3F32(point_id, mesh.position.start, &point_data.values), 1.0);
 
+  // Write indices
+  output.cell_id = cell_id;
+  output.prop_id = actor.id;
+  output.composite_id = mesh.composite_id;
+  output.process_id = 0u;
+
   ///------------------------///
   // NDC transforms
   ///------------------------///
@@ -164,7 +170,7 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
     output.color = getTuple4F32(point_id, mesh.point_color.start, &point_data.values);
   } else if mesh.cell_color.num_tuples > 0u {
     // Flat shading
-    output.color = getTuple4F32(output.cell_id, mesh.cell_color.start, &cell_data.values);
+    output.color = getTuple4F32(cell_id, mesh.cell_color.start, &cell_data.values);
   }
 
   ///------------------------///
@@ -173,7 +179,7 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
   ///------------------------///
   if mesh.cell_normal.num_tuples > 0u {
     // pull normal of this vertex from cell normals
-    let normal_mc = getTuple3F32(output.cell_id, mesh.cell_normal.start, &cell_data.values);
+    let normal_mc = getTuple3F32(cell_id, mesh.cell_normal.start, &cell_data.values);
     output.normal_vc = scene_transform.normal * actor.transform.normal * normal_mc;
   } else if mesh.point_tangent.num_tuples > 0u {
     // pull tangent of this vertex from point tangents
@@ -194,7 +200,7 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
 struct FragmentOutput {
   @builtin(frag_depth) frag_depth: f32,
   @location(0) color: vec4<f32>,
-  @location(1) cell_id: u32
+  @location(1) ids: vec4<u32>, // cell_id, prop_id, composite_id, process_id
 }
 
 //-------------------------------------------------------------------
@@ -207,6 +213,11 @@ fn fragmentMain(vertex: VertexOutput) -> FragmentOutput {
 
   var opacity: f32;
 
+  output.ids.x = vertex.cell_id + 1;
+  output.ids.y = vertex.prop_id + 1;
+  output.ids.z = vertex.composite_id + 1;
+  output.ids.w = vertex.process_id + 1;
+
   ///------------------------///
   // Colors are acquired either from a global per-actor color, or from per-vertex colors, or from cell colors.
   ///------------------------///
@@ -217,10 +228,10 @@ fn fragmentMain(vertex: VertexOutput) -> FragmentOutput {
     ambient_color = actor.color_options.vertex_color;
     diffuse_color = actor.color_options.vertex_color;
     opacity = actor.color_options.opacity;
-  } else if (mesh.override_colors.apply_override_colors == 1u) {
-    ambient_color = mesh.override_colors.ambient_color.rgb;
-    diffuse_color = mesh.override_colors.diffuse_color.rgb;
-    opacity = mesh.override_colors.opacity;
+  } else if (mesh.apply_override_colors == 1u) {
+    ambient_color = mesh.ambient_color.rgb;
+    diffuse_color = mesh.diffuse_color.rgb;
+    opacity = mesh.opacity;
   } else if (has_mapped_colors) {
     ambient_color = vertex.color.rgb;
     diffuse_color = vertex.color.rgb;
@@ -311,6 +322,5 @@ fn fragmentMain(vertex: VertexOutput) -> FragmentOutput {
   }
   // pre-multiply colors
   output.color = vec4(output.color.rgb * opacity, opacity);
-  output.cell_id = vertex.cell_id;
   return output;
 }
diff --git a/Rendering/WebGPU/wgsl/SurfaceMeshShader.wgsl b/Rendering/WebGPU/wgsl/SurfaceMeshShader.wgsl
index 2ec283b0b11496fdcb68c19e00ad656659427548..7a5db6c50a91b7fafa45f685576bdb74969d4c90 100644
--- a/Rendering/WebGPU/wgsl/SurfaceMeshShader.wgsl
+++ b/Rendering/WebGPU/wgsl/SurfaceMeshShader.wgsl
@@ -34,14 +34,6 @@ struct MeshAttributeArrayDescriptor {
   num_components: u32
 }
 
-//-------------------------------------------------------------------
-struct OverrideColorDescriptor {
-  apply_override_colors: u32,
-  opacity: f32,
-  ambient_color: vec3<f32>,
-  diffuse_color: vec3<f32>
-}
-
 //-------------------------------------------------------------------
 struct MeshDescriptor {
   position: MeshAttributeArrayDescriptor,
@@ -51,7 +43,12 @@ struct MeshDescriptor {
   point_uv: MeshAttributeArrayDescriptor,
   cell_color: MeshAttributeArrayDescriptor,
   cell_normal: MeshAttributeArrayDescriptor,
-  override_colors: OverrideColorDescriptor
+  apply_override_colors: u32,
+  opacity: f32,
+  composite_id: u32,
+  ambient_color: vec3<f32>,
+  process_id: u32,
+  diffuse_color: vec3<f32>,
 }
 
 //-------------------------------------------------------------------
@@ -100,8 +97,11 @@ struct VertexOutput {
   @location(2) normal_vc: vec3<f32>,
   @location(3) tangent_vc: vec3<f32>,
   @location(4) edge_dists: vec3<f32>,
-  @location(5) @interpolate(flat) cell_id: u32,
-  @location(6) @interpolate(flat) hide_edge: f32,
+  @location(5) @interpolate(flat) hide_edge: f32,
+  @location(6) @interpolate(flat) cell_id: u32,
+  @location(7) @interpolate(flat) prop_id: u32,
+  @location(8) @interpolate(flat) composite_id: u32,
+  @location(9) @interpolate(flat) process_id: u32,
 }
 
 //-------------------------------------------------------------------
@@ -113,12 +113,18 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
   ///------------------------///
   let pull_vertex_id: u32 = vertex.vertex_id;
   // get CellID from vertex ID -> VTK cell map.
-  output.cell_id = topology[pull_vertex_id].cell_id;
+  let cell_id = topology[pull_vertex_id].cell_id;
   // pull the point id
   let point_id = topology[pull_vertex_id].point_id;
   // pull the position for this vertex.
   let vertex_mc = vec4<f32>(getTuple3F32(point_id, mesh.position.start, &point_data.values), 1.0);
 
+  // Write indices
+  output.cell_id = cell_id;
+  output.prop_id = actor.id;
+  output.composite_id = mesh.composite_id;
+  output.process_id = 0u;
+
   ///------------------------///
   // NDC transforms
   ///------------------------///
@@ -133,7 +139,7 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
     output.color = getTuple4F32(point_id, mesh.point_color.start, &point_data.values);
   } else if mesh.cell_color.num_tuples > 0u {
     // Flat shading
-    output.color = getTuple4F32(output.cell_id, mesh.cell_color.start, &cell_data.values);
+    output.color = getTuple4F32(cell_id, mesh.cell_color.start, &cell_data.values);
   }
 
   ///------------------------///
@@ -188,7 +194,7 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
   ///------------------------///
   if mesh.cell_normal.num_tuples > 0u {
     // pull normal of this vertex from cell normals
-    let normal_mc = getTuple3F32(output.cell_id, mesh.cell_normal.start, &cell_data.values);
+    let normal_mc = getTuple3F32(cell_id, mesh.cell_normal.start, &cell_data.values);
     output.normal_vc = scene_transform.normal * actor.transform.normal * normal_mc;
   } else if mesh.point_tangent.num_tuples > 0u {
     // pull tangent of this vertex from point tangents
@@ -216,7 +222,7 @@ fn vertexMain(vertex: VertexInput) -> VertexOutput {
 //-------------------------------------------------------------------
 struct FragmentOutput {
   @location(0) color: vec4<f32>,
-  @location(1) cell_id: u32
+  @location(1) ids: vec4<u32>, // cell_id, prop_id, composite_id, process_id
 }
 
 //-------------------------------------------------------------------
@@ -232,14 +238,19 @@ fn fragmentMain(
 
   var opacity: f32;
 
+  output.ids.x = vertex.cell_id + 1;
+  output.ids.y = vertex.prop_id + 1;
+  output.ids.z = vertex.composite_id + 1;
+  output.ids.w = vertex.process_id + 1;
+
   ///------------------------///
   // Colors are acquired either from a global per-actor color, or from per-vertex colors, or from cell colors.
   ///------------------------///
   let has_mapped_colors: bool = mesh.point_color.num_tuples > 0u || mesh.cell_color.num_tuples > 0u;
-  if (mesh.override_colors.apply_override_colors == 1u) {
-    ambient_color = mesh.override_colors.ambient_color.rgb;
-    diffuse_color = mesh.override_colors.diffuse_color.rgb;
-    opacity = mesh.override_colors.opacity;
+  if (mesh.apply_override_colors == 1u) {
+    ambient_color = mesh.ambient_color.rgb;
+    diffuse_color = mesh.diffuse_color.rgb;
+    opacity = mesh.opacity;
   } else if (has_mapped_colors) {
     ambient_color = vertex.color.rgb;
     diffuse_color = vertex.color.rgb;
@@ -333,6 +344,5 @@ fn fragmentMain(
   }
   // pre-multiply colors
   output.color = vec4(output.color.rgb * opacity, opacity);
-  output.cell_id = vertex.cell_id;
   return output;
 }