Willkommen auf unserem Seminar-Blog

Immer auf dem aktuellen Stand bleiben

Dieser Seminar-Blog befindet sich noch im Aufbau und wird in den kommenden Tagen entsprechend verfeinert.

Member Login

Lost your password?

Registration is closed

Sorry, you are not allowed to register by yourself on this site!

You must either be invited by one of our team member or request an invitation by email at viad.info {at} zhdk {dot} ch.

15. VJ Tool Final

24. Dezember 2010

Für die Präsentation habe ich den Code überarbeitet und Zeichensets zusammengestellt, die zur gewählten Musik passen. Als Musikstück habe ich "Tuning In" von Groove Armada aus dem Album "Love Box" ausgewählt. Die Übergänge der Permutationen, sowie das Wobbling habe ich dann auf dieses Stück entsprechend angepasst. Als Start werden zwei Permutationen hin- und hergeloopt. Mittels Tasten können neue Sets hinzugefügt werden, wobei jeweils die letzten zwei Sets endlos geloopt werden. Es können auch mehrere Tasten schnell nacheinander gedrückt werden, die Sets werden dem Animations-Array hinzugefügt und dann "abgearbeitet". Am Schluss gibt es wieder einen Endlos-Loop der letzten beiden Einträge, solange bis weitere Tasten gedrückt werden. Die Leertaste schaltet zwischen einem schwarzen und weissen Hintergrund um. Drehen der Zeichen ist ebenfalls mit einer Taste möglich, mehrmaliges Drücken erhöht die Drehgeschwindigkeit. Weitere Angaben finden sich hier: 14. Erweiterungen Interaktion. Snapshots Hauptprogramm-Code
// libraries
import ddf.minim.*;
//import ddf.minim.analysis.*;
import fullscreen.*;

SoftFullScreen fs;
AudioPlayer song;
//BeatDetect beat;
//BeatListener beatL;

// basic ini
int backgroundColor = 255;
int keyMode = 1; // toogle key values (1|-1), e.g. switch bg color

// ini vars signs
int numSigns = 7;
Sign[] signs =  new Sign[numSigns*numSigns]; // holds all objects of signs
int stageMargin = 100;
int stageHeight = 768;
int stageWidth = 768;
float   xStep;
float   yStep;

// ini appearance signs
float scaleRangeTop = 0.1; // 1.0: original sign size
float scaleRangeBottom = 0.2; // 1.0: original sign size
float strokeRangeTop = 0.5;
float strokeRangeBottom = 0.5;
float heightRangeTop = 20;
float heightRangeBottom = 10;
float borderRadiusBlack = 0;
float borderRadiusWhite = 0;
int mirrorToggle = 1; // whether negative values are set to positive ones (ring)
char keyParam = '1'; // used to store key to de- or increase sign parameters
int signSize = 40; // default sign size

// ini animation
Stacks stack; // object for single data (transformation), added to array list animation stacks
ArrayList animationStacks = new ArrayList(); // sets of values for animation
int keyAnim = 0; // key of stack in animations arrayList
int durationAnimStepDefault = 1322; // default duration of one tranformation
int durationAnimStep = durationAnimStepDefault;
//int durationAnimStepFast = 622; // not yet in use
int animationStart = 3200; // milliseconds when animation starts playing
int animationStop = 128000; // end of animation
boolean animationPlaying = false; // whether animation is playing or not
float signWobble = 0.1; // wobble start sequence
float signWobbleKeyStack = 0.2; // wobble default signs added with key stacks

float prevBorderRadiusBlack = borderRadiusBlack;
float prevBorderRadiusWhite = borderRadiusWhite;
float prevScaleRangeTop = scaleRangeTop;
float prevScaleRangeBottom = scaleRangeBottom;
float prevStrokeRangeTop = strokeRangeTop;
float prevStrokeRangeBottom = strokeRangeBottom;

float prevHeightRangeTop = heightRangeTop;
float prevHeightRangeBottom = heightRangeBottom;
float prevSignwobble = signWobble;
int prevMirrorToggle = mirrorToggle;

int animationPrevTimeLimit=0;
int timerStack=0;
int idleCompleted=0;
int currentStack=0;
int stackHolder=1;
Stacks nextStack; // key pressed = stack replaced in animation list
ArrayList nextStacks = new ArrayList(); // filled in with sign placed on keys, added one by one to animation list
boolean signIncRotation = false; // signs rotate 360 deg in specific time, this increases duration stepwise
int animEndCircleRad = 0; // radius growing circle at end of animation

