export interface FilterParam {
  key: string;
  type: 'int' | 'float' | 'bool' | 'select';
  default: number | boolean | string;
  min?: number;
  max?: number;
  step?: number;
  label: string;
  options?: string[];
}

export interface FilterDef {
  id: string;
  name: string;
  params: FilterParam[];
  implemented: boolean;
}

export interface FilterCategory {
  name: string;
  filters: FilterDef[];
}

export const FILTER_CATEGORIES: FilterCategory[] = [
  {
    name: 'Smoothing',
    filters: [
      {
        id: 'laplacian_smooth',
        name: 'Laplacian Smooth',
        implemented: true,
        params: [
          { key: 'iterations', type: 'int', default: 1, min: 1, max: 100, label: 'Iterations' },
        ],
      },
      {
        id: 'taubin_smooth',
        name: 'Taubin Smooth',
        implemented: true,
        params: [
          { key: 'lambda', type: 'float', default: 0.5, min: 0, max: 1, step: 0.01, label: 'Lambda' },
          { key: 'mu', type: 'float', default: -0.53, min: -1, max: 0, step: 0.01, label: 'Mu' },
          { key: 'iterations', type: 'int', default: 10, min: 1, max: 100, label: 'Iterations' },
        ],
      },
    ],
  },
  {
    name: 'Remeshing',
    filters: [
      {
        id: 'simplification',
        name: 'Quadric Simplification',
        implemented: true,
        params: [
          { key: 'targetFaces', type: 'int', default: 0, min: 0, label: 'Target face count (0 = half)' },
        ],
      },
      {
        id: 'subdivision',
        name: 'Midpoint Subdivision',
        implemented: true,
        params: [
          { key: 'iterations', type: 'int', default: 1, min: 1, max: 5, label: 'Iterations' },
        ],
      },
      {
        id: 'loop_subdivision',
        name: 'Loop Subdivision',
        implemented: true,
        params: [
          { key: 'iterations', type: 'int', default: 1, min: 1, max: 4, label: 'Iterations' },
        ],
      },
      {
        id: 'butterfly_subdivision',
        name: 'Butterfly Subdivision',
        implemented: true,
        params: [
          { key: 'iterations', type: 'int', default: 1, min: 1, max: 4, label: 'Iterations' },
        ],
      },
      {
        id: 'isotropic_remeshing',
        name: 'Explicit Isotropic Remeshing',
        implemented: true,
        params: [
          { key: 'targetEdgeLength', type: 'float', default: 0, min: 0, step: 0.01, label: 'Target edge length (0=auto)' },
          { key: 'iterations', type: 'int', default: 5, min: 1, max: 20, label: 'Iterations' },
        ],
      },
    ],
  },
  {
    name: 'Cleaning',
    filters: [
      { id: 'remove_duplicate_vertices', name: 'Remove Duplicate Vertices', implemented: false, params: [] },
      { id: 'remove_unreferenced_vertices', name: 'Remove Unreferenced Vertices', implemented: false, params: [] },
      { id: 'compute_normals', name: 'Recompute Normals', implemented: true, params: [] },
    ],
  },
  {
    name: 'Transform',
    filters: [
      {
        id: 'scale',
        name: 'Scale',
        implemented: true,
        params: [
          { key: 'x', type: 'float', default: 1, step: 0.1, label: 'X' },
          { key: 'y', type: 'float', default: 1, step: 0.1, label: 'Y' },
          { key: 'z', type: 'float', default: 1, step: 0.1, label: 'Z' },
          { key: 'uniform', type: 'bool', default: true, label: 'Uniform' },
        ],
      },
      {
        id: 'translate',
        name: 'Translate',
        implemented: true,
        params: [
          { key: 'x', type: 'float', default: 0, step: 0.1, label: 'X' },
          { key: 'y', type: 'float', default: 0, step: 0.1, label: 'Y' },
          { key: 'z', type: 'float', default: 0, step: 0.1, label: 'Z' },
        ],
      },
      {
        id: 'rotate',
        name: 'Rotate',
        implemented: true,
        params: [
          { key: 'axis', type: 'select', options: ['X', 'Y', 'Z'], default: 'X', label: 'Axis' },
          { key: 'angle', type: 'float', default: 0, min: -360, max: 360, step: 1, label: 'Angle (deg)' },
        ],
      },
    ],
  },
  {
    name: 'Normals',
    filters: [
      { id: 'invert_faces', name: 'Invert Faces Orientation', implemented: true, params: [] },
    ],
  },
  {
    name: 'Color',
    filters: [
      {
        id: 'colorize_gaussian_curvature', name: 'Colorize Gaussian Curvature', implemented: true,
        params: [
          { key: 'colormap', type: 'select', options: ['rainbow', 'jet', 'viridis', 'inferno', 'coolwarm', 'grayscale', 'redblue'], default: 'coolwarm', label: 'Color Map' },
          { key: 'autoClamp', type: 'bool', default: true, label: 'Auto range' },
          { key: 'clampMin', type: 'float', default: 0, label: 'Min value' },
          { key: 'clampMax', type: 'float', default: 1, label: 'Max value' },
        ],
      },
      {
        id: 'colorize_mean_curvature', name: 'Colorize Mean Curvature', implemented: true,
        params: [
          { key: 'colormap', type: 'select', options: ['rainbow', 'jet', 'viridis', 'inferno', 'coolwarm', 'grayscale', 'redblue'], default: 'coolwarm', label: 'Color Map' },
          { key: 'autoClamp', type: 'bool', default: true, label: 'Auto range' },
          { key: 'clampMin', type: 'float', default: 0, label: 'Min value' },
          { key: 'clampMax', type: 'float', default: 1, label: 'Max value' },
        ],
      },
      {
        id: 'color_from_quality', name: 'Quality to Color', implemented: true,
        params: [
          { key: 'colormap', type: 'select', options: ['rainbow', 'jet', 'viridis', 'inferno', 'coolwarm', 'grayscale', 'redblue'], default: 'viridis', label: 'Color Map' },
          { key: 'clampMin', type: 'float', default: 0, label: 'Min value (0=auto)' },
          { key: 'clampMax', type: 'float', default: 0, label: 'Max value (0=auto)' },
        ],
      },
    ],
  },
  {
    name: 'Repair',
    filters: [
      { id: 'fill_holes', name: 'Fill Holes', implemented: true, params: [
        { key: 'maxEdges', type: 'int', default: 0, min: 0, label: 'Max hole size (0=all)' },
      ]},
      { id: 'remove_small_components', name: 'Remove Small Components', implemented: true, params: [
        { key: 'minFaces', type: 'int', default: 10, min: 1, label: 'Min face count' },
      ]},
      { id: 'fix_non_manifold_edges', name: 'Fix Non-Manifold Edges', implemented: true, params: [] },
      { id: 'remove_degenerate_faces', name: 'Remove Degenerate Faces', implemented: true, params: [] },
      { id: 'remove_flipped_faces', name: 'Remove Flipped Faces', implemented: true, params: [
        { key: 'angleDeg', type: 'float', default: 160, min: 90, max: 180, step: 1, label: 'Angle threshold' },
      ]},
      { id: 'auto_repair', name: 'Auto-Repair All', implemented: true, params: [] },
    ],
  },
  {
    name: 'Texture',
    filters: [
      { id: 'parametrize_trivial', name: 'Trivial Per-Triangle UV', implemented: true, params: [
        { key: 'textureSize', type: 'int', default: 1024, min: 256, max: 4096, label: 'Texture size' },
      ]},
      { id: 'uv_checker_pattern', name: 'Apply Checker Pattern', implemented: true, params: [
        { key: 'size', type: 'int', default: 8, min: 2, max: 64, label: 'Checker grid size' },
      ]},
    ],
  },
  {
    name: 'Alignment',
    filters: [
      { id: 'freeze_transform', name: 'Freeze Transform Matrix', implemented: true, params: [] },
      { id: 'reset_transform', name: 'Reset Transform Matrix', implemented: true, params: [] },
      { id: 'align_icp', name: 'ICP Alignment', implemented: true, params: [
        { key: 'maxIterations', type: 'int', default: 50, min: 1, max: 500, label: 'Max iterations' },
        { key: 'samplingRatio', type: 'float', default: 0.1, min: 0.01, max: 1.0, step: 0.01, label: 'Sampling ratio' },
      ]},
    ],
  },
  {
    name: 'Reconstruction',
    filters: [
      { id: 'estimate_normals', name: 'Estimate Normals', implemented: true, params: [
        { key: 'kNeighbors', type: 'int', default: 10, min: 5, max: 50, label: 'K neighbors' },
      ]},
      { id: 'marching_cubes', name: 'Marching Cubes', implemented: true, params: [
        { key: 'resolution', type: 'int', default: 64, min: 16, max: 256, label: 'Grid resolution' },
      ]},
    ],
  },
  {
    name: 'Sampling',
    filters: [
      { id: 'montecarlo_sampling', name: 'Montecarlo Sampling', implemented: true, params: [
        { key: 'sampleNum', type: 'int', default: 1000, min: 10, max: 1000000, label: 'Number of samples' },
      ]},
      { id: 'poisson_disk_sampling', name: 'Poisson-disk Sampling', implemented: true, params: [
        { key: 'sampleNum', type: 'int', default: 1000, min: 10, max: 1000000, label: 'Number of samples' },
        { key: 'radius', type: 'float', default: 0, min: 0, step: 0.01, label: 'Min radius (0=auto)' },
      ]},
      { id: 'hausdorff_distance', name: 'Hausdorff Distance', implemented: true, params: [
        { key: 'targetLayer', type: 'int', default: 0, min: 0, label: 'Target layer handle' },
        { key: 'sampleNum', type: 'int', default: 10000, min: 100, max: 100000, label: 'Sample count' },
      ]},
    ],
  },
  {
    name: 'Curvature',
    filters: [
      {
        id: 'colorize_principal_k1', name: 'Colorize Principal Curvature (k1)', implemented: true,
        params: [
          { key: 'colormap', type: 'select', options: ['rainbow', 'jet', 'viridis', 'inferno', 'coolwarm', 'grayscale', 'redblue'], default: 'coolwarm', label: 'Color Map' },
          { key: 'autoClamp', type: 'bool', default: true, label: 'Auto range' },
          { key: 'clampMin', type: 'float', default: 0, label: 'Min value' },
          { key: 'clampMax', type: 'float', default: 1, label: 'Max value' },
        ],
      },
      {
        id: 'colorize_principal_k2', name: 'Colorize Principal Curvature (k2)', implemented: true,
        params: [
          { key: 'colormap', type: 'select', options: ['rainbow', 'jet', 'viridis', 'inferno', 'coolwarm', 'grayscale', 'redblue'], default: 'coolwarm', label: 'Color Map' },
          { key: 'autoClamp', type: 'bool', default: true, label: 'Auto range' },
          { key: 'clampMin', type: 'float', default: 0, label: 'Min value' },
          { key: 'clampMax', type: 'float', default: 1, label: 'Max value' },
        ],
      },
      {
        id: 'colorize_shape_index', name: 'Colorize Shape Index', implemented: true,
        params: [
          { key: 'colormap', type: 'select', options: ['rainbow', 'jet', 'viridis', 'inferno', 'coolwarm', 'grayscale', 'redblue'], default: 'coolwarm', label: 'Color Map' },
          { key: 'autoClamp', type: 'bool', default: true, label: 'Auto range' },
          { key: 'clampMin', type: 'float', default: 0, label: 'Min value' },
          { key: 'clampMax', type: 'float', default: 1, label: 'Max value' },
        ],
      },
    ],
  },
  {
    name: 'Boolean',
    filters: [
      { id: 'mesh_boolean', name: 'Mesh Boolean (CSG)', implemented: true, params: [
        { key: 'targetLayer', type: 'int', default: 0, min: 0, label: 'Target layer handle' },
        { key: 'operation', type: 'select', options: ['Union', 'Intersection', 'Difference'], default: 'Union', label: 'Operation' },
        { key: 'resolution', type: 'int', default: 64, min: 32, max: 256, label: 'Grid resolution' },
      ]},
    ],
  },
  {
    name: 'Mesh Creation',
    filters: [
      { id: 'create_box', name: 'Create Box', implemented: true, params: [
        { key: 'sizeX', type: 'float', default: 1, min: 0.01, step: 0.1, label: 'Size X' },
        { key: 'sizeY', type: 'float', default: 1, min: 0.01, step: 0.1, label: 'Size Y' },
        { key: 'sizeZ', type: 'float', default: 1, min: 0.01, step: 0.1, label: 'Size Z' },
      ]},
      { id: 'create_sphere', name: 'Create Sphere', implemented: true, params: [
        { key: 'radius', type: 'float', default: 1, min: 0.01, step: 0.1, label: 'Radius' },
        { key: 'subdivisions', type: 'int', default: 3, min: 0, max: 6, label: 'Subdivisions' },
      ]},
      { id: 'create_torus', name: 'Create Torus', implemented: true, params: [
        { key: 'majorRadius', type: 'float', default: 2, min: 0.1, step: 0.1, label: 'Major radius' },
        { key: 'minorRadius', type: 'float', default: 0.5, min: 0.01, step: 0.1, label: 'Minor radius' },
        { key: 'segments', type: 'int', default: 32, min: 3, max: 128, label: 'Segments' },
        { key: 'sides', type: 'int', default: 16, min: 3, max: 64, label: 'Sides' },
      ]},
      { id: 'create_cone', name: 'Create Cone', implemented: true, params: [
        { key: 'radius', type: 'float', default: 1, min: 0.01, step: 0.1, label: 'Radius' },
        { key: 'height', type: 'float', default: 2, min: 0.01, step: 0.1, label: 'Height' },
        { key: 'segments', type: 'int', default: 32, min: 3, max: 128, label: 'Segments' },
      ]},
      { id: 'create_plane', name: 'Create Plane', implemented: true, params: [
        { key: 'width', type: 'float', default: 2, min: 0.01, step: 0.1, label: 'Width' },
        { key: 'height', type: 'float', default: 2, min: 0.01, step: 0.1, label: 'Height' },
        { key: 'segW', type: 'int', default: 10, min: 1, max: 100, label: 'Width segments' },
        { key: 'segH', type: 'int', default: 10, min: 1, max: 100, label: 'Height segments' },
      ]},
    ],
  },
  {
    name: 'Layer',
    filters: [
      { id: 'split_connected_components', name: 'Split in Connected Components', implemented: true, params: [] },
      { id: 'flatten_visible_layers', name: 'Flatten Visible Layers', implemented: true, params: [] },
    ],
  },
  {
    name: 'Selection',
    filters: [
      { id: 'select_by_face_quality', name: 'Select by Face Quality', implemented: true, params: [
        { key: 'minQ', type: 'float', default: 0, label: 'Min quality' },
        { key: 'maxQ', type: 'float', default: 1, label: 'Max quality' },
      ]},
      { id: 'erode_selection', name: 'Erode Selection', implemented: true, params: [] },
      { id: 'dilate_selection', name: 'Dilate Selection', implemented: true, params: [] },
    ],
  },
  // Sprint N categories
  {
    name: 'Smoothing Extended',
    filters: [
      { id: 'hc_laplacian_smooth', name: 'HC Laplacian Smooth', implemented: true, params: [
        { key: 'iterations', type: 'int', default: 3, min: 1, max: 50, label: 'Iterations' },
      ]},
      { id: 'scale_dependent_smooth', name: 'Scale Dependent Smooth', implemented: true, params: [
        { key: 'iterations', type: 'int', default: 3, min: 1, max: 50, label: 'Iterations' },
        { key: 'delta', type: 'float', default: 0.01, min: 0, step: 0.001, label: 'Delta' },
      ]},
      { id: 'two_step_smooth', name: 'Two Step Smooth', implemented: true, params: [
        { key: 'normalIterations', type: 'int', default: 3, min: 1, max: 50, label: 'Normal iterations' },
        { key: 'vertexIterations', type: 'int', default: 3, min: 1, max: 50, label: 'Vertex iterations' },
      ]},
      { id: 'depth_smooth', name: 'Depth Smooth', implemented: true, params: [
        { key: 'iterations', type: 'int', default: 3, min: 1, max: 50, label: 'Iterations' },
      ]},
      { id: 'unsharp_mask_geometry', name: 'UnSharp Mask Geometry', implemented: true, params: [
        { key: 'weight', type: 'float', default: 0.3, min: 0, max: 5, step: 0.1, label: 'Weight' },
        { key: 'iterations', type: 'int', default: 1, min: 1, max: 10, label: 'Smooth iterations' },
      ]},
      { id: 'unsharp_mask_normals', name: 'UnSharp Mask Normals', implemented: true, params: [
        { key: 'weight', type: 'float', default: 0.3, min: 0, max: 5, step: 0.1, label: 'Weight' },
        { key: 'iterations', type: 'int', default: 1, min: 1, max: 10, label: 'Smooth iterations' },
      ]},
      { id: 'unsharp_mask_quality', name: 'UnSharp Mask Quality', implemented: true, params: [
        { key: 'weight', type: 'float', default: 0.3, min: 0, max: 5, step: 0.1, label: 'Weight' },
        { key: 'iterations', type: 'int', default: 1, min: 1, max: 10, label: 'Smooth iterations' },
      ]},
      { id: 'smooth_vertex_quality', name: 'Smooth Vertex Quality', implemented: true, params: [
        { key: 'iterations', type: 'int', default: 3, min: 1, max: 50, label: 'Iterations' },
      ]},
      { id: 'smooth_face_normals', name: 'Smooth Face Normals', implemented: true, params: [
        { key: 'iterations', type: 'int', default: 3, min: 1, max: 50, label: 'Iterations' },
      ]},
    ],
  },
  {
    name: 'Color Extended',
    filters: [
      { id: 'vertex_color_fill', name: 'Vertex Color Fill', implemented: true, params: [
        { key: 'r', type: 'int', default: 200, min: 0, max: 255, label: 'Red' },
        { key: 'g', type: 'int', default: 200, min: 0, max: 255, label: 'Green' },
        { key: 'b', type: 'int', default: 200, min: 0, max: 255, label: 'Blue' },
      ]},
      { id: 'vertex_color_brightness_contrast_gamma', name: 'Brightness Contrast Gamma', implemented: true, params: [
        { key: 'brightness', type: 'float', default: 0, min: -1, max: 1, step: 0.01, label: 'Brightness' },
        { key: 'contrast', type: 'float', default: 1, min: 0, max: 3, step: 0.01, label: 'Contrast' },
        { key: 'gamma', type: 'float', default: 1, min: 0.1, max: 5, step: 0.1, label: 'Gamma' },
      ]},
      { id: 'vertex_color_levels', name: 'Vertex Color Levels', implemented: true, params: [
        { key: 'inMin', type: 'float', default: 0, min: 0, max: 1, step: 0.01, label: 'Input min' },
        { key: 'inMax', type: 'float', default: 1, min: 0, max: 1, step: 0.01, label: 'Input max' },
        { key: 'gamma', type: 'float', default: 1, min: 0.1, max: 5, step: 0.1, label: 'Gamma' },
        { key: 'outMin', type: 'float', default: 0, min: 0, max: 1, step: 0.01, label: 'Output min' },
        { key: 'outMax', type: 'float', default: 1, min: 0, max: 1, step: 0.01, label: 'Output max' },
      ]},
      { id: 'vertex_color_white_balance', name: 'White Balance', implemented: true, params: [
        { key: 'refR', type: 'int', default: 128, min: 1, max: 255, label: 'Reference R' },
        { key: 'refG', type: 'int', default: 128, min: 1, max: 255, label: 'Reference G' },
        { key: 'refB', type: 'int', default: 128, min: 1, max: 255, label: 'Reference B' },
      ]},
      { id: 'color_noise', name: 'Color Noise', implemented: true, params: [
        { key: 'amount', type: 'int', default: 10, min: 1, max: 128, label: 'Amount' },
      ]},
      { id: 'perlin_color', name: 'Perlin Color', implemented: true, params: [
        { key: 'frequency', type: 'float', default: 1, min: 0.01, max: 100, step: 0.1, label: 'Frequency' },
        { key: 'octaves', type: 'int', default: 4, min: 1, max: 8, label: 'Octaves' },
      ]},
      { id: 'smooth_vertex_colors', name: 'Smooth Vertex Colors', implemented: true, params: [
        { key: 'iterations', type: 'int', default: 1, min: 1, max: 50, label: 'Iterations' },
      ]},
      { id: 'smooth_face_colors', name: 'Smooth Face Colors', implemented: true, params: [
        { key: 'iterations', type: 'int', default: 1, min: 1, max: 50, label: 'Iterations' },
      ]},
      { id: 'voronoi_vertex_coloring', name: 'Voronoi Vertex Coloring', implemented: true, params: [
        { key: 'seedCount', type: 'int', default: 10, min: 2, max: 1000, label: 'Seed count' },
      ]},
      { id: 'ambient_occlusion', name: 'Ambient Occlusion', implemented: true, params: [
        { key: 'numRays', type: 'int', default: 32, min: 8, max: 256, label: 'Num rays' },
      ]},
    ],
  },
  {
    name: 'Remeshing Extended',
    filters: [
      { id: 'catmull_clark_subdivision', name: 'Catmull-Clark Subdivision', implemented: true, params: [
        { key: 'iterations', type: 'int', default: 1, min: 1, max: 4, label: 'Iterations' },
      ]},
      { id: 'clustering_decimation', name: 'Clustering Decimation', implemented: true, params: [
        { key: 'cellSize', type: 'float', default: 0.1, min: 0.001, step: 0.01, label: 'Cell size' },
      ]},
      { id: 'screened_poisson', name: 'Screened Poisson Reconstruction', implemented: true, params: [
        { key: 'depth', type: 'int', default: 6, min: 4, max: 8, label: 'Depth' },
      ]},
      { id: 'ball_pivoting', name: 'Ball Pivoting Surface Reconstruction', implemented: true, params: [
        { key: 'radius', type: 'float', default: 0, min: 0, step: 0.01, label: 'Radius (0=auto)' },
      ]},
      { id: 'merge_close_vertices', name: 'Merge Close Vertices', implemented: true, params: [
        { key: 'threshold', type: 'float', default: 0.001, min: 0, step: 0.0001, label: 'Distance threshold' },
      ]},
    ],
  },
  {
    name: 'Mesh Creation Extended',
    filters: [
      { id: 'create_annulus', name: 'Create Annulus', implemented: true, params: [
        { key: 'innerRadius', type: 'float', default: 0.5, min: 0.01, step: 0.1, label: 'Inner radius' },
        { key: 'outerRadius', type: 'float', default: 1, min: 0.01, step: 0.1, label: 'Outer radius' },
        { key: 'segments', type: 'int', default: 32, min: 3, max: 128, label: 'Segments' },
      ]},
      { id: 'create_sphere_cap', name: 'Create Sphere Cap', implemented: true, params: [
        { key: 'radius', type: 'float', default: 1, min: 0.01, step: 0.1, label: 'Radius' },
        { key: 'angle', type: 'float', default: 90, min: 1, max: 180, step: 1, label: 'Angle (degrees)' },
        { key: 'segments', type: 'int', default: 32, min: 3, max: 128, label: 'Segments' },
      ]},
      { id: 'create_points_on_sphere', name: 'Points on a Sphere', implemented: true, params: [
        { key: 'numPoints', type: 'int', default: 100, min: 4, max: 10000, label: 'Number of points' },
      ]},
    ],
  },
  {
    name: 'Sampling Extended',
    filters: [
      { id: 'clustered_vertex_sampling', name: 'Clustered Vertex Sampling', implemented: true, params: [
        { key: 'cellSize', type: 'float', default: 0.1, min: 0.001, step: 0.01, label: 'Cell size' },
      ]},
      { id: 'mesh_element_subsampling', name: 'Mesh Element Subsampling', implemented: true, params: [
        { key: 'stride', type: 'int', default: 2, min: 2, max: 100, label: 'Stride' },
      ]},
      { id: 'uniform_mesh_resampling', name: 'Uniform Mesh Resampling', implemented: true, params: [
        { key: 'cellSize', type: 'float', default: 0.1, min: 0.001, step: 0.01, label: 'Cell size' },
      ]},
      { id: 'point_cloud_simplification', name: 'Point Cloud Simplification', implemented: true, params: [
        { key: 'targetCount', type: 'int', default: 1000, min: 10, max: 1000000, label: 'Target count' },
      ]},
    ],
  },
  {
    name: 'Selection Extended',
    filters: [
      { id: 'select_by_color_range', name: 'Select by Color Range', implemented: true, params: [
        { key: 'r', type: 'int', default: 128, min: 0, max: 255, label: 'Red' },
        { key: 'g', type: 'int', default: 128, min: 0, max: 255, label: 'Green' },
        { key: 'b', type: 'int', default: 128, min: 0, max: 255, label: 'Blue' },
        { key: 'tolerance', type: 'int', default: 30, min: 0, max: 255, label: 'Tolerance' },
      ]},
      { id: 'select_by_dihedral_angle', name: 'Select by Dihedral Angle', implemented: true, params: [
        { key: 'minAngle', type: 'float', default: 0, min: 0, max: 180, step: 1, label: 'Min angle' },
        { key: 'maxAngle', type: 'float', default: 180, min: 0, max: 180, step: 1, label: 'Max angle' },
      ]},
      { id: 'select_ugly_faces', name: 'Select Ugly Faces', implemented: true, params: [
        { key: 'ratio', type: 'float', default: 10, min: 1, max: 100, step: 0.5, label: 'Aspect ratio threshold' },
      ]},
    ],
  },
];
