Link (currently only works in Chrome):



I figured I would track the nose and both the eyes to create 3 meta balls. Later, I added a fourth one to add some irregularity.



The code is really long and unorganized. I will clean it up later as I later make some improvements. The current code can be found here:



I wanted to make a real time 3D interactive sketch. While browsing through ThreeJS examples, I saw a sketch with moving isosurfaces, and I was instantly hooked. The way those balls formed surfaces based on proximity was really satisfying to watch.

I looked up how to make such surfaces. It could be done by something called "marching cubes." The underlying mechanisms of 3D graphics are really fascinating. It would have been really rewarding to make the whole sketch from scratch with WebGL, but I didn't have time. So I cloned the ThreeJS examples to my local repository and started making modifications to the original example code.

I originally wanted to work with refraction or reflection, but soon found out I would need to use something called cube maps. I couldn't figure out how to convert the flat webcam data to a cube map, so then I looked into texture mapping onto the isosurface. There is just one file dedicated to marching cubes in ThreeJS, and had some shortcomings, so I had to work around some things to get my current result.


Spectacle is characterized as being more passionate about technology than the underlying theory. Speculation, on the other hand, is tends towards criticism and reflection rather than rapid adoption of new technologies. If technology wasn't advancing so fast, the academia would have caught up, keeping a thorough record of things, putting things in perspective, and constructing relevant theories. But currently, the two fields operate at a different pace with contrasting ethos.

I think Ken Goldberg & Joseph Santarromana's Telegarden (1995) is a great example that marries speculation and spectacle. By incorporating a new and popular technology into a very familiar discourse, they correctly exhibit the current state of technology. More importantly, they speculatively bring the technology into an everyday situation, and engage the audience in contemplating the future. It's full of theory. Below is how I see the work positioned between Warburton's dichotomies:



Link :

There are surprisingly many emojis out there (or more accurately stored in your OS). I wanted to make use of this rich source of images somehow. This Emoji Editor grabs the emojis from the hidden file of your computer, enlarges them, and lets you conveniently reconstruct images. You can create virtually infinite number of combinations with various transformations. The resulting images look familiar, but still feel somewhat different from ones we're used to seeing.

There were maybe too many trials and errors. At the end, I got rid of libraries and used plain Javascript. So it took me longer, but the experience was somewhat rewarding. The app is still a bit buggy and is missing a few functions. But I finished much of what I planned for. My goal was to make the whole image-making process simple and addictive. The interface turned out a bit complicated. But I'm still hooked on this idea, and I'm planning to refine the app in the following couple weeks.



I thought of a digital clock with each digit restlessly trying to stand still, while continuously having to offset external forces to stay balanced. I think such state is called dynamic stability. I was inspired by Jacob Tonski's Balance From Within. I used processing with geomerative and fisica libraries.

1. Every time a digit needs to update, it disappears and falls again from a fixed position. Same rule when a digit goes out of bounds. This can cause some unexpected chain reactions in the following few seconds.
2. Each digit has an inherent "tremble" generated by noise. The digit would try to offset the torque by shifting its body left or right. But once it falls to its side, it will be hard to get back up again. Sadly, it will stay there until it needs update and a new number takes its place.

when the clock first turns on

some tension from 8

I like how 0 falls on the 5.

I think my current code cannot perfectly offset the forces. It could be more interesting if the numbers stayed on their feet longer. Also, I first imagined the numbers kind of bouncing left and right micro-scale (like a person does on one foot) and bumping into one another, but couldn't implement that in time. But I can still somewhat see how the numbers are reluctant to fall on its side, and I like that.

