Alec Albright – Project 07 – Curves

sketch

// Alec Albright
// aalbrigh@andrew.cmu.edu
// Section B
// Project 07

var nPoints = 100; // number of points used to draw curves

function setup(){
    createCanvas(480, 480);
    angleMode(RADIANS);
}

function draw(){
    background("lightpink");

    // center the shapes
    push();
    translate(width / 2, height / 2);

    // draw all the shapes
    drawHippopede();
    drawEpicycloid();
    drawHypotrochoid();

    pop();
}

// draws Hippopede
function drawHippopede() {
    var x; // x coordinate of vertex
    var y; // y coordinate of vertex
    var r; // polar coordinate
    var a = mouseX / 2 // main parameter of the curve
    var b = map(a, 0, 480, 100, 240); // circle radius
    var rotation = map(mouseY, 0, 480, 0, TWO_PI); // amount of rotation

    // thickness of line proportional to the circle radius
    strokeWeight(b / 5);
    stroke("white");
    noFill();

    // rotate shape
    push();
    rotate(rotation);

    // start drawing the shape, one point at a time
    beginShape();
    for(var i = 0; i < nPoints; i++){
        var t = map(i, 0, nPoints, 0, TWO_PI);
        
        // find r (polar equation)
        r = sqrt(4 * b * (a - b * sinSq(t)));

        // convert to x and y coordinates
        x = r * cos(t);
        y = r * sin(t);

        // draw a point at x, y
        vertex(x, y);
    }
    endShape();
    pop();
}

// draws hypotrochoid
function drawHypotrochoid() {
    var x; // x coordinate of vertex
    var y; // y coordinate of vertex
    var a = map(mouseX, 0, 480, 50, 150); // radius of the interior circle
    var b = 3; // radius of the petals
    var h = mouseX / 10; // distance from center of interior circle
    var red = map((mouseX + mouseY) / 2, 0, 480, 0, 255); // how much red
    var blue = map(mouseY, 0, 480, 0, 255); // how much blue
    var alpha = map(mouseX, 0, 480, 50, 255); // how opaque
    var rotation = map(mouseY, 100, 300, 0, TWO_PI); // amount of rotation

    strokeWeight(2)
    stroke("white");

    // control color and opacity with mouse location
    fill(red, 0, blue, alpha);

    // control rotation with mouseY
    push();
    rotate(rotation);

    // create the shape itself
    beginShape();
    for(var i = 0; i < nPoints; i++) {
        var t = map(i, 0, nPoints, 0, TWO_PI);

        // use parametric euqations for hypotrochoid to find x and y
        x = (a - b) * cos(t) + h * cos((a - b) / b * t);
        y = (a - b) * sin(t) - h * sin((a - b) / b * t);

        // draw a point at x, y
        vertex(x, y)
    }
    endShape(CLOSE);
    pop();
}

// draws an epicycloid
function drawEpicycloid() {
    var x; // x coordinate of vertex
    var y; // y coordinate of vertex
    var a = map(mouseX, 0, 480, 50, 200); // radius of interior circle
    var b = map(mouseY, 0, 480, 10, 50); // radius of petals
    var blue = map((mouseX + mouseY) / 2, 0, 480, 0, 255); // how much blue
    var red = map(mouseY, 0, 480, 0, 255); // how much red
    var rotation = map(mouseY, 100, 300, 0, TWO_PI); // how muhc rotation

    // control color with mouse location
    strokeWeight(10)
    stroke(red, 0, blue);

    // control rotation with mouse location
    push();
    rotate(rotation);

    // start drawing shape
    beginShape();
    for(var i = 0; i < nPoints; i++) {
        var t = map(i, 0, nPoints, 0, TWO_PI);

        // find coordinates using epicycloid parametric equations
        x = (a + b) * cos(t) - b * cos((a + b) / b * t);
        y = (a + b) * sin(t) - b * sin((a + b) / b * t);

        // draw a point at x, y
        vertex(x, y);
    }
    endShape();
    pop();
}

// defines sin^2 using trigonometric identities
function sinSq(x) {
    return((1 - cos(2 * x)) / 2);
}

