designcoding
About Table of Contents Keywords Monthly Archive
Support designcoding!

Differential Growth

June 16, 2025 | Algorithms
#grasshopper #growth #rhino-python #simulation #vector-field

Differential growth is a process where different parts of a structure grow at different rates, leading to complex forms. After watching this, I decided to try it in Grasshopper. Here, differential growth mimics this behavior by applying rules such as Repulsion to avoid crowding or overlapping, Cohesion to keep parts connected or within a range, and Insertion to add new elements when a part stretches too far. The algorithm I present here simulates a differential growth process starting from a set of points along a curve. All agents apply repulsion forces to each other if they are within a certain distance. Each agent checks its neighbors: it pushes or pulls them. Additionally, when two neighbors become too far apart, the code inserts a new (point) agent. Over time, this interaction leads to growing patterns shown below:

Differential Growth animation

I developed this Grasshopper Python code in Rhino 8 (Python 3). This means it will NOT work in Rhino 7. Crv is the initial curve for the starting agents. I is the distance threshold above which a new agent is inserted. R is the range within which global repulsion is applied. K is the scaling factor for force accumulation. Q is the damping coefficient (controls how fast they slow down). N is the maximum number of agents. When Run is triggered, it triggers one iteration of the simulation. I attached a Grasshopper Timer component to repeat it. The outputs are the points and the vectors. This implementation makes some optimizations, but it still checks every boid with every other. So it becomes very (really) slow when you increase the N value too much. Below is the Python code inside the Grasshopper definition. You can find the definition at the bottom of this page.

import rhinoscriptsyntax as rs
import math
insertDistance = I
repulsionDistance = R
k = K
q = Q
def vector_add(a, b):
	return [a[0]+b[0], a[1]+b[1], a[2]+b[2]]
def vector_subtract(a, b):
	return [a[0]-b[0], a[1]-b[1], a[2]-b[2]]
def vector_scale(v, s):
	return [v[0]*s, v[1]*s, v[2]*s]
def vector_length(v):
	return math.sqrt(v[0]**2 + v[1]**2 + v[2]**2)
def vector_unitize(v):
	length = vector_length(v)
	if length == 0:
		return [0,0,0]
	return [v[0]/length, v[1]/length, v[2]/length]
def vector_distance_sq(a, b):
	return (a[0]-b[0])**2 + (a[1]-b[1])**2 + (a[2]-b[2])**2
class Boid():
	def __init__(self, pos, vel):
		self.pos = list(pos)
		self.vel = list(vel)	
	def updateVel(self, i):
		forces = [0,0,0]
		for boid in flock:
			if boid != self:
				dis = vector_distance_sq(boid.pos, self.pos)
				if dis < repulsionDistance ** 2:
					dif = vector_subtract(boid.pos, self.pos)
					dif = vector_unitize(dif)
					dif = vector_scale(dif, -1 / dis)
					forces = vector_add(forces, dif)
		n_boid = flock[i-1]
		p_boid = flock[(i+1) % len(flock)]
		p_dis = vector_distance_sq(p_boid.pos, self.pos)
		p_dif = vector_subtract(p_boid.pos, self.pos)
		p_dif = vector_unitize(p_dif)
		p_dif = vector_scale(p_dif, 1 / p_dis)
		if p_dis < (insertDistance * 0.5) **2:
			p_dif = vector_scale(p_dif, -1)
		forces = vector_add(forces, p_dif)
		n_dis = vector_distance_sq(n_boid.pos, self.pos)
		n_dif = vector_subtract(n_boid.pos, self.pos)
		n_dif = vector_unitize(n_dif)
		n_dif = vector_scale(n_dif, 1 / n_dis)
		if n_dis < (insertDistance * 0.5) **2:
			n_dif = vector_scale(n_dif, -1)
		forces = vector_add(forces, n_dif)
		forces = vector_scale(forces, k)
		self.vel = vector_add(self.vel, forces)
	def updatePos(self):
		self.pos = vector_add(self.pos, self.vel)
		self.vel = vector_scale(self.vel, q)
