From 6870d74fca3e6ba8f2d49c2653d98fe9ea8a6727 Mon Sep 17 00:00:00 2001 From: Celeste Date: Fri, 8 Aug 2025 21:34:23 -0400 Subject: [PATCH 1/5] add Basic Geo nodes --- apps/web/app/registry/NodeRegistry.ts | 10 + apps/web/app/registry/nodes/CapsuleNode.ts | 95 +++++++++ apps/web/app/registry/nodes/ConeNode.ts | 133 ++++++++++++ apps/web/app/registry/nodes/GridNode.ts | 95 +++++++++ apps/web/app/registry/nodes/PlaneNode.ts | 113 ++++++++++ apps/web/app/registry/nodes/TorusNode.ts | 113 ++++++++++ apps/web/app/registry/nodes/index.ts | 5 + apps/web/next.config.ts | 10 + apps/web/package.json | 2 +- package-lock.json | 233 ++++++++++++++++++++- 10 files changed, 804 insertions(+), 5 deletions(-) create mode 100644 apps/web/app/registry/nodes/CapsuleNode.ts create mode 100644 apps/web/app/registry/nodes/ConeNode.ts create mode 100644 apps/web/app/registry/nodes/GridNode.ts create mode 100644 apps/web/app/registry/nodes/PlaneNode.ts create mode 100644 apps/web/app/registry/nodes/TorusNode.ts diff --git a/apps/web/app/registry/NodeRegistry.ts b/apps/web/app/registry/NodeRegistry.ts index 27d00ac..f95ee41 100644 --- a/apps/web/app/registry/NodeRegistry.ts +++ b/apps/web/app/registry/NodeRegistry.ts @@ -10,7 +10,12 @@ import { transformNodeDefinition, outputNodeDefinition, sphereNodeDefinition, + planeNodeDefinition, + torusNodeDefinition, + coneNodeDefinition, + gridNodeDefinition, cylinderNodeDefinition, + capsuleNodeDefinition, vectorMathNodeDefinition, joinNodeDefinition, subdivideMeshNodeDefinition, @@ -105,7 +110,12 @@ export class NodeRegistry { this.register(timeNodeDefinition); this.register(cubeNodeDefinition); this.register(sphereNodeDefinition); + this.register(planeNodeDefinition); + this.register(torusNodeDefinition); + this.register(coneNodeDefinition); + this.register(gridNodeDefinition); this.register(cylinderNodeDefinition); + this.register(capsuleNodeDefinition); this.register(mathNodeDefinition); this.register(vectorMathNodeDefinition); this.register(transformNodeDefinition); diff --git a/apps/web/app/registry/nodes/CapsuleNode.ts b/apps/web/app/registry/nodes/CapsuleNode.ts new file mode 100644 index 0000000..66bc484 --- /dev/null +++ b/apps/web/app/registry/nodes/CapsuleNode.ts @@ -0,0 +1,95 @@ +import { NodeDefinition } from '../../types/nodeSystem'; +import { Cylinder } from 'lucide-react'; +import * as THREE from 'three'; + +// CAPSULE NODE - Creates a capsule geometry (cylinder with rounded ends) +export const capsuleNodeDefinition: NodeDefinition = { + type: 'capsule', + name: 'Capsule', + description: 'Creates a capsule geometry (cylinder with rounded ends)', + category: 'geometry', + color: { + primary: '#ea580c', + secondary: '#c2410c' + }, + + inputs: [ + { + id: 'radius', + name: 'Radius', + type: 'number', + defaultValue: 0.5, + min: 0.1, + step: 0.1, + description: 'Capsule radius' + }, + { + id: 'height', + name: 'Height', + type: 'number', + defaultValue: 2, + min: 0.1, + step: 0.1, + description: 'Capsule height (including end caps)' + }, + { + id: 'radialSegments', + name: 'Radial Segments', + type: 'integer', + defaultValue: 32, + min: 3, + max: 128, + step: 1, + description: 'Radial segments around the capsule' + }, + { + id: 'heightSegments', + name: 'Height Segments', + type: 'integer', + defaultValue: 16, + min: 2, + max: 64, + step: 1, + description: 'Height segments along the capsule' + }, + { + id: 'material', + name: 'Material', + type: 'material', + required: false, + description: 'Optional material to apply' + } + ], + outputs: [ + { + id: 'geometry', + name: 'Geometry', + type: 'geometry', + description: 'Generated capsule geometry' + } + ], + parameters: [], + ui: { + width: 220, + icon: Cylinder, + advanced: ['radialSegments', 'heightSegments'] + }, + execute: (inputs, parameters) => { + // Get values from inputs (can come from UI or connections) + const radius = inputs.radius || 0.5; + const height = inputs.height || 2; + const radialSegments = inputs.radialSegments || 32; + const heightSegments = inputs.heightSegments || 16; + const material = inputs.material; + + // Create capsule geometry using Three.js CapsuleGeometry + const geometry = new THREE.CapsuleGeometry(radius, height - 2 * radius, radialSegments, heightSegments); + + // Apply material if provided + if (material) { + (geometry as any).material = material; + } + + return { geometry }; + } +}; diff --git a/apps/web/app/registry/nodes/ConeNode.ts b/apps/web/app/registry/nodes/ConeNode.ts new file mode 100644 index 0000000..71ccabf --- /dev/null +++ b/apps/web/app/registry/nodes/ConeNode.ts @@ -0,0 +1,133 @@ +import { NodeDefinition } from '../../types/nodeSystem'; +import { Triangle } from 'lucide-react'; +import * as THREE from 'three'; + +// CONE PRIMITIVE - Unified input system +export const coneNodeDefinition: NodeDefinition = { + type: 'cone', + name: 'Cone', + description: 'Creates a cone geometry', + category: 'geometry', + color: { + primary: '#ea580c', + secondary: '#c2410c' + }, + + inputs: [ + { + id: 'radius', + name: 'Radius', + type: 'number', + defaultValue: 1, + min: 0.1, + step: 0.1, + description: 'Cone base radius' + }, + { + id: 'height', + name: 'Height', + type: 'number', + defaultValue: 2, + min: 0.1, + step: 0.1, + description: 'Cone height' + }, + { + id: 'radialSegments', + name: 'Radial Segments', + type: 'integer', + defaultValue: 32, + min: 3, + max: 64, + step: 1, + description: 'Number of segments around the cone circumference' + }, + { + id: 'heightSegments', + name: 'Height Segments', + type: 'integer', + defaultValue: 1, + min: 1, + max: 32, + step: 1, + description: 'Number of segments along the cone height' + }, + { + id: 'openEnded', + name: 'Open Ended', + type: 'boolean', + defaultValue: false, + description: 'Whether the cone is open at the bottom' + }, + { + id: 'thetaStart', + name: 'Theta Start', + type: 'number', + defaultValue: 0, + min: 0, + max: Math.PI * 2, + step: 0.1, + description: 'Start angle in radians' + }, + { + id: 'thetaLength', + name: 'Theta Length', + type: 'number', + defaultValue: Math.PI * 2, + min: 0.1, + max: Math.PI * 2, + step: 0.1, + description: 'Arc length in radians' + }, + { + id: 'material', + name: 'Material', + type: 'material', + required: false, + description: 'Optional material to apply' + } + ], + outputs: [ + { + id: 'geometry', + name: 'Geometry', + type: 'geometry', + description: 'Generated cone geometry' + } + ], + parameters: [], // No parameters - everything is inputs + ui: { + icon: Triangle, + advanced: ['radialSegments', 'heightSegments', 'openEnded', 'thetaStart', 'thetaLength'], + width: 250, + height: 200 + }, + execute: (inputs, parameters) => { + // Get values from inputs (can come from UI or connections) + const radius = inputs.radius || 1; + const height = inputs.height || 2; + const radialSegments = inputs.radialSegments || 32; + const heightSegments = inputs.heightSegments || 1; + const openEnded = inputs.openEnded || false; + const thetaStart = inputs.thetaStart || 0; + const thetaLength = inputs.thetaLength || Math.PI * 2; + const material = inputs.material; + + const geometry = new THREE.ConeGeometry( + radius, + height, + radialSegments, + heightSegments, + openEnded, + thetaStart, + thetaLength + ); + + // Apply material if provided + if (material) { + (geometry as any).material = material; + } + + return { geometry }; + } +}; diff --git a/apps/web/app/registry/nodes/GridNode.ts b/apps/web/app/registry/nodes/GridNode.ts new file mode 100644 index 0000000..cf564ca --- /dev/null +++ b/apps/web/app/registry/nodes/GridNode.ts @@ -0,0 +1,95 @@ +import { NodeDefinition } from '../../types/nodeSystem'; +import { Grid } from 'lucide-react'; +import * as THREE from 'three'; + +// GRID PRIMITIVE - Unified input system +export const gridNodeDefinition: NodeDefinition = { + type: 'grid', + name: 'Grid', + description: 'Creates a grid geometry', + category: 'geometry', + color: { + primary: '#ea580c', + secondary: '#c2410c' + }, + + inputs: [ + { + id: 'width', + name: 'Width', + type: 'number', + defaultValue: 10, + min: 0.1, + step: 0.1, + description: 'Grid width' + }, + { + id: 'height', + name: 'Height', + type: 'number', + defaultValue: 10, + min: 0.1, + step: 0.1, + description: 'Grid height' + }, + { + id: 'widthSegments', + name: 'Width Segments', + type: 'integer', + defaultValue: 10, + min: 1, + max: 100, + step: 1, + description: 'Number of segments along the width' + }, + { + id: 'heightSegments', + name: 'Height Segments', + type: 'integer', + defaultValue: 10, + min: 1, + max: 100, + step: 1, + description: 'Number of segments along the height' + }, + { + id: 'material', + name: 'Material', + type: 'material', + required: false, + description: 'Optional material to apply' + } + ], + outputs: [ + { + id: 'geometry', + name: 'Geometry', + type: 'geometry', + description: 'Generated grid geometry' + } + ], + parameters: [], // No parameters - everything is inputs + ui: { + icon: Grid, + advanced: ['widthSegments', 'heightSegments'], + width: 250, + height: 200 + }, + execute: (inputs, parameters) => { + // Get values from inputs (can come from UI or connections) + const width = inputs.width || 10; + const height = inputs.height || 10; + const widthSegments = inputs.widthSegments || 10; + const heightSegments = inputs.heightSegments || 10; + const material = inputs.material; + + const geometry = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments); + + // Apply material if provided + if (material) { + (geometry as any).material = material; + } + + return { geometry }; + } +}; diff --git a/apps/web/app/registry/nodes/PlaneNode.ts b/apps/web/app/registry/nodes/PlaneNode.ts new file mode 100644 index 0000000..42d85c1 --- /dev/null +++ b/apps/web/app/registry/nodes/PlaneNode.ts @@ -0,0 +1,113 @@ +import { NodeDefinition } from '../../types/nodeSystem'; +import { Square } from 'lucide-react'; +import * as THREE from 'three'; + +// PLANE PRIMITIVE - Unified input system +export const planeNodeDefinition: NodeDefinition = { + type: 'plane', + name: 'Plane', + description: 'Creates a plane geometry', + category: 'geometry', + color: { + primary: '#ea580c', + secondary: '#c2410c' + }, + + inputs: [ + { + id: 'width', + name: 'Width', + type: 'number', + defaultValue: 1, + min: 0.1, + step: 0.1, + description: 'Plane width' + }, + { + id: 'height', + name: 'Height', + type: 'number', + defaultValue: 1, + min: 0.1, + step: 0.1, + description: 'Plane height' + }, + { + id: 'subdivision', + name: 'Subdivision', + type: 'integer', + defaultValue: 1, + min: 1, + max: 64, + step: 1, + description: 'Uniform subdivision for both axes' + }, + { + id: 'subdivisionX', + name: 'Subdivision X', + type: 'integer', + defaultValue: 1, + min: 1, + max: 64, + step: 1, + description: 'Horizontal subdivision' + }, + { + id: 'subdivisionY', + name: 'Subdivision Y', + type: 'integer', + defaultValue: 1, + min: 1, + max: 64, + step: 1, + description: 'Vertical subdivision' + }, + { + id: 'material', + name: 'Material', + type: 'material', + required: false, + description: 'Optional material to apply' + } + ], + outputs: [ + { + id: 'geometry', + name: 'Geometry', + type: 'geometry', + description: 'Generated plane geometry' + } + ], + parameters: [], // No parameters - everything is inputs + ui: { + icon: Square, + width: 250, + height: 200, + advanced: ['subdivision', 'subdivisionX', 'subdivisionY'] + }, + execute: (inputs, parameters) => { + // Get values from inputs (can come from UI or connections) + const width = inputs.width || 1; + const height = inputs.height || 1; + const subdivision = inputs.subdivision || 1; + const subdivisionX = inputs.subdivisionX || 1; + const subdivisionY = inputs.subdivisionY || 1; + const material = inputs.material; + + // Use subdivision if provided, otherwise use individual X/Y subdivisions + const widthSegments = subdivision > 1 ? subdivision : subdivisionX; + const heightSegments = subdivision > 1 ? subdivision : subdivisionY; + + const geometry = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments); + + // Rotate the plane to be horizontal (rotate 90 degrees around X-axis) + geometry.rotateX(-Math.PI / 2); + + // Apply material if provided + if (material) { + (geometry as any).material = material; + } + + return { geometry }; + } +}; diff --git a/apps/web/app/registry/nodes/TorusNode.ts b/apps/web/app/registry/nodes/TorusNode.ts new file mode 100644 index 0000000..5b5f692 --- /dev/null +++ b/apps/web/app/registry/nodes/TorusNode.ts @@ -0,0 +1,113 @@ +import { NodeDefinition } from '../../types/nodeSystem'; +import { Circle } from 'lucide-react'; +import * as THREE from 'three'; + +// TORUS PRIMITIVE - Unified input system +export const torusNodeDefinition: NodeDefinition = { + type: 'torus', + name: 'Torus', + description: 'Creates a torus geometry', + category: 'geometry', + color: { + primary: '#ea580c', + secondary: '#c2410c' + }, + + inputs: [ + { + id: 'radius', + name: 'Radius', + type: 'number', + defaultValue: 1, + min: 0.1, + step: 0.1, + description: 'Torus radius (distance from center to tube center)' + }, + { + id: 'tubeRadius', + name: 'Tube Radius', + type: 'number', + defaultValue: 0.3, + min: 0.01, + max: 0.99, + step: 0.01, + description: 'Tube radius (thickness of the torus)' + }, + { + id: 'radialSegments', + name: 'Radial Segments', + type: 'integer', + defaultValue: 16, + min: 3, + max: 64, + step: 1, + description: 'Number of segments around the torus circumference' + }, + { + id: 'tubularSegments', + name: 'Tubular Segments', + type: 'integer', + defaultValue: 32, + min: 3, + max: 128, + step: 1, + description: 'Number of segments around the tube circumference' + }, + { + id: 'arc', + name: 'Arc', + type: 'number', + defaultValue: Math.PI * 2, + min: 0.1, + max: Math.PI * 2, + step: 0.1, + description: 'Arc length in radians (0 to 2π for full torus)' + }, + { + id: 'material', + name: 'Material', + type: 'material', + required: false, + description: 'Optional material to apply' + } + ], + outputs: [ + { + id: 'geometry', + name: 'Geometry', + type: 'geometry', + description: 'Generated torus geometry' + } + ], + parameters: [], // No parameters - everything is inputs + ui: { + icon: Circle, + advanced: ['radialSegments', 'tubularSegments', 'arc'], + width: 250, + height: 200 + }, + execute: (inputs, parameters) => { + // Get values from inputs (can come from UI or connections) + const radius = inputs.radius || 1; + const tubeRadius = inputs.tubeRadius || 0.3; + const radialSegments = inputs.radialSegments || 16; + const tubularSegments = inputs.tubularSegments || 32; + const arc = inputs.arc || Math.PI * 2; + const material = inputs.material; + + const geometry = new THREE.TorusGeometry( + radius, + tubeRadius, + radialSegments, + tubularSegments, + arc + ); + + // Apply material if provided + if (material) { + (geometry as any).material = material; + } + + return { geometry }; + } +}; diff --git a/apps/web/app/registry/nodes/index.ts b/apps/web/app/registry/nodes/index.ts index 6b750a8..92bca65 100644 --- a/apps/web/app/registry/nodes/index.ts +++ b/apps/web/app/registry/nodes/index.ts @@ -5,7 +5,12 @@ export { mathNodeDefinition } from './MathNode'; export { transformNodeDefinition } from './TransformNode'; export { outputNodeDefinition } from './OutputNode'; export { sphereNodeDefinition } from './SphereNode'; +export { planeNodeDefinition } from './PlaneNode'; +export { torusNodeDefinition } from './TorusNode'; +export { coneNodeDefinition } from './ConeNode'; +export { gridNodeDefinition } from './GridNode'; export { cylinderNodeDefinition } from './CylinderNode'; +export { capsuleNodeDefinition } from './CapsuleNode'; export { vectorMathNodeDefinition } from './VectorMathNode'; export { joinNodeDefinition } from './JoinNode'; export { subdivideMeshNodeDefinition } from './SubdivideMeshNode'; diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index aaaecbd..ab0c798 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -8,6 +8,16 @@ const nextConfig: NextConfig = { 'localhost', '127.0.0.1' ], + // Experimental features + experimental: { + // Disable Turbopack for now due to path resolution issues + turbo: false, + }, + // Ensure proper path resolution + webpack: (config, { isServer }) => { + // Add any webpack customizations here if needed + return config; + }, }; export default nextConfig; diff --git a/apps/web/package.json b/apps/web/package.json index 95a715a..ffab6b6 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev --turbopack", + "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" diff --git a/package-lock.json b/package-lock.json index 5c8851e..cd7fee7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,8 +15,8 @@ "turbo": "^2.5.5" }, "engines": { - "node": ">=18.0.0", - "npm": ">=9.0.0" + "node": "22.x", + "npm": ">=10.0.0" } }, "apps/web": { @@ -34,7 +34,7 @@ "fastest-levenshtein": "^1.0.16", "html-to-image": "^1.11.11", "lucide-react": "^0.525.0", - "next": "^15.4.6", + "next": "15.4.2", "react": "19.1.0", "react-dom": "19.1.0", "reactflow": "^11.11.4", @@ -50,6 +50,220 @@ "typescript": "^5" } }, + "apps/web/node_modules/@next/env": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.4.2.tgz", + "integrity": "sha512-kd7MvW3pAP7tmk1NaiX4yG15xb2l4gNhteKQxt3f+NGR22qwPymn9RBuv26QKfIKmfo6z2NpgU8W2RT0s0jlvg==", + "license": "MIT" + }, + "apps/web/node_modules/@next/swc-darwin-arm64": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.2.tgz", + "integrity": "sha512-ovqjR8NjCBdBf1U+R/Gvn0RazTtXS9n6wqs84iFaCS1NHbw9ksVE4dfmsYcLoyUVd9BWE0bjkphOWrrz8uz/uw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "apps/web/node_modules/@next/swc-darwin-x64": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.4.2.tgz", + "integrity": "sha512-I8d4W7tPqbdbHRI4z1iBfaoJIBrEG4fnWKIe+Rj1vIucNZ5cEinfwkBt3RcDF00bFRZRDpvKuDjgMFD3OyRBnw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "apps/web/node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.4.2.tgz", + "integrity": "sha512-lvhz02dU3Ec5thzfQ2RCUeOFADjNkS/px1W7MBt7HMhf0/amMfT8Z/aXOwEA+cVWN7HSDRSUc8hHILoHmvajsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "apps/web/node_modules/@next/swc-linux-arm64-musl": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.4.2.tgz", + "integrity": "sha512-v+5PPfL8UP+KKHS3Mox7QMoeFdMlaV0zeNMIF7eLC4qTiVSO0RPNnK0nkBZSD5BEkkf//c+vI9s/iHxddCZchA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "apps/web/node_modules/@next/swc-linux-x64-gnu": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.4.2.tgz", + "integrity": "sha512-PHLYOC9W2cu6I/JEKo77+LW4uPNvyEQiSkVRUQPsOIsf01PRr8PtPhwtz3XNnC9At8CrzPkzqQ9/kYDg4R4Inw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "apps/web/node_modules/@next/swc-linux-x64-musl": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.4.2.tgz", + "integrity": "sha512-lpmUF9FfLFns4JbTu+5aJGA8aR9dXaA12eoNe9CJbVkGib0FDiPa4kBGTwy0xDxKNGlv3bLDViyx1U+qafmuJQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "apps/web/node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.4.2.tgz", + "integrity": "sha512-aMjogoGnRepas0LQ/PBPsvvUzj+IoXw2IoDSEShEtrsu2toBiaxEWzOQuPZ8nie8+1iF7TA63S7rlp3YWAjNEg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "apps/web/node_modules/@next/swc-win32-x64-msvc": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.4.2.tgz", + "integrity": "sha512-FxwauyexSFu78wEqR/+NB9MnqXVj6SxJKwcVs2CRjeSX/jBagDCgtR2W36PZUYm0WPgY1pQ3C1+nn7zSnwROuw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "apps/web/node_modules/next": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/next/-/next-15.4.2.tgz", + "integrity": "sha512-oH1rmFso+84NIkocfuxaGKcXIjMUTmnzV2x0m8qsYtB4gD6iflLMESXt5XJ8cFgWMBei4v88rNr/j+peNg72XA==", + "license": "MIT", + "dependencies": { + "@next/env": "15.4.2", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.4.2", + "@next/swc-darwin-x64": "15.4.2", + "@next/swc-linux-arm64-gnu": "15.4.2", + "@next/swc-linux-arm64-musl": "15.4.2", + "@next/swc-linux-x64-gnu": "15.4.2", + "@next/swc-linux-x64-musl": "15.4.2", + "@next/swc-win32-arm64-msvc": "15.4.2", + "@next/swc-win32-x64-msvc": "15.4.2", + "sharp": "^0.34.3" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "apps/web/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/@ai-sdk/provider": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", @@ -767,7 +981,8 @@ "version": "15.4.6", "resolved": "https://registry.npmjs.org/@next/env/-/env-15.4.6.tgz", "integrity": "sha512-yHDKVTcHrZy/8TWhj0B23ylKv5ypocuCwey9ZqPyv4rPdUdRzpGCkSi03t04KBPyU96kxVtUqx6O3nE1kpxASQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@next/swc-darwin-arm64": { "version": "15.4.6", @@ -781,6 +996,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 10" } @@ -797,6 +1013,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 10" } @@ -813,6 +1030,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -829,6 +1047,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -845,6 +1064,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -861,6 +1081,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -877,6 +1098,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 10" } @@ -893,6 +1115,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 10" } @@ -3137,6 +3360,7 @@ "resolved": "https://registry.npmjs.org/next/-/next-15.4.6.tgz", "integrity": "sha512-us++E/Q80/8+UekzB3SAGs71AlLDsadpFMXVNM/uQ0BMwsh9m3mr0UNQIfjKed8vpWXsASe+Qifrnu1oLIcKEQ==", "license": "MIT", + "peer": true, "dependencies": { "@next/env": "15.4.6", "@swc/helpers": "0.5.15", @@ -3203,6 +3427,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", From da68fdbec2659d564ebfe37b8182819f7f6f42a9 Mon Sep 17 00:00:00 2001 From: Celeste Date: Fri, 8 Aug 2025 23:15:41 -0400 Subject: [PATCH 2/5] update each collection --- apps/web/app/components/ContextMenu.tsx | 20 +++-- .../app/registry/nodes/BreakTransformNode.ts | 2 +- .../web/app/registry/nodes/BreakVectorNode.ts | 2 +- apps/web/app/registry/nodes/CapsuleNode.ts | 2 +- apps/web/app/registry/nodes/ConeNode.ts | 2 +- apps/web/app/registry/nodes/CubeNode.ts | 2 +- apps/web/app/registry/nodes/CylinderNode.ts | 2 +- .../app/registry/nodes/GenericBreakNode.ts | 2 +- .../web/app/registry/nodes/GenericMakeNode.ts | 2 +- apps/web/app/registry/nodes/GesnerWaveNode.ts | 2 +- apps/web/app/registry/nodes/GridNode.ts | 2 +- apps/web/app/registry/nodes/JoinNode.ts | 2 +- apps/web/app/registry/nodes/LighthouseNode.ts | 2 +- .../web/app/registry/nodes/LowPolyRockNode.ts | 2 +- .../app/registry/nodes/MakeTransformNode.ts | 2 +- apps/web/app/registry/nodes/MakeVectorNode.ts | 2 +- .../registry/nodes/ParametricSurfaceNode.ts | 2 +- apps/web/app/registry/nodes/PlaneNode.ts | 2 +- apps/web/app/registry/nodes/SeagullNode.ts | 2 +- apps/web/app/registry/nodes/SphereNode.ts | 2 +- .../web/app/registry/nodes/SpiralStairNode.ts | 2 +- apps/web/app/registry/nodes/TimeNode.ts | 2 +- apps/web/app/registry/nodes/TorusNode.ts | 2 +- apps/web/app/registry/nodes/TransformNode.ts | 2 +- apps/web/app/types/nodeSystem.ts | 77 +++++++++++++------ 25 files changed, 91 insertions(+), 52 deletions(-) diff --git a/apps/web/app/components/ContextMenu.tsx b/apps/web/app/components/ContextMenu.tsx index 38afccb..a96a034 100644 --- a/apps/web/app/components/ContextMenu.tsx +++ b/apps/web/app/components/ContextMenu.tsx @@ -38,6 +38,7 @@ interface NodeMenuItem { label: string; description: string; category: string; + categoryIcon: string; color: string; icon?: string | React.ComponentType; } @@ -98,6 +99,7 @@ export default function ContextMenu({ position, onClose, onAddNode, onOpenCustom label: definition.name, description: definition.description, category: categoryMeta?.description || definition.category, + categoryIcon: categoryMeta?.icon || '⚫', color: `bg-${categoryMeta?.color || 'gray'}-600`, icon: definition.ui?.icon || categoryMeta?.icon }; @@ -162,11 +164,14 @@ export default function ContextMenu({ position, onClose, onAddNode, onOpenCustom // Group filtered items by category const categories = filteredItems.reduce((acc, item) => { if (!acc[item.category]) { - acc[item.category] = []; + acc[item.category] = { + items: [], + icon: item.categoryIcon + }; } - acc[item.category].push(item); + acc[item.category].items.push(item); return acc; - }, {} as Record); + }, {} as Record); // Don't render anything if position is null if (!position) { @@ -255,12 +260,13 @@ export default function ContextMenu({ position, onClose, onAddNode, onOpenCustom scrollbarColor: 'rgba(75, 85, 99, 0.6) transparent' }} > - {Object.entries(categories).map(([category, items]) => ( + {Object.entries(categories).map(([category, categoryData]) => (
-
- {category} +
+ {categoryData.icon} + {category}
- {items.map((item, index) => ( + {categoryData.items.map((item, index) => (