Skip to content

Commit 801eaca

Browse files
committed
better packaging and ssr compatibility
1 parent 2911a34 commit 801eaca

15 files changed

+257
-170
lines changed

README.md

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## Nebula
2-
### Nebula is a lightweight JavaScript library for creating univers animations.
2+
### Nebula is a lightweight JavaScript library for creating univers animations with React.
3+
Including configurable Stars, Nebulas, Comets, Planets and Suns.
4+
Compatible with SSR
5+
6+
<img src="demo.jpg" />
37

48
### `Installation`
59
```
@@ -17,9 +21,9 @@ key | option type / notes | default
1721
`astres` | `AstreDescription[]` | `[]`
1822
`scale` | `number` | `1`
1923
`speed` | `number` | `1`
20-
`starsCount` | `number` | `150`
24+
`starsCount` | `number` | `200`
2125
`starsColor` | `string` | `#ffffff` (white)
2226
`starsRotationSpeed` | `number` | `5`
23-
`cometFrequence` | `number` | `1`
24-
`nebulasIntensity` | `number` | `1`
27+
`cometFrequence` | `number` | `3`
28+
`nebulasIntensity` | `number` | `8`
2529
`nebulasColors` | `string[]` accept rgb and hex | `["rgb(5,63,157)", "rgb(42,112,25)", "rgb(182,41,44)"]`

demo.jpg

689 KB
Loading

index.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { smallSolarSystem } from "src/templates/smallSolarSystem";
22
import { bigSolarSystem } from "src/templates/bigSolarSystem";
3-
import type { AstreDescription } from "src/astres/types";
43
import { ReactNebula } from "src/ReactNebula";
4+
import { PlanetDescription, SunDescription } from "src/astres/types";
55

6-
export type {AstreDescription}
7-
export {smallSolarSystem, bigSolarSystem, ReactNebula}
6+
type AstreDescription = PlanetDescription | SunDescription;
7+
export type { AstreDescription };
8+
export { smallSolarSystem, bigSolarSystem, ReactNebula };

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@flodlc/nebula",
3-
"version": "1.0.8",
3+
"version": "1.0.15",
44
"main": "dist/index.cjs.js",
55
"module": "dist/index.es.js",
66
"typings": "dist/index.d.ts",

src/DEFAULT_CONFIG.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { AstreDescription } from "src/astres/types";
2+
3+
export const DEFAULT_CONFIG = {
4+
astres: [] as AstreDescription[],
5+
cometFrequence: 3,
6+
scale: 1,
7+
speed: 1,
8+
starsCount: 200,
9+
starsColor: "#FFFFFF",
10+
starsRotationSpeed: 5,
11+
nebulasIntensity: 8,
12+
nebulasColors: ["rgb(27,2,140)", "rgb(22,91,2)", "#880554"],
13+
};

src/ReactNebula.tsx

+48-90
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,86 @@
11
import React, { useLayoutEffect, useRef, useState } from "react";
2-
import { Planet } from "src/astres/Planet";
3-
import { Star } from "src/astres/Star";
4-
import { Galaxy } from "src/astres/Galaxy";
5-
import { parseColor } from "src/utils/parseColor";
6-
import { Sun } from "src/astres/Sun";
7-
import { Nebula } from "src/astres/Nebula";
8-
import { AstreDescription } from "src/astres/types";
9-
import { Astre } from "src/astres/Astre";
102
import { generateStars } from "src/utils/starGenerator";
113
import { generateNebulas } from "src/utils/generateNebulas";
124
import { generateComet } from "src/utils/generateComet";
135
import { SystemConfig } from "src/types";
14-
15-
const DEFAULT_CONFIG = {
16-
astres: [] as AstreDescription[],
17-
cometFrequence: 1,
18-
scale: 0.8,
19-
speed: 0.3,
20-
starsCount: 150,
21-
starsColor: "#FFFFFF",
22-
starsRotationSpeed: 5,
23-
nebulasIntensity: 6,
24-
nebulasColors: ["rgb(5,63,157)", "rgb(42,112,25)", "rgb(182,41,44)"],
25-
};
6+
import { DEFAULT_CONFIG } from "src/DEFAULT_CONFIG";
7+
import { drawAstres } from "src/draw";
268

