No description provided
The showcase player uses a modified version of Processing.js in combination with jsweet to let students program their apps in Java code while still allowing for browser support.
Content created by students is scaled to fit the showcase frame while maintaining aspect ratio and cursor position. This is why some projects may appear blurry in fullscreen, or why some small details may not be visible on a small screen
<iframe width='500px' height='400px' src='https://nest.ktbyte.com/nest#108191' allowfullscreen></iframe>
// CREDITS: // hcy to rgb conversion: http://www.chilliant.com/rgb2hsv.html // save icon: http://iconmonstr.com/ // INSPIRATIONS: // Krita HSY' color selector: http://wolthera.info/?p=726 // Online HCL Creator: http://hclwizard.org/why-hcl/ // DEFINITIONS: (https://en.wikipedia.org/wiki/HSL_and_HSV#Formal_derivation) // HUE (H): // The "attribute of a visual sensation according to which an area appears to be similar to one of the // perceived colors: red, yellow, green, and blue, or to a combination of two of them". // CHROMA (C): // The "colorfulness relative to the brightness of a similarly illuminated white". // LUMA (Y'): // The weighted sum of gamma-corrected R′, G′, and B′ values. /*-------------------------*/ ColorSelector sel; PaletteGenerator gen; /*-------------------------*/ void setup() { size(800, 550); sel = new ColorSelector(160, 160, 81); gen = new PaletteGenerator(390, 40, 350); PVector hcy = gen.getColor(350/2); sel.update(hcy); } /*-------------------------*/ void draw() { background(230); sel.interact(mouseX, mouseY); gen.interact(mouseX, mouseY); sel.display(); gen.display(mouseX, mouseY); // display title pushStyle(); textAlign(LEFT, TOP); textSize(22); fill(127); text("HCY' Palette Generator", 50, 475); popStyle(); } /*-------------------------*/ void mousePressed() { sel.click(mouseX, mouseY); gen.click(mouseX, mouseY, sel); } /*-------------------------*/ void mouseReleased() { sel.release(); gen.release(); } /*-------------------------*/ class Button { PVector pos; float r; String title; /*----*/ Button(float x, float y, String title_) { pos = new PVector(x, y); r = 10; title = title_; } /*----*/ boolean insideButton(float mx, float my) { return dist(mx, my, pos.x, pos.y) < r; } /*----*/ void display() { fill(127); noStroke(); ellipse(pos.x, pos.y, 2*r, 2*r); fill(230); text(title, pos.x, pos.y); } } /*-------------------------*/ // icon by iconmonstr //available at: http://iconmonstr.com/save-1/ class SaveButton { PVector pos; PVector bSize; PShape ps; /*----*/ SaveButton(float x, float y, float w, float h) { pos = new PVector(x, y); bSize = new PVector(w, h); ps = loadShape("save.svg"); ps.disableStyle(); } /*----*/ boolean insideButton(float mx, float my) { boolean testX = mx >= pos.x && mx < pos.x + bSize.x; boolean testY = my >= pos.y && my < pos.y + bSize.y; return testX && testY; } /*----*/ void display() { fill(127); noStroke(); shape(ps, pos.x, pos.y, bSize.x, bSize.y); } } /*-------------------------*/ class ColorDisplay { PVector pos; float diam; color col; PVector hcy, rgb; /*----*/ ColorDisplay(float x, float y, float r) { pos = new PVector(x, y); diam = 2*r; hcy = new PVector(0, 0, 0); update(0, 0.5, 0.5); } /*----*/ void update(float h, float c, float y) { hcy.set(h, c, y); col = color(HCYtoRGB(h, c, y)); } /*----*/ void display() { noStroke(); fill(col); ellipse(pos.x, pos.y, diam, diam); String hcyColor = "h: " + nf(360*hcy.x, 1, 2) + "°, c: = " + nf(100*hcy.y, 1, 2) + "%, y': " + nf(100*hcy.z, 1, 2) + "%"; String rgbColor = "r: " + (col >> 16 & 0xFF) + ", g: = " + (col >> 8 & 0xFF) + ", b: " + (col & 0xFF); String hexColor = "#" + hex(col, 6); fill(100); textAlign(CENTER); text(hcyColor, pos.x, pos.y + diam); text(rgbColor, pos.x, pos.y + diam + 20); text(hexColor, pos.x, pos.y + diam + 40); } } /*-------------------------*/ class ColorSelector { RoundSelector rdSel; SquareSelector sqSel; ColorDisplay disp; /*----*/ ColorSelector(float x, float y, float r) { rdSel = new RoundSelector(x, y, r, r/3); sqSel = new SquareSelector(x, y, 2*r/sqrt(2), 2*r/sqrt(2)); disp = new ColorDisplay(x, y + 2*r, r/3); } /*----*/ void click(int mx, int my) { rdSel.click(mx, my); sqSel.click(mx, my); } /*----*/ void interact(int mx, int my) { rdSel.drag(mx, my); sqSel.drag(mx, my); if (rdSel.dragging) { // update the square selector when the round selector is modified sqSel.update(rdSel.col); } else if (sqSel.dragging) { // update the round selector when the square selector is modified rdSel.update(sqSel.col.x, 1 - sqSel.col.y); } if (rdSel.dragging || sqSel.dragging) { // update the display when the selectors are modified disp.update(rdSel.col, sqSel.col.x, 1 - sqSel.col.y); } } /*----*/ void release() { rdSel.release(); sqSel.release(); } /*----*/ void display() { rdSel.display(); sqSel.display(); disp.display(); } /*----*/ // update selectors and display with a given hcy color (used to show a color of the palette/gradient) void update(PVector hcy) { rdSel.update(hcy.y, hcy.z); sqSel.update(hcy.x); disp.update(hcy.x, hcy.y, hcy.z); sqSel.col.set(hcy.y, 1-hcy.z); rdSel.col = hcy.x; } } /*-------------------------*/ class Gradient { PVector pos; PGraphics pg; SaveButton bSave; /*----*/ Gradient(float x, float y, float w, float h) { pos = new PVector(x, y); pg = createGraphics(int(w), int(h)); bSave = new SaveButton(x + w + 10, y + 0.1*h, 0.8*h, 0.8*h); } /*----*/ void selectColor(float mx, float my, PaletteGenerator p, ColorSelector sel) { boolean testX = mx >= pos.x && mx < pos.x + pg.width; boolean testY = my >= pos.y && my < pos.y + pg.height; if (testX && testY) { PVector hcy = p.getColor(mx); sel.update(hcy); } } /*----*/ void update(PaletteGenerator p) { pg.loadPixels(); for (int i = 0; i < pg.width; i += 1) { PVector hcy = p.getColor(i); color col = HCYtoRGB(hcy.x, hcy.y, hcy.z); for (int j = 0; j < pg.height; j += 1) { pg.pixels[i + j*pg.width] = color(col); } } pg.updatePixels(); } /*----*/ void display(ArrayList<PaletteColor> col) { image(pg, pos.x, pos.y); bSave.display(); noStroke(); fill(127); for(int i = 0; i < col.size()-1; i += 1) { ellipse(col.get(i).value + col.get(1).value/2, pg.height+3, 5, 5); } } /*----*/ void saveImage(float mx, float my) { if (bSave.insideButton(mx, my)) { pg.save("gradient" + frameCount + ".png"); } } } /*-------------------------*/ class Graphic { PVector pos; PVector gSize; PVector scale; boolean dispAxeX,dispAxeY; boolean interacting; String title; ArrayList<GraphicPoint> p; /*----*/ Graphic(int x, int y, int w, int h, float max, boolean aX, boolean aY, String t) { pos = new PVector(x, y); gSize = new PVector(w, h); scale = new PVector(100., max); dispAxeX = aX; dispAxeY = aY; interacting = false; title = t; p = new ArrayList<GraphicPoint>(); // create initial points with dragging as false p.add(new GraphicPoint(0, 0, false)); // first point (not displayed) p.add(new GraphicPoint(0, random(h), false)); // random initial point at 0 p.add(new GraphicPoint(w, random(h), false)); // random initial point at 100 p.add(new GraphicPoint(w, 0, false)); // last point (not displayed) } /*----*/ void click(float mx, float my) { boolean overAnyPoint = false; int i = 1; while (!overAnyPoint && i < p.size()-1) { boolean overThisPoint = p.get(i).click(mx - pos.x, my - pos.y); // if the mouse is over point i, interact with it and return true if (overThisPoint) { overAnyPoint = true; if (mouseButton == RIGHT) { p.remove(i); } else { interacting = true; } } i += 1; } if (!overAnyPoint && insideGraphic(mx - pos.x, my - pos.y) && mouseButton == LEFT) { addPoint(mx - pos.x, my - pos.y); interacting = true; } } /*----*/ void interact(float mx, float my) { for (int i = 1; i < p.size()-1; i += 1) { // ignore first and last point p.get(i).drag(mx - pos.x, my - pos.y); p.get(i).constrainX(p.get(i-1), p.get(i+1), gSize.y); // constrain x coordinate to the neighbors position } // first and last point get the y coordinate of the nearest point p.get(0).pos.y = p.get(1).pos.y; p.get(p.size()-1).pos.y = p.get(p.size()-2).pos.y; } /*----*/ void release() { for (int i = 1; i < p.size()-1; i += 1) { p.get(i).release(); } interacting = false; } /*----*/ void display(float mx, float my) { pushMatrix(); translate(pos.x, pos.y); // graphic background noStroke(); fill(255); rect(0, 0, gSize.x, gSize.y); // display lines strokeWeight(2); stroke(127); noFill(); beginShape(); for (int i = 0; i < p.size(); i += 1) { p.get(i).displayLine(); } endShape(); // display points noStroke(); fill(241, 131, 176, 100); for (int i = 1; i < p.size()-1; i += 1) { // ignore first and last points p.get(i).display(); } displayAxis(dispAxeX, dispAxeY); displayLocation(mx - pos.x, my - pos.y); popMatrix(); } /*----*/ void displayLocation(float mx, float my) { boolean testX = mx >= 0 && mx < gSize.x; boolean testY = my >= 0 && my < gSize.y; strokeWeight(1); stroke(230); if ((testX && testY) || interacting) { // display horizontal lines when over the graphic or interacting with it line(0, my, gSize.x, my); } if (testX) { // display vertical lines when mx is over the graphic line(mx, 0, mx, gSize.y); } // display values when interacting with the graphic fill(100); textAlign(CENTER, CENTER); if (testX && interacting) { text(int( scale.x * mx/gSize.x), mx, -10); } if (testY && interacting) { text(nf(scale.y * ( 1 - my/gSize.y), 1, 2), gSize.x + 15, my); } } /*----*/ void displayAxis(boolean displayX, boolean displayY) { strokeWeight(2); stroke(100); fill(100); textAlign(CENTER, CENTER); if (displayX) { line(0, gSize.y + 10, gSize.x, gSize.y + 10); // X axis //min line(0, gSize.y + 12, 0, gSize.y + 8); text(0, 0, gSize.y + 20); //max line(gSize.x, gSize.y + 12, gSize.x, gSize.y + 8); text(int(scale.x), gSize.x, gSize.y + 20); } if (displayY) { line(-10, 0, -10, gSize.y); // Y axis text(title, -50, gSize.y/2); // name of the graphic //min line(-12, gSize.y, -8, gSize.y); text(0, -25, gSize.y); //max line(-12, 0, -8, 0); text(int(scale.y), -25, 0); } } /*----*/ void addPoint(float mx, float my) { for (int i = 0; i < p.size(); i += 1) { // loop through existent points to find the position of the new point if (p.get(i).afterPoint(mx) && p.get(i+1).beforePoint(mx)) { p.add(i+1, new GraphicPoint(mx, my, true)); break; } } } /*----*/ float getValue(float x) { for (int i = 0; i < p.size(); i += 1) { if (p.get(i).afterPoint(x) && p.get(i+1).beforePoint(x)) { // find points that define x return p.get(i).calcY(p.get(i+1), x); // calculate the value } } return 0; } /*----*/ boolean insideGraphic(float mx, float my) { boolean testX = mx >= 0 && mx < gSize.x; boolean testY = my >= 0 && my < gSize.y; return testX && testY; } } /*-------------------------*/ class GraphicPoint { PVector pos, dpos; float d; boolean dragging; /*----*/ GraphicPoint(float x, float y, boolean dragNewPoint) { pos = new PVector(x, y); d = 10; dragging = dragNewPoint; } /*----*/ boolean click(float mx, float my) { if (dist(mx, my, pos.x, pos.y) < d/2) { dragging = true; return true; } return false; } /*----*/ void drag(float mx, float my) { if (dragging) { pos.set(mx, my); } } /*----*/ void release() { dragging = false; } /*----*/ void display() { ellipse(pos.x, pos.y, d, d); } /*----*/ void displayLine() { vertex(pos.x, pos.y); } /*----*/ void constrainX(GraphicPoint p0, GraphicPoint p1, float h) { pos.x = constrain(pos.x, p0.pos.x, p1.pos.x); pos.y = constrain(pos.y, 0, h); } /*----*/ boolean beforePoint(float mx) { return mx < pos.x; } /*----*/ boolean afterPoint(float mx) { return mx >= pos.x; } /*----*/ float calcY(GraphicPoint p, float x) { float a = (p.pos.y - pos.y) / (p.pos.x - pos.x); float b = pos.y - a*pos.x; float y = a*x + b; return map(y, 0, 100, 1, 0); } } /*-------------------------*/ class Palette { PVector pos; PGraphics pg; SaveButton bSave; /*----*/ Palette(float x, float y, float w, float h) { pos = new PVector(x, y); pg = createGraphics(int(w), int(h)); bSave = new SaveButton(x + w + 10, y + 0.1*h, 0.8*h, 0.8*h); } /*----*/ void selectColor(float mx, float my, float gridSize, PaletteGenerator p, ColorSelector sel) { boolean testX = mx >= pos.x && mx < pos.x + pg.width; boolean testY = my >= pos.y && my < pos.y + pg.height; if (testX && testY) { PVector hcy = p.getColor(int(mx/gridSize)*gridSize + gridSize/2); sel.update(hcy); } } /*----*/ void update(PaletteGenerator p, ArrayList<PaletteColor> col) { float gridSize = col.get(1).value; pg.beginDraw(); pg.noStroke(); for (int i = 0; i < col.size()-1; i += 1) { PVector hcy = p.getColor(col.get(i).value + gridSize/2); pg.fill(HCYtoRGB(hcy.x, hcy.y, hcy.z)); pg.rect(col.get(i).value, 0, gridSize, pg.height); } pg.endDraw(); } /*----*/ void display() { image(pg, pos.x, pos.y); bSave.display(); } /*----*/ void saveImage(float mx, float my) { if (bSave.insideButton(mx, my)) { pg.save("palette" + frameCount + ".png"); } } } /*-------------------------*/ class PaletteDisplay { PVector pos; float dWidth; Gradient gra; Palette pal; Button[] b; ArrayList<PaletteColor> col; /*----*/ PaletteDisplay(float x, float y, int w) { pos = new PVector(x, y); dWidth = w; gra = new Gradient(0, 0, w, 30); pal = new Palette(0, 50, w, 30); b = new Button[2]; b[0] = new Button(-20, 50, "+"); b[1] = new Button(-20, 80, "-"); col = new ArrayList<PaletteColor>(); for(int i = 0; i < 6; i += 1) { // begin with a 5-color palette col.add(new PaletteColor()); } distributePoints(); } /*----*/ void distributePoints() { for (int i = 0; i < col.size(); i += 1) { col.get(i).value = i * dWidth/(col.size()-1); } } /*----*/ void update(PaletteGenerator p) { gra.update(p); pal.update(p, col); } /*----*/ void click(float mx, float my, PaletteGenerator gen, ColorSelector sel) { addColor(mx, my); removeColor(mx, my); selecColor(mx, my, gen, sel); saveImage(mx, my); } /*----*/ void addColor(float mx, float my) { if (b[0].insideButton(mx - pos.x, my - pos.y)) { col.add(new PaletteColor()); distributePoints(); } } /*----*/ void removeColor(float mx, float my) { if (b[1].insideButton(mx - pos.x, my - pos.y) && col.size() > 2) { col.remove(0); distributePoints(); } } /*----*/ void selecColor(float mx, float my, PaletteGenerator gen, ColorSelector sel) { gra.selectColor(mx - pos.x, my - pos.y, gen, sel); pal.selectColor(mx - pos.x, my - pos.y, col.get(1).value, gen, sel); } /*----*/ void saveImage(float mx, float my) { gra.saveImage(mx - pos.x, my - pos.y); pal.saveImage(mx - pos.x, my - pos.y); } /*----*/ void display() { pushMatrix(); translate(pos.x, pos.y); gra.display(col); pal.display(); for (int i = 0; i < b.length; i += 1) { b[i].display(); } popMatrix(); } } /*-------------------------*/ class PaletteColor { float value; PaletteColor() { value = 0; } } /*-------------------------*/ class PaletteGenerator { Graphic[] g; PaletteDisplay disp; /*----*/ PaletteGenerator(int x, int y, int w) { g = new Graphic[3]; g[0] = new Graphic(x, y, w, 100, 360, false, true, "Hue (H)"); g[1] = new Graphic(x, y + 120, w, 100, 1, false, true, "Chroma (C)"); g[2] = new Graphic(x, y + 240, w, 100, 1, true, true, "Luma (Y') \n Rec. 709"); disp = new PaletteDisplay(x, y + 380, w); disp.update(this); } /*----*/ void click(float mx, float my, ColorSelector sel) { for (int i = 0; i < g.length; i += 1) { g[i].click(mx, my); } disp.click(mx, my, this, sel); } /*----*/ void interact(float mx, float my) { for (int i = 0; i < g.length; i += 1) { g[i].interact(mx, my); } disp.update(this); } /*----*/ void release() { for (int i = 0; i < g.length; i += 1) { g[i].release(); } } /*----*/ void display(float mx, float my) { for (int i = 0; i < g.length; i += 1) { g[i].display(mx, my); } disp.display(); } /*----*/ PVector getColor(float x) { return new PVector(g[0].getValue(x), g[1].getValue(x), g[2].getValue(x)); } } /*-------------------------*/ class RoundSelector { PGraphics pg; float ri, re; PVector pos; float col; boolean dragging; /*----*/ RoundSelector(float x, float y, float r, float dr) { ri = r; re = r + dr; pg = createGraphics(int(2*re), int(2*re)); pos = new PVector(x, y); col = 0; update(0.5, 0.5); dragging = false; } /*----*/ void click(int mx, int my) { float r = dist(mx, my, pos.x, pos.y); if (r >= ri && r < re) { dragging = true; } } /*----*/ void drag(int mx, int my) { if (dragging) { float theta = atan2(my - pos.y, mx - pos.x); col = theta/TWO_PI; col = (col + 1)%1; // keep hue between 0 and 1 } } /*----*/ void release() { dragging = false; } /*----*/ void update(float y, float z) { pg.beginDraw(); pg.background(0, 0); pg.pushMatrix(); pg.translate(re, re); pg.noStroke(); for (int i = 0; i < 360; i++) { pg.rotate(radians(1)); pg.fill(HCYtoRGB(i/360., y, z)); pg.rectMode(CORNERS); pg.rect(ri, 0, 0.98*re, 2*re*radians(1)); } pg.popMatrix(); pg.endDraw(); } /*----*/ void display() { pushMatrix(); translate(pos.x, pos.y); image(pg, -re, -re); // -re, -re to center the circle strokeWeight(1); rotate(TWO_PI*col); stroke(0); line(ri, 0, 0.98*re, 0); stroke(255); rotate(radians(0.8)); line(ri, 0, 0.98*re, 0); popMatrix(); } } /*-------------------------*/ // HCY to RGB convertion by Ian Taylor and David Schaeffer based on work by Kuzma Shapran // available at: http://www.chilliant.com/rgb2hsv.html color HCYtoRGB(float h, float c, float y) { final PVector REC709y = new PVector(0.2126, 0.7152, 0.0722); PVector hcy = new PVector(h, c, y); float r = constrain(abs(6*h - 3) - 1, 0, 1); float g = constrain(2 - abs(6*h - 2), 0, 1); float b = constrain(2 - abs(6*h - 4), 0, 1); PVector rgb = new PVector(r, g, b); float z = rgb.dot(REC709y); if (z >= hcy.z) { hcy.y *= hcy.z / z; } else if (z < 1) { hcy.y *= (1 - hcy.z) / (1 - z); } rgb.sub(z, z, z); rgb.mult(hcy.y); rgb.add(hcy.z, hcy.z, hcy.z); rgb.mult(255); return color(rgb.x, rgb.y, rgb.z); } /*-------------------------*/ class SquareSelector { PGraphics pg; PVector pos; PVector col; boolean dragging; /*----*/ SquareSelector(float x, float y, float w, float h) { pg = createGraphics(int(w), int(h)); pos = new PVector(x - w/2, y - h/2); col = new PVector(0.5, 0.5); update(0); dragging = false; } /*----*/ void click(int mx, int my) { boolean testX = mx >= pos.x && mx < pos.x + pg.width; boolean testY = my >= pos.y && my < pos.y + pg.height; if (testX && testY) { dragging = true; } } /*----*/ void drag(int mx, int my) { if (dragging) { float x = constrain((mx - pos.x)/pg.width, 0, 1); float y = constrain((my - pos.y)/pg.height, 0, 1); col.set(x, y); } } /*----*/ void release() { dragging = false; } /*----*/ void update(float z) { pg.loadPixels(); for (int i = 0; i < pg.width; i += 1) { for (int j = 0; j < pg.height; j += 1) { pg.pixels[i + j*pg.width] = HCYtoRGB(z, float(i)/pg.width, 1 - float(j)/pg.height); } } pg.updatePixels(); } /*----*/ void display() { pushMatrix(); translate(pos.x, pos.y); imageMode(CORNER); image(pg, 0, 0); translate(col.x*pg.width, col.y*pg.height); noFill(); strokeWeight(1); stroke(255); ellipse(0, 0, 7, 7); stroke(0); ellipse(0, 0, 9, 9); popMatrix(); } }