feat(canvas): Add Phase 3+4 - Bidirectional sync, templates, and visual polish

Phase 3 - Bidirectional Sync:
- Add loadFromIntent and loadFromConfig to canvas store
- Create useIntentParser hook for parsing Claude messages
- Create ConfigImporter component (file upload, paste JSON, load study)
- Add import/clear buttons to CanvasView header

Phase 4 - Templates & Polish:
- Create template library with 5 presets:
  - Mass Minimization (single-objective)
  - Multi-Objective Pareto (NSGA-II)
  - Turbo Mode (with MLP surrogate)
  - Mirror Zernike (optical optimization)
  - Frequency Optimization (modal)
- Create TemplateSelector component with category filters
- Enhanced BaseNode with animations, glow effects, status indicators
- Add colorBg to all node types for visual distinction
- Add notification toast system
- Update all exports

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-14 20:30:28 -05:00
parent 1ae35382da
commit 5bd142780f
18 changed files with 1389 additions and 35 deletions

View File

@@ -0,0 +1,5 @@
// Canvas Library Exports
export * from './schema';
export * from './intent';
export * from './validation';
export * from './templates';

View File

@@ -0,0 +1,278 @@
/**
* Canvas Templates - Pre-built optimization workflow templates
*
* Each template provides a complete starting point for common optimization scenarios.
*/
import { OptimizationIntent } from './intent';
export interface CanvasTemplate {
id: string;
name: string;
description: string;
category: 'structural' | 'optical' | 'general';
icon: string;
intent: OptimizationIntent;
}
/**
* Template 1: Mass Minimization
* Single-objective optimization to minimize structural mass while maintaining stiffness
*/
const massMinimizationTemplate: CanvasTemplate = {
id: 'mass_minimization',
name: 'Mass Minimization',
description: 'Minimize structural mass while maintaining stiffness constraints. Ideal for brackets, housings, and weight-critical components.',
category: 'structural',
icon: '⚖️',
intent: {
version: '1.0',
source: 'canvas',
timestamp: new Date().toISOString(),
model: {
path: undefined,
type: 'prt',
},
solver: {
type: 'SOL101',
},
design_variables: [
{ name: 'wall_thickness', min: 1.0, max: 10.0, unit: 'mm' },
{ name: 'rib_height', min: 5.0, max: 25.0, unit: 'mm' },
{ name: 'fillet_radius', min: 1.0, max: 5.0, unit: 'mm' },
],
extractors: [
{ id: 'E4', name: 'BDF Mass', config: {} },
{ id: 'E1', name: 'Max Displacement', config: { node_set: 'ALL' } },
],
objectives: [
{ name: 'mass', direction: 'minimize', weight: 1.0, extractor: 'E4' },
],
constraints: [
{ name: 'max_displacement', operator: '<=', value: 0.5, extractor: 'E1' },
],
optimization: {
method: 'TPE',
max_trials: 100,
},
},
};
/**
* Template 2: Multi-Objective Pareto
* Trade-off between mass and stiffness using NSGA-II
*/
const multiObjectiveTemplate: CanvasTemplate = {
id: 'multi_objective',
name: 'Multi-Objective Pareto',
description: 'Explore trade-offs between competing objectives. Generates a Pareto front for informed decision-making.',
category: 'structural',
icon: '📊',
intent: {
version: '1.0',
source: 'canvas',
timestamp: new Date().toISOString(),
model: {
path: undefined,
type: 'prt',
},
solver: {
type: 'SOL101',
},
design_variables: [
{ name: 'thickness', min: 2.0, max: 15.0, unit: 'mm' },
{ name: 'width', min: 10.0, max: 50.0, unit: 'mm' },
{ name: 'height', min: 20.0, max: 80.0, unit: 'mm' },
],
extractors: [
{ id: 'E4', name: 'BDF Mass', config: {} },
{ id: 'E1', name: 'Max Displacement', config: { node_set: 'ALL' } },
{ id: 'E3', name: 'Max Stress', config: { element_set: 'ALL' } },
],
objectives: [
{ name: 'mass', direction: 'minimize', weight: 1.0, extractor: 'E4' },
{ name: 'displacement', direction: 'minimize', weight: 1.0, extractor: 'E1' },
],
constraints: [
{ name: 'max_stress', operator: '<=', value: 250.0, extractor: 'E3' },
],
optimization: {
method: 'NSGA-II',
max_trials: 200,
},
},
};
/**
* Template 3: Turbo Mode with Surrogate
* High-efficiency optimization using neural network surrogates
*/
const turboModeTemplate: CanvasTemplate = {
id: 'turbo_mode',
name: 'Turbo Mode',
description: 'Accelerated optimization using neural network surrogates. Run thousands of virtual trials with periodic FEA validation.',
category: 'general',
icon: '🚀',
intent: {
version: '1.0',
source: 'canvas',
timestamp: new Date().toISOString(),
model: {
path: undefined,
type: 'prt',
},
solver: {
type: 'SOL101',
},
design_variables: [
{ name: 'param_1', min: 0.0, max: 100.0 },
{ name: 'param_2', min: 0.0, max: 100.0 },
{ name: 'param_3', min: 0.0, max: 100.0 },
{ name: 'param_4', min: 0.0, max: 100.0 },
],
extractors: [
{ id: 'E1', name: 'Objective Extractor', config: {} },
],
objectives: [
{ name: 'objective', direction: 'minimize', weight: 1.0, extractor: 'E1' },
],
constraints: [],
optimization: {
method: 'TPE',
max_trials: 50,
},
surrogate: {
enabled: true,
type: 'MLP',
min_trials: 20,
},
},
};
/**
* Template 4: Mirror Zernike Optimization
* Optical surface optimization using Zernike polynomial decomposition
*/
const mirrorZernikeTemplate: CanvasTemplate = {
id: 'mirror_zernike',
name: 'Mirror Zernike',
description: 'Optimize optical mirror surface quality using Zernike wavefront error metrics. Specialized for precision optics.',
category: 'optical',
icon: '🔭',
intent: {
version: '1.0',
source: 'canvas',
timestamp: new Date().toISOString(),
model: {
path: undefined,
type: 'prt',
},
solver: {
type: 'SOL101',
},
design_variables: [
{ name: 'rib_thickness', min: 5.0, max: 30.0, unit: 'mm' },
{ name: 'back_thickness', min: 10.0, max: 50.0, unit: 'mm' },
{ name: 'cell_count', min: 6, max: 24 },
{ name: 'lightweighting_ratio', min: 0.3, max: 0.8 },
],
extractors: [
{ id: 'E8', name: 'Zernike WFE', config: { terms: [4, 5, 6, 7, 8, 9, 10, 11], method: 'op2' } },
{ id: 'E4', name: 'BDF Mass', config: {} },
],
objectives: [
{ name: 'wfe_rms', direction: 'minimize', weight: 0.7, extractor: 'E8' },
{ name: 'mass', direction: 'minimize', weight: 0.3, extractor: 'E4' },
],
constraints: [
{ name: 'max_mass', operator: '<=', value: 150.0, extractor: 'E4' },
],
optimization: {
method: 'TPE',
max_trials: 150,
},
surrogate: {
enabled: true,
type: 'GNN',
min_trials: 30,
},
},
};
/**
* Template 5: Frequency Optimization
* Maximize natural frequencies for dynamic performance
*/
const frequencyOptimizationTemplate: CanvasTemplate = {
id: 'frequency_optimization',
name: 'Frequency Optimization',
description: 'Maximize natural frequencies to avoid resonance. Essential for rotating machinery and vibration-sensitive equipment.',
category: 'structural',
icon: '📈',
intent: {
version: '1.0',
source: 'canvas',
timestamp: new Date().toISOString(),
model: {
path: undefined,
type: 'prt',
},
solver: {
type: 'SOL103',
},
design_variables: [
{ name: 'base_thickness', min: 5.0, max: 25.0, unit: 'mm' },
{ name: 'stiffener_height', min: 10.0, max: 40.0, unit: 'mm' },
{ name: 'stiffener_spacing', min: 20.0, max: 80.0, unit: 'mm' },
],
extractors: [
{ id: 'E2', name: 'First Frequency', config: { mode: 1 } },
{ id: 'E4', name: 'BDF Mass', config: {} },
],
objectives: [
{ name: 'frequency_1', direction: 'maximize', weight: 1.0, extractor: 'E2' },
],
constraints: [
{ name: 'max_mass', operator: '<=', value: 50.0, extractor: 'E4' },
],
optimization: {
method: 'TPE',
max_trials: 100,
},
},
};
/**
* All available templates
*/
export const templates: CanvasTemplate[] = [
massMinimizationTemplate,
multiObjectiveTemplate,
turboModeTemplate,
mirrorZernikeTemplate,
frequencyOptimizationTemplate,
];
/**
* Get template by ID
*/
export function getTemplate(id: string): CanvasTemplate | undefined {
return templates.find(t => t.id === id);
}
/**
* Get templates by category
*/
export function getTemplatesByCategory(category: CanvasTemplate['category']): CanvasTemplate[] {
return templates.filter(t => t.category === category);
}
/**
* Create a fresh copy of a template's intent with updated timestamp
*/
export function instantiateTemplate(template: CanvasTemplate): OptimizationIntent {
return {
...template.intent,
timestamp: new Date().toISOString(),
};
}