void setup()
{
  // basic setup
  size(stageWidth, stageHeight);
  smooth(); // anitaliasing
  noCursor(); // hide mouse cursor
  frameRate(24);

  // steps s/y between signs
  xStep = (width - 2 * stageMargin) / (float)(numSigns-1);
  yStep = (height - 2 * stageMargin) / (float)(numSigns-1);

  // sound
  Minim minim = new Minim(this);
  song = minim.loadFile("Tuning_Short.mp3", 1024);
  song.play();
  //beat = new BeatDetect(song.bufferSize(), song.sampleRate());
  //beat.setSensitivity(30);
  //beatL = new BeatListener(beat, song);
  // use this to get audio input via microphone
  //in = minim.getLineIn(Minim.STEREO, 512);

  // fullscreen
  fs = new SoftFullScreen(this); // add (... ,1) to display on second display
  //fs.setShortcutsEnabled(true); // enable shortcut (cmd f)
  fs.enter();

  // create sign objects
  int signIndex = 0;
  for(int y=0; y<numSigns;y++)
  {
    for(int x=0; x<numSigns;x++)
    {
      signs[signIndex] = new Sign(signIndex);
      ++signIndex;
    }
  }

  // transformations
  stack = new Stacks(keyAnim);
  stack.setDuration(0);
  stack._completed = true;
  animationStacks.add(stack);

  // starter set stacks
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setName("best flower");
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(74);
  stack.setBorderRadiusWhite(68);
  stack.setHeightRange(0, 10);
  stack.setScaleRange(2.1, 0.9);
  stack.setStrokeRange(0.5, 6.5);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.doWobble(signWobble);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(2.1);
  stack.setBorderRadiusWhite(2.0);
  stack.setHeightRange(0, 10);
  stack.setScaleRange(1.0, 2.0);
  stack.setStrokeRange(0.5, 6.5);
  animationStacks.add(stack);

}

void draw()
{
  // basic setting
  background(backgroundColor);

  // cursor index
  pushStyle();
    int cursorIndexColor = (backgroundColor==255) ? 0 : 255;
    noStroke();
    fill(cursorIndexColor);
    rect(mouseX,0,5,5);
    rect(0,mouseY,5,5);
  popStyle();

  // animation setting transformation values
  animation();

  // draw signs
  int signIndex = 0;
  for(int y=0; y<numSigns;y++)
  {
    for(int x=0; x<numSigns;x++)
    {
      //Animation anim = new Animation(signs[signIndex]);
      signs[signIndex].setMirrorToggle(mirrorToggle);
      signs[signIndex].doWobble(signWobble);
      signs[signIndex].doRotate(signIncRotation);
      signs[signIndex].setSize(signSize); // initial size
      signs[signIndex].setScaleRange(scaleRangeBottom,scaleRangeTop);
      signs[signIndex].setStrokeRange(strokeRangeBottom,strokeRangeTop);
      signs[signIndex].setHeightRange(heightRangeBottom,heightRangeTop);
      signs[signIndex].setBorderRadiusBlack(borderRadiusBlack); // radius black layers
      signs[signIndex].setBorderRadiusWhite(borderRadiusWhite); // radius white layers
      signs[signIndex].setPositionMouse(mouseX,mouseY); // store mouse position
      signs[signIndex].setPosition((int)xStep*x+stageMargin,(int)yStep*y+stageMargin); // set position sign
      signs[signIndex].draw();
      ++signIndex;
    }
  }

  // animation
  //beat = new BeatDetect();
  if (song.position()>animationStop)
  {
    // growing circle at end of animation, overlays sign transformations
    pushStyle();
      fill(0);
      noStroke();
      ellipseMode(CENTER);
      if (animEndCircleRad<width) animEndCircleRad+=10;
      ellipse(width/2,height/2,animEndCircleRad*2,animEndCircleRad*2);
    popStyle();
  }
  else if (song.position()>animationStart)
  {
    animationPlay(false); // start animation after intro
  }
  if (signIncRotation==true) signIncRotation = false; // reset rotation increase (button once pushed inceares rotatoin duration)

}

