main
Elias Almqvist 8 months ago
parent ae1a514854
commit ac4b24e4a2
No known key found for this signature in database
GPG Key ID: E31A99CE3E75A158
  1. 164
      src/components/3d/curves/thing.ts
  2. 68
      src/components/3d/renderedsection.tsx
  3. 228
      src/components/3d/renderer.tsx
  4. 41
      src/components/ui/card.tsx

@ -1,82 +1,82 @@
"use client"; "use client";
import * as THREE from "three"; import * as THREE from "three";
import { CurveProps } from "../renderer"; import { CurveProps } from "../renderer";
const maxParticles = 20000; const maxParticles = 20000;
const startScatter = 0.1; const startScatter = 0.1;
const init = () => { const init = () => {
var arrayCurve = []; var arrayCurve = [];
var x = 0.01, var x = 0.01,
y = 0.01, y = 0.01,
z = 0.01; z = 0.01;
var a = 0.9; var a = 0.9;
var b = 3.4; var b = 3.4;
var f = 9.9; var f = 9.9;
var g = 1; var g = 1;
var t = 0.001; var t = 0.001;
for (var i = 0; i < maxParticles; i++) { for (var i = 0; i < maxParticles; i++) {
x = x - t * a * x + t * y * y - t * z * z + t * a * f; x = x - t * a * x + t * y * y - t * z * z + t * a * f;
y = y - t * y + t * x * y - t * b * x * z + t * g; y = y - t * y + t * x * y - t * b * x * z + t * g;
z = z - t * z + t * b * x * y + t * x * z; z = z - t * z + t * b * x * y + t * x * z;
arrayCurve.push( arrayCurve.push(
new THREE.Vector3(x, y, z).multiplyScalar( new THREE.Vector3(x, y, z).multiplyScalar(
1 - startScatter / 2 + Math.random() * startScatter, 1 - startScatter / 2 + Math.random() * startScatter,
), ),
); );
} }
return arrayCurve; return arrayCurve;
}; };
const update = (pc: THREE.Points<THREE.BufferGeometry>, group: THREE.Group) => { const update = (pc: THREE.Points<THREE.BufferGeometry>, group: THREE.Group) => {
//Varying the points on each frame //Varying the points on each frame
// step += 0.01; // step += 0.01;
var geometry = pc.geometry; var geometry = pc.geometry;
var a = 0.9; //+ Math.random() * .2; var a = 0.9; //+ Math.random() * .2;
var b = 3.4; //+ Math.random() * .1; var b = 3.4; //+ Math.random() * .1;
var f = 9.9; //+ Math.random() * .2; var f = 9.9; //+ Math.random() * .2;
var g = 1; //+ Math.random() * .1; var g = 1; //+ Math.random() * .1;
var t = 0.001; var t = 0.001;
var positions = geometry.attributes.position; var positions = geometry.attributes.position;
const numPoints = positions.array.length / 3; const numPoints = positions.array.length / 3;
for (let i = 0; i < numPoints; i++) { for (let i = 0; i < numPoints; i++) {
let x = positions.getX(i), let x = positions.getX(i),
y = positions.getY(i), y = positions.getY(i),
z = positions.getZ(i); z = positions.getZ(i);
positions.setXYZ( positions.setXYZ(
i, i,
x - t * a * x + t * y * y - t * z * z + t * a * f, x - t * a * x + t * y * y - t * z * z + t * a * f,
y - t * y + t * x * y - t * b * x * z + t * g, y - t * y + t * x * y - t * b * x * z + t * g,
z - t * z + t * b * x * y + t * x * z, z - t * z + t * b * x * y + t * x * z,
); );
} }
positions.needsUpdate = true; positions.needsUpdate = true;
// TODO: remove // TODO: remove
// group.rotation.x += 0.0005; // group.rotation.x += 0.0005;
// group.rotation.y += 0.001; // group.rotation.y += 0.001;
// group.rotation.z -= 0.0005; // group.rotation.z -= 0.0005;
}; };
// INFO: Curve definition // INFO: Curve definition
const ThingCurve = { const ThingCurve = {
func: { init: init, update: update }, func: { init: init, update: update },
cam: { cam: {
pos: new THREE.Vector3(0, 0, 18).multiplyScalar(1.7), pos: new THREE.Vector3(0, 0, 18).multiplyScalar(1.7),
rotation: new THREE.Vector3(0, 0, 180), rotation: new THREE.Vector3(0, 0, 180),
}, },
particles: { particles: {
max: maxParticles, max: maxParticles,
size: 0.07, size: 0.07,
color: "#888", color: "#888",
darkcolor: "#444", darkcolor: "#444",
opacity: 0.4, opacity: 0.4,
}, // 87a }, // 87a
}; };
export default ThingCurve; export default ThingCurve;

@ -1,34 +1,34 @@
"use client"; "use client";
import React, { ReactNode, HTMLProps } from "react"; import React, { ReactNode, HTMLProps } from "react";
import Renderer, { CurveProps } from "@/components/3d/renderer"; import Renderer, { CurveProps } from "@/components/3d/renderer";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
const RenderedSection: React.FC< const RenderedSection: React.FC<
HTMLProps<HTMLElement> & { HTMLProps<HTMLElement> & {
children?: ReactNode; children?: ReactNode;
evenly?: boolean; evenly?: boolean;
curve: CurveProps; curve: CurveProps;
curveClassname?: string; curveClassname?: string;
} }
> = ({ > = ({
children, children,
className, className,
curveClassname, curveClassname,
evenly = false, evenly = false,
curve, curve,
...props ...props
}) => { }) => {
return ( return (
<div className="flex w-full h-full flex-col items-center align-middle relative"> <div className="flex w-full h-full flex-col items-center align-middle relative">
<div className={cn("absolute", curveClassname)}> <div className={cn("absolute", curveClassname)}>
<Renderer {...curve} /> <Renderer {...curve} />
</div> </div>
<section className={cn("relative", className)} {...props}> <section className={cn("relative", className)} {...props}>
{children} {children}
</section> </section>
</div> </div>
); );
}; };
export default RenderedSection; export default RenderedSection;

@ -1,114 +1,114 @@
"use client"; "use client";
import * as THREE from "three"; import * as THREE from "three";
import React, { ComponentPropsWithRef, useEffect, useRef } from "react"; import React, { ComponentPropsWithRef, useEffect, useRef } from "react";
import { Canvas, useFrame, useThree } from "@react-three/fiber"; import { Canvas, useFrame, useThree } from "@react-three/fiber";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
export type FuncProps = { export type FuncProps = {
init: () => THREE.Vector3[]; init: () => THREE.Vector3[];
update: (pc: THREE.Points<THREE.BufferGeometry>, group: THREE.Group) => void; update: (pc: THREE.Points<THREE.BufferGeometry>, group: THREE.Group) => void;
}; };
export type ParticleProps = { export type ParticleProps = {
max?: number; max?: number;
size?: number; size?: number;
color?: string; color?: string;
darkcolor?: string; darkcolor?: string;
opacity?: number; opacity?: number;
}; };
export type CameraProps = { export type CameraProps = {
pos?: THREE.Vector3; pos?: THREE.Vector3;
lookAt?: THREE.Vector3; lookAt?: THREE.Vector3;
rotation?: THREE.Vector3; rotation?: THREE.Vector3;
}; };
export type CurveProps = { export type CurveProps = {
func: FuncProps; func: FuncProps;
cam?: CameraProps; cam?: CameraProps;
particles?: ParticleProps; particles?: ParticleProps;
}; };
export const FuncRenderer = ({ export const FuncRenderer = ({
func, func,
cam = { cam = {
pos: new THREE.Vector3(0, 0, 0), pos: new THREE.Vector3(0, 0, 0),
lookAt: new THREE.Vector3(0, 0, 0), lookAt: new THREE.Vector3(0, 0, 0),
rotation: new THREE.Vector3(0, 0, 0), rotation: new THREE.Vector3(0, 0, 0),
}, },
particles = { particles = {
max: 10000, max: 10000,
size: 1, size: 1,
color: "#000", color: "#000",
darkcolor: "#fff", darkcolor: "#fff",
opacity: 1, opacity: 1,
}, },
}: CurveProps) => { }: CurveProps) => {
const groupRef = useRef<THREE.Group>(null); const groupRef = useRef<THREE.Group>(null);
const { gl, camera } = useThree(); const { gl, camera } = useThree();
const { theme } = useTheme(); const { theme } = useTheme();
const isDarkMode = theme === "dark"; const isDarkMode = theme === "dark";
useEffect(() => { useEffect(() => {
if (cam.pos) camera.position.copy(cam.pos); if (cam.pos) camera.position.copy(cam.pos);
if (cam.lookAt) camera.lookAt(cam.lookAt); if (cam.lookAt) camera.lookAt(cam.lookAt);
if (cam.rotation) { if (cam.rotation) {
camera.rotateX(cam.rotation.x); camera.rotateX(cam.rotation.x);
camera.rotateY(cam.rotation.y); camera.rotateY(cam.rotation.y);
camera.rotateZ(cam.rotation.z); camera.rotateZ(cam.rotation.z);
} }
// Initialize and set up the points on mount // Initialize and set up the points on mount
if (groupRef.current) { if (groupRef.current) {
const arrayCurve = func.init(); const arrayCurve = func.init();
const romCurve = new THREE.CatmullRomCurve3(arrayCurve); const romCurve = new THREE.CatmullRomCurve3(arrayCurve);
const points = romCurve.getPoints(particles.max); const points = romCurve.getPoints(particles.max);
const geometry = new THREE.BufferGeometry().setFromPoints(points); const geometry = new THREE.BufferGeometry().setFromPoints(points);
const pcMat = new THREE.PointsMaterial({ const pcMat = new THREE.PointsMaterial({
size: particles.size, size: particles.size,
color: isDarkMode ? particles.darkcolor : particles.color, color: isDarkMode ? particles.darkcolor : particles.color,
opacity: particles.opacity, opacity: particles.opacity,
transparent: true, transparent: true,
}); });
// pcMat.blending = THREE.AdditiveBlending; // pcMat.blending = THREE.AdditiveBlending;
const pc = new THREE.Points(geometry, pcMat); const pc = new THREE.Points(geometry, pcMat);
groupRef.current.add(pc); groupRef.current.add(pc);
} }
return () => { return () => {
// Clean up any resources if needed // Clean up any resources if needed
}; };
}, [cam, func, particles, camera, isDarkMode]); }, [cam, func, particles, camera, isDarkMode]);
useFrame(() => { useFrame(() => {
gl.setPixelRatio(window.devicePixelRatio); gl.setPixelRatio(window.devicePixelRatio);
if (groupRef.current && groupRef.current.children.length > 0) { if (groupRef.current && groupRef.current.children.length > 0) {
const pc = groupRef.current.children[0] as THREE.Points; const pc = groupRef.current.children[0] as THREE.Points;
if (pc.geometry) { if (pc.geometry) {
func.update(pc, groupRef.current); func.update(pc, groupRef.current);
} }
} }
}); });
return <group ref={groupRef} />; return <group ref={groupRef} />;
}; };
const Renderer: React.FC< const Renderer: React.FC<
ComponentPropsWithRef<typeof FuncRenderer> & { ComponentPropsWithRef<typeof FuncRenderer> & {
cam?: CameraProps; cam?: CameraProps;
} }
> = ({ cam = { pos: new THREE.Vector3(0, 0, 0) }, ...props }) => { > = ({ cam = { pos: new THREE.Vector3(0, 0, 0) }, ...props }) => {
return ( return (
<Canvas gl={{ alpha: true }} className="transform"> <Canvas gl={{ alpha: true }} className="transform">
<pointLight position={[0, 0, 0]} color="#fff" /> <pointLight position={[0, 0, 0]} color="#fff" />
<perspectiveCamera position={cam.pos} /> <perspectiveCamera position={cam.pos} />
<FuncRenderer cam={cam} {...props} /> <FuncRenderer cam={cam} {...props} />
</Canvas> </Canvas>
); );
}; };
export default Renderer; export default Renderer;

@ -1,6 +1,6 @@
import * as React from "react" import * as React from "react";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
const Card = React.forwardRef< const Card = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -10,12 +10,12 @@ const Card = React.forwardRef<
ref={ref} ref={ref}
className={cn( className={cn(
"rounded-lg border bg-card text-card-foreground shadow-sm", "rounded-lg border bg-card text-card-foreground shadow-sm",
className className,
)} )}
{...props} {...props}
/> />
)) ));
Card.displayName = "Card" Card.displayName = "Card";
const CardHeader = React.forwardRef< const CardHeader = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -26,8 +26,8 @@ const CardHeader = React.forwardRef<
className={cn("flex flex-col space-y-1.5 p-6", className)} className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props} {...props}
/> />
)) ));
CardHeader.displayName = "CardHeader" CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef< const CardTitle = React.forwardRef<
HTMLParagraphElement, HTMLParagraphElement,
@ -37,12 +37,12 @@ const CardTitle = React.forwardRef<
ref={ref} ref={ref}
className={cn( className={cn(
"text-2xl font-semibold leading-none tracking-tight", "text-2xl font-semibold leading-none tracking-tight",
className className,
)} )}
{...props} {...props}
/> />
)) ));
CardTitle.displayName = "CardTitle" CardTitle.displayName = "CardTitle";
const CardDescription = React.forwardRef< const CardDescription = React.forwardRef<
HTMLParagraphElement, HTMLParagraphElement,
@ -53,16 +53,16 @@ const CardDescription = React.forwardRef<
className={cn("text-sm text-muted-foreground", className)} className={cn("text-sm text-muted-foreground", className)}
{...props} {...props}
/> />
)) ));
CardDescription.displayName = "CardDescription" CardDescription.displayName = "CardDescription";
const CardContent = React.forwardRef< const CardContent = React.forwardRef<
HTMLDivElement, HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} /> <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
)) ));
CardContent.displayName = "CardContent" CardContent.displayName = "CardContent";
const CardFooter = React.forwardRef< const CardFooter = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -73,7 +73,14 @@ const CardFooter = React.forwardRef<
className={cn("flex items-center p-6 pt-0", className)} className={cn("flex items-center p-6 pt-0", className)}
{...props} {...props}
/> />
)) ));
CardFooter.displayName = "CardFooter" CardFooter.displayName = "CardFooter";
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
};

Loading…
Cancel
Save