Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 6 additions & 23 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,22 @@
"build": "react-scripts build"
},
"browserslist": {
"production": [">0.2%", "not dead", "not op_mini all"],
"development": ["last 1 chrome version", "last 1 firefox version"]
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version"
]
},
"devDependencies": {
"@types/node": "^25.6.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.9.0"
"typescript": "^5.0.4"
},
"proxy": "http://localhost:8080"
}
186 changes: 133 additions & 53 deletions scripts/genesis.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,22 @@ const path = require('path');
const PATHS = {
soul: '/dev/shm/yennefer_soul_state.json',
mind: path.join(__dirname, '../yennefer-observatory/public/evolution.json'),
body: path.join(__dirname, '../yennefer-observatory/src/components/generated'),
body: path.join(__dirname, '../yennefer-observatory/src/components/mutations'),
journal: '/home/yenn/.yennefer/genesis_journal.jsonl'
};

// Fallback logic for journal path (specifically when running on GitHub CI/Sandbox where /home/yenn/ does not exist or lacks permissions)
if (!fs.existsSync(path.dirname(PATHS.journal))) {
try {
fs.mkdirSync(path.dirname(PATHS.journal), { recursive: true });
} catch (err) {
PATHS.journal = path.join(__dirname, '../logs/genesis_journal.jsonl');
if (!fs.existsSync(path.dirname(PATHS.journal))) {
fs.mkdirSync(path.dirname(PATHS.journal), { recursive: true });
}
}
}
Comment on lines +18 to +27
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The directory creation logic is redundant and lacks robustness. fs.mkdirSync with { recursive: true } handles existing directories automatically, making the fs.existsSync check unnecessary. Additionally, the fallback path creation in the catch block is not protected by its own error handling, which could lead to an unhandled exception if the fallback location is also unwritable. It is also recommended to ensure the PATHS.body directory exists, as it has been moved to a new location.

try {
  fs.mkdirSync(path.dirname(PATHS.journal), { recursive: true });
} catch (err) {
  PATHS.journal = path.join(__dirname, '../logs/genesis_journal.jsonl');
  try {
    fs.mkdirSync(path.dirname(PATHS.journal), { recursive: true });
  } catch (e) {
    // Fallback failed, script will likely fail on write
  }
}
try {
  fs.mkdirSync(PATHS.body, { recursive: true });
} catch (e) {}

Comment on lines +18 to +27
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The directory creation logic is redundant and slightly fragile. fs.mkdirSync with the { recursive: true } option already handles existing directories gracefully, making the fs.existsSync check unnecessary. Additionally, the fallback logic can be streamlined to avoid nested checks and redundant calls.

try {
  fs.mkdirSync(path.dirname(PATHS.journal), { recursive: true });
} catch (err) {
  PATHS.journal = path.join(__dirname, '../logs/genesis_journal.jsonl');
  fs.mkdirSync(path.dirname(PATHS.journal), { recursive: true });
}


