summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Powers <mark@marks.kitchen>2022-02-19 21:00:19 -0600
committerMark Powers <mark@marks.kitchen>2022-02-19 21:00:19 -0600
commit6867994e8a8742c78d38ee4b97c6632c305d9fc6 (patch)
treebea7685555d0ba5de3807135cc88918266bfed6e
Initial commit
-rw-r--r--draw-component.js229
-rw-r--r--index.html37
-rw-r--r--keyboard-component.js22
-rw-r--r--main.js70
-rw-r--r--mouse-component.js94
-rw-r--r--package-lock.json395
-rw-r--r--package.json16
-rw-r--r--update-component.js463
8 files changed, 1326 insertions, 0 deletions
diff --git a/draw-component.js b/draw-component.js
new file mode 100644
index 0000000..9604507
--- /dev/null
+++ b/draw-component.js
@@ -0,0 +1,229 @@
+normalDraw = {
+ draw: function(){
+ color("#aaa" )
+ ctx.fillRect(0, 0, WIDTH, HEIGHT)
+ for(var i = 0; i < HEIGHT; i+=4){
+ color("#ccc" )
+ ctx.fillRect(0, i, WIDTH, 2)
+ }
+ // Where each message bottom is
+ let bottomY = HEIGHT/2;
+ for(var i = 0; i < messages.length; i++){
+ let message = messages[i];
+ let totalHeigt;
+ switch(message.type){
+ case 0:
+ color("#111")
+ totalHeigt = roundedRect(0, bottomY, 3, 10);
+
+ color("#888")
+ roundedRect(1, bottomY-1, 3, 8, true);
+ color("#444")
+ roundedRect(1, bottomY-1, 3, 8);
+
+ color("#111")
+ font(10, "NANO CHAT", 3, bottomY - totalHeigt + 3)
+ break;
+ case 1:
+ color("#111")
+ totalHeigt = roundedRect(0, bottomY, 3, 10);
+
+ color("#000")
+ roundedRect(1, bottomY-1, 3, 8, true);
+ color("#444")
+ roundedRect(1, bottomY-1, 3, 8);
+
+ color("yellow")
+ font(10, "Now entering: ", 3, bottomY - totalHeigt + 3)
+ color("#ccc")
+ font(10, message.text, 85, bottomY - totalHeigt + 3)
+ break;
+ case 2:
+ totalHeigt = drawMessage(0, bottomY, message.from, message.text, message.pixels)
+ break;
+ }
+ bottomY -= totalHeigt;
+
+ // stop drawing if we are beyond the screen
+ if(bottomY < 0) break;
+ }
+ // Draw current message
+ drawMessage(0, HEIGHT * 3 / 4, username, currentMessageText, currentMessagePixels, true)
+
+ // Draw send button
+ color("#444")
+ roundedRect(WIDTH - 50, HEIGHT - 48, 3, 39, true, 55)
+ roundedRect(WIDTH - 50, HEIGHT - 2, 3, 39, true, 53)
+ color("#bbb")
+ roundedRect(WIDTH - 49, HEIGHT - 49, 3, 37, true, 55)
+ roundedRect(WIDTH - 49, HEIGHT - 3, 3, 37, true, 55)
+ color("#444")
+ ctx.beginPath()
+ ctx.moveTo(WIDTH - 30, HEIGHT - 62)
+ ctx.lineTo(WIDTH - 30, HEIGHT - 72)
+ ctx.lineTo(WIDTH - 35, HEIGHT - 72)
+ ctx.lineTo(WIDTH - 26, HEIGHT - 82)
+ ctx.lineTo(WIDTH - 17, HEIGHT - 72)
+ ctx.lineTo(WIDTH - 22, HEIGHT - 72)
+ ctx.lineTo(WIDTH - 22, HEIGHT - 62)
+ ctx.fill()
+ let centerX = WIDTH - 26
+ let centerY = HEIGHT - 30
+ let radius = 10;
+ for(var i = 0; i < 8; i++){
+ var x = centerX + Math.cos(Math.PI / 4 * i) * radius
+ var y = centerY + Math.sin(Math.PI / 4 * i) * radius
+ ctx.beginPath()
+ ctx.moveTo(x-1, y-1)
+ ctx.lineTo(x+1, y-1)
+ ctx.lineTo(x+1, y+1)
+ ctx.lineTo(x-1, y+1)
+ ctx.fill()
+ }
+
+ ctx.fillText("SEND", WIDTH - 39, HEIGHT - 60)
+ ctx.fillText("CLEAR", WIDTH - 41, HEIGHT - 14)
+
+ drawKeyboard()
+ }
+}
+function drawMessage(x, y, from, text, pixels, current=false){
+ var parts = split_into_parts(text)
+ var trueHeight = Math.max(parts.length, 1) * 14 + 7
+ if(current || pixels.length != 0){
+ trueHeight = 91
+ }
+
+ color("white")
+ roundedRect(x, y , 3, trueHeight-6, true);
+ color("blue")
+ roundedRect(x, y , 3, trueHeight-6);
+ color("#b3b3ff")
+ roundedRect(x, y - trueHeight + 18 , 3, 12, true, 88);
+ color("blue")
+ roundedRect(x, y - trueHeight + 18, 3, 12, false, 88);
+ font(12, from, 3, y - trueHeight+6)
+ color("black")
+ font(12, text, 3, y - trueHeight+6, true)
+ color("black")
+ for(var i = 0; i < pixels.length; i++){
+ var pixel = pixels[i]
+ ctx.fillRect(pixel.x, pixel.y + y, 2, 2)
+ }
+ return trueHeight
+}
+var capsOn = false
+var shiftOn = false
+function drawKeyboard(){
+ color("#444")
+ roundedRect(1, HEIGHT - 1, 3, HEIGHT/4 - 10, true, WIDTH-52)
+ color("#bbb")
+ roundedRect(2, HEIGHT - 2, 3, HEIGHT/4 - 12, true, WIDTH-54)
+
+ ctx.font = 12 + "px Mono";
+ var keys = [
+ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "="],
+ ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"],
+ ["a", "s", "d", "f", "g", "h", "j", "k", "l"],
+ ["z", "x", "c", "v", "b", "n", "m", ",", ".", "/"]
+ ]
+ var d1 = Math.floor( (WIDTH-54) / 12) - 1
+ var d2 = Math.ceil( (WIDTH-54) / 12) - 1
+ for(var j = 0; j < keys.length; j++){
+ var x = 6 + 8*j
+ var y = HEIGHT / 4 * 3 + 5 + (d1+1)*j
+ for(var i = 0; i < keys[j].length; i++){
+ color("#ddd")
+ ctx.fillRect(x, y, d1, d1)
+ color("#444")
+ var char = keys[j][i]
+ if(capsOn || shiftOn){
+ char = char.toUpperCase()
+ }
+ ctx.fillText(char, x + 4, y + 3)
+ x += d2
+ }
+ }
+ // space
+ color("#ddd")
+ ctx.fillRect(6, HEIGHT - 27, WIDTH-65, 24)
+ color("#444")
+ ctx.fillText("space", 80, HEIGHT-20)
+ ctx.font = 7 + "px Mono";
+ // shift
+ color("#ddd")
+ ctx.fillRect(6, HEIGHT - 27 - d2, d1+8, d1)
+ color("#444")
+ ctx.fillText("shift", 7, HEIGHT - 22 - d2)
+ // caps
+ color("#ddd")
+ ctx.fillRect(6, HEIGHT - 27 - 2 * d2, d1, d1)
+ color("#444")
+ ctx.fillText("cap", 7, HEIGHT - 22 - 2 * d2)
+ // enter
+ color("#ddd")
+ ctx.fillRect(d1*11+1, HEIGHT - 27 - 2 * d2, d1*2+1, d1)
+ color("#444")
+ ctx.fillText("enter", d1*11+5, HEIGHT - 22 - 2 * d2)
+ // backspace
+ color("#ddd")
+ ctx.fillRect(d1*11.5+1.5, HEIGHT - 27 - 3 * d2, d1+8, d1)
+ color("#444")
+ ctx.fillText("del", d1*11.5+5.5, HEIGHT - 22 - 3 * d2)
+}
+function roundedRect(x, y, radius, height, fill = false, width = WIDTH){
+ ctx.beginPath();
+ ctx.arc(x + radius, y - radius - height, radius, 3/2 * Math.PI, Math.PI, true)
+ ctx.arc(x + radius, y - radius, radius, Math.PI, 1/2 * Math.PI, true)
+ ctx.arc(x + width - radius, y-radius, radius, 1/2 * Math.PI, 0, true)
+ ctx.arc(x + width - radius, y-radius - height, radius, 0, 3/2 * Math.PI, true)
+ ctx.lineTo(x + radius, y - (radius * 2 ) - height)
+ if(fill){
+ ctx.fill();
+ } else {
+ ctx.stroke();
+ }
+
+ return radius*2 + height
+}
+function color(c) {
+ ctx.fillStyle = c;
+ ctx.strokeStyle = c;
+}
+function font(size, what, x, y, wrap = false) {
+ ctx.textBaseline = "top"
+ ctx.font = size + "px Mono";
+ if(wrap){
+ var parts = split_into_parts(what, true);
+ parts.forEach((element, i) => {
+ ctx.fillText(element, x, y + i*(size + 2));
+ });
+ } else {
+ ctx.fillText(what, x, y);
+ }
+}
+function split_into_parts(what, drawing=false){
+ var parts = [];
+ var line = "";
+ if(drawing){
+ line = " "
+ }
+ for(var i = 0; i < what.length; i++){
+ if(what.charAt(i) == "\n"){
+ parts.push(line + "\n");
+ line = ""
+ } else if(line.length == 34){
+ parts.push(line);
+ line = what.charAt(i);
+ } else {
+ line += what.charAt(i)
+ }
+ if(parts.length == 6){
+ break;
+ }
+ }
+ if(line.length != 0 && parts.length < 6){
+ parts.push(line)
+ }
+ return parts;
+} \ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..3a60280
--- /dev/null
+++ b/index.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html lang="en">
+
+<head>
+ <title>Nano Chat</title>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+ <style>
+ @font-face {
+ font-family: 'Gameboy';
+ src: url('Assets/font.ttf');
+ }
+ canvas {
+ transform-origin: top left;
+ transform: scale(2, 2);
+ position: absolute;
+ left: 0;
+ top: 0;
+ }
+ </style>
+</head>
+
+<body style="padding:0; margin:0; overflow:hidden;">
+ <canvas id="canvas"></canvas>
+ <script>
+ var FPS = 10;
+ var WIDTH = 256;
+ var HEIGHT = 192 * 2;
+ </script>
+ <script src="update-component.js"></script>
+ <script src="draw-component.js"></script>
+ <script src="keyboard-component.js"></script>
+ <script src="mouse-component.js"></script>
+ <script src="main.js"></script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/keyboard-component.js b/keyboard-component.js
new file mode 100644
index 0000000..ce590ae
--- /dev/null
+++ b/keyboard-component.js
@@ -0,0 +1,22 @@
+typingMessageComponent = {
+ keyDown: function(e){
+ if(e.keyCode == 48 && e.key == "Delete"){ // Mark delete as backspace
+ e.keyCode = 8
+ }
+
+ if(e.keyCode >= 32 && e.key.length == 1){ // Printable character (probably)
+ currentMessageText += e.key
+ } else if(e.keyCode == 13){ // Enter
+ currentMessageText += "\n";
+ } else if(e.keyCode == 8) { // delete
+ if(currentMessageText.length >= 1){
+ currentMessageText = currentMessageText.substring(0, currentMessageText.length - 1)
+ } else {
+ currentMessageText = ""
+ }
+ }
+ currentMessageParts = split_into_parts(currentMessageText)
+ currentMessageText = currentMessageParts.join("")
+ mouseIsDown = false
+ }
+} \ No newline at end of file
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..6e387be
--- /dev/null
+++ b/main.js
@@ -0,0 +1,70 @@
+var canvas, ctx;
+var t; // Frame counter
+var gameInterval;
+var components;
+
+var messages, username, currentMessageText, currentMessageParts, currentMessagePixels, mouseIsDown;
+
+window.onload = function () {
+ canvas = document.getElementById("canvas");
+ ctx = canvas.getContext("2d");
+ document.addEventListener("keydown", keyDown);
+
+ document.addEventListener("mousedown", mouseDown)
+ document.addEventListener("mousemove", mouseMove)
+ document.addEventListener("mouseup", mouseUp)
+ window.addEventListener('resize', resizeCanvas, false);
+ window.addEventListener('orientationchange', resizeCanvas, false);
+
+ init();
+ resizeCanvas();
+}
+function init() {
+ components = {
+ keyboard: typingMessageComponent,
+ mouse: drawMessageComponent,
+ draw: normalDraw,
+ update: normalUpdate
+ }
+ t = 0
+
+ username = "Mark"
+ messages = []
+ messages.unshift({
+ type: 0,
+ })
+ messages.unshift({
+ type: 1,
+ text: username
+ })
+ currentMessageText = ""
+ currentMessagePixels = []
+ gameInterval = setInterval(game, 1000 / FPS);
+}
+function resizeCanvas() {
+ canvas.width = WIDTH;
+ canvas.height = HEIGHT;
+}
+function keyDown(e) {
+ components.keyboard.keyDown(e);
+}
+function mouseDown(e){
+ components.mouse.mouseDown(e);
+}
+function mouseUp(e){
+ components.mouse.mouseUp(e);
+}
+function mouseMove(e){
+ components.mouse.mouseMove(e);
+}
+function update() {
+ components.update.update()
+}
+function draw(){
+ components.draw.draw()
+}
+
+function game() {
+ update();
+ draw();
+}
diff --git a/mouse-component.js b/mouse-component.js
new file mode 100644
index 0000000..10684cc
--- /dev/null
+++ b/mouse-component.js
@@ -0,0 +1,94 @@
+drawMessageComponent = {
+ mouseDown: function(e){
+ mouseIsDown = true
+ let x = e.x/2;
+ let y = e.y/2;
+
+ if(206 < x && x < WIDTH && 292 < y && y < 336){
+ messages.unshift({
+ type: 2,
+ from: username,
+ text: currentMessageText,
+ pixels: currentMessagePixels
+ })
+ currentMessageText = ""
+ currentMessagePixels = []
+ } else if(206 < x && x < WIDTH && 338 < y && y < 382){
+ currentMessageText = ""
+ currentMessagePixels = []
+ } else if(0 < x && x < WIDTH && 198 < y && y < 288){
+ currentMessagePixels.push({x: x, y: y - 288})
+ }
+ checkKeyBoardClick(x, y)
+ },
+ mouseUp: function(e){
+ mouseIsDown = false
+ },
+ mouseMove: function(e){
+ let x = Math.floor(e.x/2);
+ let y = Math.floor(e.y/2);
+ if(mouseIsDown && 0 < x && x < WIDTH && 198 < y && y < 288){
+ currentMessagePixels.push({x: x, y: y - 288})
+ }
+ },
+}
+function inBox(x, y, boxX, boxY, width, height){
+ return boxX < x && x < boxX + width && boxY < y && y < boxY + height
+}
+var normalKeys = [
+ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "="],
+ ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"],
+ ["a", "s", "d", "f", "g", "h", "j", "k", "l"],
+ ["z", "x", "c", "v", "b", "n", "m", ",", ".", "/"]
+]
+var keys = normalKeys
+function checkKeyBoardClick(mouseX, mouseY){
+ var d1 = Math.floor( (WIDTH-54) / 12) - 1
+ var d2 = Math.ceil( (WIDTH-54) / 12) - 1
+ for(var j = 0; j < keys.length; j++){
+ var x = 6 + 8*j
+ var y = HEIGHT / 4 * 3 + 5 + (d1+1)*j
+ for(var i = 0; i < keys[j].length; i++){
+ if(inBox(mouseX, mouseY, x, y, d1, d1)){
+ var char = keys[j][i]
+ if(capsOn || shiftOn){
+ char = char.toUpperCase()
+ }
+ shiftOn = false
+ keyDown({
+ keyCode: 32, // any printable char code (yeah probably a bad idea)
+ key: char // the char
+ })
+ }
+ x += d2
+ }
+ }
+ // space
+ if(inBox(mouseX, mouseY, 6, HEIGHT - 27, WIDTH-65, 24)){
+ keyDown({
+ keyCode: 32,
+ key: " "
+ })
+ }
+ // shift
+ if(inBox(mouseX, mouseY, 6, HEIGHT - 27 - d2, d1+8, d1)){
+ shiftOn = true && !shiftOn
+ }
+ // caps
+ if(inBox(mouseX, mouseY, 6, HEIGHT - 27 - 2 * d2, d1, d1)){
+ capsOn = !capsOn
+ }
+ // enter
+ if(inBox(mouseX, mouseY, d1*11+1, HEIGHT - 27 - 2 * d2, d1*2+1, d1)){
+ keyDown({
+ keyCode: 13
+ })
+ }
+ // backspace
+ if(inBox(mouseX, mouseY, d1*11.5+1.5, HEIGHT - 27 - 3 * d2, d1+8, d1)){
+ keyDown({
+ keyCode: 8
+ })
+ }
+
+} \ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..82d6582
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,395 @@
+{
+ "name": "nanochat",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "requires": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "requires": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ }
+ },
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+ },
+ "content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ },
+ "cookie": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+ "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ },
+ "express": {
+ "version": "4.17.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+ "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+ "requires": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "http-errors": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ },
+ "lodash-compat": {
+ "version": "3.10.2",
+ "resolved": "https://registry.npmjs.org/lodash-compat/-/lodash-compat-3.10.2.tgz",
+ "integrity": "sha1-xpQBKKnTD46QLNLPmf0Muk7PwYM="
+ },
+ "lodash-fp": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/lodash-fp/-/lodash-fp-0.10.4.tgz",
+ "integrity": "sha1-KnjGVLJaDEZ1OiCqeG32Qcf4Lmc=",
+ "requires": {
+ "lodash-compat": "^3.10.2"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "mime-db": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
+ "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
+ },
+ "mime-types": {
+ "version": "2.1.27",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
+ "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
+ "requires": {
+ "mime-db": "1.44.0"
+ }
+ },
+ "ml-sentiment": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/ml-sentiment/-/ml-sentiment-2.0.7.tgz",
+ "integrity": "sha1-+LWaha0sQQfDMtCvtd6okntBHoE=",
+ "requires": {
+ "lodash-fp": "^0.10.4"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "proxy-addr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
+ "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+ "requires": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.9.1"
+ }
+ },
+ "qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ },
+ "raw-body": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+ "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "requires": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "send": {
+ "version": "0.17.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+ "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+ "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ },
+ "toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..5149d2f
--- /dev/null
+++ b/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "nanochat",
+ "version": "1.0.0",
+ "description": "",
+ "main": "main.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "body-parser": "^1.19.0",
+ "express": "^4.17.1",
+ "ml-sentiment": "^2.0.7"
+ }
+}
diff --git a/update-component.js b/update-component.js
new file mode 100644
index 0000000..2fd4819
--- /dev/null
+++ b/update-component.js
@@ -0,0 +1,463 @@
+events = {}
+events[5 * FPS] = function(){
+ messages.unshift({
+ type: 1,
+ text: "l0st"
+ })
+}
+events[8 * FPS] = function(){
+ messages.unshift({
+ type: 2,
+ from: "l0st",
+ text: "hi...",
+ pixels: []
+ })
+}
+normalUpdate = {
+ update: function(){
+ if(t in events){
+ events[t]()
+ }
+ t++
+ if(currentMessagePixels.length >= smile.length){
+ currentMessagePixels = currentMessagePixels.slice(0, smile.length)
+ transform(currentMessagePixels, smile, 100)
+ }
+ }
+}
+function transform(fromPixels, toPixels, period){
+ for(var i = 0 ; i < toPixels.length; i++){
+ var actualDX = toPixels[i].x - fromPixels[i].x;
+ var actualDY = toPixels[i].y - fromPixels[i].y;
+ var dX = Math.sign(actualDX) * Math.min(1, Math.abs(actualDX))
+ var dY = Math.sign(actualDY) * Math.min(1, Math.abs(actualDY))
+ fromPixels[i].x += dX
+ fromPixels[i].y += dY
+ }
+}
+var smile = [
+ {
+ "x": 117,
+ "y": -62.5
+ },
+ {
+ "x": 116,
+ "y": -63
+ },
+ {
+ "x": 116,
+ "y": -62
+ },
+ {
+ "x": 115,
+ "y": -62
+ },
+ {
+ "x": 114,
+ "y": -61
+ },
+ {
+ "x": 114,
+ "y": -61
+ },
+ {
+ "x": 115,
+ "y": -61
+ },
+ {
+ "x": 115,
+ "y": -61
+ },
+ {
+ "x": 115,
+ "y": -61
+ },
+ {
+ "x": 116,
+ "y": -61
+ },
+ {
+ "x": 116,
+ "y": -60
+ },
+ {
+ "x": 116,
+ "y": -60
+ },
+ {
+ "x": 116,
+ "y": -60
+ },
+ {
+ "x": 116,
+ "y": -60
+ },
+ {
+ "x": 116,
+ "y": -60
+ },
+ {
+ "x": 116,
+ "y": -60
+ },
+ {
+ "x": 117,
+ "y": -60
+ },
+ {
+ "x": 117,
+ "y": -60
+ },
+ {
+ "x": 117,
+ "y": -61
+ },
+ {
+ "x": 142.5,
+ "y": -62
+ },
+ {
+ "x": 142,
+ "y": -62
+ },
+ {
+ "x": 142,
+ "y": -62
+ },
+ {
+ "x": 142,
+ "y": -62
+ },
+ {
+ "x": 142,
+ "y": -62
+ },
+ {
+ "x": 142,
+ "y": -61
+ },
+ {
+ "x": 142,
+ "y": -61
+ },
+ {
+ "x": 142,
+ "y": -61
+ },
+ {
+ "x": 142,
+ "y": -61
+ },
+ {
+ "x": 143,
+ "y": -61
+ },
+ {
+ "x": 143,
+ "y": -61
+ },
+ {
+ "x": 143,
+ "y": -61
+ },
+ {
+ "x": 144,
+ "y": -61
+ },
+ {
+ "x": 144,
+ "y": -62
+ },
+ {
+ "x": 144,
+ "y": -62
+ },
+ {
+ "x": 144,
+ "y": -62
+ },
+ {
+ "x": 143,
+ "y": -62
+ },
+ {
+ "x": 143,
+ "y": -62
+ },
+ {
+ "x": 143,
+ "y": -62
+ },
+ {
+ "x": 142,
+ "y": -61
+ },
+ {
+ "x": 142,
+ "y": -60
+ },
+ {
+ "x": 142,
+ "y": -59
+ },
+ {
+ "x": 142,
+ "y": -59
+ },
+ {
+ "x": 142,
+ "y": -59
+ },
+ {
+ "x": 143,
+ "y": -59
+ },
+ {
+ "x": 143,
+ "y": -59
+ },
+ {
+ "x": 144,
+ "y": -59
+ },
+ {
+ "x": 144,
+ "y": -59
+ },
+ {
+ "x": 145,
+ "y": -59
+ },
+ {
+ "x": 145,
+ "y": -59
+ },
+ {
+ "x": 145,
+ "y": -60
+ },
+ {
+ "x": 145,
+ "y": -60
+ },
+ {
+ "x": 145,
+ "y": -60
+ },
+ {
+ "x": 144,
+ "y": -60
+ },
+ {
+ "x": 114,
+ "y": -35.5
+ },
+ {
+ "x": 114,
+ "y": -36
+ },
+ {
+ "x": 114,
+ "y": -36
+ },
+ {
+ "x": 114,
+ "y": -35
+ },
+ {
+ "x": 114,
+ "y": -35
+ },
+ {
+ "x": 114,
+ "y": -34
+ },
+ {
+ "x": 114,
+ "y": -33
+ },
+ {
+ "x": 114,
+ "y": -33
+ },
+ {
+ "x": 114,
+ "y": -32
+ },
+ {
+ "x": 115,
+ "y": -32
+ },
+ {
+ "x": 117,
+ "y": -31
+ },
+ {
+ "x": 119,
+ "y": -30
+ },
+ {
+ "x": 120,
+ "y": -29
+ },
+ {
+ "x": 121,
+ "y": -28
+ },
+ {
+ "x": 122,
+ "y": -27
+ },
+ {
+ "x": 123,
+ "y": -26
+ },
+ {
+ "x": 125,
+ "y": -26
+ },
+ {
+ "x": 126,
+ "y": -25
+ },
+ {
+ "x": 127,
+ "y": -25
+ },
+ {
+ "x": 128,
+ "y": -24
+ },
+ {
+ "x": 129,
+ "y": -24
+ },
+ {
+ "x": 130,
+ "y": -24
+ },
+ {
+ "x": 131,
+ "y": -24
+ },
+ {
+ "x": 131,
+ "y": -24
+ },
+ {
+ "x": 132,
+ "y": -24
+ },
+ {
+ "x": 133,
+ "y": -24
+ },
+ {
+ "x": 134,
+ "y": -24
+ },
+ {
+ "x": 135,
+ "y": -24
+ },
+ {
+ "x": 136,
+ "y": -24
+ },
+ {
+ "x": 138,
+ "y": -25
+ },
+ {
+ "x": 139,
+ "y": -25
+ },
+ {
+ "x": 140,
+ "y": -26
+ },
+ {
+ "x": 141,
+ "y": -27
+ },
+ {
+ "x": 142,
+ "y": -27
+ },
+ {
+ "x": 143,
+ "y": -28
+ },
+ {
+ "x": 143,
+ "y": -29
+ },
+ {
+ "x": 144,
+ "y": -30
+ },
+ {
+ "x": 145,
+ "y": -30
+ },
+ {
+ "x": 145,
+ "y": -31
+ },
+ {
+ "x": 146,
+ "y": -32
+ },
+ {
+ "x": 146,
+ "y": -32
+ },
+ {
+ "x": 147,
+ "y": -33
+ },
+ {
+ "x": 147,
+ "y": -33
+ },
+ {
+ "x": 148,
+ "y": -34
+ },
+ {
+ "x": 148,
+ "y": -35
+ },
+ {
+ "x": 148,
+ "y": -35
+ },
+ {
+ "x": 148,
+ "y": -36
+ },
+ {
+ "x": 149,
+ "y": -36
+ },
+ {
+ "x": 149,
+ "y": -37
+ },
+ {
+ "x": 149,
+ "y": -37
+ },
+ {
+ "x": 149,
+ "y": -38
+ },
+ {
+ "x": 149,
+ "y": -38
+ },
+ {
+ "x": 149,
+ "y": -39
+ }
+ ] \ No newline at end of file