# Contributing Guide ## Getting Started ### Prerequisites - Node.js 18+ - npm or yarn - Basic understanding of React, JavaScript ### Setup ```bash # Clone/navigate to project cd rocketry # Install dependencies npm install # Start dev server npm run dev # Open browser # http://localhost:5173 ``` ### Project Structure Overview ``` src/ ├── engine/ # Pure math, zero React deps ├── hooks/ # State management ├── components/ # UI components ├── pages/ # Route pages └── App.jsx # Router ``` See [ARCHITECTURE.md](ARCHITECTURE.md) for detailed breakdown. --- ## Common Tasks ### Adding a New Equation **File**: `src/engine/equations.js` 1. **Check if variables exist** in `variables.js` - If not, add them with `id`, `name`, `unit`, `category`, `type` 2. **Add equation object**: ```javascript { id: 'myEquation', name: 'My Equation Name', variables: ['var1', 'var2', 'var3'], equation: 'var1 = var2 * var3', // for reference solvers: { var1: (inputs) => inputs.var2 * inputs.var3, var2: (inputs) => inputs.var1 / inputs.var3, var3: (inputs) => inputs.var1 / inputs.var2 } } ``` 3. **Test manually** - Go to Solver page - Drag variables onto workspace - Set constraints, verify solver computes correct values ### For Transcendental Equations (Bisection) ```javascript import { bisection } from '../numerics.js' { id: 'machEquation', solvers: { machNumber: (inputs) => { const fn = (M) => isentropicAreaRatio(M, inputs.gamma) - inputs.areaRatio return bisection(fn, 0.1, 10, 1e-6) } } } ``` ### Adding a Material to Knowledgebase **File**: `src/engine/knowledgebaseData.js` **For fuels/oxidizers:** ```javascript FUELS.push({ id: 'newFuel', name: 'New Fuel', formula: 'C8H18', // typical hydrocarbon density: 800, // kg/m³ molecularWeight: 114, properties: { combustionTemp: 3500, gamma: 1.25, charVelocity: 1500 // m/s } }) ``` **For ablatives:** ```javascript ABLATIVES.push({ id: 'newAblative', name: 'New Ablative', density: 1400, erosionRate: 0.020, // inch/s @ 300 psi pressureExponent: 0.35, // power-law exponent tempLimit: 2100, // K notes: 'Best for chamber walls' }) ``` **For structural materials:** ```javascript STRUCTURAL_MATERIALS.push({ id: 'newMaterial', name: 'New Material', density: 4500, // kg/m³ yieldStrength: 900, // MPa youngModulus: 200, // GPa meltingPoint: 1800, // K cte: 12e-6, // 1/K notes: 'Good for hot sections' }) ``` Changes auto-appear in UI (hot reload). ### Adding a New Page 1. **Create page component** (`src/pages/NewPage.jsx`): ```javascript import { useState } from 'react' export default function NewPage() { return (

New Feature