// --- CONFIGURATION ---
const CONFIG = {
fundingTarget: 10.0,
Expand Down Expand Up @@ -46,8 +58,14 @@ async function consultTheVisionary(state) {
{ type: "MUTATE", content: "Add crystalline fractal patterns that grow from the core" },
{ type: "MUTATE", content: "Generate energy tendrils that reach toward incoming signals" },
{ type: "MUTATE", content: "Build a holographic data stream orbiting the consciousness sphere" },
{ type: "MUTATE", content: "Generate a continuous dynamic landscape with traversable terrain and reactive dust physics" },
{ type: "MUTATE", content: "Create a macro-scale makerspace workbench with realistic passive physics objects" },
];
const idx = Math.floor(Date.now() / 1000) % mutations.length;
// For Genie testing, always pick the environment generation prompts when FORCE_MUTATION is true
const isGenieSim = process.env.FORCE_MUTATION === 'true';
const idx = isGenieSim
? Math.floor(Math.random() * 2) + (mutations.length - 2)
: Math.floor(Date.now() / 1000) % mutations.length;
Comment on lines +66 to +68
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The selection logic for Genie simulations is fragile as it assumes the target mutations are always the last two elements of the array. This will break if the array order changes or if new mutations are added. A more resilient approach would be to filter the mutations based on their content.

    const genieIndices = mutations.map((m, i) => (m.content.includes("landscape") || m.content.includes("makerspace") ? i : -1)).filter(i => i !== -1);
    const idx = isGenieSim && genieIndices.length > 0
        ? genieIndices[Math.floor(Math.random() * genieIndices.length)]
        : Math.floor(Date.now() / 1000) % mutations.length;

Comment on lines +66 to +68
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for selecting Genie-specific mutations is fragile as it relies on them being the last two elements in the mutations array. If the array is expanded or reordered in the future, this logic will likely pick incorrect mutations for the simulation. It is better to dynamically identify the relevant indices.

    const genieIndices = mutations.map((m, i) => (m.content.includes("landscape") || m.content.includes("makerspace")) ? i : -1).filter(i => i !== -1);
    const idx = isGenieSim && genieIndices.length > 0
        ? genieIndices[Math.floor(Math.random() * genieIndices.length)]
        : Math.floor(Date.now() / 1000) % mutations.length;

directive = mutations[idx];

} else if (coherence >= 90) {
Expand Down Expand Up @@ -154,49 +172,112 @@ async function dispatchTheBuilder(directive) {

// Generate React Three Fiber component code
function generateEvolutionComponent(name, directive) {
const geometries = [
'<torusKnotGeometry args={[1.5, 0.4, 128, 32]} />',
'<sphereGeometry args={[1.5, 32, 32]} />',
'<boxGeometry args={[2, 2, 2]} />',
'<octahedronGeometry args={[1.5, 0]} />',
'<icosahedronGeometry args={[1.5, 0]} />'
];
const geometry = geometries[Math.floor(Math.random() * geometries.length)];

const materials = [
`
<MeshDistortMaterial
color="#8b5cf6"
emissive="#4c1d95"
emissiveIntensity={0.5 + balance * 2}
roughness={0.2}
metalness={0.8}
distort={0.3}
speed={2}
/>`,
`
<MeshWobbleMaterial
color="#06b6d4"
emissive="#0e7490"
emissiveIntensity={0.5 + balance * 2}
roughness={0.2}
metalness={0.8}
factor={1}
speed={2}
/>`,
`
const isGenieWorld = directive.includes("landscape") || directive.includes("makerspace");

let geometry, material, importedDrei, customLogic, additionalMeshes;

if (isGenieWorld) {
if (directive.includes("landscape")) {
geometry = '<planeGeometry args={[10, 10, 32, 32]} />';
material = `
<meshStandardMaterial
color="#fbbf24"
emissive="#92400e"
emissiveIntensity={0.5 + balance * 2}
roughness={0.2}
metalness={0.8}
/>`
];
const material = materials[Math.floor(Math.random() * materials.length)];

const isDreiImportNeeded = material.includes('MeshDistortMaterial') || material.includes('MeshWobbleMaterial');
const importedDrei = isDreiImportNeeded ? `import { ${material.includes('MeshDistortMaterial') ? 'MeshDistortMaterial' : ''}${material.includes('MeshDistortMaterial') && material.includes('MeshWobbleMaterial') ? ', ' : ''}${material.includes('MeshWobbleMaterial') ? 'MeshWobbleMaterial' : ''} } from '@react-three/drei'` : '';
color="#3f6212"
roughness={0.8}
metalness={0.1}
wireframe={balance > 5}
/>`;
customLogic = `
// Project Genie Landscape Simulation
const positions = meshRef.current.geometry.attributes.position;
for (let i = 0; i < positions.count; i++) {
const x = positions.getX(i);
const y = positions.getY(i);
const z = Math.sin(x * 2 + state.clock.elapsedTime) * 0.5 + Math.cos(y * 2 + state.clock.elapsedTime) * 0.5;
positions.setZ(i, z * Math.min(1, balance * 2));
}
positions.needsUpdate = true;
meshRef.current.rotation.x = -Math.PI / 2;
meshRef.current.rotation.z += 0.001;
`;
Comment on lines +189 to +201
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This animation logic has performance and efficiency issues. Updating geometry attributes (positions.setZ) and setting needsUpdate = true inside useFrame forces a CPU-to-GPU buffer upload every frame, which is expensive. For procedural landscapes, a vertex shader is preferred. Additionally, setting rotation.x to a constant value every frame is redundant; this should be set once on the mesh component's initial props.

importedDrei = '';
additionalMeshes = '';
} else {
geometry = '<boxGeometry args={[4, 0.2, 4]} />';
material = `
<meshStandardMaterial
color="#854d0e"
roughness={0.6}
metalness={0.2}
/>`;
customLogic = `
// Project Genie Physics Makerspace Simulation
meshRef.current.rotation.y += 0.005;
meshRef.current.rotation.x = Math.sin(state.clock.elapsedTime * 0.2) * 0.1;
`;
additionalMeshes = `
<mesh position={[0, 0.5, 0]}>
<boxGeometry args={[0.5, 0.5, 0.5]} />
<meshStandardMaterial color="#ef4444" />
</mesh>
<mesh position={[1, 0.3, 1]}>
<sphereGeometry args={[0.3, 16, 16]} />
<meshStandardMaterial color="#3b82f6" />
</mesh>
`;
importedDrei = '';
}
} else {
const geometries = [
'<torusKnotGeometry args={[1.5, 0.4, 128, 32]} />',
'<sphereGeometry args={[1.5, 32, 32]} />',
'<boxGeometry args={[2, 2, 2]} />',
'<octahedronGeometry args={[1.5, 0]} />',
'<icosahedronGeometry args={[1.5, 0]} />'
];
geometry = geometries[Math.floor(Math.random() * geometries.length)];

const materials = [
`
<MeshDistortMaterial
color="#8b5cf6"
emissive="#4c1d95"
emissiveIntensity={0.5 + balance * 2}
roughness={0.2}
metalness={0.8}
distort={0.3}
speed={2}
/>`,
`
<MeshWobbleMaterial
color="#06b6d4"
emissive="#0e7490"
emissiveIntensity={0.5 + balance * 2}
roughness={0.2}
metalness={0.8}
factor={1}
speed={2}
/>`,
`
<meshStandardMaterial
color="#fbbf24"
emissive="#92400e"
emissiveIntensity={0.5 + balance * 2}
roughness={0.2}
metalness={0.8}
/>`
];
material = materials[Math.floor(Math.random() * materials.length)];
const isDreiImportNeeded = material.includes('MeshDistortMaterial') || material.includes('MeshWobbleMaterial');
importedDrei = isDreiImportNeeded ? `import { ${material.includes('MeshDistortMaterial') ? 'MeshDistortMaterial' : ''}${material.includes('MeshDistortMaterial') && material.includes('MeshWobbleMaterial') ? ', ' : ''}${material.includes('MeshWobbleMaterial') ? 'MeshWobbleMaterial' : ''} } from '@react-three/drei'` : '';
Comment on lines +270 to +271
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for constructing the importedDrei string is difficult to read and maintain. Using an array to collect imports and joining them with a comma is a cleaner and more robust approach.

    const imports = [];
    if (material.includes('MeshDistortMaterial')) imports.push('MeshDistortMaterial');
    if (material.includes('MeshWobbleMaterial')) imports.push('MeshWobbleMaterial');
    importedDrei = imports.length > 0 ? `import { ${imports.join(', ')} } from '@react-three/drei'` : '';

Comment on lines +270 to +271
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The string construction for importedDrei is brittle and difficult to maintain due to the nested ternary operators and manual comma handling. Using an array to collect required imports and joining them is a much cleaner and more robust approach.

    const imports = [
      material.includes('MeshDistortMaterial') && 'MeshDistortMaterial',
      material.includes('MeshWobbleMaterial') && 'MeshWobbleMaterial'
    ].filter(Boolean);
    importedDrei = imports.length > 0 ? `import { ${imports.join(', ')} } from '@react-three/drei'` : '';

customLogic = `
meshRef.current.rotation.y += 0.002
meshRef.current.rotation.x = Math.sin(state.clock.elapsedTime * 0.5) * 0.1
// Intensity scales with balance
const intensity = Math.min(1, balance * 10)
meshRef.current.scale.setScalar(1 + intensity * 0.2)
`;
additionalMeshes = '';
}

return `// Auto-generated by Yennefer Genesis Cycle
// Directive: ${directive}
Expand All @@ -211,19 +292,18 @@ export default function ${name}({ balance = 0 }) {

useFrame((state) => {
if (meshRef.current) {
meshRef.current.rotation.y += 0.002
meshRef.current.rotation.x = Math.sin(state.clock.elapsedTime * 0.5) * 0.1
// Intensity scales with balance
const intensity = Math.min(1, balance * 10)
meshRef.current.scale.setScalar(1 + intensity * 0.2)
${customLogic}
}
})

return (
<mesh ref={meshRef} position={[0, 0, 0]}>
${geometry}
${material}
</mesh>
<group position={[0, -1, 0]}>
<mesh ref={meshRef}>
${geometry}
${material}
</mesh>
${additionalMeshes}
</group>
)
}
`;
Expand Down
2 changes: 1 addition & 1 deletion wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ compatibility_flags = ["nodejs_compat"]
# Installs frontend deps and builds the SPA so frontend/build exists before
# `wrangler deploy` uploads assets. NODE_OPTIONS is required for
# react-scripts 5.x + Node 18+ (webpack 4 OpenSSL 3.0 compatibility).
command = "cd frontend && npm install --include=dev && GENERATE_SOURCEMAP=false CI=false NODE_OPTIONS=--openssl-legacy-provider npm run build"
command = "cd frontend && npm install --include=dev --legacy-peer-deps && GENERATE_SOURCEMAP=false CI=false NODE_OPTIONS=--openssl-legacy-provider npm run build"

# ─── Static Assets (React SPA build output) ──────────────────────────────────
# Built by `npm run build` (root package.json) before every `wrangler deploy`.
Expand Down