void keyPressed()
{
  if (key == CODED)
  {
    // @DEPRECATED numeric keys used to change parameters of signs with arrow keys
    /**if (keyCode == UP) {
      keyMode = 1;
    } else if (keyCode == DOWN) {
      keyMode = -1;
    }
    // USED FOR CREATING SIGNS
    // added here key passed with ... to de- or increase values with arrow keys
    switch(keyParam) {
        // numeric keys
       case '2':
          //println("scale range top");
          scaleRangeTop+=0.1*keyMode;
          println("fast");
          break;
        case '1':
          scaleRangeBottom+=0.1*keyMode;
          break;
        case '4':
          strokeRangeTop+=0.5*keyMode;
          break;
        case '3':
          strokeRangeBottom+=0.5*keyMode;
          break;
        case '6':
          heightRangeTop+=0.5*keyMode;
          break;
        case '5':
          heightRangeBottom+=1*keyMode;
          break;
        case '7':
          borderRadiusBlack+=1*keyMode;
          break;
        case '8':
          borderRadiusWhite+=1*keyMode;
          break;
        case '9':
          mirrorToggle = 1*keyMode;
          break;
    }*/
  } else {
    switch(key) {
        case '0': // save screenshot
          save("screens/permutation_"+hour()+"-"+minute()+"-"+second()+".jpg");
          break;
        case ' ':
          backgroundColor = (backgroundColor==255) ? 0 : 255;
          break;
        // alphabetic keys
        case 'x':
          signIncRotation = true;
          break;
        case 'q':
          stack = new Stacks(stackHolder);
          stack.setName("default hell wölbung nach vorne");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(2.0);
          stack.setBorderRadiusWhite(2.0);
          stack.setHeightRange(9, 14);
          stack.setScaleRange(2.2, -1.3);
          stack.setStrokeRange(0.5, 0.5);
          stack.doWobble(signWobbleKeyStack);
          nextStack = stack;
          nextStacks.add(stack);
          break;
        case 'w':
          stack = new Stacks(stackHolder);
          stack.setName("kristall an faden");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(27.0);
          stack.setBorderRadiusWhite(32.0);
          stack.setHeightRange(10, 20);
          stack.setScaleRange(2.9, -0.3);
          stack.setStrokeRange(2.0, 2.0);
          stack.doWobble(signWobbleKeyStack);
          nextStack = stack;
          nextStacks.add(stack);
          break;
        case 'e':
          stack = new Stacks(stackHolder);
          stack.setName("quadrate spitz flach");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(-26.0);
          stack.setBorderRadiusWhite(-20.0);
          stack.setHeightRange(0, 27);
          stack.setScaleRange(1.9, 0.2);
          stack.setStrokeRange(0.5, 14.5);
          stack.doWobble(signWobbleKeyStack);
          nextStack = stack;
          nextStacks.add(stack);
          break;
        case 'r':
          stack = new Stacks(stackHolder);
          stack.setDuration(durationAnimStep);
          stack.setName("spitzen hell netzstruktur");
          stack.setBorderRadiusBlack(27.0);
          stack.setBorderRadiusWhite(24.0);
          stack.setHeightRange(10, 20);
          stack.setScaleRange(2.6, -1.8);
          stack.setStrokeRange(2.0, 2.0);
          stack.doWobble(signWobbleKeyStack);
          nextStack = stack;
          nextStacks.add(stack);
          break;
       case 't':
          stack = new Stacks(stackHolder);
          stack.setName("3d height multiple bounces");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(-271.0);
          stack.setBorderRadiusWhite(104.0);
          stack.setHeightRange(0, -6.0);
          stack.setScaleRange(0.2, 0.18);
          stack.setStrokeRange(2.0, 2.0);
          stack.doWobble(0);
          nextStack = stack;
          nextStacks.add(stack);
          break;
        case 'z':
          stack = new Stacks(stackHolder);
          stack.setName("blume zentral hell / dunkel floral");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(-227.0);
          stack.setBorderRadiusWhite(321.0);
          stack.setHeightRange(10, 20);
          stack.setScaleRange(0.8, -5.0);
          stack.setStrokeRange(2.0, 2.0);
          stack.doWobble(0);
          stack.setMirrorToggle(-1); // mirrorToggle
          nextStack = stack;
          nextStacks.add(stack);
          break;
        case 'u':
          stack = new Stacks(stackHolder);
          stack.setName("kacheln fett");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(-12.0);
          stack.setBorderRadiusWhite(-33.0);
          stack.setHeightRange(0.25, 8.9);
          stack.setScaleRange(2.3, 2.3);
          stack.setStrokeRange(-9.0, -9.0);
          stack.doWobble(signWobbleKeyStack);
          nextStack = stack;
          nextStacks.add(stack);
          break;
        case 'a':
          stack = new Stacks(stackHolder);
          stack.setName("best flower");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(59);
          stack.setBorderRadiusWhite(54);
          stack.setHeightRange(9.8,50);
          stack.setScaleRange(2.1, 0.9);
          stack.setStrokeRange(1.1, 1.1);
          stack.doWobble(signWobbleKeyStack);
          nextStack = stack;
          nextStacks.add(stack);
          break;
        case 's':
          stack = new Stacks(stackHolder);
          stack.setName("best flower");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(11.0);
          stack.setBorderRadiusWhite(10.0);
          stack.setHeightRange(0.25, 8.9);
          stack.setScaleRange(2.3, 2.3);
          stack.setStrokeRange(-9.5, -9.5);
          stack.doWobble(signWobbleKeyStack);
          nextStacks.add(stack);
          break;
        case 'd':
          stack = new Stacks(stackHolder);
          stack.setName("scheiben dunkel flach 3d");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(11.0);
          stack.setBorderRadiusWhite(10.0);
          stack.setHeightRange(0, 52);
          stack.setScaleRange(2.3, 2.3);
          stack.setStrokeRange(2.6, 18.1);
          stack.doWobble(signWobbleKeyStack);
          nextStacks.add(stack);
          break;
        case 'f':
          stack = new Stacks(stackHolder);
          stack.setName("scheiben dunkel flach 3d");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(20.0);
          stack.setBorderRadiusWhite(-3.0);
          stack.setHeightRange(-5, 40);
          stack.setScaleRange(2.3, 2.4);
          stack.setStrokeRange(0.5, 26);
          stack.doWobble(signWobbleKeyStack);
          nextStacks.add(stack);
          break;
        case 'g':
          stack = new Stacks(stackHolder);
          stack.setName("scheiben dunkel flach");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(11.0);
          stack.setBorderRadiusWhite(10.0);
          stack.setHeightRange(0.25, 8.9);
          stack.setScaleRange(2.3, 2.3);
          stack.setStrokeRange(9.5, 9.5);
          stack.doWobble(signWobbleKeyStack);
          nextStacks.add(stack);
          break;
        case 'h':
          stack = new Stacks(stackHolder);
          stack.setName("weisse scheiben (schwarzer hintergrund)");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(39.0);
          stack.setBorderRadiusWhite(195.0);
          stack.setHeightRange(10.8, 18.1);
          stack.setScaleRange(0.2, 0.18);
          stack.setStrokeRange(2.0, 2.0);
          stack.doWobble(signWobbleKeyStack);
          nextStacks.add(stack);
          break;
        case 'j':
          stack = new Stacks(stackHolder);
          stack.setName("hal eye");
          stack.setDuration(durationAnimStep);
          stack.setBorderRadiusBlack(-7.0);
          stack.setBorderRadiusWhite(28.0);
          stack.setHeightRange(27, 31);
          stack.setScaleRange(2.3, 2.4);
          stack.setStrokeRange(0.5, 26);
          stack.doWobble(signWobbleKeyStack);
          nextStacks.add(stack);
          break;
        default:
          // used for numeric keys to de- increase sign parameters
          keyParam = key;
          break;
    }
  }
}