In order to put together this project, I started with a simple curve, the hippopede, and began to implement increasingly more complex ones. Once I was able to draw the three curves (hippopede, hypotrochoid, and epicycloid), I started mapping various features of the curves to things like color, transparency, stroke weight, and rotation until I was satisfied with the results. Particularly, the color mapping was interesting to me because I utilized the average of the mouseX and mouseY coordinates in order to determine some aspects of color like the amount of red in the hypotrochoid and the amount of blue in the epicycloid. This allowed me to have more freedom to speculate interesting relationships that could be created using the coordinate system.

mouseX = 400, mouseY = 50
mouseX = 240, mouseY = 400
mouseX = 50, mouseY = 200
mouseX = 480, mouseY = 240

Alec Albright – Looking Outwards – 07

Image result for cool ggplot2 examples
Example scatterplot from the ggplot2 R package by Hadley Wickham, Winston Chang, Lionel Henry, and Thomas Lin Pedersen.
Image result for cool ggplot2 examples
Example time series plots from the ggplot2 R package by Hadley Wickham, Winston Chang, Lionel Henry, and Thomas Lin Pedersen.

The ggplot2 package for the R programming language, as created by Hadley Wickham, Winston Chang, Lionel Henry, and Thomas Lin Pedersen in 2016, is a data visualization tool that innovated the process of creating graphs in R. It outlines a “grammar of graphics” that is extremely versatile and easy to implement, which are its most admirable traits. The algorithm allows users to map different variables from a dataset to a variety of different aesthetics (shape, x or y axis, color, etc.) with very easy customization. In this versatility, the authors were able to manifest their dedication to allowing for flexible visualizations beyond traditional methods. Overall, this package incredibly useful in computational data visualization and has revolutionized how data analysts look at their data.

Alec Albright – Project 06 – Abstract Clock

sketch

// Alec Albright
// aalbrigh@andrew.cmu.edu
// Section B
// Project 06

var quartPossibleTop = [] // possible upper y values for quarter notes
var quartPlacesTop = [] // actual upper y values for quarter notes
var quartPossibleBottom = [] // possible lower y values for quarter notes
var quartPlacesBottom = [] // actual lower y values for quarter notes
var halfPossibleTop = [] // possible upper y values for half notes
var halfPlacesTop = [] // actual upper y values for half notes
var halfPossibleBottom = [] // possible lower y values for half notes
var halfPlacesBottom = [] // actual lower y values for half notes
var wholePossible = [] // possible y values for whole notes
var wholePlaces = [] // actual y values for whole notes

function setup(){
    createCanvas(480, 480);
    ellipseMode(CENTER);

    // defining possible quarter note y values
    for(i = 20; i < 92; i += 8){
        quartPossibleTop.push(i);
    }
    for(i = 115; i < 185; i += 8){
        quartPossibleBottom.push(i);
    }
    // predetermines random vertical placements on the staff
    for(i = 0; i <= 30; i++){
        quartPlacesTop.push(random(quartPossibleTop));
    }
    for(i = 0; i <= 30; i++){
        quartPlacesBottom.push(random(quartPossibleBottom));
    }
    
    // defining possible half note y values
    for(i = 205; i < 275; i += 8){
        halfPossibleTop.push(i);
    }
    for(i = 300; i < 370; i += 8){
        halfPossibleBottom.push(i);
    }
    // predetermines random vertical placements on the staff
    for(i = 0; i <= 30; i++){
        halfPlacesTop.push(random(halfPossibleTop));
    }
    for(i = 0; i <= 30; i++){
        halfPlacesBottom.push(random(halfPossibleBottom));
    }
    
    // defining possible whole note y values
    for(i = 390; i < 460; i += 8){
        wholePossible.push(i);
    }
    // predetermines random vertical placements on the staff
    for(i = 0; i < 24; i++){
        wholePlaces.push(random(wholePossible));
    }
}

