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

Character Controls

  1. // Character Controls "clean version" with Trails...
  2.  
  3. // dynamically handle keys instead of explicitly
  4. // checking each one
  5. const keys = {}
  6. document.addEventListener('keydown', e => {
  7.   e.preventDefault();
  8.  
  9.   // store a boolean on the `keys` object
  10.   // to keep track of whick keys are down
  11.   keys[e.key] = true;
  12. });
  13.  
  14. document.addEventListener('keyup', e => {
  15.   e.preventDefault();
  16.    keys[e.key] = false;
  17. });
  18.  
  19. // setup motion
  20. let x = 100;
  21. let y = 300;
  22. let vx = 4;
  23. let vy = -10;
  24.  
  25. // put gravity in a variable
  26. const GRAVITY = 1;
  27. // replace "magic numbers" with constants
  28. const FLOOR_BOUNCE = -.33;
  29. const JUMP_POWER = 15;
  30. const ARROW_VEL = 3;
  31. const VX_DECAY = .8;
  32.  
  33. const TRAIL_NUM = 10;
  34. const chars = [];
  35. // store the size of the character
  36. const charWidth = 50;
  37. const charHeight = 80;
  38. for (let i = 0; i < TRAIL_NUM; i++) {
  39.   // create the character
  40.   const char = document.createElement('div');
  41.   chars.push({ char, x, y });
  42.   Object.assign(char.style, {
  43.     position: 'absolute',
  44.     width: `${charWidth}px`,
  45.     height: `${charHeight}px`,
  46.     background: 'black',
  47.     // add border radius for no reason
  48.     borderTopLeftRadius: '20px',
  49.     borderTopRightRadius: '20px',
  50.     opacity: i === 0 ? 1 : .25 - (.25 / TRAIL_NUM) * i
  51.   });
  52.  
  53.   document.body.appendChild(char);
  54. }
  55. const char = chars[0].char
  56.  
  57. function setLocs({ x, y }) {
  58.   for (let i = 0; i < TRAIL_NUM; i++) {
  59.     const char = chars[i];
  60.     if (x != null) char.x = x;
  61.     if (y != null) char.y = y;
  62.   }
  63. }
  64.  
  65.  
  66. // some bounds variables for the screen
  67. let floor;
  68. let screenRight;
  69. let screenLeft;
  70.  
  71. // main loop
  72. function loop() {
  73.   // we want to recalculate these
  74.   // so things work when the screen resizes
  75.   floor = innerHeight - 80;
  76.   screenRight = innerWidth + 50;
  77.   screenLeft = -charWidth;
  78.  
  79.   // update the characters velocity
  80.   x += vx;
  81.   y += vy;
  82.  
  83.  
  84.   // handle floor and screen sides
  85.   if (y > floor) {
  86.     vy *= FLOOR_BOUNCE;
  87.     y = floor;
  88.  
  89.     // @TODO set char xs
  90.   }
  91.  
  92.   if (x > screenRight) {
  93.     x = screenLeft
  94.     setLocs({ x })
  95.   }
  96.  
  97.   if (x < screenLeft) {
  98.     x = screenRight;
  99.     setLocs({ x })
  100.   }
  101.  
  102.  
  103.   // update the characters velocity with arrow keys
  104.   if (keys['ArrowRight']) {
  105.     vx += ARROW_VEL;
  106.   }
  107.   if (keys['ArrowLeft']) {
  108.     vx -= ARROW_VEL;
  109.   }
  110.  
  111.   // character can only jump up when it is on the floor
  112.   if (keys['ArrowUp'] && y >= floor) {
  113.     vy -= JUMP_POWER;
  114.   }
  115.  
  116.   if (keys['ArrowDown']) {
  117.     vy += ARROW_VEL;
  118.   }
  119.  
  120.   vy += GRAVITY;
  121.   vx *= VX_DECAY
  122.  
  123.   // update the characters styles
  124.   Object.assign(
  125.     char.style, {
  126.       // use template string instead of x + 'px'
  127.       left: `${x}px`,
  128.       top: `${y}px`
  129.     }
  130.   );
  131.  
  132.   // update trails stuff
  133.   chars[0].x = x;
  134.   chars[0].y = y;
  135.   for (let i = 1; i < TRAIL_NUM; i++) {
  136.     const char = chars[i]
  137.     char.x += (chars[i - 1].x - char.x) / 4;
  138.     char.y += (chars[i - 1].y - char.y) / 4;
  139.  
  140.     Object.assign(
  141.       chars[i].char.style, {
  142.         // use template string instead of x + 'px'
  143.         left: `${char.x}px`,
  144.         top: `${char.y}px`
  145.       }
  146.     );
  147.   }
  148.  
  149.   requestAnimationFrame(loop);
  150. }
  151. loop();