// start animation
// once called after start delay
// stacks are resetted to start
void animationPlay(boolean force)
{
  if (animationPlaying==false || force==true)
  {
    animationPlaying = true;
    for(int i=0; i<animationStacks.size(); i++)
    {
      if (i>0)
      {
        Stacks stack = (Stacks)animationStacks.get(i);
        stack._completed=false; // reset
        animationPrevTimeLimit = millis();
        timerStack = 0;
      }
    }
  }
}

// toggle where to add signs added by keys
// if sign added by key -> is being displayed after completion of current transformation
void switchStackHolder()
{
   stackHolder = stackHolder==1 ? 2 : 1;
}

void animation()
{
 // animation
  int timerStack = millis() - animationPrevTimeLimit;
  for(int i=0; i<animationStacks.size(); i++) // loop second to third entry
  {

    if (i>0 && idleCompleted==0) { // i==0 first entry omitted (idle screen before start)
      Stacks stack = (Stacks)animationStacks.get(i);
      Stacks stackPrev = (Stacks)animationStacks.get(i-1);
      if (((stackPrev._completed==true && stack._completed==false)) && timerStack < stack._duration) {

        // single tranformation, evaluate transformation values (previous sign to current)
        borderRadiusBlack = ((stack._borderRadiusBlack - prevBorderRadiusBlack) * timerStack / stack._duration) + prevBorderRadiusBlack;
        borderRadiusWhite = ((stack._borderRadiusWhite - prevBorderRadiusWhite) * timerStack / stack._duration) + prevBorderRadiusWhite;
        scaleRangeBottom = ((stack._scaleRangeBottom - prevScaleRangeBottom) * timerStack / stack._duration) + prevScaleRangeBottom;
        scaleRangeTop = ((stack._scaleRangeTop - prevScaleRangeTop) * timerStack / stack._duration) + prevScaleRangeTop;
        strokeRangeBottom = ((stack._strokeRangeBottom - prevStrokeRangeBottom) * timerStack / stack._duration) + prevStrokeRangeBottom;
        strokeRangeTop = ((stack._strokeRangeTop - prevStrokeRangeTop) * timerStack / stack._duration) + prevStrokeRangeTop;
        heightRangeBottom = ((stack._heightRangeBottom - prevHeightRangeBottom) * timerStack / stack._duration) + prevHeightRangeBottom;
        heightRangeTop = ((stack._heightRangeTop - prevHeightRangeTop) * timerStack / stack._duration) + prevHeightRangeTop;
        signWobble = ((stack._signwobble - prevSignwobble) * timerStack / stack._duration) + prevSignwobble;
        mirrorToggle = stack._mirrorToggle;
        if (prevMirrorToggle==-1) mirrorToggle = -1; // keep mirror toggle deactivated to prevent gap in animation

      } else if (stack._completed==false  && timerStack > stack._duration) {

        // single transformation completed
        stack._completed = true;

        // store values of this sign to transform to next one
        prevBorderRadiusBlack = borderRadiusBlack = stack._borderRadiusBlack;
        prevBorderRadiusWhite = borderRadiusWhite = stack._borderRadiusWhite;
        prevScaleRangeBottom = scaleRangeBottom = stack._scaleRangeBottom;
        prevScaleRangeTop = scaleRangeTop = stack._scaleRangeTop;
        prevStrokeRangeBottom = stack._strokeRangeBottom;
        prevStrokeRangeTop = stack._strokeRangeTop;
        prevHeightRangeBottom = stack._heightRangeBottom;
        prevHeightRangeTop = stack._heightRangeTop;
        prevSignwobble = stack._signwobble;
        prevMirrorToggle = stack._mirrorToggle;

        animationPrevTimeLimit = millis()+stack._idleCompleted;
        timerStack = 0;
        idleCompleted = stack._idleCompleted; // idle time at the end of transformation
        currentStack = i;

        // add key stack
        if (nextStacks.size()>0 && stackHolder==currentStack)
        {
            switchStackHolder(); // replace neighbouring array entry
            nextStack = (Stacks)nextStacks.get(0); // get first entry
            nextStacks.remove(0); // delete first entry
            nextStack._completed = false;

            animationStacks.remove(stackHolder);
            animationStacks.add(stackHolder,nextStack);
         }

      }
    } else {

       // idle when at end of each transformation
       if (idleCompleted>0 && animationPrevTimeLimit < millis())
       {
         idleCompleted=0;

         // loop, last entry reached
         if (currentStack==animationStacks.size()-1)
         {
           animationPlay(true);
         }
       }
    }
  }
}
Zeichenklasse Stellt Zeichen gemäss Wertesets dar
/**
 * CLASS SIGN
 * draws single sign
 */
