Trajectories
This commit is contained in:
496
docs/CONTRIBUTING.md
Normal file
496
docs/CONTRIBUTING.md
Normal file
@@ -0,0 +1,496 @@
|
||||
# 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 (
|
||||
<div className="flex-1 overflow-auto p-6">
|
||||
<h1 className="text-3xl font-bold mb-4">New Feature</h1>
|
||||
{/* Your content */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
2. **Add route** in `src/App.jsx`:
|
||||
|
||||
```javascript
|
||||
import NewPage from './pages/NewPage.jsx'
|
||||
|
||||
// In Routes:
|
||||
<Route path="/new-feature" element={<NewPage />} />
|
||||
```
|
||||
|
||||
3. **Add navigation link** in header if needed:
|
||||
|
||||
```javascript
|
||||
<NavLink
|
||||
to="/new-feature"
|
||||
className={/* classes */}
|
||||
>
|
||||
New Feature
|
||||
</NavLink>
|
||||
```
|
||||
|
||||
### 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 (
|
||||
<Canvas>
|
||||
<ambientLight intensity={0.6} />
|
||||
<directionalLight position={[5, 5, 5]} />
|
||||
<mesh>
|
||||
<boxGeometry args={[1, 1, 1]} />
|
||||
<meshStandardMaterial color="red" />
|
||||
</mesh>
|
||||
<OrbitControls />
|
||||
</Canvas>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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 <div>...</div>
|
||||
}
|
||||
```
|
||||
|
||||
### Styling
|
||||
|
||||
- Use **Tailwind CSS** classes
|
||||
- Keep dark theme (slate-950 background)
|
||||
- Responsive: mobile-first, use Tailwind breakpoints
|
||||
|
||||
```javascript
|
||||
<div className="px-4 py-2 rounded-md bg-slate-800 hover:bg-slate-700 transition-colors">
|
||||
Click me
|
||||
</div>
|
||||
```
|
||||
|
||||
### 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(<VariableCard variable={{name: 'thrust'}} />)
|
||||
expect(screen.getByDisplayValue('0')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
test('updates on input change', () => {
|
||||
const { getByDisplayValue } = render(<VariableCard />)
|
||||
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 <input onChange={onChange} />
|
||||
})
|
||||
```
|
||||
|
||||
### 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
|
||||
Reference in New Issue
Block a user