Click once on the preview area to give keyboard focus – then use arrow keys to move the character. I recently created a tutorial about this over on dev.to… check it out…

Regex Match Words and More

  1. const phrase = `"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.`;
  2. const words = phrase.toLocaleLowerCase()
  3.   .replace(/["!.:,]/g, '')
  4.   .split(/\s\'|\'\s|\n|\s/g);
  5.   console.log(words);

Recently did this for a stackoverflow question… check it out…

There are other great (better) answers like this one by use MMMahdy-PAPION:

  1. const phrase = `"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.`
  2. console.log(
  3.   phrase.toLocaleLowerCase().match(/(?!')[\w']*\w/g)
  4. );

Old Codepen 2013

  1. $(function () {
  2.   var canvas = $("<canvas>").appendTo("body"),
  3.     win = $(window),
  4.     cnvs = canvas[0],
  5.     c = cnvs.getContext("2d"),
  6.     el = $("<div>"),
  7.     letters = [],
  8.     NUM = 10,
  9.     TWO_PI = Math.PI * 2;
  10.  
  11.   c.font = "16px sans-serif";
  12.  
  13.   win
  14.     .resize(function () {
  15.       cnvs.width = win.width();
  16.       cnvs.height = win.height();
  17.       c.fillStyle = "white";
  18.       c.fillRect(0, 0, cnvs.width, cnvs.height);
  19.     })
  20.     .trigger("resize");
  21.  
  22.   function symbol() {
  23.     var r = parseInt(Math.random() * 9999),
  24.       s = "&#" + r + ";";
  25.     el.html(s);
  26.     return el.html();
  27.   }
  28.  
  29.   function Letter() {}
  30.  
  31.   Letter.prototype.init = function () {
  32.     this.x = Math.random() * win.width();
  33.     this.y = Math.random() * win.height();
  34.  
  35.     this.sym = symbol();
  36.     this.rot = Math.random() * 2 * Math.PI;
  37.     this.rotVel = Math.random() * 0.02 - 0.01;
  38.  
  39.     this.size = 1 + Math.random() * 10;
  40.     this.sizeVel = Math.random() * 0.2;
  41.     this.col = ["black", "white", "#999"][parseInt(Math.random() * 3)];
  42.  
  43.     this.rad = Math.random();
  44.     this.vx = this.rad * Math.cos(Math.random() * TWO_PI);
  45.     this.vy = this.rad * Math.sin(Math.random() * TWO_PI);
  46.  
  47.     this.life = 0;
  48.     this.maxLife = parseInt(Math.random() * 200);
  49.  
  50.     if (Math.random() < 0.1) {
  51.       this.doGrad = true;
  52.       this.channel = parseInt(Math.random() * 200);
  53.     }
  54.  
  55.     this.shadow = false;
  56.     if (Math.random() < 0.1) {
  57.       this.shadow = true;
  58.     }
  59.   };
  60.  
  61.   Letter.prototype.run = function () {
  62.     if (this.doGrad) {
  63.       this.channel += 1;
  64.  
  65.       this.col =
  66.         "rgb(" + this.channel + "," + this.channel + "," + this.channel + ")";
  67.     }
  68.  
  69.     if (this.shadow == true) {
  70.       c.shadowBlur = 100;
  71.       c.shadowColor = "rgba(76,105,135,0.2)";
  72.     }
  73.  
  74.     this.size += this.sizeVel;
  75.     this.rot += this.rotVel;
  76.     this.x += this.vx;
  77.     this.y += this.vy;
  78.  
  79.     c.save();
  80.  
  81.     c.translate(this.x, this.y);
  82.     c.scale(this.size, this.size);
  83.     c.rotate(this.rot);
  84.  
  85.     c.fillStyle = this.col;
  86.     c.fillText(this.sym, -this.size / 2, -this.size / 2);
  87.  
  88.     c.restore();
  89.  
  90.     this.life++;
  91.  
  92.     if (this.life >= this.maxLife) {
  93.       this.init();
  94.       //console.log("respurn");
  95.     }
  96.   };
  97.  
  98.   for (var i = 0; i < NUM; i++) {
  99.     var letter = (letters[i] = new Letter());
  100.     letter.init();
  101.   }
  102.  
  103.   setInterval(function () {
  104.     for (var i = 0; i < NUM; i++) {
  105.       letters[i].run();
  106.     }
  107.   }, 30);
  108. });

It’s fun to look through old code….

See the Pen Symbolz by Zevan Rosser (@ZevanRosser) on CodePen.

toString Radix

  1. for (let i = 2; i < 36; i++) {
  2.   console.log((234).toString(i), ` = 234 in base ${i}`)
  3. }

Use the radix argument of toString

Oera Linda Inspired Symbols

  1. var canvas = document.createElement("canvas"),
  2.   c = canvas.getContext("2d"),
  3.   title = document.createElement("h1");
  4.  
  5. canvas.style.transformOrigin = "top left";
  6. canvas.style.transform = "scale(0.5, 0.5)";
  7.  
  8. document.body.appendChild(canvas);
  9.  
  10. title.innerHTML = "Oera Linda Inspired Symbols";
  11. document.body.appendChild(title);
  12.  
  13. var erase = function () {
  14.   c.fillStyle = "#244250";
  15.   c.fillRect(0, 0, canvas.width, canvas.height);
  16. };
  17.  
  18. var shuffle = function () {
  19.   return 0.5 - Math.random();
  20. };
  21.  
  22. var Symbol = function (x, y, radius) {
  23.   this.x = x;
  24.   this.y = y;
  25.   this.radius = radius;
  26.   this.halfRadius = this.radius / 2;
  27.   this.draw();
  28. };
  29.  
  30. Symbol.ARC_NUM = 8;
  31. Symbol.TOTAL_SEGS = 23;
  32. Symbol.nodeMap = [
  33.   // [node index][list of possible node connections]
  34.   [7, 0, 9],
  35.   [10, 0, 2],
  36.   [11, 3, 1],
  37.   [4, 2, 12],
  38.   [3, 5, 13],
  39.   [4, 6, 14],
  40.   [5, 7, 15],
  41.   [6, 0, 16],
  42.   [0, 9],
  43.   [8, 10, 11, 12, 13, 14, 15, 16],
  44.   [1, 9],
  45.   [2, 9],
  46.   [3, 9],
  47.   [4, 9],
  48.   [5, 9],
  49.   [6, 9],
  50.   [7, 9]
  51. ];
  52.  
  53. Symbol.segMap = {
  54.   // [node-node][segment function index]
  55.   "0-1": 0,
  56.   "1-2": 1,
  57.   "2-3": 2,
  58.   "3-4": 3,
  59.   "4-5": 4,
  60.   "5-6": 5,
  61.   "6-7": 6,
  62.   "7-0": 7,
  63.  
  64.   "0-8": 9,
  65.   "8-9": 8,
  66.  
  67.   "9-10": 10,
  68.   "9-11": 12,
  69.   "9-12": 14,
  70.   "9-13": 16,
  71.   "9-14": 18,
  72.   "9-15": 20,
  73.   "9-16": 22,
  74.  
  75.   "1-10": 11,
  76.   "2-11": 13,
  77.   "3-12": 15,
  78.   "4-13": 17,
  79.   "5-14": 19,
  80.   "6-15": 21,
  81.   "7-16": 23
  82. };
  83.  
  84. // add reverse node connection keys
  85. for (var i in Symbol.segMap) {
  86.   var key = i.split("-").reverse().join("-");
  87.   Symbol.segMap[key] = Symbol.segMap[i];
  88. }
  89.  
  90. // store all keys
  91. Symbol.segMapKeys = [];
  92. for (var i in Symbol.segMap) {
  93.   Symbol.segMapKeys.push(i);
  94. }
  95.  
  96. Symbol.prototype = {
  97.   constructor: Symbol,
  98.   arcSegLength: (Math.PI * 2) / Symbol.ARC_NUM,
  99.   mirrors: [
  100.     [-1, -1],
  101.     [1, -1],
  102.     [-1, 1]
  103.   ],
  104.  
  105.   line: function (offset, isInner) {
  106.     var theta = this.arcSegLength * offset,
  107.       cos = Math.cos(theta),
  108.       sin = Math.sin(theta),
  109.       x1 = this.halfRadius * cos,
  110.       y1 = this.halfRadius * sin,
  111.       x2,
  112.       y2;
  113.  
  114.     if (isInner) {
  115.       x2 = 0;
  116.       y2 = 0;
  117.     } else {
  118.       x2 = this.radius * cos;
  119.       y2 = this.radius * sin;
  120.     }
  121.  
  122.     c.beginPath();
  123.     c.moveTo(x1, y1);
  124.     c.lineTo(x2, y2);
  125.     c.stroke();
  126.   },
  127.  
  128.   arc: function (offset) {
  129.     var step = this.arcSegLength * offset;
  130.     c.beginPath();
  131.     c.arc(0, 0, this.radius, step, step + this.arcSegLength, false);
  132.     c.stroke();
  133.   },
  134.  
  135.   drawAll: function () {
  136.     c.save();
  137.     c.translate(this.x, this.y);
  138.     for (var i = 0; i <= Symbol.TOTAL_SEGS; i++) {
  139.       this[i]();
  140.     }
  141.     c.restore();
  142.   },
  143.  
  144.   sequence: function (num) {
  145.     var keys = Symbol.segMapKeys,
  146.       index = Math.floor(keys.length * Math.random()),
  147.       curr = keys[index],
  148.       seq = [curr];
  149.  
  150.     for (var i = 0; i < num; i++) {
  151.       var comp = curr.split("-"),
  152.         end = comp[1],
  153.         begin = comp[0];
  154.  
  155.       for (var j = 0; j < keys.length; j++) {
  156.         var cc = keys[j].split("-");
  157.         if (cc[0] === end && cc[1] !== begin) {
  158.           curr = keys[j];
  159.           seq.push(curr);
  160.           break;
  161.         }
  162.       }
  163.     }
  164.     return seq;
  165.   },
  166.  
  167.   draw: function () {
  168.     var steps = 1 + Math.floor(Math.random() * 5);
  169.     (keys = this.sequence(steps)),
  170.       (indices = []),
  171.       (memory = {}),
  172.       (mirrorProb = 0.3),
  173.       (multiMirrorProb = 0.1),
  174.       (mirrorIter = 1),
  175.       (scales = []);
  176.  
  177.     c.lineWidth = 1;
  178.     c.strokeStyle = "rgba(255,255,255,0.15)";
  179.     this.drawAll();
  180.  
  181.     c.lineWidth = 2;
  182.     c.strokeStyle = "rgb(255,255,255)";
  183.  
  184.     c.save();
  185.     c.translate(this.x, this.y);
  186.     for (var i = 0; i < keys.length; i++) {
  187.       var index = Symbol.segMap[keys[i]];
  188.       this[index]();
  189.       indices.push(index);
  190.     }
  191.     c.restore();
  192.  
  193.     if (Math.random() < mirrorProb) {
  194.       mirrorIter = 1;
  195.  
  196.       if (Math.random() < multiMirrorProb) {
  197.         mirrorIter = 2 + Math.round(Math.random());
  198.       }
  199.  
  200.       scales = this.mirrors.sort(shuffle);
  201.  
  202.       for (var i = 0; i < mirrorIter; i++) {
  203.         c.save();
  204.         c.translate(this.x, this.y);
  205.         c.scale(scales[i][0], scales[i][1]);
  206.         for (var j = 0; j < indices.length; j++) {
  207.           this[indices[j]]();
  208.         }
  209.         c.restore();
  210.       }
  211.     }
  212.   }
  213. };
  214.  
  215. // arc partials:
  216. for (var i = 0; i < Symbol.ARC_NUM; i++) {
  217.   (function (i) {
  218.     Symbol.prototype[i] = function () {
  219.       this.arc(i);
  220.     };
  221.   })(i);
  222. }
  223.  
  224. // line partials:
  225. var j = 0;
  226. for (var i = Symbol.ARC_NUM; i <= Symbol.TOTAL_SEGS; i += 2) {
  227.   // inner
  228.   (function (i, j) {
  229.     Symbol.prototype[i] = function () {
  230.       this.line(j, true);
  231.     };
  232.   })(i, j);
  233.  
  234.   // outer
  235.   (function (i, j) {
  236.     Symbol.prototype[i] = function () {
  237.       this.line(j, false);
  238.     };
  239.   })(i + 1, j);
  240.   j++;
  241. }
  242.  
  243. var render = function () {
  244.   var radius = 70,
  245.     diameter = radius * 2,
  246.     padding = 10,
  247.     size = diameter + padding * 2,
  248.     winWidth = window.innerWidth * 2,
  249.     winHeight = window.innerHeight * 2,
  250.     cols = Math.floor(winWidth / size),
  251.     rows = Math.floor(winHeight / size),
  252.     num = cols * rows,
  253.     offX = Math.abs(winWidth - cols * size) / 2,
  254.     offY = Math.abs(winHeight - rows * size) / 2;
  255.  
  256.   for (var i = cols; i < num; i++) {
  257.     var x = offX + radius + (i % cols) * size;
  258.     var y = offY + radius + parseInt(i / cols) * size;
  259.     var s = new Symbol(x, y, radius);
  260.   }
  261. };
  262.  
  263. var renderTimeout;
  264. var rerender = function () {
  265.   clearInterval(renderTimeout);
  266.   renderTimeout = setTimeout(render, 500);
  267. };
  268.  
  269. var resize = function (e) {
  270.   canvas.width = window.innerWidth * 2;
  271.   canvas.height = window.innerHeight * 2;
  272.   erase();
  273.   if (e) {
  274.     rerender();
  275.   }
  276. };
  277.  
  278. window.addEventListener("resize", resize);
  279. resize();
  280. render();
  281.  
  282. document.addEventListener("click", function () {
  283.   erase();
  284.   render();
  285. });

Always fun to look through old codepen stuff…

See the Pen Better Oera Linda Inspired Symbols by Zevan Rosser (@ZevanRosser) on CodePen.

// canvas
snippet.zone ~ 2021-24 /// {s/z}