)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

Cut Hole in Canvas (eraser)

  1. document.body.style.background = 'gray';
  2. const canvas = document.createElement('canvas');
  3. const c = canvas.getContext('2d');
  4.  
  5. canvas.width = 300;
  6. canvas.height = 300;
  7.  
  8. c.fillStyle='rgba(255, 0, 0, 0.8)'
  9. c.fillRect(0, 0, canvas.width, canvas.height);
  10.  
  11. c.globalCompositeOperation = 'destination-out';
  12. c.fillStyle = 'black';
  13. c.fillRect(100, 100, 150, 50);
  14.  
  15. document.body.appendChild(canvas);

destination-out is great for creating masks and eraser tools – things like that – in this case a 150×50 rectangle is cut out of a red background.

Thinking About Colors

  1. const { assign } = Object
  2. const { min, max, floor, round, abs } = Math
  3.  
  4. // `hslToRgb` and `rgbToHsl` functions from the amazing Raphael library
  5. // by Dmitry Baranovskiy
  6. // https://github.com/DmitryBaranovskiy/raphael/blob/master/raphael.js
  7.  
  8. export function hslToRgb({ h, s, l, a }) {
  9.   let H = h
  10.   let S = s
  11.   let L = l
  12.  
  13.   s /= 100
  14.   l /= 100
  15.  
  16.   let r, g, b, x, c
  17.   h = (h % 360) / 60
  18.   c = 2 * s * (l < .5 ? l : 1 - l)
  19.   x = c * (1 - abs(h % 2 - 1))
  20.   r = g = b = l - c / 2;
  21.   h = floor(h)
  22.   r += [c, x, 0, 0, x, c][h]
  23.   g += [x, c, c, x, 0, 0][h]
  24.   b += [0, 0, x, c, c, x][h]
  25.   r *= 255; g *= 255; b *= 255
  26.   r = round(r)
  27.   g = round(g)
  28.   b = round(b)
  29.   return { r, g, b, h: H, s: S, l: L, a }
  30. }
  31.  
  32. export function rgbToHsl({ r, g, b, a }) {
  33.   let R = r
  34.   let G = g
  35.   let B = b
  36.  
  37.   r /= 255
  38.   g /= 255
  39.   b /= 255
  40.  
  41.   let h, s, l, w, m, c;
  42.   w = max(r, g, b);
  43.   m = min(r, g, b);
  44.   c = w - m;
  45.   h = (c == 0 ? null :
  46.         w == r ? (g - b) / c :
  47.         w == g ? (b - r) / c + 2 :
  48.                  (r - g) / c + 4)
  49.   h = ((h + 360) % 6) * 60 / 360;
  50.  
  51.   l = (w + m) / 2;
  52.   s = (c == 0 ? 0 : l < .5 ?
  53.     c / (2 * l) :
  54.     c / (2 - 2 * l));
  55.   h *= 360
  56.   s *= 100
  57.   l *= 100
  58.   h = round(h)
  59.   s = round(s)
  60.   l = round(l);
  61.   return { h, s, l, r: R, g: G, b: B, a }
  62. }
  63.  
  64. const fromDec = dec => ({
  65.   r: dec >> 16,
  66.   g: dec >> 8 & 255,
  67.   b: dec & 255
  68. })
  69.  
  70. const fromHex = hex =>
  71.   fromDec(Number('0x' + hex.slice(1)))
  72.  
  73. const components = def =>
  74.   def.match(/[0-9\.]+/g).map(parseFloat)
  75.  
  76. const fromRgb = rgb => {
  77.   const [r, g, b, a] = components(rgb)
  78.   return { r, g, b, a: a ?? 1 }
  79. }
  80.  
  81. const fromHsl = hsl => {
  82.   const [h, s, l, a] = components(hsl)
  83.   return { h, s, l, a: a ?? 1 }
  84. }
  85.  
  86. const utils = {
  87.   hex: (def, o) => assign(o, rgbToHsl(
  88.     fromHex(def)), { a: o.a ?? 1 }
  89.   ),
  90.   rgb: (def, o) => assign(o, rgbToHsl(fromRgb(def))),
  91.   hsl: (def, o) => assign(o, hslToRgb(fromHsl(def))),
  92.   prop: (def, o) => {
  93.     const name = Object.keys(def)[0]
  94.     o[name] = def[name]
  95.     if (name.match(/[rgb]/)) assign(o, rgbToHsl(o))
  96.     if (name.match(/[hsl]/)) assign(o, hslToRgb(o))
  97.  
  98.     return o
  99.   }
  100. }
  101.  
  102. const types = { '#': 'hex', r: 'rgb', h: 'hsl', '[': 'prop' }
  103. const type = str => types[str[0]]
  104.  
  105. const hx = c => {
  106.   const chan = (+c).toString(16)
  107.   if (chan.length === 0) return '00'
  108.   if (chan.length === 1) return '0' + chan
  109.   return chan
  110. };
  111.  
  112. export function shade(def) {
  113.   const o = {
  114.     set(def) {
  115.       const method = utils[type(String(def))]
  116.       if (method != null) method(def, o)
  117.     },
  118.     hsl: _ => `hsla(${o.h}, ${o.s}%, ${o.l}%, ${o.a})`,
  119.     rgb: _ => `rgba(${o.r}, ${o.g}, ${o.b}, ${o.a})`,
  120.     hex: _ => `#${hx(o.r)}${hx(o.g)}${hx(o.b)}`
  121.   }
  122.   o.set(def)
  123.   return o;
  124. }

