This is example of a spinning glyph. The hue controls the spin and the saturation and lightness control the two different halves. A small dot was added as a refrence point to reduce the visual symmetry.
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/addons/p5.dom.js"></script>
<script src="z_hsluv-0.0.3.min.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript" src="z_purview_helper.js"></script>
<script language="javascript" type="text/javascript" src="z_color_helper.js"></script>
<script language="javascript" type="text/javascript" src="glyph.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<style>
body { padding: 0; margin: 0; }
.inner { position: absolute; }
#controls {
font: 300 12px "Helvetica Neue";
padding: 5;
margin: 5;
background: #f0f0f0;
opacity: 0.0;
-webkit-transition: opacity 0.2s ease;
-moz-transition: opacity 0.2s ease;
-o-transition: opacity 0.2s ease;
-ms-transition: opacity 0.2s ease;
}
#controls:hover { opacity: 0.9; }
</style>
</head>
<body style="background-color:white">
<div class="outer">
<div class="inner">
<div id="canvasContainer"></div>
</div>
<div class="inner" id="controls" height="500px">
<table>
<tr>
<td>Hue</td>
<td id="slider1Container"></td>
</tr>
<tr>
<td>Saturation</td>
<td id="slider2Container"></td>
</tr>
<tr>
<td>Lightness</td>
<td id="slider3Container"></td>
</tr>
<tr>
<td>
<hr>
</td>
</tr>
<tr>
<td>Mode</td>
<td id="selector1Container"></td>
</tr>
<tr>
<td>Size</td>
<td id="selector3Container"></td>
</tr>
<tr>
<td>Display</td>
<td id="selector2Container"></td>
</tr>
<tr>
<td>Show Guide</td>
<td id="checkContainer"></td>
</tr>
<tr>
<td></td>
<td id="buttonContainer"></td>
</tr>
</div>
</div>
</table>
</body>
/* change default application behavior */
var defaultMode = "random";
var defaultSize = 128;
var defaultDisplay = "both"
var defaultEmoji = 100;
var backgroundColor = "hsb(0, 0%, 94%)";
function Glyph() {
/*
* values is an array of 3 numbers: [hue, saturation, lightness]
* + hue ranges from 0..360
* + saturation ranges from 0..100
* + lightness ranges from 0..100
*
* size is the number of pixels for width and height
*
* use p5.js to draw a round grayscale glyph
* the glyph should stay within the ellipse [0, 0, width, height]
* this is a grayscale glyph, so only lightness can be adjusted.
* the range for lightness is 0..100
*
* When setting the lightness of stroke or fill always use either strokeUniform()
* or fillUniform() calls. Each takes one arguement - the lightness from
* 0 to 100. Examples:
* - fillUniform(50); // ranges from 0-100
* - strokeUniform(100); // white
*/
this.draw = function(values, size) {
let s2 = size/2;
translate(s2, s2, 0);
// map lightness to large circle shade
let spin = map(values[0], 0, 360, 0, 2*PI)
rotate(spin)
let bg = map(values[1], 0, 100, 50, 100);
let fg = map(values[2], 0, 100, 50, 0);
fillUniform(bg);
ellipse(0, 0, size, size);
fillUniform(0);
ellipse(0, -(2*s2/3), s2/3, s2/3);
fillUniform(fg);
arc(0, 0, size, size, 0, PI);
}
}
{
"commits": [
{
"sha": "e5f0ddcfa4f1338f91ca6b24e22f103ff2b98637",
"name": "example2: spinner"
},
{
"sha": "2602d38da41ef93c92cb2fc1c17b2d14ad8cd087",
"name": "example1: stripe box"
},
{
"sha": "1b92f81f552ec3a3b1932bc6d67a98094c0ddd1a",
"name": "sketch example"
}
]
}
if (typeof defaultMode === 'undefined') {
var defaultMode = "sketch";
}
if (typeof defaultSize === 'undefined') {
var defaultSize = "128";
}
if (typeof defaultDisplay === 'undefined') {
var defaultDisplay = "both";
}
if (typeof defaultEmoji === 'undefined') {
var defaultDisplay = 76;
}
if (typeof backgroundColor === 'undefined') {
var backgroundColor = "rgb(232, 232, 232)";
}
let canvasWidth = 960;
let canvasHeight = 500;
let glyphSelector;
let modeSelector;
let sizeSelector;
let show_oddball = false;
let oddball_row = 0;
let oddball_col = 0;
let val_sliders = [];
let max_vals = [360, 100, 100];
let curEmoji = defaultEmoji;
let NUM_EMOJI = 872;
let EMOJI_WIDTH = 38;
let lastKeyPressedTime;
let secondsUntilSwapMode = 10;
let secondsPerEmoji = 5;
let isSwappingEmoji = false;
let emojiSwapLerp = 0;
let prevEmoji = 0;
let lastEmojiSwappedTime;
let emojiImg;
let sketchImg;
let curEmojiImg;
let curEmojiPixels;
let curEmojiColors, nextEmojiColors, prevEmojiColors;
function preload() {
emojiImg = loadImage("twemoji36b_montage.png");
sketchImg = loadImage("sketch.png");
}
function setup() {
// create the drawing canvas, save the canvas element
let main_canvas = createCanvas(canvasWidth, canvasHeight);
main_canvas.parent('canvasContainer');
let now = millis();
lastKeyPressedTime = now;
lastEmojiSwappedTime = now;
// create two sliders
for (i=0; i<3; i++) {
let slider = createSlider(0, 10*max_vals[i], 10*max_vals[i]/2);
slider.parent("slider" + (i+1) + "Container")
slider.changed(sliderUpdated);
slider.mouseMoved(sliderUpdated);
slider.touchMoved(sliderUpdated);
val_sliders.push(slider);
}
modeSelector = createSelect();
modeSelector.option('sketch');
modeSelector.option('edit');
modeSelector.option('random');
modeSelector.option('gradient');
modeSelector.option('oddball');
modeSelector.option('image');
modeSelector.changed(modeChangedEvent);
modeSelector.value(defaultMode);
modeSelector.parent('selector1Container');
glyphSelector = createSelect();
glyphSelector.option('color');
glyphSelector.option('glyph');
glyphSelector.option('both');
glyphSelector.value(defaultDisplay);
glyphSelector.parent('selector2Container');
sizeSelector = createSelect();
sizeSelector.option('32');
sizeSelector.option('64');
sizeSelector.option('128');
sizeSelector.parent('selector3Container');
sizeSelector.value(defaultSize);
sizeSelector.changed(sizeChangedEvent);
guideCheckbox = createCheckbox('', false);
guideCheckbox.parent('checkContainer');
guideCheckbox.changed(guideChangedEvent);
button = createButton('redo');
button.mousePressed(buttonPressedEvent);
button.parent('buttonContainer');
curEmojiImg = createImage(36, 36);
// create an array for HSB values: [18][18][3]
curEmojiPixels = Array(18);
curEmojiColors = Array(18);
for(let i=0; i<18; i++) {
curEmojiPixels[i] = Array(18);
curEmojiColors[i] = Array(18);
for(let j=0; j<18; j++) {
curEmojiPixels[i][j] = Array(3);
}
}
gray_glyph = new Glyph();
refreshGridData();
modeChangedEvent();
}
function sliderUpdated() {
redraw();
}
function mouseClicked() {
if (mouseX > width/4) {
refreshGridData();
}
redraw();
}
function dataInterpolate(data1, data2, val) {
let d = new Array(3);
for(let i=0; i<3; i++) {
d[i] = lerp(data1[i], data2[i], val);
}
return d;
}
let numGridRows;
let numGridCols;
let gridValues; // row, col order
let gridOffsetX, gridOffsetY;
let gridSpacingX, gridSpacingY;
// Generate data for putting glyphs in a grid
function clamp(num, min, max) {
return Math.min(Math.max(num, min), max);
}
function refreshGridData() {
let mode = modeSelector.value();
let glyphSize = parseInt(sizeSelector.value(), 10);
if (mode == "image") {
if(glyphSize == 32) {
numGridCols = 18;
numGridRows = 17;
gridOffsetX = 320;
gridSpacingX = 31;
gridOffsetY = 2;
gridSpacingY = 29;
}
else if(glyphSize == 64) {
numGridCols = 10;
numGridRows = 9;
gridOffsetX = 280;
gridSpacingX = 66;
gridOffsetY = -18;
gridSpacingY = 59;
}
else if(glyphSize == 128) {
numGridCols = 6;
numGridRows = 5;
gridOffsetX = 164;
gridSpacingX = 132;
gridOffsetY = -50;
gridSpacingY = 118;
}
else if(glyphSize == 256) {
numGridCols = 3;
numGridRows = 3;
gridOffsetX = 172;
gridSpacingX = 262;
gridOffsetY = -100;
gridSpacingY = 234;
}
}
else if(glyphSize == 128) {
numGridCols = 6;
numGridRows = 3;
gridOffsetX = 38;
gridSpacingX = 156;
gridOffsetY = 32;
gridSpacingY = 166;
}
else if(glyphSize == 256) {
numGridCols = 3;
numGridRows = 1;
gridOffsetX = 20;
gridSpacingX = 320;
gridOffsetY = 100;
gridSpacingY = 500;
}
else if(glyphSize == 64) {
numGridCols = 12;
numGridRows = 6;
gridOffsetX = 15;
gridSpacingX = 78;
gridOffsetY = 15;
gridSpacingY = 81;
}
else if(glyphSize == 32) {
numGridCols = 21;
numGridRows = 11;
gridOffsetX = 22;
gridSpacingX = 44;
gridOffsetY = 22;
gridSpacingY = 42;
}
gridValues = new Array(numGridRows);
for (let i=0; i<numGridRows; i++) {
gridValues[i] = new Array(numGridCols);
for (let j=0; j<numGridCols; j++) {
gridValues[i][j] = new Array(8);
}
}
if (mode == "gradient" || mode == 'oddball') {
let top_left = Array(3);
let top_right = Array(3);
let bottom_left = Array(3);
let bottom_right = Array(3);
for (let k=0; k<3; k++) {
top_left[k] = random(max_vals[k]);
top_right[k] = random(max_vals[k]);
bottom_left[k] = random(max_vals[k]);
bottom_right[k] = random(max_vals[k]);
}
for (let i=0; i<numGridRows; i++) {
let frac_down = 0;
if(numGridRows != 1) {
frac_down = i / (numGridRows - 1.0);
}
d_left = dataInterpolate(top_left, bottom_left, frac_down);
d_right = dataInterpolate(top_right, bottom_right, frac_down);
for (let j=0; j<numGridCols; j++) {
let frac_over = 0;
if(numGridCols != 0) {
frac_over = j / (numGridCols - 1.0);
}
gridValues[i][j] = dataInterpolate(d_left, d_right, frac_over);
}
}
if (mode == 'oddball') {
// replace an entry at random
oddball_row = Math.floor(random(numGridRows))
oddball_col = Math.floor(random(numGridCols))
for (let k=0; k<3; k++) {
gridValues[oddball_row][oddball_col][k] = random(max_vals[k]);
}
}
}
else if(mode == "image") {
for (let i=0; i<numGridRows; i++) {
for (let j=0; j<numGridCols; j++) {
for (let k=0; k<3; k++) {
gridValues[i][j][k] = curEmojiPixels[i][j][k];
}
}
}
}
else {
for (let i=0; i<numGridRows; i++) {
for (let j=0; j<numGridCols; j++) {
for (let k=0; k<3; k++) {
gridValues[i][j][k] = random(max_vals[k]);
}
}
}
}
}
function sizeChangedEvent() {
let mode = modeSelector.value();
if (mode != 'edit') {
refreshGridData();
}
redraw();
}
function guideChangedEvent() {
show_oddball = guideCheckbox.checked();
redraw();
}
function modeChangedEvent() {
let mode = modeSelector.value();
// enable/disable sliders
if (mode === 'edit') {
// disable the button
// button.attribute('disabled','');
// enable the size selector
sizeSelector.removeAttribute('disabled');
// enable the first four sliders
for(let i=0; i<3; i++) {
val_sliders[i].removeAttribute('disabled');
}
}
else {
// enable the button
// button.removeAttribute('disabled');
// disable the sliders
for(let i=0; i<3; i++) {
val_sliders[i].attribute('disabled','');
}
// enable the size selector
// sizeSelector.removeAttribute('disabled');
// refresh data
refreshGridData();
}
if (mode === "image") {
// get current emoji image
let offsetX = 36 * (curEmoji % 38);
let offsetY = 36 * Math.floor(curEmoji / 38);
let squareOffsets = [ [0,0], [0,1], [1,1], [1, 0] ];
curEmojiImg.copy(emojiImg, offsetX, offsetY, 36, 36, 0, 0, 36, 36);
curEmojiImg.loadPixels();
for(let i=0; i<17; i++) {
// i is y
let maxX = 18;
let offsetX = 0;
if (i%2 == 1) {
maxX = 17;
offsetX = 1;
}
for(let j=0; j<maxX; j++) {
// j is x
let sumColor = [0, 0, 0];
for(let k=0; k<4; k++) {
// k is summing over 4 adacent pixels
let curColor = curEmojiImg.get(j*2 + squareOffsets[k][0] + offsetX, 1 + i*2 + squareOffsets[k][1]);
for(let l=0; l<3; l++) {
sumColor[l] += curColor[l] / 4.0;
}
}
let curColor = color(sumColor);
curEmojiColors[i][j] = curColor;
let rgba = curColor._array;
let rgb = [ rgba[0], rgba[1], rgba[2] ];
let hscol = hsluv.rgbToHsluv(rgb);
curEmojiPixels[i][j][0] = hscol[0];
curEmojiPixels[i][j][1] = hscol[1];
curEmojiPixels[i][j][2] = hscol[2];
}
}
// refresh data
refreshGridData();
}
redraw();
}
function buttonPressedEvent() {
refreshGridData();
redraw();
}
// function fillHsluv(h, s, l) {
// var rgb = hsluv.hsluvToRgb([h, s, l]);
// fill(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
// }
function ColorGlyph() {
this.draw = function(values, size) {
let rgb = hsluv.hsluvToRgb(values);
fillHsluv(values[0], values[1], values[2]);
// print(values);
// fill(rgb[0]*255, rgb[1]*255, rgb[2]*255);
stroke(0);
let s2 = size/2;
ellipse(s2, s2, size);
}
}
let color_glyph = new ColorGlyph();
function highlightGlyph(glyphSize) {
let halfSize = glyphSize / 2.0;
stroke(0, 0, 255, 128);
noFill();
strokeWeight(4);
ellipse(halfSize, halfSize, glyphSize+4);
fill(0);
strokeWeight(1);
}
function getGyphObject() {
return gray_glyph;
}
function drawGlyph(glyphValues, glyphSize) {
let shawdowShift = glyphSize / 5.0;
let glyphMode = glyphSelector.value();
if(glyphMode != "glyph") {
translate(-shawdowShift, -shawdowShift);
color_glyph.draw(glyphValues, glyphSize);
translate(shawdowShift, shawdowShift);
}
if(glyphMode != "color") {
gray_glyph.draw(glyphValues, glyphSize);
}
}
function drawDriveMode() {
let glyphSize = 320;
let halfSize = glyphSize / 2;
background(backgroundColor);
let middle_x = canvasWidth / 2;
let middle_y = canvasHeight / 2;
middle_x = middle_x + glyphSize / 10.0;
middle_y = middle_y + glyphSize / 10.0;
let val = [0,0,0];
for(i=0; i<3; i++) {
val[i] = val_sliders[i].value() / 10.0;
}
resetMatrix();
translate(middle_x - halfSize, middle_y - halfSize);
drawGlyph(val, glyphSize);
if (show_oddball) {
resetMatrix();
translate(middle_x - halfSize, middle_y - halfSize);
highlightGlyph(glyphSize)
}
// resetMatrix();
// translate(middle_x + halfSize + 32, middle_y - halfSize);
// color_glyph.draw(val, glyphSize);
}
function drawGridMode() {
let mode = modeSelector.value();
let glyphSize = parseInt(sizeSelector.value(), 10);
background(backgroundColor);
if (show_oddball && mode == 'oddball') {
resetMatrix();
translate(gridOffsetX + oddball_col * gridSpacingX, gridOffsetY + oddball_row * gridSpacingY);
highlightGlyph(glyphSize)
}
let hexOffset = (mode == "image");
for (let i=0; i<numGridRows; i++) {
let tweakedNumGridCols = numGridCols;
let offsetX = 0;
if (hexOffset && i%2 == 1) {
offsetX = gridSpacingX / 2;
tweakedNumGridCols = numGridCols - 1;
}
for (let j=0; j<tweakedNumGridCols; j++) {
resetMatrix();
translate(gridOffsetX + j * gridSpacingX + offsetX, gridOffsetY + i * gridSpacingY);
drawGlyph(gridValues[i][j], glyphSize);
resetMatrix();
}
}
}
function colorCopyArray(c) {
d = Array(18);
for(let i=0; i<18; i++) {
d[i] = Array(18);
for(let j=0; j<18; j++) {
d[i][j] = c[i][j];
}
}
return d;
}
function checkImageUpdate() {
let mode = modeSelector.value();
isSwappingEmoji = false;
if (mode == "image") {
now = millis();
if(lastKeyPressedTime + 1000 * secondsUntilSwapMode < now) {
// key not pressed recently
if(lastEmojiSwappedTime + 1000 * secondsPerEmoji < now) {
prevEmoji = curEmoji;
prevEmojiColors = colorCopyArray(curEmojiColors);
// no swaps recently
updateEmoji(1);
nextEmojiColors = colorCopyArray(curEmojiColors);
lastEmojiSwappedTime = now;
}
if(now - lastEmojiSwappedTime < 1000) {
isSwappingEmoji = true;
emojiSwapLerp = (now - lastEmojiSwappedTime) / 1000.0;
// print("LERP: " + emojiSwapLerp);
for (let i=0; i<numGridRows; i++) {
for (let j=0; j<numGridCols; j++) {
// let curColor = lerpColor(prevEmojiColors[i][j], nextEmojiColors[i][j], emojiSwapLerp);
let curColor = prevEmojiColors[i][j];
if (curColor) {
curColor = lerpColor(prevEmojiColors[i][j], nextEmojiColors[i][j], emojiSwapLerp);
curEmojiPixels[i][j][0] = curColor._getHue();
curEmojiPixels[i][j][1] = curColor._getSaturation();
curEmojiPixels[i][j][2] = curColor._getBrightness();
}
}
}
refreshGridData();
}
else {
for (let i=0; i<numGridRows; i++) {
for (let j=0; j<numGridCols; j++) {
let curColor = nextEmojiColors[i][j];
if (curColor) {
curEmojiPixels[i][j][0] = curColor._getHue();
curEmojiPixels[i][j][1] = curColor._getSaturation();
curEmojiPixels[i][j][2] = curColor._getBrightness();
}
}
}
refreshGridData();
}
}
}
}
let is_drawing = false;
function draw () {
if (is_drawing) {
return;
}
is_drawing = true;
let mode = modeSelector.value();
if (mode == "sketch") {
image(sketchImg, 0, 0, width, height);
is_drawing = false;
return;
}
checkImageUpdate();
if (mode == 'edit') {
drawDriveMode();
}
else {
drawGridMode();
}
resetMatrix();
if (mode == "image") {
image(curEmojiImg, 96, height-32-36);
}
is_drawing = false;
}
function keyTyped() {
if (key == '!') {
saveBlocksImages();
}
else if (key == '@') {
saveBlocksImages(true);
}
else if (key == ' ') {
refreshGridData();
redraw();
}
else if (key == 'd') {
let curGlyph = glyphSelector.value()
if(curGlyph == "color") {
glyphSelector.value('glyph');
}
else if(curGlyph == "glyph") {
glyphSelector.value('both');
}
else if(curGlyph == "both") {
glyphSelector.value('color');
}
redraw();
}
else if (key == 'c') {
let old_value = guideCheckbox.checked();
guideCheckbox.checked(!old_value);
guideChangedEvent();
}
else if (key == '1') {
sizeSelector.value('32');
sizeChangedEvent()
}
else if (key == '2') {
sizeSelector.value('64');
sizeChangedEvent()
}
else if (key == '3') {
sizeSelector.value('128');
sizeChangedEvent()
}
else if (key == 's') {
modeSelector.value('sketch');
modeChangedEvent()
}
else if (key == 'e') {
modeSelector.value('edit');
modeChangedEvent()
}
else if (key == 'g') {
modeSelector.value('gradient');
modeChangedEvent()
}
else if (key == 'r') {
modeSelector.value('random');
modeChangedEvent()
}
else if (key == 'o') {
modeSelector.value('oddball');
modeChangedEvent()
}
else if (key == 'i') {
modeSelector.value('image');
modeChangedEvent()
}
}
function updateEmoji(offset) {
curEmoji = (curEmoji + NUM_EMOJI + offset) % NUM_EMOJI;
modeChangedEvent()
}
function keyPressed() {
lastKeyPressedTime = millis();
if (keyCode == LEFT_ARROW) {
updateEmoji(-1);
}
else if (keyCode == RIGHT_ARROW) {
updateEmoji(1);
}
else if (keyCode == UP_ARROW) {
updateEmoji(-38);
}
else if (keyCode == DOWN_ARROW) {
updateEmoji(38);
}
}
function mouseMoved() {
lastKeyPressedTime = millis();
}
function mouseDragged() {
lastKeyPressedTime = millis();
}
function fillHsluv(h, s, l) {
var rgb = hsluv.hsluvToRgb([h, s, l]);
fill(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
}
function strokeHsluv(h, s, l) {
var rgb = hsluv.hsluvToRgb([h, s, l]);
stroke(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
}
function fillUniform(brightness) {
fillHsluv(0, 0, brightness);
}
function strokeUniform(brightness) {
strokeHsluv(0, 0, brightness);
}
(function() {function f(a){var c=[],b=Math.pow(a+16,3)/1560896;b=b>g?b:a/k;for(var d=0;3>d;){var e=d++,h=l[e][0],w=l[e][1];e=l[e][2];for(var x=0;2>x;){var y=x++,z=(632260*e-126452*w)*b+126452*y;c.push({b:(284517*h-94839*e)*b/z,a:((838422*e+769860*w+731718*h)*a*b-769860*y*a)/z})}}return c}function m(a){a=f(a);for(var c=Infinity,b=0;b<a.length;){var d=a[b];++b;c=Math.min(c,Math.abs(d.a)/Math.sqrt(Math.pow(d.b,2)+1))}return c}
function n(a,c){c=c/360*Math.PI*2;a=f(a);for(var b=Infinity,d=0;d<a.length;){var e=a[d];++d;e=e.a/(Math.sin(c)-e.b*Math.cos(c));0<=e&&(b=Math.min(b,e))}return b}function p(a,c){for(var b=0,d=0,e=a.length;d<e;){var h=d++;b+=a[h]*c[h]}return b}function q(a){return.0031308>=a?12.92*a:1.055*Math.pow(a,.4166666666666667)-.055}function r(a){return.04045<a?Math.pow((a+.055)/1.055,2.4):a/12.92}function t(a){return[q(p(l[0],a)),q(p(l[1],a)),q(p(l[2],a))]}
function u(a){a=[r(a[0]),r(a[1]),r(a[2])];return[p(v[0],a),p(v[1],a),p(v[2],a)]}function A(a){var c=a[0],b=a[1];a=c+15*b+3*a[2];0!=a?(c=4*c/a,a=9*b/a):a=c=NaN;b=b<=g?b/B*k:116*Math.pow(b/B,.3333333333333333)-16;return 0==b?[0,0,0]:[b,13*b*(c-C),13*b*(a-D)]}function E(a){var c=a[0];if(0==c)return[0,0,0];var b=a[1]/(13*c)+C;a=a[2]/(13*c)+D;c=8>=c?B*c/k:B*Math.pow((c+16)/116,3);b=0-9*c*b/((b-4)*a-b*a);return[b,c,(9*c-15*a*c-a*b)/(3*a)]}
function F(a){var c=a[0],b=a[1],d=a[2];a=Math.sqrt(b*b+d*d);1E-8>a?b=0:(b=180*Math.atan2(d,b)/Math.PI,0>b&&(b=360+b));return[c,a,b]}function G(a){var c=a[1],b=a[2]/360*2*Math.PI;return[a[0],Math.cos(b)*c,Math.sin(b)*c]}function H(a){var c=a[0],b=a[1];a=a[2];if(99.9999999<a)return[100,0,c];if(1E-8>a)return[0,0,c];b=n(a,c)/100*b;return[a,b,c]}function I(a){var c=a[0],b=a[1];a=a[2];if(99.9999999<c)return[a,0,100];if(1E-8>c)return[a,0,0];var d=n(c,a);return[a,b/d*100,c]}
function J(a){var c=a[0],b=a[1];a=a[2];if(99.9999999<a)return[100,0,c];if(1E-8>a)return[0,0,c];b=m(a)/100*b;return[a,b,c]}function K(a){var c=a[0],b=a[1];a=a[2];if(99.9999999<c)return[a,0,100];if(1E-8>c)return[a,0,0];var d=m(c);return[a,b/d*100,c]}function L(a){for(var c="#",b=0;3>b;){var d=b++;d=Math.round(255*a[d]);var e=d%16;c+=M.charAt((d-e)/16|0)+M.charAt(e)}return c}
function N(a){a=a.toLowerCase();for(var c=[],b=0;3>b;){var d=b++;c.push((16*M.indexOf(a.charAt(2*d+1))+M.indexOf(a.charAt(2*d+2)))/255)}return c}function O(a){return t(E(G(a)))}function P(a){return F(A(u(a)))}function Q(a){return O(H(a))}function R(a){return I(P(a))}function S(a){return O(J(a))}function T(a){return K(P(a))}
var l=[[3.240969941904521,-1.537383177570093,-.498610760293],[-.96924363628087,1.87596750150772,.041555057407175],[.055630079696993,-.20397695888897,1.056971514242878]],v=[[.41239079926595,.35758433938387,.18048078840183],[.21263900587151,.71516867876775,.072192315360733],[.019330818715591,.11919477979462,.95053215224966]],B=1,C=.19783000664283,D=.46831999493879,k=903.2962962,g=.0088564516,M="0123456789abcdef";
window.hsluv={hsluvToRgb:Q,rgbToHsluv:R,hpluvToRgb:S,rgbToHpluv:T,hsluvToHex:function(a){return L(Q(a))},hexToHsluv:function(a){return R(N(a))},hpluvToHex:function(a){return L(S(a))},hexToHpluv:function(a){return T(N(a))},lchToHpluv:K,hpluvToLch:J,lchToHsluv:I,hsluvToLch:H,lchToLuv:G,luvToLch:F,xyzToLuv:A,luvToXyz:E,xyzToRgb:t,rgbToXyz:u,lchToRgb:O,rgbToLch:P};})();
// note: this file is poorly named - it can generally be ignored.
// helper functions below for supporting blocks/purview
function saveBlocksImages(doZoom) {
if(doZoom == null) {
doZoom = false;
}
// generate 960x500 preview.jpg of entire canvas
// TODO: should this be recycled?
var offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = 960;
offscreenCanvas.height = 500;
var context = offscreenCanvas.getContext('2d');
// background is flat white
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, 960, 500);
context.drawImage(this.canvas, 0, 0, 960, 500);
// save to browser
var downloadMime = 'image/octet-stream';
var imageData = offscreenCanvas.toDataURL('image/jpeg');
imageData = imageData.replace('image/jpeg', downloadMime);
p5.prototype.downloadFile(imageData, 'preview.jpg', 'jpg');
// generate 230x120 thumbnail.png centered on mouse
offscreenCanvas.width = 230;
offscreenCanvas.height = 120;
// background is flat white
context = offscreenCanvas.getContext('2d');
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, 230, 120);
if(doZoom) {
// pixelDensity does the right thing on retina displays
var pd = this._pixelDensity;
var sx = pd * mouseX - pd * 230/2;
var sy = pd * mouseY - pd * 120/2;
var sw = pd * 230;
var sh = pd * 120;
// bounds checking - just displace if necessary
if (sx < 0) {
sx = 0;
}
if (sx > this.canvas.width - sw) {
sx = this.canvas.width - sw;
}
if (sy < 0) {
sy = 0;
}
if (sy > this.canvas.height - sh) {
sy = this.canvas.height - sh;
}
// save to browser
context.drawImage(this.canvas, sx, sy, sw, sh, 0, 0, 230, 120);
}
else {
// now scaledown
var full_width = this.canvas.width;
var full_height = this.canvas.height;
context.drawImage(this.canvas, 0, 0, full_width, full_height, 0, 0, 230, 120);
}
imageData = offscreenCanvas.toDataURL('image/png');
imageData = imageData.replace('image/png', downloadMime);
// call this function after 1 second
setTimeout(function(){
p5.prototype.downloadFile(imageData, 'thumbnail.png', 'png');
}, 1000);
}