class Sign
{
  int _size = 75; // initial size of sign
  int _posX; // position x on grid
  int _posY; // position y on grid
  PVector _position = new PVector();
  int _mouseX; // position mouse x
  int _mouseY; // position mouse y
  PVector _mousePos = new PVector();
  float[] _scaleRange = {3.0,1.0}; // flip range
  float[] _strokeRange = {0.2, 10.0};
  float[] _heightRange = {1.0, 2.0};
  float _borderRadiusBlack = 0; // radius for black rectangles
  float _borderRadiusWhite = 0; // radous for white ractangles
  int numSignRect = 5; // how many rectangles

  // animation
  int _currentM; // milliseconds since start
  boolean _rotate = false; // whether to rotate signs or not
  float _rotation = 0.0; // rotation in degrees
  int _rotationDuration = 0; // duration rotation in milliseconds
  int _rotationIncDuration = 800; // duration increment rotation in milliseconds
  int _rotationMstart; // start rotation, millis()
  int _rotationMend; // end rotation, millis()
  int _rotateCycles = 0; // how many cycles in rotation
  float _wobble = 0; // allows wobbling to beat
  int _wobbleStep = 0;
  int _wobbleStepMax = 2;
  float _wobbleInc = 0.0;
  int _wobbleSwitch = 1;
  int _mirrorToggle;

  // constructor
  Sign(int index)
  {
    // setup

  }

