-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from source-academy/dev
[0.0.4] Update Storybook and add Transformations
- Loading branch information
Showing
153 changed files
with
2,983 additions
and
979 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { Meta, Story } from "@storybook/blocks"; | ||
|
||
<Meta title="Contribute" /> | ||
|
||
# Contribute | ||
|
||
**nbody** is maintained by the open-source [Source Academy](https://github.com/source-academy/) development community based in National University of Singapore. Anyone from anywhere is free and welcome to contribute to our project and our community. | ||
|
||
- [Developer Guide](#developer-guide) | ||
- [Clone the repository](#clone-the-repository) | ||
- [Install packages](#install-packages) | ||
- [Developer Setup](#developer-setup) | ||
- [Directory Structure](#directory-structure) | ||
- [CLI Commands](#cli-commands) | ||
- [Roadmap](#roadmap) | ||
## Developer Guide | ||
|
||
Here's a quick guide to get started on contributing to _nbody_. | ||
|
||
### Clone the repository | ||
|
||
```bash | ||
git clone https://github.com/source-academy/nbody | ||
``` | ||
|
||
### Install packages | ||
|
||
We use [Yarn 1](https://classic.yarnpkg.com/lang/en/) as the package manager for its speed and developer experience. This installs all depenedencies required for the development of the project. | ||
|
||
```bash | ||
cd nbody | ||
yarn install | ||
``` | ||
|
||
### Developer Setup | ||
|
||
Core libraries used in the project | ||
- [three](https://threejs.org/) - For 3D rendering | ||
- [plotly.js](https://plotly.com/javascript/) - For 2D rendering | ||
- [lil-gui](https://lil-gui.georgealways.com/) - For GUI controls | ||
|
||
Development setup of the project | ||
|
||
- Source code is written in ES6 format in [Typescript](https://www.typescriptlang.org/) | ||
- [ESLint](https://eslint.org/) for linting and ensuring code quality. If developing in VSCode, install the ESLint extension for real-time linting and format on save. | ||
- Code comments in JSdoc format, API documentation generated using [Typedoc](https://typedoc.org/) | ||
- [Storybook](https://storybook.js.org/) for general documentation and demo showcase | ||
- [React](https://react.dev/) and [Vite](https://vitejs.dev/) template for component development | ||
|
||
### Directory Structure | ||
|
||
- `.storybook` | ||
- Contains configuration and components for Storybook documentation | ||
- `dist` | ||
- Contains transpiled code along with type definitions | ||
- `docs` | ||
- Built documentation | ||
- `api` | ||
- Built API documentation | ||
- `scripts` | ||
- Contains miscellaneous scripts for development like clean | ||
- `src` | ||
- Contains source code | ||
- package.json | ||
- tsconfig.json | ||
|
||
|
||
|
||
### CLI Commands | ||
|
||
- **clean** - Clean `dist` (build) and `docs` folders | ||
- **lint** - Run ESLint on `src` directory to ensure source code adheres to coding standards | ||
- **docs** - Generate documentation - both Storybook and API reference | ||
- **docs:api** - Generate only API documentation | ||
- **docs:storybook** - Generate only Storybook documentation | ||
- **storybook** - Preview Storybook components | ||
- **build** - Build the project - lints, cleans, transpiles and generates documentation. Used for deployment. | ||
- **dev** - Simple build and linking for local development | ||
- **test** - Run tests | ||
|
||
## Roadmap | ||
|
||
Contributors are free to pick up any of the following tasks or suggest new features. | ||
|
||
- Setup a bundled version of the project for CDN deployment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { Meta, Story } from '@storybook/blocks'; | ||
|
||
<Meta title="Define/Force" /> | ||
|
||
# Force | ||
|
||
A force object encapsulates logic for calculating forces acting on celestial bodies due to other objects or environment. It has a getForces method that takes in an array of celestial bodies and returns an array of forces acting on each body. It is defined as the following Typescript interface. | ||
|
||
```typescript | ||
interface Force { | ||
getForces(bodies: CelestialBody[]): Vector3[]; | ||
} | ||
``` | ||
|
||
Full API reference can be found [here](https://source-academy.github.io/nbody/api/interfaces/Force.html). | ||
|
||
- [Inbuilt Forces](#inbuilt-forces) | ||
- [Javascript](#javascript) | ||
- [Typescript](#typescript) | ||
|
||
## Inbuilt Forces | ||
|
||
### Gravity | ||
|
||
Create a [newtonian gravitational](https://en.wikipedia.org/wiki/Newton%27s_law_of_universal_gravitation) force object with a gravitational constant of `6.674e-11`. You can also pass in a custom gravitational constant. | ||
|
||
```javascript | ||
new Gravity(); | ||
new Gravity(10); | ||
``` | ||
|
||
### Centripetal Force | ||
|
||
Create a [centripetal](https://en.wikipedia.org/wiki/Centripetal_force) force object with a center of rotation. Default center is `(0, 0, 0)`. | ||
|
||
```javascript | ||
new CentripetalForce(); | ||
new CentripetalForce(new Vector3(x, y, z)); | ||
``` | ||
|
||
### Combined Force | ||
|
||
Create a force object that is a result of additively combining multiple forces acting on a system of bodies. | ||
|
||
```javascript | ||
new CombinedForce([new Gravity(), new CentripetalForce()]); | ||
``` | ||
|
||
### Lambda Force | ||
|
||
Create a force object that uses a [lambda/arrow](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) function to calculate forces. | ||
|
||
```javascript | ||
new LambdaForce((bodies) => { | ||
return bodies.map(body => new Vector3(0, 0, 0)); // zero force | ||
}); | ||
``` | ||
|
||
## Javascript | ||
|
||
You can define and configure your own force object in javascript with a getForces method as follows | ||
|
||
```javascript | ||
// gravitational constant | ||
const G = 6.67430e-11; | ||
|
||
// define your own newtonian gravitational force | ||
const gravity = { | ||
// must contain a getForces method | ||
getForces(bodies) { | ||
let n = bodies.length; | ||
let ans = []; | ||
for (let i = 0; i < n; i++) { | ||
ans.push(new Vector3(0, 0, 0)); | ||
} | ||
for (let i = 0; i < n; i++) { | ||
for (let j = i + 1; j < n; j++) { | ||
let currForce = this.calcNewtonian(bodies[i], bodies[j]); | ||
ans[i].add(currForce); | ||
ans[j].sub(currForce); | ||
} | ||
} | ||
return ans; | ||
}, | ||
// helper function to calculate force between two bodies | ||
calcNewtonian(a, b) { | ||
let distSq = a.position.distanceToSquared(b.position); | ||
let forceVal = (G * a.mass * b.mass) / distSq; | ||
return b.position | ||
.clone() | ||
.sub(a.position) | ||
.normalize() | ||
.multiplyScalar(forceVal); | ||
} | ||
} | ||
``` | ||
|
||
## Typescript | ||
|
||
You can define and configure your own force object in typescript by implementing the Force interface as follows | ||
|
||
```typescript | ||
class Gravity implements Force { | ||
readonly G: number = 6.674e-11; | ||
|
||
getForces(bodies: CelestialBody[]): Vector3[] { | ||
let n = bodies.length; | ||
let ans: Vector3[] = []; | ||
for (let i = 0; i < n; i++) { | ||
ans.push(new Vector3(0, 0, 0)); | ||
} | ||
for (let i = 0; i < n; i++) { | ||
for (let j = i + 1; j < n; j++) { | ||
let currForce = this.calcNewtonian(bodies[i], bodies[j]); | ||
ans[i].add(currForce); | ||
ans[j].sub(currForce); | ||
} | ||
} | ||
return ans; | ||
} | ||
|
||
private calcNewtonian(a: CelestialBody, b: CelestialBody): Vector3 { | ||
let distSq = a.position.distanceToSquared(b.position); | ||
let forceVal = (this.G * a.mass * b.mass) / distSq; | ||
return b.position | ||
.clone() | ||
.sub(a.position) | ||
.normalize() | ||
.multiplyScalar(forceVal); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Meta, Story } from '@storybook/blocks'; | ||
|
||
<Meta title="Define/Intro" /> | ||
|
||
# Define | ||
|
||
The library provides a set of predefined building blocks (force, simulate function, transformation) that can be used to define a simulation. However, the library is designed to be extensible and allows users to define their own building blocks in either JavaScript or TypeScript. Check out each building block's page for more details. | ||
|
||
- [Force](?path=/docs/define-force--docs) | ||
- [Simulate Function](?path=/docs/define-simulate-function--docs) | ||
- [Transformation](?path=/docs/define-transformation--docs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { Meta, Story } from '@storybook/blocks'; | ||
|
||
<Meta title="Define/Simulate Function" /> | ||
|
||
# Simulate Function | ||
|
||
A **Simulate Function** object encapsulates logic for advancing the state of the universe over time, usually using [numerical integration](https://en.wikipedia.org/wiki/Numerical_integration). It has a simulate method that takes in a time step, current state of the universe, (optionally the previous state of the universe) and returns the next state of the universe. | ||
|
||
```typescript | ||
interface SimulateFunction { | ||
simulate(deltaT: number, currState: State, prevState: State): State | ||
} | ||
``` | ||
|
||
Full API reference can be found [here](https://source-academy.github.io/nbody/api/interfaces/SimulateFunction.html). | ||
|
||
- [Inbuilt Simulate Functions](#inbuilt-simulate-functions) | ||
- [Javascript](#javascript) | ||
- [Typescript](#typescript) | ||
|
||
## Inbuilt Simulate Functions | ||
|
||
### Velocity Verlet | ||
|
||
Create a [velocity verlet](https://en.wikipedia.org/wiki/Verlet_integration#Velocity_Verlet) integrator. Uses newtonian gravity by default, or the provided force object. | ||
|
||
```javascript | ||
new VelocityVerletSim(); | ||
new VelocityVerletSim(customForce); | ||
``` | ||
|
||
### Explicit Euler | ||
|
||
Create a [explicit euler](https://en.wikipedia.org/wiki/Explicit_and_implicit_methods) integrator. Uses newtonian gravity by default, or the provided force object. | ||
|
||
```javascript | ||
new ExplicitEulerSim(); | ||
new ExplicitEulerSim(customForce); | ||
``` | ||
|
||
### Semi Implicit Euler | ||
|
||
Create a [semi-implicit euler](https://en.wikipedia.org/wiki/Explicit_and_implicit_methods) integrator. Uses newtonian gravity by default, or the provided force object. | ||
|
||
```javascript | ||
new SemiImplicitEulerSim(); | ||
new SemiImplicitEulerSim(customForce); | ||
``` | ||
|
||
### Runge-Kutta Order 4 | ||
|
||
Create a [runge-kutta order 4](https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods) integrator. Uses newtonian gravity by default, or the provided force object. Optionally, you can provide the weight coefficients for the averaging step. | ||
|
||
```javascript | ||
new RungeKutta4Sim(); | ||
new RungeKutta4Sim(customForce); | ||
new RungeKutta4Sim(customForce, [1, 2, 2, 1]); | ||
``` | ||
|
||
### Lambda integrator | ||
|
||
Create a simulate function from a lambda function. | ||
|
||
```javascript | ||
new LambdaSim((deltaT, currState, prevState) => { | ||
// your logic here | ||
}); | ||
``` | ||
|
||
## Javascript | ||
|
||
You can define and configure your own simulate function object in javascript with a simulate method as follows | ||
|
||
```javascript | ||
const explicitEulerSim = { | ||
simulate(deltaT, currState, prevState) { | ||
const updatedBodies = currState.bodies.map((b) => | ||
b.clone( | ||
this.rateUpdate(b.position, b.velocity, deltaT), | ||
this.rateUpdate(b.velocity, b.acceleration, deltaT) | ||
) | ||
); | ||
const updatedForces = customForce.getForces(updatedBodies); | ||
updatedBodies.forEach((b, i) => { | ||
b.acceleration = updatedForces[i].divideScalar(b.mass); | ||
}); | ||
return new State(updatedBodies); | ||
}, | ||
rateUpdate(prev, rate, deltaT) { | ||
return rate.clone().multiplyScalar(deltaT).add(prev); | ||
}, | ||
}; | ||
``` | ||
|
||
## Typescript | ||
|
||
You can define and configure your own simulate function object in Typescript by implementing the SimulateFunction interface as follows | ||
|
||
```typescript | ||
class ExplicitEulerSim implements SimulateFunction { | ||
force: Force = new Gravity(); | ||
|
||
simulate(deltaT: number, currState: State): State { | ||
const updatedBodies = currState.bodies.map((b) => b.clone( | ||
this.rateUpdate(b.position, b.velocity, deltaT), | ||
this.rateUpdate(b.velocity, b.acceleration, deltaT), | ||
)); | ||
const updatedForces = this.force.getForces(updatedBodies); | ||
updatedBodies.forEach((b, i) => { | ||
b.acceleration = updatedForces[i].divideScalar(b.mass); | ||
}); | ||
return new State(updatedBodies); | ||
} | ||
|
||
private rateUpdate(prev: Vector3, rate: Vector3, deltaT: number) { | ||
return rate.clone() | ||
.multiplyScalar(deltaT) | ||
.add(prev); | ||
} | ||
} | ||
|
||
``` |
Oops, something went wrong.