Community Gardens is a data-driven generative art installation that runs inside a browser.
Built using javascript and threejs, it generates plants. Each plant represents a student that we have food and housing insecurity information about.
Dr Mary Haskett conducted a survey last year that collects information from students. Some students are well-resourced and others face insecurities. The survey clarified exactly how much insecurity students face, and we learned that 9.6% of students experienced homeless over the past year.
My job starts with the data. The survey results are exported from a spreadsheet to a json file. The file is zipped to preserve bandwidth. It was an 8 meg json file, but I got it down to 145k by removing irrelevant values and zipping the file.
Once the file is loaded and unzipped, the Insecurity Calculator processes the data. It calculates:
These values drive a bunch of plant characteristics, but we're not done with the data yet. We need to aggregate the data in meaningful ways.
Gardens can be created based around a certain statistic, and derived at any time. Available stastics are:
Once the aggregate data is available, gardens are created. A garden consists of a data model, a grouping of plants and a layout for the plants. Gardens can also be configured with colors and backgrounds.
The available chapters are:
Each garden creates multiple Spawn instances. a Spawn is responsible for deriving plant properties based on the data, instantiating and managing (animateIn and removal of) the plant instances.
Available Spawn classes are:
The connection of data-to-plant-properties happens in the Transformers
. Each transformer accepts data input (calculated from the InsecurityCalculator) and outputs plant properties, as defined in attribute modifiers
.
For instance, the age modifier accepts a student's age and then transforms the props.petalCount
accordingly.
The available modifiers are:
The plants are essentially data holders for the transformed properties when they are instantiated, but once the createChildren
method is called, the geometry, materials, and mesh are created and added to the scene. This method of deferred instantiation prevents dropped frames while creating multiple plants.
The geometries are created algorithmically in three parts:
The algorithm creates geometries and applies different materials based on the properties assigned to the plant.
Each plant property is settable and will trigger a redraw of the plant. The available properties are:
setAnimated(animated)
setDuration(duration)
setDelay(delay)
setRandomSeed(randomSeed) setWindForce(windForce)
setWindDirection(windDirection)
setHeight(height)
setOffset(offset)
setDisplacement(displacement)
setThickness(thickness)
setPointCount(pointCount)
setPetalStartPoint(petalStartPoint)
setPetalEndPoint(petalEndPoint)
setRotationStart(rotationStart)
setRotationEnd(rotationEnd)
setSizeStart(sizeStart)
setSizeEnd(sizeEnd)
setColor(color)
setHSLBase(hslBase)
setHSLRange(hslRange)
setBerryCount(berryCount)
setBerrySize(berrySize)
setBerryRotation(berryRotation)
setBerryColor(berryColor)
setBerryDistanceFromStem(berryDistanceFromStem)
setBerrySpiral(berrySpiral)
setOpenness(openness)
setPetalCount(petalCount)
setLeafCount(leafCount)
setLeafStartPoint(leafStartPoint)
setLeafEndPoint(leafEndPoint)
setRearPetalCount(rearPetalCount)
setPetalWidth(petalWidth)
setPetalLength(petalLength)
setPetalDistanceFromCenter(petalDistanceFromCenter)
setRotationAxis(rotationAxis)
setRotationAngle(rotationAngle)
setTranslateToY(translateToY)
setPetalRotation(petalRotation)
BasePlant is responsible for common plant tasks, like drawing the stem, handling setter methods for all the properties, cleaning the instance for garbage collection, the animateIn and animateOut methods.
BaseRenderable is resonsible for managing state in a react-like manner. Even if multiple properties change, the render method is only called once.
A plant has a focal point which tells the camera where exactly to look at it while focusing.
Plants can be arranged in a variety of layouts.
Layouts can be sized with a bounds
object, which is a Vector3
of width, height, and depth.
The available layouts are:
Once the meshes have been created with the appropriate data and added to a scene, threejs handles rendering.
Threejs supports moving and rotating any 3d object, including the camera. Assigning camera position
props as part of a TweenMax
tween, we can create fluid camera movement.
The specific process is to choose a random plant and obtain its focal point. Tween the camera and the cameraTarget to that location. Once the camera completes its tween, another plant is chosen and the process is repeated.
The application behaves differently depending on the device it's running. There are two main breakpoints:
timeMultiplier
parameter set to 0.3, which slows the entire scene down to 30%. Certain displays also turn sidebars and 3D titles on to display additional content, and the camera is set to autopilot.Properties can be manually overriden via query string. The available query strings are:
?dpr=0.1
for mad pixelation.?debug=1
to enable debug mode. This includes framerate stats, color palletes, and a gui for manipulating the camera.Although threejs is all javascript, it's not immediately obvious how to render it inside a react compnent's render method, especially if you need to share data from redux. I followed this direction, which worked quite well.
The project is all javascript and WebGL, meaning it runs on 20' walls in the Hunt Library's Immersion Theatre, on a desktop, or a mobile device (although with fewer plants on smaller devices to make sure phones don't blow up).
Learn more about how the data affects each individual plant, or commit to making a change.
This project was funded by the
Andrew W. Mellon Foundation.
Copyright © 2019 lucastswick. All rights reserved.