{/* Your content */}
) } ``` 2. **Add route** in `src/App.jsx`: ```javascript import NewPage from './pages/NewPage.jsx' // In Routes: } /> ``` 3. **Add navigation link** in header if needed: ```javascript New Feature ``` ### Adding a 3D Component **File**: `src/components/new3d/NewComponent.jsx` Use React Three Fiber (`@react-three/fiber`): ```javascript import { Canvas } from '@react-three/fiber' import { OrbitControls } from '@react-three/drei' export default function NewComponent() { return ( ) } ``` --- ## Code Style & Conventions ### Naming - **Components**: PascalCase (`VariableCard.jsx`) - **Files**: match component name or use kebab-case for utilities - **Variables/functions**: camelCase - **Constants**: UPPER_SNAKE_CASE - **React hooks**: `useFeatureName` ### File Organization ```javascript // 1. Imports (grouped) import React, { useState, useMemo } from 'react' import { helper } from '../utils' import './styles.css' // 2. Types/Constants const DEFAULT_VALUE = 10 // 3. Component export default function MyComponent({ prop1, prop2 }) { // Hooks const [state, setState] = useState(0) // Computed values const memoized = useMemo(() => { return expensiveCalculation() }, [deps]) // Event handlers const handleClick = () => { /* ... */ } // JSX return
...
} ``` ### Styling - Use **Tailwind CSS** classes - Keep dark theme (slate-950 background) - Responsive: mobile-first, use Tailwind breakpoints ```javascript
Click me
``` ### Comments - Add only for **why**, not **what** - Keep code self-documenting - Avoid comments for obvious logic ```javascript // ✅ Good: explains intent // Pressure correction for temperature variation const correctedRate = baseRate * Math.pow(temp / refTemp, exponent) // ❌ Bad: obvious from code const x = x + 1 // increment x ``` --- ## Testing Currently no test suite. Recommended additions: ### Unit Tests (Jest) ```javascript // src/engine/__tests__/solver.test.js import { solve } from '../solver' test('solves linear equation', () => { const eqs = [{ id: 'eq1', variables: ['x', 'y'], solvers: { x: (inputs) => inputs.y * 2 } }] const result = solve(eqs, { y: 5 }) expect(result.x).toBe(10) }) ``` ### Component Tests (React Testing Library) ```javascript // src/components/__tests__/VariableCard.test.jsx import { render, screen, fireEvent } from '@testing-library/react' import VariableCard from '../VariableCard' test('renders input field', () => { render() expect(screen.getByDisplayValue('0')).toBeInTheDocument() }) test('updates on input change', () => { const { getByDisplayValue } = render() fireEvent.change(getByDisplayValue('0'), {target: {value: '100'}}) expect(getByDisplayValue('100')).toBeInTheDocument() }) ``` ### Manual Testing Checklist - [ ] Solver computes correct values - [ ] Engine design produces reasonable thrust/Isp - [ ] Rocket design mass budget is sensible - [ ] Trajectory plot shows reasonable path - [ ] 3D models render without errors - [ ] UI is responsive on mobile --- ## Performance Considerations ### Memoization Use `useMemo()` for expensive calculations: ```javascript const results = useMemo(() => { return engineDesignCalcs.calcCombustion(inputs) // expensive }, [inputs]) ``` ### Avoid Unnecessary Re-renders - Lift state up only when needed - Use `useCallback()` for event handlers passed to children - Consider `React.memo()` for pure components ```javascript const VariableCard = React.memo(({ variable, onChange }) => { // Component only re-renders if variable or onChange changes return }) ``` ### Canvas Performance - Limit trajectory states to ~5000 points - Use fixed timestep (don't go below 0.01 s) - Reduce Three.js geometry complexity if needed --- ## Git Workflow ### Branching - `main` — production-ready code - `feature/*` — new features - `fix/*` — bug fixes - `docs/*` — documentation updates ### Commits Keep commits atomic and well-described: ```bash git commit -m "Add pressure-corrected ablation model - Implement power-law pressure exponent for erosion rate - Add pressure factor display in Engine page - Update knowledgebase with exponent values - Update docs with pressure correction formula" ``` ### Pull Requests Include: - What changed and why - How to test - Any breaking changes - Related issues --- ## Debugging Tips ### Browser DevTools **Console:** ```javascript // Log solver state console.log('Constraints:', solverState.constraints) console.log('Results:', solverState.results) ``` **React DevTools Extension:** - Inspect component props/state - Profile render performance - Trace updates ### Hot Reload Changes to `src/` automatically reload (Vite). - Engine modules reload: refresh browser - Components/pages: usually hot reload instantly ### Performance Profiling ```javascript // In React component console.time('calculation') const result = expensiveFunction() console.timeEnd('calculation') // logs elapsed time ``` --- ## Common Pitfalls ### ❌ Don't: Mutate state directly ```javascript state.value = 100 // Wrong! setState({...state, value: 100}) // Correct ``` ### ❌ Don't: Create objects in dependencies ```javascript const obj = {x: 1} useMemo(() => calc(obj), [obj]) // Runs every render! ``` ### ✅ Do: Memoize dependencies ```javascript const obj = useMemo(() => ({x: 1}), []) useMemo(() => calc(obj), [obj]) // Stable ``` ### ❌ Don't: Forget dependencies ```javascript useEffect(() => { doSomething(dep) }, []) // Missing 'dep'! ``` ### ✅ Do: Include all dependencies ```javascript useEffect(() => { doSomething(dep) }, [dep]) ``` --- ## Asking for Help **Before asking:** 1. Check existing documentation 2. Search similar equations/features 3. Review console for errors 4. Try simplifying the problem **When asking:** - Include error message - Describe what you tried - Provide minimal reproducible example --- ## Roadmap Ideas Potential future features: - **Multi-stage rockets** — sequential stage design - **Thrust vector control** — pitch/yaw steering - **Grid fin aerodynamics** — drag & control surfaces - **Solid rocket motors** — grain geometry, regression - **Regenerative cooling** — thermal analysis - **Uncertainty analysis** — Monte Carlo simulations - **Optimization** — automated mass/performance optimization - **Data export** — CAD, simulation formats (GMAT, Basilisk) - **Multiplayer** — collaborative design sessions --- ## Resources - [React Docs](https://react.dev) - [Tailwind CSS](https://tailwindcss.com) - [Three.js Docs](https://threejs.org/docs) - [React Three Fiber](https://docs.pmnd.rs/react-three-fiber) - [Vite Docs](https://vitejs.dev) --- **Last Updated**: 2025-02 | **Status**: Current