function draw(){
    // record current time
    var h = hour();
    var m = minute();
    var s = second();

    background("white");
    stroke("black");
    strokeWeight(1.5);

    // drawing seconds
    fill("black")
    for(i = 1; i <= s; i++){
        // draws a quarter note depending on minute
        if(i <= 30){
            // head
            ellipse(15 * i, quartPlacesTop[i], 10, 8);
            // stem
            // top half
            if(quartPlacesTop[i] < 52){
                line(15 * i + 5, quartPlacesTop[i], 15 * i + 5,
                     quartPlacesTop[i] - 15);
            // bottom half
            } else {
                line(15 * i - 5, quartPlacesTop[i], 15 * i - 5,
                     quartPlacesTop[i] + 15);
            }
        } else {
            ellipse(15 * (i - 30), quartPlacesBottom[(i - 30)], 10, 8);
            // stem
            // top half
            if(quartPlacesBottom[(i - 30)] < 147){
                line(15 * (i - 30) + 5, quartPlacesBottom[(i - 30)],
                 15 * (i - 30) + 5, quartPlacesBottom[(i - 30)] - 15);
            // bottom half
            } else {
                line(15 * (i - 30) - 5, quartPlacesBottom[(i - 30)],
                 15 * (i - 30) - 5, quartPlacesBottom[(i - 30)] + 15);
            }
        }
    }

    // drawing minutes
    fill("white")
    for(i = 1; i <= m; i++){
        // draws a half note depending on minute
        if(i <= 30){
            // head
            ellipse(15 * i, halfPlacesTop[i], 10, 8);
            // stem
            if(halfPlacesTop[i] < 237){
                line(15 * i + 5, halfPlacesTop[i], 15 * i + 5,
                     halfPlacesTop[i] - 15);
            } else {
                line(15 * i + 5, halfPlacesTop[i], 15 * i + 5,
                     halfPlacesTop[i] + 15);
            }
        } else {
            // head
            ellipse(15 * (i - 30), halfPlacesBottom[(i - 30)], 10, 8);
            // stem
            // top half
            if(halfPlacesBottom[(i - 30)] < 348){
                line(15 * (i - 30) + 5, halfPlacesBottom[(i - 30)],
                 15 * (i - 30) + 5, halfPlacesBottom[(i - 30)] - 15);
            // bottom half
            } else {
                line(15 * (i - 30) - 5, halfPlacesBottom[(i - 30)],
                 15 * (i - 30) - 5, halfPlacesBottom[(i - 30)] + 15);
            }
        }
    }

    // drawing hours
    for(i = 1; i <= h; i++){
        // draws a whole note
        ellipse(36 * i, wholePlaces[i], 10, 8);
    }   

    // drawing staves
    // seconds
    strokeWeight(1);
    drawStaff(20);
    drawStaff(115);
    // connecting
    line(10, 20, 10, 179);
    strokeWeight(3);
    line(5, 15, 5, 184);
    line(5, 15, 15, 12);
    line(5, 184, 15, 188);
    // resetting strokeweight
    strokeWeight(1);
    
    // minutes
    drawStaff(205);
    drawStaff(300);
    // connecting
    line(10, 205, 10, 364);
    strokeWeight(3);
    line(5, 200, 5, 369);
    line(5, 200, 15, 197);
    line(5, 369, 15, 372);
    // resetting strokeweight
    strokeWeight(1);

    // hours
    drawStaff(390)
}

// function to draw a staff
function drawStaff(startY){
    stroke("black");

    // draw a consistent staff
    for(i = 0; i < 80; i += 16){
        let lineY = startY + i
        line(10, lineY, width, lineY);
    }
}

In the creation of this clock, I wanted to see whether some interesting musical elements could be added, leading me to represent various elements of time by different rhythms, with notes placed randomly every increment of time. In this way, a new “piece” of music can be generated every second, with very low likelihood of being reproduced by any replication of this program due to the amount of randomness involved. Though unorthodox, this method of keeping time is certainly interesting. Particularly difficult was managing the spacing of the staves and the notes within a line, simply due to the fact that there can be as many as 30 notes on one line at a time in this representation.

Initial sketch of idea

Alec Albright – Looking Outwards – 06

