@stackvibe-studio/three 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -0
- package/dist/components/orb-cluster.d.ts +6 -0
- package/dist/components/wave-canvas.d.ts +6 -0
- package/dist/index.cjs +106 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +94 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @stackvibe-studio/three
|
|
2
|
+
|
|
3
|
+
Product-grade 3D visual primitives, canvas environments, and WebGL components built with Three.js and React Three Fiber.
|
|
4
|
+
|
|
5
|
+
Designed for immersive hero sections, interactive landing page surfaces, and futuristic product cards with smooth 60fps animations.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@stackvibe-studio/three)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **WaveCanvas**: WebGL undulating sinusoidal mesh and wave canvas with dynamic light physics.
|
|
13
|
+
- **Glass3DCard**: Glassmorphism-style 3D card wrapper with realistic specular reflection and tilt.
|
|
14
|
+
- **FloatingSphere**: Physics-based floating sphere with ambient lighting and rotation.
|
|
15
|
+
- **OrbCluster**: Multi-layered 3D orb cluster designed for ambient hero backgrounds.
|
|
16
|
+
- **Zero layout shift**: Fully responsive canvas containers with graceful fallback rendering.
|
|
17
|
+
- **Framework agnostic**: Works with Next.js (App Router & Pages Router), Vite, Remix, and Gatsby.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add @stackvibe-studio/three three @react-three/fiber @react-three/drei
|
|
23
|
+
# or
|
|
24
|
+
npm install @stackvibe-studio/three three @react-three/fiber @react-three/drei
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### WaveCanvas (Hero Backgrounds)
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { WaveCanvas } from '@stackvibe-studio/three';
|
|
33
|
+
|
|
34
|
+
export function HeroSection() {
|
|
35
|
+
return (
|
|
36
|
+
<div className="relative h-[500px] w-full overflow-hidden rounded-2xl bg-zinc-950">
|
|
37
|
+
<WaveCanvas
|
|
38
|
+
wireframe={false}
|
|
39
|
+
speed={1.2}
|
|
40
|
+
color="#6366f1"
|
|
41
|
+
className="absolute inset-0"
|
|
42
|
+
/>
|
|
43
|
+
<div className="relative z-10 flex h-full flex-col items-center justify-center text-center p-8">
|
|
44
|
+
<h1 className="text-4xl font-bold text-white">Next-Gen Interface Canvas</h1>
|
|
45
|
+
<p className="mt-2 text-zinc-400">Interactive 3D surfaces rendered in real-time WebGL.</p>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Glass3DCard & OrbCluster
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { Glass3DCard, OrbCluster } from '@stackvibe-studio/three';
|
|
56
|
+
|
|
57
|
+
export function FeatureCard() {
|
|
58
|
+
return (
|
|
59
|
+
<div className="relative flex items-center justify-center p-12">
|
|
60
|
+
<OrbCluster className="absolute inset-0 pointer-events-none opacity-60" />
|
|
61
|
+
<Glass3DCard className="w-80 h-96 p-6">
|
|
62
|
+
<h3 className="text-xl font-bold text-white">Pro Access</h3>
|
|
63
|
+
<p className="text-zinc-400 mt-2">Enterprise-grade WebGL rendering primitives.</p>
|
|
64
|
+
</Glass3DCard>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Components Reference
|
|
71
|
+
|
|
72
|
+
| Component | Description | Props |
|
|
73
|
+
| :--- | :--- | :--- |
|
|
74
|
+
| `WaveCanvas` | Real-time undulating 3D sine-wave plane | `wireframe?: boolean`, `speed?: number`, `color?: string`, `className?: string` |
|
|
75
|
+
| `Glass3DCard` | 3D glass card with reflective lighting | `children?: ReactNode`, `className?: string` |
|
|
76
|
+
| `FloatingSphere` | Autonomous 3D floating orb with glow | `color?: string`, `wireframe?: boolean`, `className?: string` |
|
|
77
|
+
| `OrbCluster` | Ambient particle cluster with floating orbs | `count?: number`, `className?: string` |
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
MIT © [StackVibe Studio](https://github.com/StackVibe-Studio/stackvibe-ui)
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __create = Object.create;
|
|
2
4
|
var __defProp = Object.defineProperty;
|
|
3
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
9
|
var __export = (target, all) => {
|
|
7
10
|
for (var name in all)
|
|
@@ -15,13 +18,23 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
18
|
}
|
|
16
19
|
return to;
|
|
17
20
|
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
18
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
30
|
|
|
20
31
|
// src/index.ts
|
|
21
32
|
var index_exports = {};
|
|
22
33
|
__export(index_exports, {
|
|
23
34
|
FloatingSphere: () => FloatingSphere,
|
|
24
|
-
Glass3DCard: () => Glass3DCard
|
|
35
|
+
Glass3DCard: () => Glass3DCard,
|
|
36
|
+
OrbCluster: () => OrbCluster,
|
|
37
|
+
WaveCanvas: () => WaveCanvas
|
|
25
38
|
});
|
|
26
39
|
module.exports = __toCommonJS(index_exports);
|
|
27
40
|
|
|
@@ -92,8 +105,99 @@ function Glass3DCard({
|
|
|
92
105
|
!interactive ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.08),transparent_55%)]" })
|
|
93
106
|
] });
|
|
94
107
|
}
|
|
108
|
+
|
|
109
|
+
// src/components/orb-cluster.tsx
|
|
110
|
+
var import_drei3 = require("@react-three/drei");
|
|
111
|
+
var import_fiber3 = require("@react-three/fiber");
|
|
112
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
113
|
+
function OrbCluster({
|
|
114
|
+
colors = ["#8b5cf6", "#22d3ee", "#f472b6", "#34d399"],
|
|
115
|
+
scale = 1,
|
|
116
|
+
speed = 1.2
|
|
117
|
+
}) {
|
|
118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "h-72 w-full overflow-hidden rounded-[2rem] border border-white/10 bg-slate-950/80", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_fiber3.Canvas, { camera: { position: [0, 0, 6] }, children: [
|
|
119
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ambientLight", { intensity: 1.2 }),
|
|
120
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("directionalLight", { position: [3, 3, 3], intensity: 1.5 }),
|
|
121
|
+
colors.map((color, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
122
|
+
import_drei3.Float,
|
|
123
|
+
{
|
|
124
|
+
speed: speed + index * 0.2,
|
|
125
|
+
rotationIntensity: 1.2,
|
|
126
|
+
floatIntensity: 2,
|
|
127
|
+
position: [(index - 1.5) * 1.6, (index % 2 === 0 ? 1 : -1) * 0.7, -1],
|
|
128
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_drei3.Sphere, { args: [0.8, 48, 48], scale: scale * (index === 0 ? 1.1 : 0.8), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
129
|
+
import_drei3.MeshDistortMaterial,
|
|
130
|
+
{
|
|
131
|
+
color,
|
|
132
|
+
roughness: 0.15,
|
|
133
|
+
metalness: 0.5,
|
|
134
|
+
distort: 0.35,
|
|
135
|
+
speed: 2,
|
|
136
|
+
transparent: true,
|
|
137
|
+
opacity: 0.82
|
|
138
|
+
}
|
|
139
|
+
) })
|
|
140
|
+
},
|
|
141
|
+
color + index
|
|
142
|
+
))
|
|
143
|
+
] }) });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/components/wave-canvas.tsx
|
|
147
|
+
var import_fiber4 = require("@react-three/fiber");
|
|
148
|
+
var import_react = require("react");
|
|
149
|
+
var THREE = __toESM(require("three"), 1);
|
|
150
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
151
|
+
function WaveMesh({ color = "#8b5cf6", wireframe = false }) {
|
|
152
|
+
const meshRef = (0, import_react.useRef)(null);
|
|
153
|
+
const { positions, originalZ } = (0, import_react.useMemo)(() => {
|
|
154
|
+
const geo = new THREE.PlaneGeometry(6, 6, 32, 32);
|
|
155
|
+
const pos = geo.attributes.position;
|
|
156
|
+
const orig = new Float32Array(pos.count);
|
|
157
|
+
for (let i = 0; i < pos.count; i++) {
|
|
158
|
+
orig[i] = pos.getZ(i);
|
|
159
|
+
}
|
|
160
|
+
return { positions: pos, originalZ: orig };
|
|
161
|
+
}, []);
|
|
162
|
+
(0, import_fiber4.useFrame)(({ clock }) => {
|
|
163
|
+
if (!meshRef.current) return;
|
|
164
|
+
const t = clock.getElapsedTime() * 1.5;
|
|
165
|
+
const geom = meshRef.current.geometry;
|
|
166
|
+
const pos = geom.attributes.position;
|
|
167
|
+
for (let i = 0; i < pos.count; i++) {
|
|
168
|
+
const u = pos.getX(i);
|
|
169
|
+
const v = pos.getY(i);
|
|
170
|
+
const z = Math.sin(u * 1.5 + t) * 0.25 + Math.cos(v * 1.5 + t) * 0.25;
|
|
171
|
+
pos.setZ(i, z);
|
|
172
|
+
}
|
|
173
|
+
pos.needsUpdate = true;
|
|
174
|
+
});
|
|
175
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("mesh", { ref: meshRef, rotation: [-Math.PI / 3, 0, 0], children: [
|
|
176
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("planeGeometry", { args: [6, 6, 32, 32] }),
|
|
177
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
178
|
+
"meshStandardMaterial",
|
|
179
|
+
{
|
|
180
|
+
color,
|
|
181
|
+
wireframe,
|
|
182
|
+
roughness: 0.3,
|
|
183
|
+
metalness: 0.5,
|
|
184
|
+
side: THREE.DoubleSide
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
] });
|
|
188
|
+
}
|
|
189
|
+
function WaveCanvas({ color = "#8b5cf6", wireframe = false, className = "" }) {
|
|
190
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: ["h-64 w-full rounded-3xl overflow-hidden bg-slate-950/50", className].join(" "), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_fiber4.Canvas, { camera: { position: [0, -1, 3], fov: 60 }, children: [
|
|
191
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ambientLight", { intensity: 0.8 }),
|
|
192
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("directionalLight", { position: [3, 5, 4], intensity: 1.5 }),
|
|
193
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pointLight", { position: [-3, -3, 2], intensity: 0.5, color: "#22d3ee" }),
|
|
194
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WaveMesh, { color, wireframe })
|
|
195
|
+
] }) });
|
|
196
|
+
}
|
|
95
197
|
// Annotate the CommonJS export names for ESM import in node:
|
|
96
198
|
0 && (module.exports = {
|
|
97
199
|
FloatingSphere,
|
|
98
|
-
Glass3DCard
|
|
200
|
+
Glass3DCard,
|
|
201
|
+
OrbCluster,
|
|
202
|
+
WaveCanvas
|
|
99
203
|
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
// src/components/floating-sphere.tsx
|
|
2
4
|
import { Float, MeshDistortMaterial, Sphere } from "@react-three/drei";
|
|
3
5
|
import { Canvas } from "@react-three/fiber";
|
|
@@ -65,7 +67,98 @@ function Glass3DCard({
|
|
|
65
67
|
!interactive ? null : /* @__PURE__ */ jsx2("div", { className: "pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.08),transparent_55%)]" })
|
|
66
68
|
] });
|
|
67
69
|
}
|
|
70
|
+
|
|
71
|
+
// src/components/orb-cluster.tsx
|
|
72
|
+
import { Float as Float3, MeshDistortMaterial as MeshDistortMaterial2, Sphere as Sphere2 } from "@react-three/drei";
|
|
73
|
+
import { Canvas as Canvas3 } from "@react-three/fiber";
|
|
74
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
75
|
+
function OrbCluster({
|
|
76
|
+
colors = ["#8b5cf6", "#22d3ee", "#f472b6", "#34d399"],
|
|
77
|
+
scale = 1,
|
|
78
|
+
speed = 1.2
|
|
79
|
+
}) {
|
|
80
|
+
return /* @__PURE__ */ jsx3("div", { className: "h-72 w-full overflow-hidden rounded-[2rem] border border-white/10 bg-slate-950/80", children: /* @__PURE__ */ jsxs3(Canvas3, { camera: { position: [0, 0, 6] }, children: [
|
|
81
|
+
/* @__PURE__ */ jsx3("ambientLight", { intensity: 1.2 }),
|
|
82
|
+
/* @__PURE__ */ jsx3("directionalLight", { position: [3, 3, 3], intensity: 1.5 }),
|
|
83
|
+
colors.map((color, index) => /* @__PURE__ */ jsx3(
|
|
84
|
+
Float3,
|
|
85
|
+
{
|
|
86
|
+
speed: speed + index * 0.2,
|
|
87
|
+
rotationIntensity: 1.2,
|
|
88
|
+
floatIntensity: 2,
|
|
89
|
+
position: [(index - 1.5) * 1.6, (index % 2 === 0 ? 1 : -1) * 0.7, -1],
|
|
90
|
+
children: /* @__PURE__ */ jsx3(Sphere2, { args: [0.8, 48, 48], scale: scale * (index === 0 ? 1.1 : 0.8), children: /* @__PURE__ */ jsx3(
|
|
91
|
+
MeshDistortMaterial2,
|
|
92
|
+
{
|
|
93
|
+
color,
|
|
94
|
+
roughness: 0.15,
|
|
95
|
+
metalness: 0.5,
|
|
96
|
+
distort: 0.35,
|
|
97
|
+
speed: 2,
|
|
98
|
+
transparent: true,
|
|
99
|
+
opacity: 0.82
|
|
100
|
+
}
|
|
101
|
+
) })
|
|
102
|
+
},
|
|
103
|
+
color + index
|
|
104
|
+
))
|
|
105
|
+
] }) });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/components/wave-canvas.tsx
|
|
109
|
+
import { Canvas as Canvas4, useFrame } from "@react-three/fiber";
|
|
110
|
+
import { useRef, useMemo } from "react";
|
|
111
|
+
import * as THREE from "three";
|
|
112
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
113
|
+
function WaveMesh({ color = "#8b5cf6", wireframe = false }) {
|
|
114
|
+
const meshRef = useRef(null);
|
|
115
|
+
const { positions, originalZ } = useMemo(() => {
|
|
116
|
+
const geo = new THREE.PlaneGeometry(6, 6, 32, 32);
|
|
117
|
+
const pos = geo.attributes.position;
|
|
118
|
+
const orig = new Float32Array(pos.count);
|
|
119
|
+
for (let i = 0; i < pos.count; i++) {
|
|
120
|
+
orig[i] = pos.getZ(i);
|
|
121
|
+
}
|
|
122
|
+
return { positions: pos, originalZ: orig };
|
|
123
|
+
}, []);
|
|
124
|
+
useFrame(({ clock }) => {
|
|
125
|
+
if (!meshRef.current) return;
|
|
126
|
+
const t = clock.getElapsedTime() * 1.5;
|
|
127
|
+
const geom = meshRef.current.geometry;
|
|
128
|
+
const pos = geom.attributes.position;
|
|
129
|
+
for (let i = 0; i < pos.count; i++) {
|
|
130
|
+
const u = pos.getX(i);
|
|
131
|
+
const v = pos.getY(i);
|
|
132
|
+
const z = Math.sin(u * 1.5 + t) * 0.25 + Math.cos(v * 1.5 + t) * 0.25;
|
|
133
|
+
pos.setZ(i, z);
|
|
134
|
+
}
|
|
135
|
+
pos.needsUpdate = true;
|
|
136
|
+
});
|
|
137
|
+
return /* @__PURE__ */ jsxs4("mesh", { ref: meshRef, rotation: [-Math.PI / 3, 0, 0], children: [
|
|
138
|
+
/* @__PURE__ */ jsx4("planeGeometry", { args: [6, 6, 32, 32] }),
|
|
139
|
+
/* @__PURE__ */ jsx4(
|
|
140
|
+
"meshStandardMaterial",
|
|
141
|
+
{
|
|
142
|
+
color,
|
|
143
|
+
wireframe,
|
|
144
|
+
roughness: 0.3,
|
|
145
|
+
metalness: 0.5,
|
|
146
|
+
side: THREE.DoubleSide
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
] });
|
|
150
|
+
}
|
|
151
|
+
function WaveCanvas({ color = "#8b5cf6", wireframe = false, className = "" }) {
|
|
152
|
+
return /* @__PURE__ */ jsx4("div", { className: ["h-64 w-full rounded-3xl overflow-hidden bg-slate-950/50", className].join(" "), children: /* @__PURE__ */ jsxs4(Canvas4, { camera: { position: [0, -1, 3], fov: 60 }, children: [
|
|
153
|
+
/* @__PURE__ */ jsx4("ambientLight", { intensity: 0.8 }),
|
|
154
|
+
/* @__PURE__ */ jsx4("directionalLight", { position: [3, 5, 4], intensity: 1.5 }),
|
|
155
|
+
/* @__PURE__ */ jsx4("pointLight", { position: [-3, -3, 2], intensity: 0.5, color: "#22d3ee" }),
|
|
156
|
+
/* @__PURE__ */ jsx4(WaveMesh, { color, wireframe })
|
|
157
|
+
] }) });
|
|
158
|
+
}
|
|
68
159
|
export {
|
|
69
160
|
FloatingSphere,
|
|
70
|
-
Glass3DCard
|
|
161
|
+
Glass3DCard,
|
|
162
|
+
OrbCluster,
|
|
163
|
+
WaveCanvas
|
|
71
164
|
};
|