import fisica.*;
import geomerative.*;
FWorld world;
RFont font;
FBody[] bodies;
int FONT_SIZE = 200;
int lastShiftTime; 
int newShiftInterval;
float randomShift;
boolean bRecording = false;
int lastMinute;
boolean[] needToCheckUpdate = {true, true, true, true};
FCharController[] controllers;
FChar[] colon;
void setup() {
  world = new FWorld();
  randomShift = random(-50, 50);
  world.setGravity( 0, 400 );
  newShiftInterval= int(random(2000,8000));
  world.setEdges(0, 0, width, height+5, color(255, 0, 0)); 
  font = RG.loadFont("cheltenham-cond-normal-300.ttf");
  colon = new FChar[2];
  colon[0] = new FChar('.', width/2-15, 142);
  colon[1] = new FChar('.', width/2-15, 75);
  controllers = new FCharController[4];
  for (int i=0; i<controllers.length; i++) {
    FCharController controller = new FCharController(i);
    controllers[i] = controller;
  lastMinute = minute();
void draw() {
  for (int i=0; i<controllers.length; i++) controllers[i].update();
void checkMinutePassed() {
  if (minute() == lastMinute) return;
  for (int i=0; i<needToCheckUpdate.length; i++) needToCheckUpdate[i] = true; lastMinute = minute(); } class FCharController { FChar charObj; int index; int lastNumber; boolean disappeared; int dropX; float shiver; float xoff; FCharController(int index) { //charObj = new FChar('9', 100, 150); this.index = index; disappeared = false; lastNumber = 0; // doesn't matter what I assign here dropX = index*150+50; if (index==1) dropX -= 20; else if (index==2) dropX += 20; } void dropNewCharObj() { needToCheckUpdate[index] = false; int newNumber = parseTime(index); println((char)(newNumber+48)); charObj = new FChar((char)(newNumber+48), dropX, -50); world.add(charObj); lastNumber = newNumber; } void dropNewCharObj(int test) { needToCheckUpdate[index] = false; int newNumber = test; println((char)(newNumber+48)); charObj = new FChar((char)(newNumber+48), dropX, -50); //charObj.setRotation(0.115*PI); world.add(charObj); } void update() { if(charObj.isTouchingBody(world.bottom)) { shiver = noise(xoff+=0.025); shiver*=10; shiver-=5; charObj.addTorque(shiver*10000); charObj.addForce(shiver*-10000, 0, 40, 0); } if (charObj.getY()>230) {
      xoff = random(100);
    if (needToCheckUpdate[index] == true) {
      if (lastNumber == parseTime(index)) return;
      int newNumber = parseTime(index);
      lastNumber = newNumber;
      xoff = random(100);
  int parseTime(int index) {
    switch (index){
      case 0: return hour()/10;
      case 1: return hour()%10;
      case 2: return minute()/10;
      case 3: return minute()%10;
    return 9;
class FChar extends FPoly {
  RShape m_shape;
  RShape m_poly;
  boolean m_bodyCreated;
  float initialAngle=0;
  FChar(char chr, float dropX, float dropY){
    this.setFill(0, 0, 0);
    if (chr=='.') {
      this.setPosition(dropX, dropY);
    else {
      this.setPosition(dropX, dropY);
    m_bodyCreated = true;
  void polygonize(char chr) {
    String txt = "";
    txt += chr;
    RG.textFont(font, FONT_SIZE);
    m_shape = RG.getText(txt);
    m_poly = RG.polygonize(m_shape);
    if (m_poly.countChildren() < 1) return;
    m_poly = m_poly.children[0];    
    // Find the longest contour of our letter    `  
    float maxLength = 0.0;
    int maxIndex = -1;
    for (int i = 0; i < m_poly.countPaths(); i++) { float currentLength = m_poly.paths[i].getCurveLength(); if (currentLength > maxLength) {
        maxLength = currentLength;
        maxIndex = i;
    if (maxIndex == -1) return;
    RPoint[] points = m_poly.paths[maxIndex].getPoints();
    for (int i=0; i<points.length; i++) {
      this.vertex(points[i].x, points[i].y);
  void setInitialAngle(char chr) {
    float randomFloat = random(1);
    switch(chr) {
      case '0':
        initialAngle = -0.01*PI;
      case '1':
        if (randomFloat<0.5) initialAngle = 0.115*PI;
        else initialAngle = -0.1*PI;
      case '2':
        if (randomFloat<0.5) initialAngle = 0.14*PI;
        else initialAngle = -0.17*PI;
      case '3':
        initialAngle = -0.15*PI;
      case '4':
        initialAngle = 0.135*PI;
      case '5':
        initialAngle = -0.1*PI;
      case '6':
        //initialAngle = 0.14*PI;
        initialAngle = 0.04*PI;
      case '7':
        initialAngle = -0.04*PI;
      case '8':
        initialAngle = -0.03*PI;
      case '9':
        initialAngle = -0.095*PI;
  boolean bodyCreated(){
    return m_bodyCreated;
  void draw(PGraphics applet){


Digital Grotesque II - Michael Hansmeyer

"What is needed is a new type of design instrument. We need tools for search and exploration, rather than simply control and execution. We require tools that go beyond the fulfillment or optimization of simple functional requirements, and that allow us to investigate and advance more ambiguous factors of the design: soft criteria."

The above excerpt from the project description effectively summarizes the core value of the artwork. Digital Grotesque II is 3.5 meter high 3D printed structure that explores both form and design/manufacture process. I am not familiar with grasshopper or any other parametric modeling tools, so I'm not sure as to how this form came about, or how much of it would be generative. But even if the form weren't completely generated by computer, I believe the result is a proof of the architect's statement that the computer "expands the imagination of the designer." Computer much exceeds the human capacity for speed and complexity in thought.

I also love how the work falls right within the range of "effective complexity"--with both identifiable architectural details and incomprehensible chaotic distortions.


This is a similar kind of question to that I've been asking myself for a long time. I believe there is often a dichotomy between hi-tech and low-tech that divides form of practice, people's tastes, and even school curriculums. I wasn't sure which of two I should side on, (I felt that both groups of people were often disapproving of each other) until recently when I started programming, and found out this was something I wanted to do.

And I very much agree with how the author closed his essay. I believe newer tools should be harnessed by more finesse. An unconditional endorsement of established tastes and rules bares some risk of falling into mannerism. And a careless collection of "novel" expressions often has a low signal-to-noise ratio, or seems to have wasted good resource. I think, by staying self-critical at the same time as being inventive and progressive, one could achieve both first and last word art.


I wanted to make a series of simple animations with circles as a main theme. But ended up only making two. I wanted to try the blur effect too, but spent too much time figuring out how to export frames from p5 without randomly skipping any frames. But I just gave up. I think slowing down the frame rate might be a solution, although I haven't tried it. Apart from that, I had fun.




void renderMyDesign (float percent) {
  float x1 = cos(percent*6*PI);
  float x2 = -cos(percent*6*PI);
  float z1 = sin(percent*6*PI);
  float z2 = -sin(percent*6*PI);
  background(0, 0, 200);
  translate(width/2, height/2);
  if (percent%(1/3f) < 1/6f) {
      map(x1, -1, 1, -160, 160), 
      200+ map(z1, -1, 1, -80, 80), 
      200+ map(z1, -1, 1, -80, 80));
      map(x2, -1, 1, -160, 160), 
      200+ map(z2, -1, 1, -80, 80), 
      200+ map(z2, -1, 1, -80, 80));
  } else {
      map(x2, -1, 1, -160, 160), 
      200+ map(z2, -1, 1, -80, 80), 
      200+ map(z2, -1, 1, -80, 80));
      map(x1, -1, 1, -160, 160), 
      200+ map(z1, -1, 1, -80, 80), 
      200+ map(z1, -1, 1, -80, 80));
var frame = 0;
var phase1 = 30;
var phase2 = 50;
var phase3 = 150; // start falling
var phase4 = 160;
var phase5 = 190;
var SIZE = 120;
var r = 255;
var g = 255;
var b = 255;
var cnv;
function setup() {
  cnv = createCanvas(640/2, 640/2);
function draw() {
  background(225, 0, 100);
  if (frame <= phase2) { translate(0, map(pennerEaseOutCubic(frame/phase2), 0, 1, -60/2, 520/2)); } // horizontal oscillation if (frame > phase1 && frame < phase4) { var osc = map(sin((frame-phase2)/PI*2), -1, 1, -50/2, 50/2); var oscScale = reverseSineEase(map(frame, phase1, phase4, 0, 2*PI)); translate(osc*oscScale, 0); // ellipse(width/2, 0, reverseSineEase(map(frame, phase1, phase4, SIZE, 400))); } if (frame > phase2 && frame <= phase3) { translate(0, map(pennerEaseInOutQuad((frame-phase2)/(phase3-phase2)), 0, 1, 520/2, 200/2)); SIZE += 1.5/2; } if (frame > phase3) {
    translate(0, map(pennerEaseInCubic((frame-phase3)/(phase5-phase3)), 0, 1, 200/2, 840/2)); 
  if (frame > phase2 + 20 && frame < phase4) { r -= 3.5; g -= 3.5; b -= 3.5; } fill(r, g, b); ellipse(width/2, 0, SIZE); frame++; if (frame>phase5) {
    SIZE = 120;
function pennerEaseOutCubic(t) {
  t = t-1.0;
  return (t*t*t + 1);
function pennerEaseInCubic(t) {
  return t*t*t;
function reverseSineEase(t) {
  return ((1-cos(t))/2)*((1-cos(t))/2);
function pennerEaseInOutQuad (t) {
  if ((t/=1/2) < 1) return 1/2*t*t;
  return -1/2 * ((--t)*(t-2) - 1);



I thought it would be fun to animate a random looking scribble like the one in the sketch below. In the setup() function, I created an array of random vertices to be connected by bezier curves, then added periodical offsets created by noise() function to each vertex just before drawing the shape. While it took me longer than I expected to implement the code, the outcome didn't seem as interesting as I thought, mainly due to the periodicity of the movement.




float[][] line = new float[120][6];
float[] num = new float[120];
int count = 0;
void setup() {
  size(792, 612); // 11x8.5" at 72DPI
  int i = 0;
  for (int y = 60; y> -60; y-=5) {
    line[i][0] = random(-60+y/3, 60-y/3);
    line[i][1] = random(-20, 20)+y;
    line[i][2] = random(-60+y/3, 60-y/3);
    line[i][3] = random(-20, 20)+y;
    line[i][4] = 0;
    line[i][5] = random(-5, 5)+y;
    num[i] = random(50);
void drawArtFrame (int whichFrame) { 
  vertex(0, 60);
  int count = 0;
  for (int i =0; i<23; i++) {
    line[i][0]+80*(getNoise(whichFrame, 0.05, num[count], num[count])-0.5),
    line[i][1]+40*(getNoiseSlow(whichFrame, 0.1, num[count], num[count])-0.5),
    line[i][2]+80*(getNoiseSlow(whichFrame, 0.1, num[count], num[count])-0.5),
    line[i][3]+40*(getNoise(whichFrame, 0.05, num[count], num[count])-0.5),
    line[i][4]+80*(getNoiseSlow(whichFrame, 0.1, num[count], num[count])-0.5),
    line[i][5]+40*(getNoiseSlow(whichFrame, 0.1, num[count], num[count])-0.5));


Question 1A
I like effective complexity in graphic layouts. Since all decisions are made by a person, it is disputable whether it can be called a complexity formed by a system (probably not). Still, the most intriguing graphic layouts to me are the ones that seem based on strict, well-informed rules, but that also arbitrarily escape them for a more graphically pleasant outcome.

Question 1B
On The Problem of Authenticity:
I like early 20th century oil paintings. I enjoy staring at them and sort of tracing the painter's intentions. An aesthetic composition in paint mediums can provide that unique, warm firsthand experience as if you're talking to the artist. Most generative art, as with the postmodern approach explained in the article, tend to lack this quality.


Slow Hot Computer - Sam Lavigne

"Slow Hot Computer is a website that makes your computer run slow and hot. Use it at work to decrease your productivity."

I love introducing this work to my friends in design school. You can surprisingly see a lot of art-phobic people in design departments, and it can be hard at times to successfully introduce a work that you like. But Slow Hot Computer has been a constant success. A friend of mine recently got into Samsung and bragged to me about how he's been spreading the site around to his coworkers.

I very much admire the transcendent experience you get from some types of artworks. And this one doesn't give you that. But it speaks to you immediately. When I show this work to people, most of them initially have a good laugh, and agree that Sam Lavigne is a genius. The main factors in play here are:

1. Humor
2. Succinctness
3. Narrative

The first two are quite obvious. This simple artifact also speaks much more about itself than it initially appears to. And that process of revelation happens pretty quick and easily, giving you a pleasant emotional burst, or that "aha" moment. I identify this quality as having a narrative.