def check_insert_particles(flock):
	i = 0
	while i < len(flock):
		boidA = flock[i]
		boidB = flock[(i + 1) % len(flock)]
		dis = vector_distance_sq(boidA.pos, boidB.pos)
		if dis > insertDistance**2:
			pos = vector_scale(vector_add(boidA.pos, boidB.pos), 0.5)
			vel = vector_scale(vector_add(boidA.vel, boidB.vel), 0.5)
			flock.insert(i+1, Boid(pos, vel))
		else:
			i += 1
def reset_flock():
	points = rs.CurvePoints(Crv)
	points = rs.CullDuplicatePoints(points)
	center = rs.CurveAreaCentroid(Crv)[0]
	for point in points:
		vel = vector_subtract(point, center)
		vel = vector_unitize(vel)
		boid = Boid(point, vel)
		flock.append(boid)
if "ready" not in globals() or Reset:
	ready = True
	flock = []
	reset_flock()
if ready and Run:
	if len(flock) < N:	
		check_insert_particles(flock)
	for i, boid in enumerate(flock):
		boid.updateVel(i)
	for boid in flock:
		boid.updatePos()
pos = [rs.CreatePoint(*boid.pos) for boid in flock]
vel = [rs.CreateVector(*boid.vel) for boid in flock]
Grasshopper definition (GH)Download

Cite this post

Yazar, T. (2025, June 16). Differential Growth. designcoding. Retrieved September 11, 2026, from https://www.designcoding.net/differential-growth/

Related Posts

Flow Map on Terrains

September 11, 2026

We previously looked at the terrain generator script we used in projects with first-year architecture students over here. Later on, we added a few analysis modules to this tool. You might remember the slope analysis tool from this link. Today’s topic is another type of analysis: flow. The idea for this code wasn’t actually mine; I developed it by looking at an existing script based on Serkan Uysal’s suggestion. Unfortunately, I don’t know who originally wrote it. Keeping track of…

Wandering Simulator

March 9, 2024

In 1986, Craig Reynolds developed an algorithm aiming to model the flocking behavior of birds, which remains a cult method used in flock simulations today. In my initial study, the bird-oids (boids) have no rules or limitations, just chilling randomly on the screen. I call this initial version Wandering Simulator. There are several reasons why this fundamental simulation is difficult in Grasshopper and Python, our parametric design interface. In Grasshopper (data flow modeling), pushing the back doors a bit is…

Syntax, Meaning, and Wasp

August 24, 2026

The question of how form emerges in architecture has always been one of the most fundamental debate topics of computational design. When I was a graduate student, we used to examine how abstract language structures made of words and rules turned into spatial and geometric systems. In this post, starting from the reflection of linguistic theories on architecture, we will talk about the logic of discrete aggregation that we study in the first year Design Computing courses. At the same…

Solar Position

May 6, 2012

Experimenting with various plug-ins for solar calculations, I found Daniel Da Rocha’s robust implementation of the solar position algorithm in vb.net. It calculates the solar angle of any place and time. Although it’s written in the old vb.net component, it still works great. I’m trying to create a fast and easy workflow to optimize Grasshopper models based on solar directions. This is done by projecting faces to the solar planes and checking how much of their area is included in…

Parametric Bricks

January 17, 2024

In 2016, archi-union architects and fab-union intelligent engineering completed the renovation of the art gallery in Shanghai, China. The distinctive feature of the building was the robotic masonry fabrication of the brick facades. The undulating and waving parametric bricks were increasingly becoming popular after the introduction of parametric design tools such as Grasshopper and the works of Gramazio & Kohler at ETH Zurich since 2008, I guess. I made two Grasshopper experiments in 2012 and 2013 to generate such structures….

  • Chapters

    • Algorithms
    • Discourses
    • Fabrications
    • Studios
  • Explore

    • All Keywords
    • Table of Contents
    • Monthly Archive
    • #polyhedra
    • #parametric-surface
    • #robot
    • #tessellation
    • #terrain
    • #boolean
    • #kuka-prc
    • #parametric-curve
    • #design-object
    • #image-sampler
    • #linear-algebra
    • #sandblasting
    • #stone
    • #dome
    • #animation
    • #art
    • #aperiodic
    • #tiling
    • #tutorial
    • #python
  • Search

  • Support designcoding!

  • Enjoying designcoding? Support me on Patreon to keep it growing. Thank you!

  • copyright 2026 designcoding.net | about | privacy policy | end user license agreement