279
export const ReactNebula = ({ config = {} }: { config?: SystemConfig }) => {
2810
const filledConfig = Object.assign({}, DEFAULT_CONFIG, config);
2911
const canvasRef = useRef<HTMLCanvasElement>(null);
30-
const [iter, setIter] = useState(0);
12+
const bgCanvasRef = useRef<HTMLCanvasElement>(null);
13+
const wrapperRef = useRef<HTMLDivElement>(null);
14+
const [size, setSize] = useState({ height: 0, width: 0 });
3115

3216
useLayoutEffect(() => {
3317
const handler = () => {
34-
setIter(iter + 1);
18+
setSize({
19+
height: wrapperRef.current?.offsetHeight ?? 0,
20+
width: wrapperRef.current?.offsetWidth ?? 0,
21+
});
3522
};
36-
if (!window) return;
23+
handler();
24+
if (typeof window === "undefined") return;
3725
window.addEventListener("resize", handler);
3826
return () => {
3927
window.removeEventListener("resize", handler);
4028
};
41-
}, [iter]);
29+
}, [setSize]);
4230

4331
useLayoutEffect(() => {
44-
if (!canvasRef.current) return;
45-
const canvas = canvasRef.current;
46-
47-
const width = canvas.width;
48-
const height = canvas.height;
49-
50-
const ctx = canvas.getContext("2d");
51-
if (!ctx) return;
52-
53-
const planets: Record<string, Astre> = {};
32+
return drawAstres({
33+
astresConfig: [
34+
...generateStars({
35+
rotationSpeed: filledConfig.starsRotationSpeed,
36+
count: filledConfig.starsCount,
37+
color: filledConfig.starsColor,
38+
}),
39+
...generateComet({
40+
frequence: filledConfig.cometFrequence,
41+
}),
42+
...filledConfig.astres,
43+
],
44+
config: filledConfig,
45+
canvas: canvasRef.current as HTMLCanvasElement,
46+
play: true,
47+
});
48+
}, [size]);
5449

