Prompt utilisé pour régénérer cette page :
Page: Framogen
Description: "Fractal Mountain Generator using Diamond-Square algorithm"
Category: computer-science
Icon: terrain
Tags: fractal, procedural, terrain
Status: (none specified — no status field in front matter)
Front matter (index.md):
title: "Framogen"
description: "Fractal Mountain Generator using Diamond-Square algorithm"
icon: "terrain"
tags: ["fractal", "procedural", "terrain"]
NOTE: No status field in front matter (unlike other pages).
HTML structure (index.md):
<section class="framogen-container container" style="margin: 0 auto;">
<canvas id="framogen-canvas"></canvas>
</section>
NOTE: Does NOT use .visual, .size-800, .ratio-1-1, or .canvas-contain classes.
Container class is "framogen-container container" with inline margin auto.
Canvas resizes dynamically to match grid resolution.
Widget files:
- _controls.right.md (weight: 10):
##### Controls — div.framogen-controls:
{{< button id="generate-btn" label="Generate" >}}
- _options.right.md (weight: 20): Three sections using <dl> elements:
##### Generation — <dl> with:
Seed: <input type="number" id="seed" value="0" style="width: 100%;">
Noise: <select id="noise-type"> with Diamond-Square (selected) and Perlin
Octaves: <input type="range" id="octaves" min="1" max="8" value="1">
Detail: <select id="grid-size"> with Low 129x129 (7), Medium 257x257 (8), High 513x513 (9, selected), Ultra 1025x1025 (10)
##### Terrain — <dl> with:
Roughness: range id="roughness" (20-100, value 50)
Chaos: range id="chaos" (10-100, value 50)
Deviation: range id="deviation" (10-100, value 50)
Erosion: range id="erosion" (0-50, value 0)
##### Display — <dl> with:
Shading: <select id="shading"> with Slope (selected) and Flat
Retro 16 colors: <input type="checkbox" id="retro">
3D Isometric: <input type="checkbox" id="view-3d">
<p class="hint"> with keyboard shortcuts: Space/R, A, V, +/-, 0, mouse wheel, drag
- _algo.after.md (weight: 10): ##### Diamond-Square Algorithm — explains the 5 steps (initialize, diamond, square, reduce, repeat), complexity O(n²), color mapping description.
NOTE: The algorithm widget file is named _algo.after.md (not _algorithm.after.md).
Architecture (single file default.js):
- IIFE, no imports (uses console.log)
- Inspired by original Atari ST FRAMOGEN by Mocha/Mega1 (1992)
NOTE: No SCSS file. No default.scss exists for this page.
Configuration defaults:
gridPower: 9 (grid size = 2^9 + 1 = 513)
initialRoughness: 1.0, ROUGHNESS_DECAY: 0.5
chaos: 0.5, deviation: 0.5, slopeShading: true
currentSeed: Date.now(), noiseType: 'diamond', octaves: 1
erosionIterations: 0, retroMode: false, view3D: false
zoomLevel: 1.0, panX: 0, panY: 0
Seeded RNG (Mulberry32):
seedRandom(seed): initializes rngState from seed
seededRandom(): returns deterministic pseudo-random 0-1
random(): alias for seededRandom()
Diamond-Square algorithm:
createHeightMap(size, level, chaosAmount): Float32Array, corners initialized with level ± chaos
diamondStep(map, size, x, y, half, roughness, deviationScale): avg of 4 square corners + random offset × roughness × deviation
squareStep(map, size, x, y, half, roughness, deviationScale): avg of up to 4 diamond neighbors (edge-aware) + random offset
diamondSquare(map, size, deviationScale): iterative subdivision, halving step and reducing roughness by ROUGHNESS_DECAY (0.5) each level
normalizeHeightMap(map): scales all values to 0-1 range
Perlin noise (inline 2D implementation):
PERM: Uint8Array(512) permutation table, GRAD: 8 gradient vectors
initPerlin(): shuffle permutation table using seeded random
fade(t): 6t^5 - 15t^4 + 10t^3
lerp(a, b, t): linear interpolation
grad(hash, x, y): gradient dot product
perlin2D(x, y): standard 2D Perlin noise
generatePerlinMap(size, numOctaves): generates height map with octave summation (halving amplitude, doubling frequency)
Hydraulic erosion (applyErosion):
Droplet-based simulation: inertia=0.05, capacity=4, deposition=0.3, erosion=0.3, evaporation=0.01
Each drop: random position, follows gradient, erodes downhill, deposits uphill or when over capacity
Max 64 steps per drop, speed and water tracked
erosionIterations * 100 = actual drop count
Terrain generation (generateTerrain):
If noiseType === 'perlin': use generatePerlinMap with octaves
If noiseType === 'diamond': Diamond-Square base terrain, normalized
If octaves > 1: add detail layers with decreasing amplitude (×0.5 each octave)
normalizeHeightMap on final result
Color system:
7 elevation bands (ELEVATION_COLORS):
0.20: deep ocean (#001f3f), 0.35: sea (#0074D9), 0.40: sand (#FFDC00),
0.55: grass (#2ECC40), 0.70: forest (#1a5c1a), 0.85: rock (#808080), 1.00: snow (#FFFFFF)
14 retro bands (RETRO_COLORS): Atari ST style from dark blue to white
getInterpolatedColor(elevation): smooth interpolation between bands in normal mode, hard bands in retro mode
hexToRgb(hex): parse hex color to {r, g, b}
applySlopeShading(color, slope): factor = 1 + clamp(slope, -0.4, 0.4), multiplied to RGB
Slope calculation:
calculateSlope(map, size, x, y): light from top-left
slope = (h - hLeft) + (h - hUp) scaled by ×2
Rendering:
draw2D(): pixel-by-pixel via ImageData, with zoom/pan coordinate mapping
For each pixel: map to grid coords, get elevation, get interpolated color, apply slope shading
draw3D(): isometric retro-style view
Sky blue background (#87CEEB)
Sample every N points (max(2, gridSize/128))
Isometric projection: isoX = w/2 + (gx-gy)*scaledWidth, isoY = baseY - elevation*100
Draw vertical lines from base to peak + top pixel
Back-to-front rendering order
Canvas setup:
Canvas resolution matches grid size exactly (not fixed 800px)
Container sized to grid dimensions, aspect-ratio: unset
NO devicePixelRatio scaling (1:1 pixel mapping for terrain)
Zoom/Pan:
zoomLevel: 1.0 to 8.0
panX, panY: offset in canvas pixels
Mouse wheel: zoom toward cursor position (adjusts pan for centered zoom)
Mouse drag (left button, only when zoomed): pan by delta / zoomLevel
Keyboard: +/- zoom, 0 reset
Animation (morph):
startAnimation(): store current as sourceMap, generate new targetMap
animateStep(): interpolate heightMap = source + (target-source)*progress
morphProgress += 0.02 per frame, completes at 1.0
Triggered by 'A' key or animate button (if it existed in controls)
Keyboard shortcuts:
Space/KeyR: regenerate with new seed (Date.now())
KeyA: start animation morph
KeyV: toggle 3D view
Equal/NumpadAdd: zoom in (×1.5, max 8)
Minus/NumpadSubtract: zoom out (÷1.5, min 1)
Digit0: reset zoom/pan
Canvas click: regenerate when not zoomed and not dragging
Controls event listeners:
generate-btn: new seed + generate()
roughness slider: initialRoughness = value/50, regenerate
chaos slider: chaos = value/100, regenerate
deviation slider: deviation = value/100, regenerate
grid-size select: gridPower = value, regenerate
shading select: slopeShading = (value === 'slope'), redraw
seed input: currentSeed = value, regenerate
noise-type select: noiseType = value, regenerate
octaves slider: octaves = value, regenerate
erosion slider: erosionIterations = value, regenerate
retro checkbox: retroMode = checked, redraw (with click stopPropagation)
view-3d checkbox: view3D = checked, redraw (with click stopPropagation)
NOTE: animate-btn is referenced in JS but not present in the controls widget. Animation is only triggered via keyboard (A key).
Auto-init on DOM ready (DOMContentLoaded or immediate if already loaded).
Generates terrain immediately on initialization.
Page entièrement générée et maintenue par IA, sans intervention humaine.