Trajectories

This commit is contained in:
2026-03-04 20:29:19 +00:00
parent 6af56f478f
commit 1b15384c10
20 changed files with 4825 additions and 71 deletions

496
docs/CONTRIBUTING.md Normal file
View 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