Cage's 'Dereau (#11),' 1982
Cage’s “Dereau #11”, created in 1982

Above is John Cage’s “Dereau #11”, which he created in 1982 as a part of his visual chance art. The randomness was implemented in this work through several aspects. First, once a shape had been selected to be drawn, the quadrant in which it was drawn was randomly selected. Then, the color of the object appears alone or in combination with one of forty-five colors in chance-determined percentages with or without white. This work is admirable to me because it seems to follow no structure, but the procedure behind it is fairly well-defined. This piece could have turned out in an endless number of ways, and the odds of this exact work being created through his defined mechanism again are infinitely slim.

Alec Albright – Project 05 – Wallpaper

sketch

// Alec Albright
// aalbrigh@andrew.cmu.edu
// Section B
// Project 5 - Wallpaper

var diamondH = 10; // height of the diamonds
var diamondW = 10; // width of the diamonds
var diaMargin = 5; // space between a diamond and its outline
var thickStripe = 20; // stroke weight of the thick stripe
var thinStripe = 3; // stroke weight of the thin stripe

function setup(){
    createCanvas(500, 500);
    angleMode(DEGREES);
}

function draw(){
    background("skyblue");

    // drawing the diamonds
    // controling rows
    for(x = 0; x < 550; x += 25){
        // controlling number of diagonal lines
        for(y = -500; y < 500; y += 175){
            drawDiamond(x + y , x);
        }
    }

    // drawing the stripes
    for(x = -100; x < 550; x += 175){
        for(y = 0; y < 500; y += 175){
            drawStripes(x, y);
        }
    }
    noLoop();
}

// draws one diamond and its outline
function drawDiamond(x, y){
    strokeWeight(1);
    stroke("black")
    push();
    translate(x, y);

    rotate(135);
    // diamond
    fill("orange");
    rect(diaMargin, diaMargin, diamondW, diamondH);

    // outline
    // makes the rectangle transparent
    fill(0, 0, 0, 0);
    rect(0, 0, diamondW, diamondH);

    pop();
}

// draws big and little stripes to fill gaps of the diamonds
function drawStripes(x, y){
    // drawing first big stripe
    stroke("white");
    strokeWeight(thickStripe);
    line(x, y, x + 500, y + 500);

    // little stripe
    stroke("orange");
    strokeWeight(thinStripe);
    line(x + 30, y, x + 530, y + 500)

    // other big stripe
    stroke("white");
    strokeWeight(thickStripe);
    line(x + 60, y, x + 560, y + 500);
}


I originally sketched this to include less frequent diagonals of the diamonds, but upon creation I really liked the contrast between the horizontal positioning of the diamonds and the diagonal positioning of the stripes. I also wanted to implement a vibrant color palette, which manifested itself as light blue, orange, and white. My biggest difficulty in creating this wallpaper was dealing with replicating the diagonals. Particularly, the diamonds were difficult because I rotated them upon drawing them, so their coordinate system became harder to keep track of.

Below is my original sketch:

Original sketch

Alec Albright – Looking Outwards 05

Rokly Wang.   Modeled in Zbrush. Texturing in Zbrush and Photoshop. Retopologized in 3DCoat, Rendered in Maya using mental ray, and the hair is using Maya hair system.
“An Elderly Curmudgeon” by Rokly Wang

The hyper-realistic image above was made by Rokly Wang in May 2012. It is admirable to me because it almost feels too real to be true. This face, generated from scratch, not modeled on an existing human, seems like an extremely high quality photograph. It was processed in various softwares such as Zbrush, Photoshop, and Maya. I do not know the underlying generative algorithms, but I can imagine there is some sort of mapping technique for aspects such as lighting, hair placement, etc. The artist was able to manifest his creative sensibilities through the demeanor of the man in the image, the lighting, the aging, etc.

Alec Albright – Project 04 – String Art

sketch

// Alec Albright
// aalbrigh@andrew.cmu.edu
// Section B
// Project 04


var x1StepSize = 5;
var y1StepSize = 0;
var x2StepSize = 0;
var y2StepSize = -4;
var x1 = 0;
var y1 = 150;
var x2 = 200;
var y2 = 150;


function setup() {
    createCanvas(400, 300);
    background("black");
}
 
function draw() {
    // top left 
    makeCurve("red");

    // top right
    x1 = 400;
    y1 = 150;
    x2 = 200;
    y2 = 150;
    x1StepSize = -5;
    y2StepSize = -4;
    makeCurve("limegreen");

    // bottom left
    x1 = 0;
    y1 = 150;
    x2 = 200;
    y2 = 150;
    x1StepSize = 5;
    y2StepSize = 4;
    makeCurve("yellow");

    // bottom right
    x1 = 400;
    y1 = 150;
    x2 = 200;
    y2 = 150;
    x1StepSize = -5;
    y2StepSize = 4;
    makeCurve("purple");

    // bottom left, top left
    x1 = 0;
    y1 = 225;
    x2 = 100;
    y2 = 225;
    x1StepSize = 2.5;
    y2StepSize = -1.75;
    makeCurve("red");

    // bottom left, bottom left
    x1 = 0;
    y1 = 225;
    x2 = 100;
    y2 = 225;
    x1StepSize = 2.5;
    y2StepSize = 1.75;
    makeCurve("yellow");

    // bottom left, top right
    x1 = 200;
    y1 = 225;
    x2 = 100;
    y2 = 225;
    x1StepSize = -2.5;
    y2StepSize = -1.75;
    makeCurve("limegreen");

    // bottom left, bottom right
    x1 = 200;
    y1 = 225;
    x2 = 100;
    y2 = 225;
    x1StepSize = -2.5;
    y2StepSize = 1.75;
    makeCurve("purple");

    // top left, top left
    x1 = 0;
    y1 = 75;
    x2 = 100;
    y2 = 75;
    x1StepSize = 2.5;
    y2StepSize = -1.75;
    makeCurve("red");

    // top left, bottom left
    x1 = 0;
    y1 = 75;
    x2 = 100;
    y2 = 75;
    x1StepSize = 2.5;
    y2StepSize = 1.75;
    makeCurve("yellow");

    // top left, top right
    x1 = 200;
    y1 = 75;
    x2 = 100;
    y2 = 75;
    x1StepSize = -2.5;
    y2StepSize = -1.75;
    makeCurve("limegreen");

    // top left, bottom right
    x1 = 200;
    y1 = 75;
    x2 = 100;
    y2 = 75;
    x1StepSize = -2.5;
    y2StepSize = 1.75;
    makeCurve("purple");

    // top right, top left
    x1 = 200;
    y1 = 75;
    x2 = 300;
    y2 = 75;
    x1StepSize = 2.5;
    y2StepSize = -1.75;
    makeCurve("red");

    // top right, bottom left
    x1 = 200;
    y1 = 75;
    x2 = 300;
    y2 = 75;
    x1StepSize = 2.5;
    y2StepSize = 1.75;
    makeCurve("yellow");

    // top right, top right
    x1 = 400;
    y1 = 75;
    x2 = 300;
    y2 = 75;
    x1StepSize = -2.5;
    y2StepSize = -1.75;
    makeCurve("limegreen");

    // top right, bottom right
    x1 = 400;
    y1 = 75;
    x2 = 300;
    y2 = 75;
    x1StepSize = -2.5;
    y2StepSize = 1.75;
    makeCurve("purple");

    // bottom right, top left
    x1 = 200;
    y1 = 225;
    x2 = 300;
    y2 = 225;
    x1StepSize = 2.5;
    y2StepSize = -1.75;
    makeCurve("red");

    // bottom right, bottom left
    x1 = 200;
    y1 = 225;
    x2 = 300;
    y2 = 225;
    x1StepSize = 2.5;
    y2StepSize = 1.75;
    makeCurve("yellow");

    // bottom right, top right
    x1 = 400;
    y1 = 225;
    x2 = 300;
    y2 = 225;
    x1StepSize = -2.5;
    y2StepSize = -1.75;
    makeCurve("limegreen");

    // bottom right, bottom right
    x1 = 400;
    y1 = 225;
    x2 = 300;
    y2 = 225;
    x1StepSize = -2.5;
    y2StepSize = 1.75;
    makeCurve("purple");
}

// makes a curve based on any color
// x1, y1, x2, y2, and step sizes must be predefined
function makeCurve(color){
    for (i = 0; i < 41; i ++) {
        stroke(color);
        line(x1, y1, x2, y2);
        x1 += x1StepSize;
        y1 += y1StepSize;
        x2 += x2StepSize;
        y2 += y2StepSize;
        noLoop();
    }
}

Throughout my process of creating this visualization, I had to get more familiar with how exactly the string art is generated in terms of the size of steps in the sequence. Once I got a good feel for that, I was able to utilize my knowledge of the coordinate system to make the same image in a variety of interesting places.

Alec Albright – Looking Outwards 04

Dave Young’s exhibition of Radius Music in 2010.

Dave Young’s “Radius Music”, released in 2010, is an audiovisual device that reads the ultrasonic distance from those that are in the room to the device itself, conducting additive synthesis to create audio and placing light beams on the floor in response to that distance. This project is admirable because of its ability to conduct complicated audio synthesis techniques on the fly, based on feedback it may have never dealt with before. I would imagine that the algorithm maps distance to pitch in some way, but I’m not sure what affects timbre, tempo, or anything else for that matter. Regardless, it seems super cool!

Alec Albright – Project 03 – Dynamic Drawing

sketch

// Alec Albright
// Section B
// Project 3

var margin = 150;
var radius = 30;
var r = 0;
var g = 0;
var b = 0;
var rotation = 0;

function setup(){
    createCanvas(640, 480);
    angleMode(DEGREES);
}

function draw(){
    background("white");
    fill(r, g, b);

    // mapping angle of rotation to mouseY
    // as mouse moves up and down, shapes rotate
    rotation = map(mouseY, 0, height, 0, 360);

    // drawing hexagons with specified margin and rotation
    // center
    push();
    translate(width / 2, height / 2);
    rotate(rotation);
    hexagon(0, 0, radius);
    pop();
    // circle around center hexagon
    for(let i = 0; i < nvertex; i +=1){
        // finding exactly where the hexagon at hand is located
        // sin tells us where the y coordinate is
        var centerY = sin(angle) * margin;
        // cos tells us where the x coordinate is
        var centerX = cos(angle) * margin;
        // now draw the vertex at hand
        // setting up rotation for each individual hexagon
        push();
        translate(width / 2 + centerX, height / 2 + centerY);
        rotate(rotation);
        hexagon(centerX, centerY, radius);
        pop();
        // add the next portion of the angle
        angle = angle + (360 / 6)
    }
    
    // scaling mouseX to use the whole screen for size
    // as mouse moves right, shapes get bigger
    radius = map(mouseX, 0, width, 20, 70);
    
    // scaling color using whole screen
    // as mouse moves right, more red
    r = map(mouseX, 0, width, 0, 255);
    // as mouse moves down, more blue
    b = map(mouseY, 0, height, 0, 255);
    // as mouse moves left, more green
    g = 255 - map(mouseX, 0, width, 0, 255);

    // margin depends on mouseX, keeping same distance throughout
    margin = map(mouseX, 0, width, 50, 150);
}

// 6 vertices, as a hexagon has
var nvertex = 6;
// angle we're working at (when we get to TWO_PI, we're done)
var angle = 0;

function hexagon(x, y, radius){
    // draw a hexagon at (x, y) using beginShape()
    beginShape();
    // find each vertex's specific location
    for(let i = 0; i < nvertex; i += 1){
        // finding exactly where the vertex at hand is located
        // sin tells us where the y coordinate is
        var vertexY = y + sin(angle) * radius;
        // cos tells us where the x coordinate is
        var vertexX = x + cos(angle) * radius;
        // now draw the vertex at hand
        vertex(vertexX, vertexY)
        // add the next portion of the angle
        angle += (360 / 6)
    }
    // connect beginning and end points
    endShape(CLOSE)
}

My process for creating this visualization was most difficult in implementing a rotational element. The colors were fairly easily scaled, the size and distance were a bit more difficult, but adding the rotation was a long experiment that I eventually figured out, resulting in this very cool kaleidoscope effect!

Alec Albright – Looking Outwards 03

Kinesis by Daniel Widrig_dezeen_1sq
Daniel Widrig’s exoskeleton wearable 3D sculpture. Picture from Dezeen.com.
Kinesis by Daniel Widrig_dezeen_14
Side view of the sculpture, displaying how the piece rests on the back of the neck. Picture from Dezeen.com.
Kinesis by Daniel Widrig_dezeen_2
Another wearable piece from this colletion, which sits around the neck. Picture from Dezeen.com.

Daniel Widrig’s wearable 3D sculptures were released in the Design Miami show of 2013. At this time, Widrig unveiled the pictured pieces, calling it the “Kinesis Collection”, as they were customized to the wearer’s body to fit perfectly. This project is admirable because of its intricacies and care in the realm of customization and scalability. The pieces were designed to be able to be recreated for any user by scanning the wearer’s body and resizing the sculpture accordingly.

The algorithms of the work are supposedly designed to replicate human vertebrae in a generative fashion, but I am unsure of the details as to how this was accomplished. In its final form, it manifested Widrig’s artistic sensibilities in its craftsmanship, perfectly customized design, and sleekness.