Prompt utilisé pour régénérer cette page :
Page: 3D Cellular Automata
Description: "Game of Life on 3D surfaces"
Category: computer-science
Icon: shape
Tags: cellular-automata, topology, 3d
Status: new
Front matter (index.md):
title: "3D Cellular Automata"
description: "Game of Life on 3D surfaces"
icon: "shape"
tags: ["cellular-automata", "topology", "3d"]
status: ["new"]
HTML structure (index.md):
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<section class="container visual size-800 ratio-1-1 canvas-contain">
<canvas id="cellular-canvas"></canvas>
</section>
NOTE: The <script type="importmap"> block goes BEFORE the section in index.md body.
The canvas element is replaced at runtime by Three.js renderer.domElement with the same ID.
Widget files:
- _controls.right.md (weight: 10): Two sections:
##### Surface — div.cellular3d-controls with:
Geometry selector: <select id="geometry-select"> with 5 options:
Klein Bottle (klein, selected), Torus (torus), Möbius Strip (mobius), Sphere (sphere), Cylinder (cylinder)
div.cellular3d-actions with 3 buttons:
{{< button id="btn-start" label="Start" class="is-start" >}}
{{< button id="btn-pause" label="Pause" class="is-pause" >}}
{{< button id="btn-reset" label="Reset" >}}
- _options.right.md (weight: 20):
##### Speed — div.cellular3d-options:
Label: "Generations/sec: <span id="speed-value">10</span>"
Speed slider: speed-slider (1-60, value 10)
- _stats.right.md (weight: 30):
##### Statistics — <dl> with Generation/Population
Stat IDs: stat-generation, stat-population
- _algorithm.after.md (weight: 10):
##### Klein Bottle Topology — explains non-orientable surface, vertical flip on horizontal wrap, emergent behavior.
Controls hint: "Drag to rotate, scroll to zoom."
Architecture (multi-file):
- default.js: Main orchestrator (IIFE), imports:
- import * as THREE from 'three'
- import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
- import { createKleinGeometry } from './_geometry-klein.js'
- import { createTorusGeometry } from './_geometry-torus.js'
- import { createMobiusGeometry } from './_geometry-mobius.js'
- import { createSphereGeometry } from './_geometry-sphere.js'
- import { createCylinderGeometry } from './_geometry-cylinder.js'
- 5 geometry ES modules: each exports a function createXxxGeometry(segments) returning a THREE.BufferGeometry
SCSS file (default.scss):
- $breakpoint-mobile: 768px
- #cellular-canvas: 100% width/height, cursor grab/grabbing, border-radius 4px
- .cellular3d-controls: flex column, .control-group with select (themed, bordered, rounded), .is-start/.is-pause toggled by .is-running
- .cellular3d-actions: flex row wrap, .button flex:1 min-width 60px (mobile: 45%)
- .cellular3d-options: flex column, label 0.875rem weight 300, range slider with custom thumb styling (webkit+moz), #speed-value weight 600 primary color
- dl: grid 2-col (1fr auto), dt 0.875rem weight 300, dd weight 600 tabular-nums right-aligned
Grid state:
- gridSize = 64 (fixed)
- grid: Uint8Array(64*64), nextGrid: Uint8Array(64*64) — double-buffered
- generation, population counters
- Rules: Game of Life standard — birth: Set([3]), survival: Set([2, 3])
Cell topology (getCell):
- Klein bottle topology:
- Vertical wrap: normal modulo (wy = ((wy % gridSize) + gridSize) % gridSize)
- Horizontal wrap: when wx < 0 or wx >= gridSize, wrap + flip wy = gridSize - 1 - wy
- countNeighbors: 8-connected Moore neighborhood via getCell
Simulation:
- randomize(density=0.25): random cells, count population
- clearGrid(): fill both grids with 0
- step(): apply birth/survival rules cell by cell, swap grid/nextGrid, increment generation, count population
Three.js setup (initThree):
- Scene: background color 0x0a0a14
- Camera: PerspectiveCamera(60, 1:1 aspect, near 0.1, far 1000), position (8, 5, 8)
- Renderer: WebGLRenderer with antialiasing, fixed 800×800 size, devicePixelRatio
- Canvas replacement: old canvas removed from DOM, renderer.domElement inserted with id="cellular-canvas"
- OrbitControls: enableDamping (0.05), autoRotate (speed 0.5)
- Lighting:
- AmbientLight(0x404040, intensity 0.5)
- DirectionalLight(0xffffff, intensity 1) at position (5, 10, 5)
- DirectionalLight(0x4488ff, intensity 0.5) at position (-5, -5, -5) — back light
Grid texture:
- Hidden 512×512 canvas (created in JS, not in DOM)
- gridCtx draws cellular automata state:
- Dead cells: #1a1a2e (dark blue), alive cells: #00d4ff (cyan)
- Cell size = 512/64 = 8px per cell, drawn with 0.5px gap
- THREE.CanvasTexture with NearestFilter (pixelated), RepeatWrapping
- MeshStandardMaterial: map=gridTexture, side=DoubleSide, roughness=0.4, metalness=0.1
- gridTexture.needsUpdate = true after each redraw
Geometry system:
- geometryFactories: object mapping name → factory function (klein/torus/mobius/sphere/cylinder)
- Initial mesh: geometryFactories[currentGeometry](80) — 80 segments
- switchGeometry(name): removes old mesh, disposes old geometry, creates new mesh with same material
Animation loop:
- animate(timestamp) runs continuously via requestAnimationFrame
- Simulation update gated by isRunning AND speed interval (1000/speed ms between steps)
- controls.update() and renderer.render(scene, camera) run every frame regardless
- On step: step() → updateGridTexture() → updateStats()
Controls:
- btn-start: starts if not running (toggleRun)
- btn-pause: pauses if running (toggleRun)
- btn-step: manual step when paused — step() + updateGridTexture() + updateStats()
- btn-reset: stop + randomize(0.25) + update
- btn-clear: stop + clearGrid() + generation=0 + update
- speed-slider: updates speed variable + display span
- geometry-select: calls switchGeometry(value)
- toggleRun(): flips isRunning, toggles .is-running on .cellular3d-controls
Initial state: random at 25% density, not running.
Auto-init on DOM ready (DOMContentLoaded or immediate if already loaded).
Page entièrement générée et maintenue par IA, sans intervention humaine.