nervous_system_hansmeyer · HyphaeNetwork
Hyphae Network
A 2D port of Nervous System's Hyphae generative jewelry. Hyphae are root-like rhizome networks that fuse Nervous System's two favourite algorithms: an L-system defines the branching skeleton, and a space-colonization pass (Runions et al., 2005) fills the interior with a venation pattern attracted to a cloud of 'auxin' points. We collapse the L-system into a single radial array of root tips and run the space-colonization loop directly. Each tip samples attractors within an attraction radius, averages their directions, advances along that vector, and removes any attractor that falls inside the kill radius. Stochastic side-branches are spawned with a small probability per tip per step, building a hierarchical root-like mesh.
Original: https://n-e-r-v-o-u-s.com/blog/?p=1392
▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.
Math essence
For each tip i and attractor a_j with |p_i - a_j| < d_attract, accumulate diff = (a_j - p_i). The new direction d = normalize(sum diffs). New tip p_i' = p_i + d * L_segment. Attractor a_j is removed when |p_i - a_j| < d_kill. With probability p_branch a tip spawns two rotated clones, yielding the rhizome-like hierarchy.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 600 | 200–1200 | Square canvas side length |
n_attractors | int | 600 | 30–4000 | Number of auxin/attractor points scattered inside the disk |
attractor_radius | float | 0.42 | 0.1–0.5 | Radius of the attractor cloud as a fraction of dim |
n_roots | int | 4 | 1–12 | Number of initial root tips |
segment_length | float | 0.0085 | 0.001–0.05 | Per-step tip advance as a fraction of dim |
attract_distance | float | 0.18 | 0.02–0.5 | Maximum distance at which an attractor influences a tip |
kill_distance | float | 0.012 | 0.001–0.1 | Distance below which an attractor is consumed |
branch_prob | float | 0.1 | 0–0.5 | Per-tip probability of spawning a side-branch per step |
branch_angle | float | 0.65 | 0.05–1.6 | Side-branch angle (radians) |
thickness_growth | float | 0.018 | 0–0.1 | Reserved for future thickness-from-flux canalization |
max_tips | int | 1200 | 30–8000 | Hard cap on live tips to bound memory |
max_steps | int | 240 | 20–1000 | Number of simulation ticks |
bg_color | tuple | 12,14,22 | null–null | Background RGB |
vein_color | tuple | 200,230,220 | null–null | Primary vein RGB |
core_color | tuple | 255,200,130 | null–null | Thick-root RGB |
seed | int | null | 0–999999 | RNG seed |
Reference
First 60 lines of reference.py. Full source:
library_external/nervous_system_hansmeyer/HyphaeNetwork/reference.py
from __future__ import annotations
from typing import ClassVar
import imageio.v2 as imageio
import numpy as np
class HyphaeNetwork:
family: ClassVar[str] = "nervous_system_hansmeyer"
sketch: ClassVar[str] = "HyphaeNetwork"
def __init__(
self,
dim: int = 600,
n_attractors: int = 600,
attractor_radius: float = 0.42,
n_roots: int = 4,
root_radius: float = 0.05,
segment_length: float = 0.0085,
attract_distance: float = 0.18,
kill_distance: float = 0.012,
branch_prob: float = 0.10,
branch_angle: float = 0.65,
thickness_growth: float = 0.018,
max_tips: int = 1200,
max_steps: int = 240,
bg_color: tuple[int, int, int] = (12, 14, 22),
vein_color: tuple[int, int, int] = (200, 230, 220),
core_color: tuple[int, int, int] = (255, 200, 130),
seed: int | None = None,
) -> None:
self.dim = dim
self.n_attractors = n_attractors
self.attractor_radius = attractor_radius
self.n_roots = n_roots
self.root_radius = root_radius
self.segment_length = segment_length
self.attract_distance = attract_distance
self.kill_distance = kill_distance
self.branch_prob = branch_prob
self.branch_angle = branch_angle
self.thickness_growth = thickness_growth
self.max_tips = max_tips
self.max_steps = max_steps
self.bg_color = np.array(bg_color, dtype=np.uint8)
self.vein_color = np.array(vein_color, dtype=np.uint8)
self.core_color = np.array(core_color, dtype=np.uint8)
self._seed = seed
self.rng = np.random.default_rng(seed)
self.canvas = np.full((dim, dim, 3), self.bg_color, dtype=np.uint8)
self._stage = 0
self.time = 0
self._nodes: list[np.ndarray] = []
self._parents: list[int] = []
self._thickness: list[float] = []
self._tips: list[int] = []
self._attractors: np.ndarray = np.zeros((0, 2), dtype=np.float32)
self.reset()
Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/nervous_system_hansmeyer/HyphaeNetwork/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from nervous system × hansmeyer
Floraform Growth
nervous_system_hansmeyer · FloraformGrowth
A 2D port of Nervous System's Floraform generative jewelry system.
Radiolarian Lattice
nervous_system_hansmeyer · RadiolarianLattice
Nervous System's Radiolaria series translates Ernst Haeckel's 19th-century radiolarian drawings into 3D-printed sculpture.
Subdivided Columns
nervous_system_hansmeyer · HansmeyerSubdivision
Michael Hansmeyer's 2014 'Subdivided Columns' is a computational-design exercise in baroque complexity from algorithmic simplicity: start with a regular polygon, subdivide each edge, perturb each new vertex by a small random offset, repeat.
Voxel Field Cross-Section
nervous_system_hansmeyer · DillenburgerVoxelField
Benjamin Dillenburger's voxel-printing research (Digital Building Technologies, ETH Zurich, ~2016) replaced the smooth isosurface extraction of conventional architectural geometry with a literal 3D voxel grid: every cell is either solid or empty, and the boundary of the field is what gets fabricated.