55-
const astres = [
56-
...generateStars({
57-
rotationSpeed: filledConfig.starsRotationSpeed,
58-
count: filledConfig.starsCount,
59-
color: filledConfig.starsColor,
60-
}),
61-
...generateNebulas({
50+
useLayoutEffect(() => {
51+
return drawAstres({
52+
astresConfig: generateNebulas({
6253
intensity: filledConfig.nebulasIntensity,
6354
colors: filledConfig.nebulasColors,
6455
}),
65-
...generateComet({
66-
frequence: filledConfig.cometFrequence,
67-
}),
68-
...filledConfig.astres,
69-
];
70-
71-
astres.forEach((astreConfig) => {
72-
const Type = {
73-
star: Star,
74-
galaxy: Galaxy,
75-
planet: Planet,
76-
sun: Sun,
77-
nebula: Nebula,
78-
}[astreConfig.type];
79-
planets[astreConfig.name] = new Type({
80-
ctx,
81-
...astreConfig,
82-
distance: astreConfig.distance * filledConfig.scale,
83-
rgb: parseColor(astreConfig.color),
84-
width: astreConfig.width * filledConfig.scale,
85-
origin: astreConfig.origin ? planets[astreConfig.origin] : undefined,
86-
rotateSpeed: astreConfig.rotateSpeed * filledConfig.speed,
87-
});
56+
config: filledConfig,
57+
canvas: bgCanvasRef.current as HTMLCanvasElement,
58+
play: false,
59+
bgColor: "rgb(8, 8, 8)",
8860
});
61+
}, [size]);
8962

90-
ctx.save();
91-
92-
let animation: number | undefined;
93-
const drawCtx = () => {
94-
ctx.clearRect(0, 0, width, height);
95-
ctx.fillStyle = "rgb(8, 8, 8)";
96-
ctx.fillRect(0, 0, width, height);
97-
Object.values(planets).forEach((planet) => planet.draw());
98-
animation = requestAnimationFrame(drawCtx);
99-
};
100-
101-
drawCtx();
102-
103-
return () => {
104-
ctx.restore();
105-
if (animation) {
106-
cancelAnimationFrame(animation);
107-
}
108-
};
109-
}, [iter]);
110-
111-
if (!window) return <div></div>;
11263
return (
11364
<div
65+
ref={wrapperRef}
11466
style={{
11567
overflow: "hidden",
11668
background: "#0a1929",
11769
height: "100%",
11870
width: "100%",
119-
position: "relative",
71+
position: "absolute",
12072
}}
12173
>
12274
<canvas
123-
width={window.innerWidth}
124-
height={window.innerHeight}
125-
style={{ height: "100%", width: "100%" }}
75+
width={size.width * 2}
76+
height={size.height * 2}
77+
style={{ height: "100%", width: "100%", position: "absolute" }}
78+
ref={bgCanvasRef}
79+
/>
80+
<canvas
81+
width={size.width * 2}
82+
height={size.height * 2}
83+
style={{ height: "100%", width: "100%", position: "absolute" }}
12684
ref={canvasRef}
12785
/>
12886
</div>

src/astres/Nebula.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { Astre } from "src/astres/Astre";
22
import { Drawable } from "src/astres/types";
33

44
export class Nebula extends Astre {
5+
intensity: number;
6+
57
constructor({
68
ctx,
79
width,
@@ -10,6 +12,7 @@ export class Nebula extends Astre {
1012
rgb,
1113
origin,
1214
startAngle = Math.random() * 360,
15+
intensity,
1316
}: {
1417
ctx: CanvasRenderingContext2D;
1518
width: number;
@@ -19,6 +22,7 @@ export class Nebula extends Astre {
1922
origin?: Drawable;
2023
invisible?: boolean;
2124
startAngle?: number;
25+
intensity: number;
2226
}) {
2327
super({
2428
ctx,
@@ -29,12 +33,13 @@ export class Nebula extends Astre {
2933
distance,
3034
rotateSpeed,
3135
});
36+
this.intensity = intensity;
3237
}
3338

3439
draw() {
3540
this.rotate();
3641
this.ctx.beginPath();
37-
this.ctx.arc(...this.getOriginCoords(), this.width * 10, 0, Math.PI * 2);
42+
this.ctx.arc(...this.getOriginCoords(), this.width * 7, 0, Math.PI * 2);
3843
this.ctx.closePath();
3944
this.ctx.shadowBlur = 0;
4045

@@ -44,11 +49,13 @@ export class Nebula extends Astre {
4449
originCoords[1],
4550
0,
4651
...originCoords,
47-
this.width * 10
52+
this.width * 7
4853
);
4954
gradient.addColorStop(
5055
0,
51-
`rgba(${this.rgb[0]}, ${this.rgb[1]}, ${this.rgb[2]}, 0.038)`
56+
`rgba(${this.rgb[0]}, ${this.rgb[1]}, ${this.rgb[2]}, ${
57+
this.intensity / 100
58+
})`
5259
);
5360
gradient.addColorStop(
5461
1,

src/astres/types.ts

+33-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,30 @@
1-
export type AstreDescription = {
1+
export type NubulaDescription = {
2+
type: "nebula";
3+
intensity?: number;
4+
} & BaseAstreDescription;
5+
6+
export type PlanetDescription = {
7+
type: "planet";
8+
intensity?: number;
9+
} & BaseAstreDescription;
10+
11+
export type SunDescription = {
12+
type: "sun";
13+
intensity?: number;
14+
} & BaseAstreDescription;
15+
16+
export type StarDescription = {
17+
type: "star";
18+
intensity?: number;
19+
} & BaseAstreDescription;
20+
21+
export type GalaxyDescription = {
22+
type: "galaxy";
23+
intensity?: number;
24+
} & BaseAstreDescription;
25+
26+
type BaseAstreDescription = {
227
name: string;
3-
type: "galaxy" | "star" | "planet" | "sun" | "nebula";
428
width: number;
529
rotateSpeed: number;
630
distance: number;
@@ -9,6 +33,13 @@ export type AstreDescription = {
933
startAngle?: number;
1034
};
1135

36+
export type AstreDescription =
37+
| NubulaDescription
38+
| PlanetDescription
39+
| SunDescription
40+
| StarDescription
41+
| GalaxyDescription;
42+
1243
export interface Drawable {
1344
draw: () => void;
1445
getOriginCoords: () => [number, number];

0 commit comments

Comments
 (0)