Skip to content

Instantly share code, notes, and snippets.

@jasoncoon
Last active September 10, 2022 16:24
Show Gist options
  • Save jasoncoon/435f8f52dce7fb5287b01de0faca4859 to your computer and use it in GitHub Desktop.
Save jasoncoon/435f8f52dce7fb5287b01de0faca4859 to your computer and use it in GitHub Desktop.
Evil Eye pattern for Lux Lavalier
/**
* Evil Eye 2D - 9/7/2022
* Jason Coon (Evil Genius Labs)
* Video demo: https://twitter.com/jasoncoon_/status/1567671615214731264
*
* Slight modification of Blinky Eyes 2D - 6/5/2022
* Debra Ansell (GeekMomProjects)
*
* Simple code to display 1 blinking eye on an LED matrix. Tested on a Lux Lavalier (40mm Fibonacci64 Micro).
* Fine tuning variable values for the best look will likely depend a lot
* on the size and resolution of the specific display.
* */
var neyes = 1; // showing 2 eyes is untested, doesn't work well on Lux Lavalier
var Amax = 0.95; // Maximum eye width (based on one eye, code will take care of shrinking for 2)
var Bmax = 0.5; // Maximum eye height (Using value of 0.25 for 1 eye, 0.20 for 2 eyes)
var Riris = 0.25; // Radius of the iris (using value of 0.16 for 1 eye, 0.12 for 2 eyes)
var lineThreshold = 0.25; // Controls thicknes of eye (ellipse) outline
var blink = false; // Are we in the middle of a blink?
var blinkPhase = 0; // How long have we been in this phase of blinking (value in seconds)
var blinkInterval = 6; // Time interval (in seconds) before the next blink
var blinkLength = 0.25; // Total time interval (in seconds) of the blink
var move = false; // Are the irises moving? (from center to side, then back again)
var movePhase = 0; // How long have we been in this phase of iris motion (value in seconds)
var moveDir = 1; // Which direction are the irises moving (either -1 or 1)
var moveInterval = 4; // Time interval (in seconds) before we move
var moveLength = 0.3; // Total time interval (in seconds) for the eye movement
var midIris = 0; // Position of the middle of the iris relative to the middle of the eye
var midIrisY = 0;
var B; // Current eye outline (ellipse) height for use in the ellipse equation (changes during the blink phase)
var t1;
// Returns the Y value for an ellipse with the given parameters a, b in a standard ellipse equation
function ellipseY(x, a, b) {
return b * sqrt(1 - (x * x) / (a * a));
}
export function beforeRender(delta) {
t1 = time(0.04);
// Update our motion timer
movePhase += delta / 1000;
if (move) {
if (movePhase > moveLength) {
// At the end of motion time interval
movePhase = 0;
move = false;
//randomize time to next movement
moveInterval = 1.6 + random(5.4);
}
// Position of iris is changing
midIris = (moveDir * (wave(movePhase) - 0.5)) / 2;
} else {
if (movePhase > moveInterval) {
// At the end of motionless time interval
movePhase = 0;
// Randomize direction of eye movement
moveDir = random(1) > 0.5 ? 1 : -1;
move = true;
}
// If not moving, iris position fixed in the center
midIris = 0;
}
blinkPhase += delta / 1000;
if (blink) {
if (blinkPhase > blinkLength) {
// At the end of blinking time interval
blinkPhase = 0;
blink = false;
// Randomize time to next blink
blinkInterval = 4 + random(4);
} else {
B = clamp(B * wave(0.5 + blinkPhase / (2 * blinkLength)), 0.05, Bmax);
}
} else {
//Not blinking
// B is at maximum value unless we are blinking
B = Bmax;
if (blinkPhase > blinkInterval) {
// At the end of non-blinking time interval
blinkPhase = 0; // Reset clock
blink = true; // Start blink mode
}
}
}
export function render2D(index, x0, y0) {
// Rescale coordinates to (0,0) in center of screen. X scale depends on whether we have 1 or 2 eyes
x = (x0 - 0.5) * neyes;
if (neyes > 1) {
x += x > 0 ? -0.5 : 0.5;
}
y = (y0 - 0.5) * neyes;
// Distance from center of iris to our pixel
dIris = hypot((midIris - x) / neyes, y);
// Distance to elipse line
dscale = hypot(x / Amax, y / B);
v = 0;
// Draw the iris if (a) not blinking (b) we're within the iris radius
if (!blink && dIris < Riris) {
// Draw iris
v = dIris / Riris; // dark center, getting brighter with increasing radius away from center of iris
v -= hypot(x, y);
v -= t1;
v *= v;
v = v % 1;
hsv(0, 1, v);
} else {
// Draw eye outline
v = dscale < 1 ? max(dscale - lineThreshold, lineThreshold) : 0;
val = v * v * v;
val *= val;
rgb(val, val, val);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment