# Atomizer Canvas - Visual Workflow Builder **Last Updated**: January 17, 2026 **Version**: 3.1 (AtomizerSpec v2.0) **Status**: Production --- ## Overview The Atomizer Canvas is a visual, node-based workflow builder for designing optimization studies. It provides a drag-and-drop interface for configuring FEA optimizations that integrates with Claude to validate and execute workflows. **New in v3.1**: The Canvas now uses **AtomizerSpec v2.0** as the unified configuration format. All studies are defined by a single `atomizer_spec.json` file that serves as the single source of truth for Canvas, Backend, Claude, and the Optimization Engine. ### Key Features - **Visual Workflow Design**: Drag-and-drop nodes to build optimization pipelines - **Professional Lucide Icons**: Clean, consistent iconography throughout the interface - **AtomizerSpec v2.0**: Unified JSON spec format (`atomizer_spec.json`) for all configuration - **Auto-Load from Studies**: Import existing studies (supports both v2.0 specs and legacy configs) - **NX Model Introspection**: Automatically extract expressions from .prt/.sim/.fem files - **File Browser**: Browse and select model files with type filtering - **Expression Search**: Searchable dropdown for design variable configuration - **One-Click Add**: Add discovered expressions as design variables instantly - **Custom Extractors**: Define custom Python extraction functions directly in the spec - **Claude Integration**: "Process with Claude" button for AI-assisted study creation - **Real-time Sync**: WebSocket-based synchronization between clients - **Responsive Layout**: Full-screen canvas that adapts to window size ### What's New in V3.1 | Feature | Description | |---------|-------------| | **AtomizerSpec v2.0** | Unified configuration format replacing `optimization_config.json` | | **Spec REST API** | Full CRUD operations on spec via `/api/studies/{id}/spec` | | **Custom Extractors** | Define custom Python functions as extractors in the spec | | **WebSocket Sync** | Real-time spec synchronization between clients | | **Legacy Migration** | Automatic migration of old `optimization_config.json` files | ### What's New in V3.0 | Feature | Description | |---------|-------------| | **File Browser** | Browse studies directory for .sim/.prt/.fem/.afem files | | **Introspection Panel** | View discovered expressions, extractors, and dependencies | | **One-Click Add** | Add expressions as design variables with a single click | | **Claude Fixes** | Fixed SQL errors, WebSocket reconnection issues | | **Health Check** | `/api/health` endpoint for database monitoring | --- ## Architecture ### Frontend Stack | Component | Technology | Purpose | |-----------|------------|---------| | Flow Engine | React Flow | Node-based graph rendering | | State Management | Zustand | Canvas state (nodes, edges, selection) | | Icons | Lucide React | Professional icon library | | Styling | Tailwind CSS | Dark theme (Atomaster palette) | | Chat | WebSocket | Real-time Claude communication | ### Node Types (8) | Node | Icon | Description | Color | |------|------|-------------|-------| | **Model** | `Cube` | NX model file (.prt, .sim, .fem) | Blue | | **Solver** | `Cpu` | Nastran solution type (SOL101, SOL103, etc.) | Violet | | **Design Variable** | `SlidersHorizontal` | Parameter to optimize with bounds | Emerald | | **Extractor** | `FlaskConical` | Physics result extraction (E1-E10) | Cyan | | **Objective** | `Target` | Optimization goal (minimize/maximize) | Rose | | **Constraint** | `ShieldAlert` | Design constraint (upper/lower bounds) | Amber | | **Algorithm** | `BrainCircuit` | Optimization method (TPE, CMA-ES, NSGA-II) | Indigo | | **Surrogate** | `Rocket` | Neural acceleration (optional) | Pink | ### File Structure ``` atomizer-dashboard/frontend/src/ ├── components/canvas/ │ ├── AtomizerCanvas.tsx # Main canvas component │ ├── nodes/ │ │ ├── index.ts # Node type registry │ │ ├── BaseNode.tsx # Base node with handles │ │ ├── ModelNode.tsx # Model file node │ │ ├── SolverNode.tsx # Solver type node │ │ ├── DesignVarNode.tsx # Design variable node │ │ ├── ExtractorNode.tsx # Extractor node │ │ ├── ObjectiveNode.tsx # Objective node │ │ ├── ConstraintNode.tsx # Constraint node │ │ ├── AlgorithmNode.tsx # Algorithm node │ │ ├── SurrogateNode.tsx # Surrogate node │ │ └── CustomExtractorNode.tsx # Custom extractor node (V3.1) │ ├── panels/ │ │ ├── NodeConfigPanel.tsx # Node configuration sidebar │ │ ├── ValidationPanel.tsx # Validation toast display │ │ ├── ExecuteDialog.tsx # Execute confirmation modal │ │ ├── ChatPanel.tsx # Claude chat sidebar │ │ ├── ConfigImporter.tsx # Study import dialog │ │ ├── TemplateSelector.tsx # Workflow template chooser │ │ ├── FileBrowser.tsx # File picker modal (V3) │ │ ├── IntrospectionPanel.tsx # Model introspection results (V3) │ │ ├── ExpressionSelector.tsx # Expression search dropdown (V3) │ │ └── CustomExtractorPanel.tsx # Code editor for custom extractors (V3.1) │ └── palette/ │ └── NodePalette.tsx # Draggable node palette ├── hooks/ │ ├── useCanvasStore.ts # Zustand store for canvas state │ ├── useSpecStore.ts # Zustand store for AtomizerSpec (V3.1) │ ├── useSpecSync.ts # WebSocket spec sync (V3.1) │ └── useCanvasChat.ts # Claude chat integration ├── lib/ │ ├── canvas/ │ │ ├── schema.ts # TypeScript type definitions │ │ ├── intent.ts # Intent serialization (legacy) │ │ ├── validation.ts # Graph validation logic │ │ └── templates.ts # Workflow templates │ └── spec/ │ └── converter.ts # AtomizerSpec ↔ ReactFlow converter (V3.1) ├── types/ │ └── atomizer-spec.ts # AtomizerSpec TypeScript types (V3.1) └── pages/ └── CanvasView.tsx # Canvas page (/canvas route) ``` ### Backend File Structure (V3.1) ``` atomizer-dashboard/backend/api/ ├── services/ │ ├── spec_manager.py # SpecManager - load/save/validate specs │ ├── claude_agent.py # Claude API integration │ └── context_builder.py # Context assembly with spec awareness └── routes/ ├── spec.py # AtomizerSpec REST API endpoints └── optimization.py # Optimization endpoints optimization_engine/ ├── config/ │ ├── spec_models.py # Pydantic models for AtomizerSpec │ ├── spec_validator.py # Semantic validation │ └── migrator.py # Legacy config migration ├── extractors/ │ └── custom_extractor_loader.py # Runtime custom function loader └── schemas/ └── atomizer_spec_v2.json # JSON Schema definition ``` --- ## User Interface ### Layout ``` ┌───────────────────────────────────────────────────────────────────┐ │ Canvas Builder Templates Import│ ├──────────┬────────────────────────────────────────────┬───────────┤ │ │ │ │ │ Node │ Canvas Area │ Config │ │ Palette │ │ Panel │ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │ [Model] │ │Model├──────│Solver├──────│Algo │ │ Label: │ │ [Solver]│ └─────┘ └──┬──┘ └─────┘ │ [____] │ │ [DVar] │ │ │ │ │ [Extr] │ ┌─────┐ ┌──┴──┐ ┌─────┐ │ Type: │ │ [Obj] │ │ DVar├──────│Extr ├──────│ Obj │ │ [____] │ │ [Const] │ └─────┘ └─────┘ └─────┘ │ │ │ [Algo] │ │ │ │ [Surr] │ │ │ │ │ │ │ ├──────────┴────────────────────────────────────────────┴───────────┤ │ [Validate] [Process with Claude] │ └───────────────────────────────────────────────────────────────────┘ ``` ### Dark Theme (Atomaster Palette) | Element | Color | Tailwind Class | |---------|-------|----------------| | Background | `#050A12` | `bg-dark-900` | | Surface | `#0A1525` | `bg-dark-850` | | Card | `#0F1E32` | `bg-dark-800` | | Border | `#1A2F4A` | `border-dark-700` | | Muted Text | `#5A7A9A` | `text-dark-400` | | Primary | `#00D4E6` | `text-primary-400` | --- ## Core Workflows ### 1. Building a Workflow 1. **Drag nodes** from the left palette onto the canvas 2. **Connect nodes** by dragging from output handle to input handle 3. **Configure nodes** by clicking to open the config panel 4. **Validate** using the Validate button 5. **Process with Claude** to create the study ### 2. Importing from Existing Study 1. Click **Import** in the header 2. Select the **Load Study** tab 3. **Search** for your study by name 4. **Select** a study with an optimization_config.json 5. Click **Load Study** to populate the canvas ### 3. Using Templates 1. Click **Templates** in the header 2. Browse available workflow templates: - **Mass Minimization**: Single-objective mass reduction - **Multi-Objective**: Pareto optimization (mass + displacement) - **Turbo Mode**: Neural-accelerated optimization - **Mirror WFE**: Zernike wavefront error optimization - **Frequency Target**: Natural frequency optimization 3. Click a template to load it ### 4. Processing with Claude 1. Build and configure your workflow 2. Click **Validate** to check for errors 3. Click **Process with Claude** to: - Validate the configuration against Atomizer protocols - Receive recommendations (method selection, trial count) - Create the optimization study --- ## Node Configuration ### Model Node | Field | Description | Example | |-------|-------------|---------| | File Path | Path to NX model | `models/bracket.sim` | | File Type | prt, sim, or fem | `sim` | When loading a `.sim` file, the system introspects to find: - Linked `.prt` (geometry part) - Linked `.fem` (FEM file) - Solver type (SOL101, SOL103, etc.) - Available expressions ### Design Variable Node | Field | Description | Example | |-------|-------------|---------| | Expression Name | NX expression to vary | `thickness` | | Min Value | Lower bound | `5.0` | | Max Value | Upper bound | `15.0` | | Unit | Engineering unit | `mm` | **Expression Selector**: Click the dropdown to: - **Search** through available expressions - **Filter** by name - **Refresh** to reload from model - **Enter manually** if expression not found ### Extractor Node | Field | Description | Options | |-------|-------------|---------| | Extractor ID | Protocol E1-E10 | E1 (Displacement), E2 (Frequency), etc. | | Name | Display name | `max_displacement` | | Config | Extractor-specific settings | Node ID, component, etc. | **Available Extractors** (SYS_12): | ID | Physics | Function | |----|---------|----------| | E1 | Displacement | `extract_displacement()` | | E2 | Frequency | `extract_frequency()` | | E3 | Stress | `extract_solid_stress()` | | E4 | BDF Mass | `extract_mass_from_bdf()` | | E5 | CAD Mass | `extract_mass_from_expression()` | | E8 | Zernike | `extract_zernike_coefficients()` | | E9 | Zernike | `extract_zernike_rms()` | | E10 | Zernike | `extract_zernike_wfe()` | ### Objective Node | Field | Description | Options | |-------|-------------|---------| | Name | Objective identifier | `mass`, `displacement` | | Direction | Optimization goal | `minimize`, `maximize` | | Weight | Multi-objective weight | `1.0` (0.0-10.0) | ### Constraint Node | Field | Description | Example | |-------|-------------|---------| | Name | Constraint identifier | `max_stress` | | Operator | Comparison type | `<=`, `>=`, `==` | | Value | Threshold value | `250.0` | ### Algorithm Node | Field | Description | Options | |-------|-------------|---------| | Method | Optimization algorithm | TPE, CMA-ES, NSGA-II, GP-BO | | Max Trials | Number of trials | `100` | | Timeout | Optional time limit | `3600` (seconds) | **Method Selection** (SYS_15): | Method | Best For | Design Vars | Objectives | |--------|----------|-------------|------------| | TPE | General purpose | 1-10 | 1 | | CMA-ES | Many variables | 5-100 | 1 | | NSGA-II | Multi-objective | 1-20 | 2-4 | | GP-BO | Expensive evaluations | 1-10 | 1 | ### Surrogate Node | Field | Description | Options | |-------|-------------|---------| | Enabled | Toggle acceleration | true/false | | Model Type | Surrogate architecture | MLP, GNN, Auto | | Min Trials | Trials before activation | `20` | --- ## Custom Extractors (V3.1) Custom extractors allow you to define arbitrary Python extraction functions directly in the AtomizerSpec. These functions are validated for safety and executed during optimization. ### Creating a Custom Extractor 1. Add a **Custom Extractor** node from the palette 2. Open the **Code Editor** in the config panel 3. Write your extraction function following the required signature 4. The code is validated in real-time for: - Correct function signature - Allowed imports only (numpy, pyNastran) - No dangerous operations (os.system, exec, eval, etc.) ### Function Signature ```python def extract(op2_path, bdf_path=None, params=None, working_dir=None): """ Custom extraction function. Args: op2_path: Path to the .op2 results file bdf_path: Path to the .bdf mesh file (optional) params: Dict of current design variable values (optional) working_dir: Path to the trial working directory (optional) Returns: Dict with output values, e.g., {"custom_metric": 42.0} """ import numpy as np from pyNastran.op2.op2 import OP2 op2 = OP2() op2.read_op2(op2_path) # Your extraction logic here result = np.max(op2.displacements[1].data) return {"custom_metric": result} ``` ### Allowed Imports | Module | Usage | |--------|-------| | `numpy` | Numerical operations | | `pyNastran` | OP2/BDF file parsing | | `math` | Basic math functions | | `pathlib` | Path manipulation | ### Security Restrictions The following are **NOT allowed** in custom extractor code: - `import os`, `import subprocess`, `import sys` - `exec()`, `eval()`, `compile()` - `__import__()`, `open()` with write mode - Network operations - File system modifications outside working_dir ### Example: Custom Stress Ratio Extractor ```python def extract(op2_path, bdf_path=None, params=None, working_dir=None): """Extract stress ratio (max_stress / allowable).""" import numpy as np from pyNastran.op2.op2 import OP2 op2 = OP2() op2.read_op2(op2_path) # Get von Mises stress from solid elements stress_data = op2.ctetra_stress[1].data max_von_mises = np.max(stress_data[:, :, 7]) # Column 7 is von Mises allowable = 250.0 # MPa stress_ratio = max_von_mises / allowable return { "stress_ratio": stress_ratio, "max_stress_mpa": max_von_mises } ``` --- ## File Browser (V3) The File Browser allows you to navigate the studies directory to select model files. ### Features - **Directory Navigation**: Browse folder hierarchy with breadcrumbs - **Type Filtering**: Filters to `.sim`, `.prt`, `.fem`, `.afem` by default - **Search**: Quick search by file name - **Single-Click Select**: Click a file to select and close ### Usage 1. Click the **Browse** button (folder icon) next to the Model file path input 2. Navigate to your study folder 3. Click a model file to select it 4. The path is automatically populated in the Model node --- ## Model Introspection (V3) Model Introspection analyzes NX model files to discover expressions, solver type, and dependencies. ### Features - **Expression Discovery**: Lists all expressions found in the model - **Solver Detection**: Infers solver type from file contents (SOL101, SOL103, etc.) - **Dependency Tracking**: Shows related .prt, .fem, .afem files - **Extractor Suggestions**: Recommends extractors based on solver type - **One-Click Add**: Add expressions as Design Variables instantly ### Usage 1. Configure a **Model** node with a valid file path 2. Click **Introspect Model** button 3. View discovered expressions, extractors, and files 4. Click **+** next to any expression to add as Design Variable 5. Click **+** next to any extractor to add to canvas ### Discovered Information | Section | Contents | |---------|----------| | **Solver Type** | Detected solver (SOL101, SOL103, etc.) | | **Expressions** | Name, current value, unit | | **Extractors** | Available extractors for this solver | | **Dependent Files** | Related .prt, .fem, .afem files | --- ## API Integration ### Backend Endpoints #### AtomizerSpec REST API (V3.1) The spec API provides full CRUD operations on the unified AtomizerSpec: ``` GET /api/studies/{study_id}/spec # Get full AtomizerSpec Returns: AtomizerSpec JSON with meta, model, design_variables, extractors, objectives, constraints, optimization, canvas PUT /api/studies/{study_id}/spec # Replace entire spec Body: AtomizerSpec JSON Returns: { hash: string, warnings: [] } PATCH /api/studies/{study_id}/spec # Partial update (JSONPath) Body: { path: "design_variables[0].bounds.max", value: 15.0, modified_by: "canvas" } Returns: { hash: string } POST /api/studies/{study_id}/spec/validate # Validate spec Returns: { valid: boolean, errors: [], warnings: [] } POST /api/studies/{study_id}/spec/nodes # Add node (design var, extractor, etc.) Body: { type: "designVar", data: {...}, modified_by: "canvas" } Returns: { node_id: "dv_002", hash: string } PATCH /api/studies/{study_id}/spec/nodes/{id} # Update node Body: { updates: {...}, modified_by: "canvas" } Returns: { hash: string } DELETE /api/studies/{study_id}/spec/nodes/{id} # Remove node Query: modified_by=canvas Returns: { hash: string } POST /api/studies/{study_id}/spec/edges # Add edge connection Query: source=ext_001&target=obj_001&modified_by=canvas Returns: { hash: string } ``` #### Study Configuration ``` GET /api/studies/ # List all studies GET /api/studies/{path}/config # Get optimization_config.json (legacy) ``` #### File Browser (V3) ``` GET /api/files/list # List files in directory Query: path=subdir&types=.sim,.prt,.fem,.afem Returns: { files: [{name, path, isDirectory}], path } ``` #### NX Introspection (V3) ``` POST /api/nx/introspect # Introspect NX model file Body: { file_path: string } Returns: { file_path, file_type, expressions, solver_type, dependent_files, extractors_available, warnings } GET /api/nx/expressions # Get expressions from model Query: file_path=path/to/model.sim Returns: { expressions: [{name, value, unit, type}] } ``` #### Health Check (V3) ``` GET /api/health # Check database and service health Returns: { status: "healthy", database: "connected" } ``` ### MCP Canvas Tools The Canvas integrates with the MCP server for Claude tool use: #### `validate_canvas_intent` Validates an optimization intent from the Canvas. ```typescript { intent: OptimizationIntent // The canvas workflow as JSON } // Returns: { valid, errors, warnings, recommendations } ``` #### `execute_canvas_intent` Creates an optimization study from a validated intent. ```typescript { intent: OptimizationIntent, study_name: string, // snake_case name auto_run?: boolean // Start optimization immediately } // Returns: { study_path, config_path, status } ``` #### `interpret_canvas_intent` Analyzes a Canvas intent and provides recommendations. ```typescript { intent: OptimizationIntent } // Returns: { // problem_type: "single-objective" | "multi-objective", // complexity: "low" | "medium" | "high", // recommended_method: string, // recommended_trials: number, // surrogate_recommended: boolean, // notes: string[] // } ``` --- ## AtomizerSpec v2.0 Schema The Canvas uses **AtomizerSpec v2.0** as the unified configuration format. This replaces the legacy `optimization_config.json` and `OptimizationIntent` with a single schema. ### Core Structure ```typescript interface AtomizerSpec { meta: { version: "2.0"; created: string; // ISO timestamp modified: string; // ISO timestamp created_by: "canvas" | "claude" | "api" | "migration" | "manual"; modified_by: "canvas" | "claude" | "api" | "migration" | "manual"; study_name: string; description?: string; tags?: string[]; }; model: { sim: { path: string; solver: string }; prt?: { path: string }; fem?: { path: string }; }; design_variables: DesignVariable[]; extractors: Extractor[]; objectives: Objective[]; constraints: Constraint[]; optimization: OptimizationConfig; canvas: CanvasLayout; } ``` ### Design Variable ```typescript interface DesignVariable { id: string; // "dv_001", "dv_002", etc. name: string; // Display name expression_name: string; // NX expression name type: "continuous" | "integer" | "categorical"; bounds: { min: number; max: number }; baseline?: number; unit?: string; enabled: boolean; canvas_position: { x: number; y: number }; } ``` ### Extractor ```typescript interface Extractor { id: string; // "ext_001", etc. name: string; // Display name type: string; // "mass", "displacement", "zernike_opd", "custom" builtin: boolean; // true for E1-E10, false for custom outputs: Array<{ name: string; units?: string }>; config?: Record; custom_function?: { // For custom extractors only code: string; // Python function code entry_point: string; // Function name (default: "extract") }; canvas_position: { x: number; y: number }; } ``` ### Objective ```typescript interface Objective { id: string; // "obj_001", etc. name: string; // Display name direction: "minimize" | "maximize"; source: { extractor_id: string; // Reference to extractor output_name: string; // Which output from the extractor }; weight?: number; // For weighted sum multi-objective enabled: boolean; canvas_position: { x: number; y: number }; } ``` ### Canvas Layout ```typescript interface CanvasLayout { edges: Array<{ source: string; target: string }>; layout_version: "2.0"; viewport?: { x: number; y: number; zoom: number }; } ``` ### Example AtomizerSpec ```json { "meta": { "version": "2.0", "created": "2026-01-17T10:00:00Z", "modified": "2026-01-17T10:30:00Z", "created_by": "canvas", "modified_by": "canvas", "study_name": "bracket_mass_optimization", "description": "Optimize bracket mass while maintaining stress limits" }, "model": { "sim": { "path": "bracket_sim1.sim", "solver": "nastran" } }, "design_variables": [ { "id": "dv_001", "name": "Thickness", "expression_name": "web_thickness", "type": "continuous", "bounds": { "min": 2.0, "max": 10.0 }, "baseline": 5.0, "unit": "mm", "enabled": true, "canvas_position": { "x": 50, "y": 100 } } ], "extractors": [ { "id": "ext_001", "name": "Mass", "type": "mass", "builtin": true, "outputs": [{ "name": "mass", "units": "kg" }], "canvas_position": { "x": 740, "y": 100 } } ], "objectives": [ { "id": "obj_001", "name": "mass", "direction": "minimize", "source": { "extractor_id": "ext_001", "output_name": "mass" }, "enabled": true, "canvas_position": { "x": 1020, "y": 100 } } ], "constraints": [], "optimization": { "algorithm": { "type": "TPE" }, "budget": { "max_trials": 100 } }, "canvas": { "edges": [ { "source": "dv_001", "target": "model" }, { "source": "model", "target": "solver" }, { "source": "solver", "target": "ext_001" }, { "source": "ext_001", "target": "obj_001" }, { "source": "obj_001", "target": "optimization" } ], "layout_version": "2.0" } } ``` ### Legacy OptimizationIntent (Deprecated) The `OptimizationIntent` format is still supported for backwards compatibility but will be automatically converted to AtomizerSpec v2.0 when saved. ```typescript interface OptimizationIntent { model: { path: string; type: 'prt' | 'sim' | 'fem'; }; solver: { type: string; // SOL101, SOL103, etc. }; design_variables: Array<{ name: string; expression: string; min: number; max: number; unit?: string; }>; extractors: Array<{ id: string; // E1, E2, etc. name: string; config?: Record; }>; objectives: Array<{ name: string; extractor: string; direction: 'minimize' | 'maximize'; weight?: number; }>; constraints?: Array<{ name: string; extractor: string; operator: '<=' | '>=' | '=='; value: number; }>; optimization: { method: string; max_trials: number; timeout?: number; }; surrogate?: { enabled: boolean; model_type?: string; min_trials?: number; }; } ``` --- ## Validation Rules The Canvas validates workflows against these rules: ### Required Components - At least 1 **Model** node - At least 1 **Solver** node - At least 1 **Design Variable** node - At least 1 **Objective** node - At least 1 **Algorithm** node ### Configuration Rules - All nodes must be **configured** (no empty fields) - Design variable **min < max** - Objective must connect to an **Extractor** - Extractor ID must be valid (E1-E10) ### Connection Rules - Model → Solver (required) - Solver → Extractor (required for each extractor) - Extractor → Objective (required for each objective) - Extractor → Constraint (optional) ### Recommendations - Multi-objective (2+ objectives) should use **NSGA-II** - Many variables (5+) may benefit from **surrogate** - High trial count (100+) should consider **neural acceleration** --- ## Templates ### Mass Minimization Single-objective mass reduction with stress constraint. - **Nodes**: 6 (Model, Solver, DVar, Extractor, Objective, Algorithm) - **Objective**: Minimize mass - **Constraint**: Max stress < limit - **Method**: TPE (100 trials) ### Multi-Objective Pareto optimization for mass vs. displacement trade-off. - **Nodes**: 7 - **Objectives**: Minimize mass, Minimize displacement - **Method**: NSGA-II (150 trials) ### Turbo Mode Neural-accelerated optimization with surrogate. - **Nodes**: 8 (includes Surrogate) - **Objective**: User-defined - **Method**: TPE + MLP Surrogate - **Trials**: 50 FEA + 5000 surrogate ### Mirror WFE Zernike wavefront error optimization for optics. - **Nodes**: 7 - **Objective**: Minimize WFE (E10) - **Method**: CMA-ES (200 trials) ### Frequency Target Natural frequency optimization with modal analysis. - **Nodes**: 6 - **Objective**: Target frequency (E2) - **Method**: TPE (100 trials) --- ## Keyboard Shortcuts | Key | Action | |-----|--------| | `Delete` / `Backspace` | Delete selected node | | `Escape` | Deselect all | | `Ctrl+Z` | Undo (future) | | `Ctrl+Shift+Z` | Redo (future) | | `Space` (hold) | Pan canvas | | Scroll | Zoom in/out | --- ## Troubleshooting ### Canvas Not Visible - Ensure you're on the `/canvas` route - Check for JavaScript errors in browser console - Verify React Flow is properly initialized ### Nodes Not Draggable - Check that drag-and-drop events are being captured - Ensure `onDragStart` sets the correct data type ### Config Panel Not Updating - Verify Zustand store is properly connected - Check that `updateNodeData` is being called ### Claude Chat Not Working - Check WebSocket connection status (green indicator) - Verify backend is running on port 8000 - Check `/api/chat/` endpoint is accessible ### Expression Dropdown Empty - Ensure a Model node is configured with a file path - Check `/api/nx/expressions` endpoint is working - Try the "Refresh" button to reload expressions --- ## Development ### Running Locally ```bash # Frontend cd atomizer-dashboard/frontend npm install npm run dev # Backend cd atomizer-dashboard/backend python -m uvicorn api.main:app --reload --port 8000 # MCP Server cd mcp-server/atomizer-tools npm run build npm run dev ``` ### Building for Production ```bash # Frontend cd atomizer-dashboard/frontend npm run build # MCP Server cd mcp-server/atomizer-tools npm run build ``` ### Adding New Node Types 1. Create node component in `components/canvas/nodes/` 2. Add type to `schema.ts` 3. Register in `nodes/index.ts` 4. Add to `NodePalette.tsx` 5. Update validation rules in `validation.ts` 6. Add serialization logic to `intent.ts` --- ## References - **AtomizerSpec v2.0 Architecture**: See `docs/plans/UNIFIED_CONFIGURATION_ARCHITECTURE.md` - **AtomizerSpec JSON Schema**: See `optimization_engine/schemas/atomizer_spec_v2.json` - **React Flow Documentation**: https://reactflow.dev/ - **Lucide Icons**: https://lucide.dev/icons/ - **Zustand**: https://github.com/pmndrs/zustand - **Atomizer Protocols**: See `docs/protocols/` - **Extractor Library**: See `SYS_12_EXTRACTOR_LIBRARY.md` - **Method Selector**: See `SYS_15_METHOD_SELECTOR.md` --- *Canvas Builder: Design optimizations visually, execute with AI.* *Powered by AtomizerSpec v2.0 - the unified configuration format.*