pni 1.0.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/dist/add-three-app.d.ts +6 -0
- package/dist/add-three-app.js +111 -0
- package/dist/app.d.ts +11 -0
- package/dist/app.js +143 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +71 -0
- package/dist/components/FeatureSelector.d.ts +21 -0
- package/dist/components/FeatureSelector.js +175 -0
- package/dist/components/ProgressIndicator.d.ts +7 -0
- package/dist/components/ProgressIndicator.js +46 -0
- package/dist/components/Summary.d.ts +8 -0
- package/dist/components/Summary.js +51 -0
- package/dist/components/WelcomeHeader.d.ts +2 -0
- package/dist/components/WelcomeHeader.js +8 -0
- package/dist/template_code/three/README.md +146 -0
- package/dist/template_code/three/World.js +133 -0
- package/dist/template_code/three/camera.js +30 -0
- package/dist/template_code/three/components/GlobeSphere.js +608 -0
- package/dist/template_code/three/components/cube.js +27 -0
- package/dist/template_code/three/components/lights.js +16 -0
- package/dist/template_code/three/components/sphere.js +26 -0
- package/dist/template_code/three/components/torus.js +25 -0
- package/dist/template_code/three/scene.js +28 -0
- package/dist/template_code/three/systems/Loop.js +43 -0
- package/dist/template_code/three/systems/Resizer.js +26 -0
- package/dist/template_code/three/systems/controls.js +19 -0
- package/dist/template_code/three/systems/post-processing.js +50 -0
- package/dist/template_code/three/systems/renderer.js +17 -0
- package/dist/template_code/three/utils/deviceDetector.js +141 -0
- package/dist/template_code/three/utils/gltfLoader.js +14 -0
- package/dist/template_code/three/utils/loadKTX2Texture.js +42 -0
- package/dist/template_code/three/utils/textureLoader.js +21 -0
- package/dist/utils/add-three.d.ts +7 -0
- package/dist/utils/add-three.js +288 -0
- package/dist/utils/app-creation.d.ts +4 -0
- package/dist/utils/app-creation.js +35 -0
- package/dist/utils/config-generator.d.ts +6 -0
- package/dist/utils/config-generator.js +508 -0
- package/dist/utils/css-variables.d.ts +4 -0
- package/dist/utils/css-variables.js +316 -0
- package/dist/utils/dependencies.d.ts +11 -0
- package/dist/utils/dependencies.js +68 -0
- package/dist/utils/package-manager.d.ts +4 -0
- package/dist/utils/package-manager.js +56 -0
- package/dist/utils/project-detection.d.ts +2 -0
- package/dist/utils/project-detection.js +60 -0
- package/dist/utils/shadcn-setup.d.ts +2 -0
- package/dist/utils/shadcn-setup.js +46 -0
- package/package.json +81 -0
- package/readme.md +119 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text, Box } from 'ink';
|
|
3
|
+
export default function Summary({ features, projectPath }) {
|
|
4
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
5
|
+
React.createElement(Box, { borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, marginBottom: 1 },
|
|
6
|
+
React.createElement(Text, { color: "green", bold: true }, "\u2728 Setup Complete!")),
|
|
7
|
+
React.createElement(Box, { flexDirection: "column", paddingLeft: 1 },
|
|
8
|
+
React.createElement(Text, { color: "cyan", bold: true }, "\uD83D\uDCCB Project Summary"),
|
|
9
|
+
React.createElement(Text, null, " "),
|
|
10
|
+
React.createElement(Box, { flexDirection: "column", paddingLeft: 2 },
|
|
11
|
+
React.createElement(Text, null,
|
|
12
|
+
React.createElement(Text, { color: "magenta" }, "Project Type:"),
|
|
13
|
+
" ",
|
|
14
|
+
React.createElement(Text, { color: "green", bold: true }, features.projectType)),
|
|
15
|
+
features.projectName && (React.createElement(Text, null,
|
|
16
|
+
React.createElement(Text, { color: "magenta" }, "Project Name:"),
|
|
17
|
+
" ",
|
|
18
|
+
React.createElement(Text, { color: "green", bold: true }, features.projectName))),
|
|
19
|
+
React.createElement(Text, null,
|
|
20
|
+
React.createElement(Text, { color: "magenta" }, "Three.js:"),
|
|
21
|
+
" ",
|
|
22
|
+
React.createElement(Text, { color: features.threejs ? 'green' : 'gray', bold: true }, features.threejs ? 'Yes' : 'No')),
|
|
23
|
+
React.createElement(Text, null,
|
|
24
|
+
React.createElement(Text, { color: "magenta" }, "CSS Variables:"),
|
|
25
|
+
" ",
|
|
26
|
+
React.createElement(Text, { color: "green", bold: true }, "Yes"),
|
|
27
|
+
" ",
|
|
28
|
+
React.createElement(Text, { color: "gray" }, "(auto-generated)")),
|
|
29
|
+
React.createElement(Text, null,
|
|
30
|
+
React.createElement(Text, { color: "magenta" }, "Project Path:"),
|
|
31
|
+
" ",
|
|
32
|
+
React.createElement(Text, { color: "white" }, projectPath))),
|
|
33
|
+
React.createElement(Text, null, " "),
|
|
34
|
+
React.createElement(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, paddingY: 1 },
|
|
35
|
+
React.createElement(Text, { color: "cyan", bold: true }, "\uD83D\uDE80 Next Steps"),
|
|
36
|
+
React.createElement(Text, null, " "),
|
|
37
|
+
React.createElement(Box, { flexDirection: "column", paddingLeft: 2 },
|
|
38
|
+
React.createElement(Text, null,
|
|
39
|
+
React.createElement(Text, { color: "yellow" }, "1."),
|
|
40
|
+
" ",
|
|
41
|
+
React.createElement(Text, { color: "white" }, "cd "),
|
|
42
|
+
React.createElement(Text, { color: "green", bold: true }, features.projectName || projectPath)),
|
|
43
|
+
React.createElement(Text, null,
|
|
44
|
+
React.createElement(Text, { color: "yellow" }, "2."),
|
|
45
|
+
" ",
|
|
46
|
+
React.createElement(Text, { color: "white" }, "Install dependencies (if not already done)")),
|
|
47
|
+
React.createElement(Text, null,
|
|
48
|
+
React.createElement(Text, { color: "yellow" }, "3."),
|
|
49
|
+
" ",
|
|
50
|
+
React.createElement(Text, { color: "white" }, "Start development server")))))));
|
|
51
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text, Box } from 'ink';
|
|
3
|
+
export default function WelcomeHeader() {
|
|
4
|
+
return (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
|
|
5
|
+
React.createElement(Box, { borderStyle: "double", borderColor: "cyan", paddingX: 2, paddingY: 1 },
|
|
6
|
+
React.createElement(Text, { color: "magenta", bold: true }, "\uD83D\uDE80 PNI - Project Setup CLI"),
|
|
7
|
+
React.createElement(Text, { color: "gray" }, "Nuxt/Vue + Three.js + CSS Variables"))));
|
|
8
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Three.js Setup for Nuxt
|
|
2
|
+
|
|
3
|
+
A professional, modular Three.js setup optimized for Nuxt 3 applications with proper cleanup and developer-friendly patterns.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
three/
|
|
9
|
+
├── World.js # Main Three.js world orchestrator
|
|
10
|
+
├── camera.js # Camera configuration
|
|
11
|
+
├── scene.js # Scene setup with meshes
|
|
12
|
+
├── components/ # 3D objects/meshes
|
|
13
|
+
│ ├── cube.js # Rotating cube
|
|
14
|
+
│ ├── torus.js # Animated torus
|
|
15
|
+
│ ├── sphere.js # Floating sphere
|
|
16
|
+
│ └── lights.js # Scene lighting
|
|
17
|
+
├── systems/ # Core Three.js systems
|
|
18
|
+
│ ├── renderer.js # WebGL renderer
|
|
19
|
+
│ ├── Loop.js # Animation loop
|
|
20
|
+
│ ├── Resizer.js # Responsive canvas
|
|
21
|
+
│ ├── controls.js # Camera controls
|
|
22
|
+
│ └── post-processing.js # Post-processing effects
|
|
23
|
+
└── utils/ # Utility functions
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage in Nuxt
|
|
27
|
+
|
|
28
|
+
### Basic Setup
|
|
29
|
+
|
|
30
|
+
```vue
|
|
31
|
+
<script setup lang="ts">
|
|
32
|
+
import {ref} from 'vue';
|
|
33
|
+
import {useThree} from '@/composables/useThree';
|
|
34
|
+
|
|
35
|
+
const webglContainer = ref<HTMLElement | null>(null);
|
|
36
|
+
const {world, isLoading, error} = useThree(webglContainer);
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<div ref="webglContainer" class="webgl-container">
|
|
41
|
+
<div v-if="isLoading">Loading 3D Scene...</div>
|
|
42
|
+
<div v-if="error">Error: {{ error.message }}</div>
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<style scoped>
|
|
47
|
+
.webgl-container {
|
|
48
|
+
position: fixed;
|
|
49
|
+
width: 100%;
|
|
50
|
+
height: 100%;
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
- ✅ **Proper Cleanup**: Automatic disposal of resources on component unmount
|
|
58
|
+
- ✅ **SSR Safe**: Works with Nuxt's server-side rendering
|
|
59
|
+
- ✅ **Modular**: Easy to add/remove 3D objects
|
|
60
|
+
- ✅ **Performance**: Optimized renderer settings and animation loop
|
|
61
|
+
- ✅ **Responsive**: Auto-resize handling
|
|
62
|
+
- ✅ **Post-processing**: Built-in effects (SMAA, noise, bloom)
|
|
63
|
+
- ✅ **Developer Friendly**: TypeScript support via composable
|
|
64
|
+
|
|
65
|
+
## Adding New Objects
|
|
66
|
+
|
|
67
|
+
Create a new file in `components/`:
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
// components/myMesh.js
|
|
71
|
+
import {BoxGeometry, Mesh, MeshStandardMaterial} from 'three';
|
|
72
|
+
|
|
73
|
+
function createMyMesh() {
|
|
74
|
+
const geometry = new BoxGeometry(1, 1, 1);
|
|
75
|
+
const material = new MeshStandardMaterial({color: '#ff0000'});
|
|
76
|
+
const mesh = new Mesh(geometry, material);
|
|
77
|
+
|
|
78
|
+
// Optional: Add animation
|
|
79
|
+
mesh.tick = delta => {
|
|
80
|
+
mesh.rotation.y += delta;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return mesh;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export {createMyMesh};
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Then add it to `scene.js`:
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
import { createMyMesh } from './components/myMesh.js';
|
|
93
|
+
|
|
94
|
+
function createScene() {
|
|
95
|
+
// ...
|
|
96
|
+
const myMesh = createMyMesh();
|
|
97
|
+
scene.add(myMesh);
|
|
98
|
+
|
|
99
|
+
// Add to updatables if it has tick method
|
|
100
|
+
scene.userData.updatables = [..., myMesh];
|
|
101
|
+
// ...
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Performance Tips
|
|
106
|
+
|
|
107
|
+
1. **Pixel Ratio**: Automatically capped at 2 for performance
|
|
108
|
+
2. **Animation Loop**: Uses `requestAnimationFrame` via Three.js
|
|
109
|
+
3. **Proper Disposal**: All resources cleaned up on unmount
|
|
110
|
+
4. **Post-processing**: Can be disabled for better performance
|
|
111
|
+
|
|
112
|
+
## Customization
|
|
113
|
+
|
|
114
|
+
### Adjust Camera
|
|
115
|
+
|
|
116
|
+
Edit `camera.js`:
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
camera.position.set(x, y, z);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Modify Controls
|
|
123
|
+
|
|
124
|
+
Edit `systems/controls.js`:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
controls.autoRotate = true;
|
|
128
|
+
controls.autoRotateSpeed = 2;
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Change Background
|
|
132
|
+
|
|
133
|
+
Edit `scene.js`:
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
scene.background = new Color('#yourcolor');
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Toggle Post-processing
|
|
140
|
+
|
|
141
|
+
Comment out in `World.js`:
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
// this.composer = createPostprocessing(...)
|
|
145
|
+
// Use this.renderer.render() instead of this.composer.render()
|
|
146
|
+
```
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {camera} from './camera.js';
|
|
2
|
+
import {createScene} from './scene.js';
|
|
3
|
+
import {createControls} from './systems/controls.js';
|
|
4
|
+
import {createRenderer} from './systems/renderer.js';
|
|
5
|
+
import {Resizer} from './systems/Resizer.js';
|
|
6
|
+
import {Loop} from './systems/Loop.js';
|
|
7
|
+
import {createPostprocessing} from './systems/post-processing.js';
|
|
8
|
+
|
|
9
|
+
class World {
|
|
10
|
+
constructor(container) {
|
|
11
|
+
this.container = container;
|
|
12
|
+
this.camera = camera;
|
|
13
|
+
this.scene = null;
|
|
14
|
+
this.renderer = createRenderer();
|
|
15
|
+
this.loop = null;
|
|
16
|
+
this.controls = null;
|
|
17
|
+
this.resizer = null;
|
|
18
|
+
this.composer = null;
|
|
19
|
+
|
|
20
|
+
// Append canvas to container
|
|
21
|
+
container.append(this.renderer.domElement);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
init() {
|
|
25
|
+
// Create scene
|
|
26
|
+
this.scene = createScene();
|
|
27
|
+
|
|
28
|
+
// Create controls
|
|
29
|
+
this.controls = createControls(this.camera, this.renderer.domElement);
|
|
30
|
+
|
|
31
|
+
// Create post-processing composer
|
|
32
|
+
this.composer = createPostprocessing(
|
|
33
|
+
this.scene,
|
|
34
|
+
this.camera,
|
|
35
|
+
this.renderer,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Create loop
|
|
39
|
+
this.loop = new Loop(this.camera, this.scene, this.renderer, this.composer);
|
|
40
|
+
|
|
41
|
+
// Add scene updatables to loop
|
|
42
|
+
if (this.scene.userData.updatables) {
|
|
43
|
+
this.loop.updatables.push(...this.scene.userData.updatables);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Add controls to loop
|
|
47
|
+
this.loop.updatables.push(this.controls);
|
|
48
|
+
|
|
49
|
+
// Initialize resizer
|
|
50
|
+
this.resizer = new Resizer(
|
|
51
|
+
this.container,
|
|
52
|
+
this.camera,
|
|
53
|
+
this.renderer,
|
|
54
|
+
this.composer,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
start() {
|
|
59
|
+
if (this.loop) {
|
|
60
|
+
this.loop.start();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
stop() {
|
|
65
|
+
if (this.loop) {
|
|
66
|
+
this.loop.stop();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
dispose() {
|
|
71
|
+
// Stop animation loop
|
|
72
|
+
this.stop();
|
|
73
|
+
|
|
74
|
+
// Dispose controls
|
|
75
|
+
if (this.controls) {
|
|
76
|
+
this.controls.dispose();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Traverse scene and dispose geometries, materials, and textures
|
|
80
|
+
if (this.scene) {
|
|
81
|
+
this.scene.traverse(object => {
|
|
82
|
+
if (object.geometry) {
|
|
83
|
+
object.geometry.dispose();
|
|
84
|
+
}
|
|
85
|
+
if (object.material) {
|
|
86
|
+
if (Array.isArray(object.material)) {
|
|
87
|
+
object.material.forEach(material => {
|
|
88
|
+
this.disposeMaterial(material);
|
|
89
|
+
});
|
|
90
|
+
} else {
|
|
91
|
+
this.disposeMaterial(object.material);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Dispose composer
|
|
98
|
+
if (this.composer) {
|
|
99
|
+
this.composer.dispose();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Dispose renderer and remove canvas
|
|
103
|
+
if (this.renderer) {
|
|
104
|
+
this.renderer.dispose();
|
|
105
|
+
if (this.renderer.domElement && this.renderer.domElement.parentNode) {
|
|
106
|
+
this.renderer.domElement.parentNode.removeChild(
|
|
107
|
+
this.renderer.domElement,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Clear references
|
|
113
|
+
this.camera = null;
|
|
114
|
+
this.scene = null;
|
|
115
|
+
this.renderer = null;
|
|
116
|
+
this.composer = null;
|
|
117
|
+
this.loop = null;
|
|
118
|
+
this.controls = null;
|
|
119
|
+
this.resizer = null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
disposeMaterial(material) {
|
|
123
|
+
if (material.map) material.map.dispose();
|
|
124
|
+
if (material.lightMap) material.lightMap.dispose();
|
|
125
|
+
if (material.bumpMap) material.bumpMap.dispose();
|
|
126
|
+
if (material.normalMap) material.normalMap.dispose();
|
|
127
|
+
if (material.specularMap) material.specularMap.dispose();
|
|
128
|
+
if (material.envMap) material.envMap.dispose();
|
|
129
|
+
material.dispose();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export {World};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {PerspectiveCamera} from 'three';
|
|
2
|
+
|
|
3
|
+
const getAspectRatio = () => {
|
|
4
|
+
if (typeof window !== 'undefined') {
|
|
5
|
+
return window.innerWidth / window.innerHeight;
|
|
6
|
+
}
|
|
7
|
+
return 16 / 9; // Default aspect ratio for SSR
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const getFov = (z = 500) => {
|
|
11
|
+
// avoid accessing window during SSR
|
|
12
|
+
if (typeof window !== 'undefined') {
|
|
13
|
+
return (180 * (2 * Math.atan(window.innerHeight / 2 / z))) / Math.PI;
|
|
14
|
+
}
|
|
15
|
+
// Use a default 16:9 height for SSR (e.g., 1080p)
|
|
16
|
+
const defaultHeight = 1080;
|
|
17
|
+
return (180 * (2 * Math.atan(defaultHeight / 2 / z))) / Math.PI;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const camera = new PerspectiveCamera(
|
|
21
|
+
50, // fov = Field Of View
|
|
22
|
+
getAspectRatio(), // aspect ratio
|
|
23
|
+
0.01, // near clipping plane
|
|
24
|
+
1000, // far clipping plane
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
camera.position.set(0, 0, 8);
|
|
28
|
+
|
|
29
|
+
export {camera};
|
|
30
|
+
export default camera;
|