  // setter methods
  void setSize(int s)
  {
    _size = s;  // overwrite default rotate incrementation
  }
  void setPosition(int posX, int posY) // position of sign
  {
    _posX = posX;
    _posY = posY;
    _position.set(posX,posY,0);
  }
  void setPositionMouse(int mX, int mY) // mouse position
  {
    _mouseX = mX;
    _mouseY = mY;
    _mousePos.set(mX,mY,0);
  }
  void setScaleRange(float start, float end)
  {
    _scaleRange[0] = start;
    _scaleRange[1] = end;
  }
  void setStrokeRange(float start, float end)
  {
    _strokeRange[0] = start;
    _strokeRange[1] = end;
  }
  void setHeightRange(float start, float end)
  {
    _heightRange[0] = start;
    _heightRange[1] = end;
  }
  void setBorderRadiusBlack(float radius)
  {
    _borderRadiusBlack = radius;
  }
  void setBorderRadiusWhite(float radius)
  {
    _borderRadiusWhite = radius;
  }
  void doRotate(boolean r) {
    _rotate = r;
  }
  void doWobble(float w) {
     _wobble = w;
  }
  void setMirrorToggle(int w) {
     _mirrorToggle = w;
  }

  // draw sign
  void draw()
  {
    // evaluate coordinates
    PVector dir = PVector.sub(_position,_mousePos); // vector distance to mouse pointer
    float distance = dir.mag(); // distance to mouse cursor

    // angle to mouse pointer
    float angleMouse = atan2(_mousePos.y - _posY, _mousePos.x - _posX);
    angleMouse+=_rotation;

    // scaling of sign (depends on distance to mouse pointer), max distance stage width
    float scaling = map(distance,0.0,width,_scaleRange[0],_scaleRange[1]); // 2,1: inverts range -> signs nearest to mous appear the biggest
    if (_mirrorToggle<0 && scaling<0.01) {
       scaling = 0.01; // only positive numbers allowed
    }

    // height range
    float heightShift = map(distance,0.0,30,_heightRange[0],_heightRange[1]);

    // stroke width depends on distance to mouse pointer
    float strokeWidth = map(distance,0.0,width,_strokeRange[0],_strokeRange[1]);
    if (strokeWidth<0) strokeWidth*=-1; // only positive numbers allowed

    // wobble
    if (_wobble>0) {
      _wobbleStep+= _wobbleSwitch;
      _wobbleInc = _wobbleStep*_wobble*(distance/(width));
      if (_wobbleStep>_wobbleStepMax || _wobbleStep<0) {
        _wobbleSwitch*=-1;
      }
    }

    // sign
    pushMatrix();

      translate(_posX,_posY); // move sign
      scale(scaling+_wobbleInc);
      rotateM(_rotate);

      pushStyle();
        noFill();
        noStroke();

        // draw bezier objects (for outlines a black and white one needed)
        for(int i=0; i<numSignRect; i++)
        {
          pushMatrix();
            translate(1*(dir.x/heightShift)*i,1*(dir.y/heightShift)*i); // centered by default, interaction mouse possible
            float w = _size-(i*_size/(numSignRect)); // width of sign (inner beziers scaled down)

            // draw black bezier
            fill(0);
            bezierRect(-1*w/2,-1*w/2,w,w, _borderRadiusBlack*(w/_size), _borderRadiusBlack*(w/_size));

            // draw white bezier
            fill(255);
            bezierRect(-1*(float)(w/2-strokeWidth/2),-1*(float)(w/2-strokeWidth/2),w-strokeWidth,w-strokeWidth, _borderRadiusWhite*(w/_size), _borderRadiusWhite*(w/_size));
          popMatrix();
        }
      popStyle();
    popMatrix();

    // animation
    _currentM = millis();
  }

  /**
  @param x  x-coordinate of upper-left
  @param y  y-coordinate of upper-left
  @param w  width of the rectangle
  @param h  height of the rectangle
  @param xr radius to inset x-coordinate corners for bezier control points
  @param yr radius to inset y-coordinate corners for bezier control points
  */
  void bezierRect(float x, float y, float w, float h, float xr, float yr) {
    float w2=w/2f, h2=h/2f, cx=x+w2, cy=y+h2;
    // used to make control points visible
    /*noFill();
    stroke(0);
    ellipse(cx,cy-h2,10,10);
    ellipse(cx+w2-xr, cy-h2,5,5);
    ellipse(cx+w2, cy-h2+yr,5,5);
    ellipse( cx+w2, cy,10,10);*/
    beginShape();
    vertex(cx,cy-h2);
    bezierVertex(cx+w2-xr, cy-h2, cx+w2, cy-h2+yr, cx+w2, cy);
    bezierVertex(cx+w2, cy+h2-yr, cx+w2-xr, cy+h2, cx, cy+h2);
    bezierVertex(cx-w2+xr, cy+h2, cx-w2, cy+h2-yr, cx-w2, cy);
    bezierVertex(cx-w2, cy-h2+yr, cx-w2+xr, cy-h2, cx, cy-h2);
    endShape();
  }

