Peter Gagliardi (ptrgags@gmail.com)
This repository is a simulation of various 3D drawing machines.
This is my alternative to this year's Inktober challenge. Instead of pen-and-ink drawings, I challenge myself to publish a new drawing machine simulation each day for the month of October.
Check back often, and enjoy!
Drawing machines are usually physical hand-operated machines that move a pen across the paper such that it makes intricate patterns. Think of the Spirograph you might have played with as a kid or the recent contender, the ThinkFun Hypnograph.
I was fascinated by these as a kid. Now, with much more math under my belt, I again find them fascinating for their mathematical intrigue.
For this project, I took the concept of drawing machines to a new level. I expanded some drawing machines that operate in 2D into 3-dimensional equivalents. Even if they are not always physically possible to build, the resulting shapes are still too pretty to dismiss.
I also combined various mechanisms to make
Inktober is a 31-day art challenge by artist Jake Parker. The goal is to draw something every day during the month of October and share the results. I've done this the past two years:
This year, I wanted to do something different. Instead of a traditional art
challenge, I am going to work on this simulation for a month. Each day I will
post a new machine to the gh-pages branch for display at
https://ptrgags.dev/drawing-machines or https://ptrgags.github.io/drawing-machines.
After October, I'll take a break for November. Then I have some further plans for this project. Stay tuned :)
Below are the roles of key classes in the source code
index.jsis the entry point of the application. It loads the machines to display, constructs aRendererRenderer.jshandles setting up the BabylonJS engine, creating the GUI, and managing a collection of active drawing machines.machines/Machine.jsis the base class that defines a drawing machine. a machine is a DAG ofParts that represents a drawing machine. It handles building and updating the parts in the correct order based on dependencies (via topological sort).parts/Part.jsis the base class for drawing machine parts. Some represent concrete concepts such asWheel, which is a cylinder that spins. Others are more abstract likeCentroidwhich computes the centroid of several moving points in the scene.Parts handle constructing BabylonJSTransformNodes and other primitives. One unusual feature is thatPartskeep their translate/rotate/scale matrices as separate matrices rather than combining them into one matrix. This makes it easier to construct complex transformation hierarchies needed for some of the drawing machines. These nodes can be accessed throughJoints. Parts can be updated each frame with a time value that gets passed in fromRenderer -> Machine -> PartJoint.jsThis is a pair of(part, node_name). It provides a convenient way of connecting a part to any other transformation matrix of a second part. Furthermore, there are a few convenience methods like computing the world position of the origin of the model matrix thisJointrepresents.parts/Trace.jsThisPartis notable because it is what actually produces the intricate parametric curves. It is a polyline that keeps track of the most recent N positions of whichever transform it is attached to (source) Furthermore, a second transformation can be used as the origin (origin), and a third can be used as the reference frame (target). Thistargettransformation is particularly interesting, since it allows for drawing on rotated reference frames (like paper attached to a turntable).waves/Wave.jsThis base class wraps 2-pi-periodic functions like sine and square waves using the Strategy design pattern. This can be used in a few parts such asOscillatororXYZOscillatorto create more nuanced motion than simple harmonic motion.parts/Prefab.jsThis class adapts aMachineto match the interface ofPart. This makes it much easier to combine machines into larger, more complex drawing machines. In terms of operation, it treats theMachineas a sub-DAG that must complete its operations before thisPartnode is complete.machines/PartViewer.jsThis class wraps aPartinto aMachine, adding an originPointand aTrace. This makes it easy to explore the motion of aPartwithout creating boilerplate classes.