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,288 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync } from 'fs';
|
|
2
|
+
import { join, dirname, basename, resolve, relative } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { detectProjectType } from './project-detection.js';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
/**
|
|
8
|
+
* Find app folder by looking for app directory going up the directory tree (Nuxt)
|
|
9
|
+
* or src folder (Vue)
|
|
10
|
+
*/
|
|
11
|
+
function findComposablesFolder(startPath, projectType) {
|
|
12
|
+
let currentPath = resolve(startPath);
|
|
13
|
+
while (currentPath !== dirname(currentPath)) {
|
|
14
|
+
if (projectType === 'nuxt') {
|
|
15
|
+
const appPath = join(currentPath, 'app');
|
|
16
|
+
if (existsSync(appPath)) {
|
|
17
|
+
return join(appPath, 'composables');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
// Vue project
|
|
22
|
+
const srcPath = join(currentPath, 'src');
|
|
23
|
+
if (existsSync(srcPath)) {
|
|
24
|
+
return join(srcPath, 'composables');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
currentPath = dirname(currentPath);
|
|
28
|
+
}
|
|
29
|
+
if (projectType === 'nuxt') {
|
|
30
|
+
throw new Error('app folder not found. Please run this command in a Nuxt project with an app directory.');
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
throw new Error('src folder not found. Please run this command in a Vue project.');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Find project root by looking for package.json going up the directory tree
|
|
38
|
+
*/
|
|
39
|
+
function findProjectRoot(startPath) {
|
|
40
|
+
let currentPath = resolve(startPath);
|
|
41
|
+
while (currentPath !== dirname(currentPath)) {
|
|
42
|
+
const packageJsonPath = join(currentPath, 'package.json');
|
|
43
|
+
if (existsSync(packageJsonPath)) {
|
|
44
|
+
return currentPath;
|
|
45
|
+
}
|
|
46
|
+
currentPath = dirname(currentPath);
|
|
47
|
+
}
|
|
48
|
+
throw new Error('Project root not found. Please run this command in a Nuxt/Vue project.');
|
|
49
|
+
}
|
|
50
|
+
export async function addThree(currentDir) {
|
|
51
|
+
const currentPath = resolve(currentDir);
|
|
52
|
+
const directoryName = basename(currentPath);
|
|
53
|
+
// Find project root to check for three.js
|
|
54
|
+
const projectRoot = findProjectRoot(currentPath);
|
|
55
|
+
const packageJsonPath = join(projectRoot, 'package.json');
|
|
56
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
57
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
58
|
+
if (!deps.three) {
|
|
59
|
+
throw new Error('Three.js is not installed. Please install it first: npm install three');
|
|
60
|
+
}
|
|
61
|
+
// Detect project type
|
|
62
|
+
const projectType = await detectProjectType(projectRoot);
|
|
63
|
+
if (projectType !== 'nuxt' && projectType !== 'vue') {
|
|
64
|
+
throw new Error('Project type not supported. Please run this command in a Nuxt or Vue project.');
|
|
65
|
+
}
|
|
66
|
+
// Find composables folder (app/composables for Nuxt, src/composables for Vue)
|
|
67
|
+
const composablesFolder = findComposablesFolder(currentPath, projectType);
|
|
68
|
+
const appFolder = projectType === 'nuxt'
|
|
69
|
+
? join(composablesFolder, '..') // app folder
|
|
70
|
+
: join(composablesFolder, '..'); // src folder
|
|
71
|
+
// Get template directory path
|
|
72
|
+
// When compiled: dist/utils/add-three.js -> dist/template_code/three
|
|
73
|
+
// When in source: source/utils/add-three.ts -> source/template_code/three
|
|
74
|
+
let templateDir = join(__dirname, '..', 'template_code', 'three');
|
|
75
|
+
if (!existsSync(templateDir)) {
|
|
76
|
+
// Try from source location (for development/testing)
|
|
77
|
+
const sourceTemplateDir = join(__dirname, '..', '..', 'source', 'template_code', 'three');
|
|
78
|
+
if (existsSync(sourceTemplateDir)) {
|
|
79
|
+
templateDir = sourceTemplateDir;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
throw new Error('Three.js template not found. Expected at: ' +
|
|
83
|
+
templateDir +
|
|
84
|
+
' or ' +
|
|
85
|
+
sourceTemplateDir);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Copy template to three/ in current directory (where command is run)
|
|
89
|
+
const targetDir = join(currentPath, 'three');
|
|
90
|
+
// Copy the template directory
|
|
91
|
+
if (existsSync(targetDir)) {
|
|
92
|
+
throw new Error('three directory already exists. Please remove it first.');
|
|
93
|
+
}
|
|
94
|
+
cpSync(templateDir, targetDir, { recursive: true });
|
|
95
|
+
// Create composables/{directoryName} inside app/src folder
|
|
96
|
+
const composablesTargetDir = join(composablesFolder, directoryName);
|
|
97
|
+
if (!existsSync(composablesTargetDir)) {
|
|
98
|
+
mkdirSync(composablesTargetDir, { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
// Calculate import path from composables/{directoryName} to three folder
|
|
101
|
+
// In Nuxt/Vue, @/ resolves to project root (Nuxt) or src (Vue), so we use the path relative to project root
|
|
102
|
+
const threePathRelative = relative(projectRoot, targetDir).replace(/\\/g, '/');
|
|
103
|
+
const importPath = `@/${threePathRelative}/World.js`;
|
|
104
|
+
// Determine file extension based on project type
|
|
105
|
+
const fileExtension = projectType === 'vue' ? 'js' : 'ts';
|
|
106
|
+
// Create usethree.{js|ts}
|
|
107
|
+
const useThreePath = join(composablesTargetDir, `usethree.${fileExtension}`);
|
|
108
|
+
// Type annotations only for TypeScript
|
|
109
|
+
const typeAnnotations = projectType === 'nuxt'
|
|
110
|
+
? `: Ref<HTMLElement | null>`
|
|
111
|
+
: '';
|
|
112
|
+
const typeImports = projectType === 'nuxt'
|
|
113
|
+
? `, type Ref`
|
|
114
|
+
: '';
|
|
115
|
+
const worldType = projectType === 'nuxt' ? `<World | null>` : '';
|
|
116
|
+
const errorType = projectType === 'nuxt' ? `<Error | null>` : '';
|
|
117
|
+
const useThreeContent = `import { ref, onMounted, onBeforeUnmount, markRaw, nextTick${typeImports} } from 'vue';
|
|
118
|
+
import { World } from '${importPath}';
|
|
119
|
+
|
|
120
|
+
export function useThree(containerRef${typeAnnotations}) {
|
|
121
|
+
const world = ref${worldType}(null);
|
|
122
|
+
const isLoading = ref(true);
|
|
123
|
+
const error = ref${errorType}(null);
|
|
124
|
+
|
|
125
|
+
const init = async () => {
|
|
126
|
+
if (!containerRef.value) {
|
|
127
|
+
error.value = new Error('Container element not found');
|
|
128
|
+
isLoading.value = false;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
// Create Three.js world and mark as non-reactive to prevent proxy issues
|
|
134
|
+
const worldInstance = new World(containerRef.value);
|
|
135
|
+
world.value = markRaw(worldInstance);
|
|
136
|
+
|
|
137
|
+
// Initialize scene
|
|
138
|
+
world.value.init();
|
|
139
|
+
|
|
140
|
+
// Start render loop
|
|
141
|
+
world.value.start();
|
|
142
|
+
|
|
143
|
+
isLoading.value = false;
|
|
144
|
+
} catch (e) {
|
|
145
|
+
error.value = e instanceof Error ? e : new Error('Failed to initialize Three.js');
|
|
146
|
+
isLoading.value = false;
|
|
147
|
+
console.error('Three.js initialization error:', e);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const cleanup = () => {
|
|
152
|
+
if (world.value) {
|
|
153
|
+
world.value.dispose();
|
|
154
|
+
world.value = null;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
onMounted(() => {
|
|
159
|
+
// Wait for next tick to ensure DOM is ready
|
|
160
|
+
nextTick(() => init());
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
onBeforeUnmount(() => {
|
|
164
|
+
cleanup();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
world,
|
|
169
|
+
isLoading,
|
|
170
|
+
error,
|
|
171
|
+
cleanup,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
`;
|
|
175
|
+
writeFileSync(useThreePath, useThreeContent, 'utf-8');
|
|
176
|
+
// Create useThreeAdvanced.{js|ts}
|
|
177
|
+
const useThreeAdvancedPath = join(composablesTargetDir, `useThreeAdvanced.${fileExtension}`);
|
|
178
|
+
const threeTypeImports = projectType === 'nuxt'
|
|
179
|
+
? `import type { Scene, Camera, WebGLRenderer } from 'three';`
|
|
180
|
+
: '';
|
|
181
|
+
const useThreeAdvancedContent = `import { ref, onMounted, onBeforeUnmount, markRaw, nextTick${typeImports} } from 'vue';
|
|
182
|
+
import { World } from '${importPath}';
|
|
183
|
+
${threeTypeImports}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Advanced Three.js composable with more control and access to internals
|
|
187
|
+
* Use this when you need direct access to scene, camera, renderer, etc.
|
|
188
|
+
*/
|
|
189
|
+
export function useThreeAdvanced(containerRef${typeAnnotations}) {
|
|
190
|
+
const world = ref${worldType}(null);
|
|
191
|
+
const isLoading = ref(true);
|
|
192
|
+
const error = ref${errorType}(null);
|
|
193
|
+
const isRunning = ref(false);
|
|
194
|
+
|
|
195
|
+
// Getters for Three.js internals
|
|
196
|
+
const scene = ref${projectType === 'nuxt' ? '<Scene | null>' : ''}(null);
|
|
197
|
+
const camera = ref${projectType === 'nuxt' ? '<Camera | null>' : ''}(null);
|
|
198
|
+
const renderer = ref${projectType === 'nuxt' ? '<WebGLRenderer | null>' : ''}(null);
|
|
199
|
+
|
|
200
|
+
const init = async () => {
|
|
201
|
+
if (!containerRef.value) {
|
|
202
|
+
error.value = new Error('Container element not found');
|
|
203
|
+
isLoading.value = false;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
// Create Three.js world and mark as non-reactive to prevent proxy issues
|
|
209
|
+
const worldInstance = new World(containerRef.value);
|
|
210
|
+
world.value = markRaw(worldInstance);
|
|
211
|
+
|
|
212
|
+
// Initialize scene
|
|
213
|
+
world.value.init();
|
|
214
|
+
|
|
215
|
+
// Store references and mark Three.js objects as non-reactive
|
|
216
|
+
scene.value = markRaw(world.value.scene${projectType === 'nuxt' ? ' as Scene' : ''});
|
|
217
|
+
camera.value = markRaw(world.value.camera);
|
|
218
|
+
renderer.value = markRaw(world.value.renderer);
|
|
219
|
+
|
|
220
|
+
// Start render loop
|
|
221
|
+
world.value.start();
|
|
222
|
+
isRunning.value = true;
|
|
223
|
+
|
|
224
|
+
isLoading.value = false;
|
|
225
|
+
} catch (e) {
|
|
226
|
+
error.value = e instanceof Error ? e : new Error('Failed to initialize Three.js');
|
|
227
|
+
isLoading.value = false;
|
|
228
|
+
console.error('Three.js initialization error:', e);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const start = () => {
|
|
233
|
+
if (world.value && !isRunning.value) {
|
|
234
|
+
world.value.start();
|
|
235
|
+
isRunning.value = true;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const stop = () => {
|
|
240
|
+
if (world.value && isRunning.value) {
|
|
241
|
+
world.value.stop();
|
|
242
|
+
isRunning.value = false;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const cleanup = () => {
|
|
247
|
+
if (world.value) {
|
|
248
|
+
world.value.dispose();
|
|
249
|
+
world.value = null;
|
|
250
|
+
scene.value = null;
|
|
251
|
+
camera.value = null;
|
|
252
|
+
renderer.value = null;
|
|
253
|
+
isRunning.value = false;
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
onMounted(() => {
|
|
258
|
+
// Wait for next tick to ensure DOM is ready
|
|
259
|
+
nextTick(() => init());
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
onBeforeUnmount(() => {
|
|
263
|
+
cleanup();
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
world,
|
|
268
|
+
scene,
|
|
269
|
+
camera,
|
|
270
|
+
renderer,
|
|
271
|
+
isLoading,
|
|
272
|
+
isRunning,
|
|
273
|
+
error,
|
|
274
|
+
start,
|
|
275
|
+
stop,
|
|
276
|
+
cleanup,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
`;
|
|
280
|
+
writeFileSync(useThreeAdvancedPath, useThreeAdvancedContent, 'utf-8');
|
|
281
|
+
return {
|
|
282
|
+
directoryName,
|
|
283
|
+
appFolder,
|
|
284
|
+
threePath: targetDir,
|
|
285
|
+
projectType,
|
|
286
|
+
fileExtension,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ProjectType } from './project-detection.js';
|
|
2
|
+
export declare function createNuxtApp(dir: string, name: string): Promise<void>;
|
|
3
|
+
export declare function createVueApp(dir: string, name: string): Promise<void>;
|
|
4
|
+
export declare function createApp(projectType: ProjectType, dir: string, name: string): Promise<void>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
export async function createNuxtApp(dir, name) {
|
|
3
|
+
try {
|
|
4
|
+
execSync(`npx nuxi@latest init ${name}`, {
|
|
5
|
+
cwd: dir,
|
|
6
|
+
stdio: 'inherit',
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
throw new Error(`Failed to create Nuxt app: ${error}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function createVueApp(dir, name) {
|
|
14
|
+
try {
|
|
15
|
+
// Use npm create vue@latest for Vue 3
|
|
16
|
+
execSync(`npm create vue@latest ${name} -- --yes`, {
|
|
17
|
+
cwd: dir,
|
|
18
|
+
stdio: 'inherit',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
throw new Error(`Failed to create Vue app: ${error}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export async function createApp(projectType, dir, name) {
|
|
26
|
+
if (projectType === 'nuxt') {
|
|
27
|
+
await createNuxtApp(dir, name);
|
|
28
|
+
}
|
|
29
|
+
else if (projectType === 'vue') {
|
|
30
|
+
await createVueApp(dir, name);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
throw new Error('Cannot create app: project type must be nuxt or vue');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ProjectType } from './project-detection.js';
|
|
2
|
+
export declare function generateNuxtConfig(projectPath: string, threejs: boolean, cssVars: boolean): Promise<void>;
|
|
3
|
+
export declare function generateViteConfig(projectPath: string, threejs: boolean, cssVars?: boolean): Promise<void>;
|
|
4
|
+
export declare function generateTailwindConfig(projectPath: string, projectType: ProjectType): Promise<void>;
|
|
5
|
+
export declare function generatePostCSSConfig(projectPath: string): Promise<void>;
|
|
6
|
+
export declare function generateConfigFiles(projectType: ProjectType, projectPath: string, threejs: boolean, cssVars: boolean): Promise<void>;
|