  // animation

  // rotation depending on milliseconds (on cycle in specific time)
  // duration can be increased stepwise (resp. key pushed twice = 2cycles)
  void rotateM(boolean r)
  {
    if (_rotateCycles==0 && _rotate==true)
    {
        // only set at start
        _rotationDuration+=_rotationIncDuration;
        _rotationMstart = _currentM;
        _rotationMend = _rotationMstart + _rotationDuration;
    }

    if (_rotate==true)
    {
        _rotationDuration+=_rotationIncDuration;
        _rotationMend+=_rotationDuration;
        _rotateCycles++;
        _rotate=false;
    }

    if (_currentM<_rotationMend)  {
      _rotation = map(_currentM-_rotationMstart,0,_rotationDuration,0,360*_rotateCycles);
      rotate(radians(_rotation)); //radians(_rotation)
    } else {
      _rotationDuration=0;
      _rotateCycles=0;
    }

  }

}
Kleine Klasse zum Speichern der Zeichenwerte Die Werte von ansprechenden Permutation habe ich mir notiert und als Objekt dieser Klasse gespeichert.
/**
 * CLASS STACKS
 * stores set of values for a specific permutation
 */
class Stacks
{
  int _id; // key in stack array
  String _name; // give your stack a name (to know later what is what)
  int _duration = 1000; // milliseconds
  int _idleCompleted = 50; // stop for a moment when transformation ended till next begins (set > 0)

  float[] _scaleRange = {3.0,1.0}; // flip range
  float[] _strokeRange = {0.2, 10.0};
  float[] _heightRange = {1.0, 2.0};

  float _borderRadiusBlack = 0; // radius for black rectangles
  float _borderRadiusWhite = 0; // radous for white ractangles

  boolean _completed = true; // is set on mouse click to false

  float _scaleRangeTop;
  float _scaleRangeBottom;
  float _strokeRangeTop;
  float _strokeRangeBottom;
  float _heightRangeTop;
  float _heightRangeBottom;
  float _signwobble;
  int _mirrorToggle;

  // constructor
  Stacks(int id)
  {
      _id = id; // key in stack array
  }