Wrote this today for something at work… it’s not done yet but figured it was worth a post… will probably post finished version tomorrow…

This can be a little golfed since it is just a demo for work and not code on a real product 😀

HWB Colors

  1. // Safari and Firefox only... no Chrome support at time of this post
  2. Object.assign(document.body.style, { 
  3.   margin: 0,
  4.   display: 'grid',
  5.   'grid-template-columns': '1fr 1fr 1fr',
  6. });
  7.  
  8. const hwbBlock = () => {
  9.   const hue = Math.round(Math.random() * 360)
  10.   const white = Math.round(
  11.     Math.random() * Math.random() * 100)
  12.   const black = Math.round(
  13.     Math.random() * Math.random() * 100)
  14.   const col = `hwb(${hue} ${white}% ${black}%)`
  15.   document.body.innerHTML += `
  16.     <div 
  17.       style="
  18.         width: 100%;
  19.         height: 4em;
  20.         font-family: sans-serif;
  21.         text-align: center;
  22.         line-height: 2.3;
  23.         color: white;
  24.         text-shadow: 1px 1px 5px black;
  25.         background:${col}">${col}</div>
  26.   `
  27. }
  28.  
  29. Array(102).fill(0).map(hwbBlock);

HWB color format… Looking forward to better support on this CSS color format…

// color // css

HSL to RGB JavaScript

  1. const hsl2rgb = (h, s, l, o) => {
  2.   if (h > 1 || s > 1 || l > 1) {
  3.       h /= 360;
  4.       s /= 100;
  5.       l /= 100;
  6.   }
  7.   h *= 360;
  8.  
  9.   let R, G, B, X, C;
  10.  
  11.   h = (h % 360) / 60;
  12.   C = 2 * s * (l < .5 ? l : 1 - l);
  13.   X = C * (1 - Math.abs(h % 2 - 1));
  14.   R = G = B = l - C / 2;
  15.  
  16.   h = ~~h;
  17.   R += [C, X, 0, 0, X, C][h];
  18.   G += [X, C, C, X, 0, 0][h];
  19.   B += [0, 0, X, C, C, X][h];
  20.   return `rgba(${~~(R * 255)}, ${~~(G * 255)}, ${~~(B * 255)}, ${o})`;
  21. };
  22.  
  23. console.log(hsl2rgb(122, 50, 50, .5));

Taken from the Raphaël source… Always fun to browse – I’ve learned lots of great stuff from it 😀

Gray Gradient Texture

  1. function rect(x1, y1, x2, y2, col, blur = 0.1) {
  2.   const dx = x1 - x2;
  3.   const dy = y1 - y2;
  4.   const dist = Math.sqrt(dx * dx + dy * dy);
  5.   return `radial-gradient(circle at ${x1}% ${y1}%, ${col} 0, ${col} ${dist}%, transparent ${dist +
  6.     blur}%)`;
  7. }
  8. const blends = 'multiply,screen,overlay,darken,lighten,color-dodge,color-burn,hard-light,soft-light,difference,exclusion,hue'.split(
  9.   ','
  10. );
  11. const cols = ['black', 'white'];
  12.  
  13. function gen() {
  14.   [...document.querySelectorAll('div')].forEach(d =>
  15.     d.parentNode.removeChild(d)
  16.   );
  17.   for (let j = 0; j < 4; j++) {
  18.     const rects = [];
  19.     for (let i = 0; i < 10; i++) {
  20.       const x = Math.random() * 100;
  21.       const y = Math.random() * 100;
  22.       const s = Math.random() * Math.random() * Math.random() * 30 + 3;
  23.       const col = cols[~~(Math.random() * cols.length)];
  24.       rects.push(rect(x, y, x + s, y + s, col, Math.random() * 10));
  25.     }
  26.     const el = document.body.appendChild(document.createElement('div'));
  27.     el.style.backgroundImage = rects.join(', ');
  28.     el.style.mixBlendMode = blends[~~(Math.random() * blends.length)];
  29.   }
  30. }
  31. gen();
  32.  
  33. document.body.innerHTML += `
  34.   <button id="regen">Regenerate</button>
  35.   <style>
  36.     body, html {
  37.       height: 100%;
  38.       background: #ccc;
  39.       margin: 0;
  40.       background-repeat: no-repeat;
  41.       width: 100%;
  42.     }
  43.     div {
  44.       position: absolute;
  45.       top: 0; left: 0;
  46.       width: 100%;
  47.       height: 100%;
  48.     }
  49.     #regen {
  50.       position: absolute;
  51.       width: 100px;
  52.       height: 30px;
  53.       background: #ccc;
  54.       border: 1px solid white;
  55.       margin: 1em;
  56.       cursor: pointer;
  57.       transition: all 250ms ease-out;
  58.       z-index: 999;
  59.     }
  60.     #regen:hover { background: #333; color: white; }
  61.   </style>
  62. `;
  63.  
  64. regen.onclick = gen;

Playing around some more with lots of linear gradients.

snippet.zone ~ 2021-23 /// {s/z}