  // setter methods
  void setName(String name)
  {
    _name = name;
  }
  void setDuration(int duration)
  {
    _duration = duration;
  }
  void setScaleRange(float start, float end)
  {
    _scaleRange[0] = start;
    _scaleRange[1] = end;
    _scaleRangeBottom = start;
    _scaleRangeTop = end;
  }
  void setStrokeRange(float start, float end)
  {
    _strokeRange[0] = start;
    _strokeRange[1] = end;
    _strokeRangeBottom = start;
    _strokeRangeTop = end;
  }
  void setHeightRange(float start, float end)
  {
    _heightRange[0] = start;
    _heightRange[1] = end;
    _heightRangeBottom = start;
    _heightRangeTop = end;
  }
  void setBorderRadiusBlack(float radius)
  {
    _borderRadiusBlack = radius;
  }
  void setBorderRadiusWhite(float radius)
  {
    _borderRadiusWhite = radius;
  }
  void doWobble(float w) {
     _signwobble = w;
  }
  void setMirrorToggle(int w) {
     _mirrorToggle = w;
  }
}
Sammlung von Wertesets, die auf Keys gemappt werden können Diese habe ich mir bei einer vorhergehenden Runde gespeichert und aus diesen dann mir die ansprechendsten rausgelesen.
// sign values that can be places on keys
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(27.0);
  stack.setBorderRadiusWhite(32.0);
  stack.setHeightRange(10, 20);
  stack.setScaleRange(2.9, -0.3);
  stack.setStrokeRange(2.0, 2.0);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(2.0);
  stack.setBorderRadiusWhite(2.0);
  stack.setHeightRange(9, 14);
  stack.setScaleRange(2.2, -1.3);
  stack.setStrokeRange(0.5, 0.5);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(27.0);
  stack.setBorderRadiusWhite(24.0);
  stack.setHeightRange(10, 20);
  stack.setScaleRange(2.6, -1.8);
  stack.setStrokeRange(2.0, 2.0);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-26.0);
  stack.setBorderRadiusWhite(-20.0);
  stack.setHeightRange(0, 27);
  stack.setScaleRange(1.9, 0.2);
  stack.setStrokeRange(0.5, 14.5);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(46.0);
  stack.setBorderRadiusWhite(25.0);
  stack.setHeightRange(10, 12.5);
  stack.setScaleRange(2.4, 0);
  stack.setStrokeRange(8, 12);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-7.0);
  stack.setBorderRadiusWhite(28.0);
  stack.setHeightRange(27, 31);
  stack.setScaleRange(2.3, 2.4);
  stack.setStrokeRange(0.5, 26);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-40.0);
  stack.setBorderRadiusWhite(98.0);
  stack.setHeightRange(10, 25);
  stack.setScaleRange(2.1, 2.4);
  stack.setStrokeRange(2, 2);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(27.0);
  stack.setBorderRadiusWhite(24.0);
  stack.setHeightRange(10, 20);
  stack.setScaleRange(2.6, -1.8);
  stack.setStrokeRange(2.0, 2.0);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-227.0);
  stack.setBorderRadiusWhite(321.0);
  stack.setHeightRange(10, 20);
  stack.setScaleRange(0.8, -5.0);
  stack.setStrokeRange(2.0, 2.0);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-227.0);
  stack.setBorderRadiusWhite(321.0);
  stack.setHeightRange(10, 20);
  stack.setScaleRange(0.44, 0.48);
  stack.setStrokeRange(2.0, 2.0);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-227.0);
  stack.setBorderRadiusWhite(321.0);
  stack.setHeightRange(10, 20);
  stack.setScaleRange(0, 0.08);
  stack.setStrokeRange(2.0, 2.0);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-371.0);
  stack.setBorderRadiusWhite(304.0);
  stack.setHeightRange(10, -6.0);
  stack.setScaleRange(0.2, 0.18);
  stack.setStrokeRange(2.0, 2.0);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-639.0);
  stack.setBorderRadiusWhite(395.0);
  stack.setHeightRange(20, 20);
  stack.setScaleRange(0.2, 0.18);
  stack.setStrokeRange(2.0, 2.0);
  animationStacks.add(stack);

  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-639.0);
  stack.setBorderRadiusWhite(395.0);
  stack.setHeightRange(20.8, 18.1);
  stack.setScaleRange(0.2, 0.18);
  stack.setStrokeRange(2.0, 2.0);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-139.0);
  stack.setBorderRadiusWhite(195.0);
  stack.setHeightRange(20.8, 18.1);
  stack.setScaleRange(0.2, 0.18);
  stack.setStrokeRange(2.0, 2.0);
  animationStacks.add(stack);

  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(23.0);
  stack.setBorderRadiusWhite(23.0);
  stack.setHeightRange(7.8, 75.6);
  stack.setScaleRange(2.3, 2.3);
  stack.setStrokeRange(1.0, 1.0);

  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(11.0);
  stack.setBorderRadiusWhite(54.0);
  stack.setHeightRange(10, 48);
  stack.setScaleRange(5.0, 0.25);
  stack.setStrokeRange(1.12, 1.12);
  animationStacks.add(stack);

  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(59.0);
  stack.setBorderRadiusWhite(54.0);
  stack.setHeightRange(10, 50);
  stack.setScaleRange(i*0.25, 5.0);
  stack.setStrokeRange(1.11, 1.11);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(56.0);
  stack.setBorderRadiusWhite(55.0);
  stack.setHeightRange(10, 50);
  stack.setScaleRange(6.7, i*-0.5);
  stack.setStrokeRange(1.11, 1.11);
  animationStacks.add(stack);

  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(11.0);
  stack.setBorderRadiusWhite(11.0);
  stack.setHeightRange(10, 50);
  stack.setScaleRange(1.4, 1.4);
  stack.setStrokeRange(0.5, 0.5);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(11.0);
  stack.setBorderRadiusWhite(10.0);
  stack.setHeightRange(0, 52);
  stack.setScaleRange(2.3, 2.3);
  stack.setStrokeRange(2.6, 18.1);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(11.0);
  stack.setBorderRadiusWhite(10.0);
  stack.setHeightRange(0.25, 8.9);
  stack.setScaleRange(2.3, 2.3);
  stack.setStrokeRange(9.5, 9.5);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(11.0);
  stack.setBorderRadiusWhite(10.0);
  stack.setHeightRange(0.25, 8.9);
  stack.setScaleRange(2.3, 2.3);
  stack.setStrokeRange(-9.5, -9.5);
  animationStacks.add(stack);
  keyAnim++;
  stack = new Stacks(keyAnim);
  stack.setDuration(durationAnimStep);
  stack.setBorderRadiusBlack(-12.0);
  stack.setBorderRadiusWhite(-33.0);
  stack.setHeightRange(0.25, 8.9);
  stack.setScaleRange(2.3, 2.3);
  stack.setStrokeRange(-9.0, -9.0);
  animationStacks.add(stack);