As a reminder, I had just watched the movie Hackers and was in search of more nostalgia. So I scrubbed through the movie and found a fun scene where two hackers battle for control over a T.V. station. So I thought I would try to recreate it in the form of an interactive website. I wanted the interaction to be kind of like using the command line in a terminal. That was a little tricky but I eventually got it working. There are still some features I would like to work out, like video synchronization when a user scrubs the video, as well as pausing and resuming play, streaming your own video, and usernames. I also tried to format the page using CSS, something I haven’t really put much time into in the past.
The clip at the right is the scene from the movie that inspired this project. The code for the project is below.
HTML
<html>
<head>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
let videoArr = ["YourName.mp4",
"TheWall.mp4",
"2001ASpace Odyssey.mp4",
"SevenSamurai.mp4",
"HeavyMetal.mp4",
"Hackers.m4v",
"GhostInTheShell.mp4",
"FantasticPlanet.m4v",
"Alien.m4v",
"Akira.mp4",
"AdriftInTheOcean.mp4",
]
var socket = io.connect();
socket.on('connect', function() {
console.log("Connected");
// Once we are connected, request the history
socket.emit('history', null);
});
// Receive from any event
socket.on('chatmessage', function (data) {
document.getElementById('messages').innerHTML = "" + data + "\n<br />"
+ "" + document.getElementById('messages').innerHTML;
if(videoArr.includes(data)){
let myVideo = document.querySelector("video")
myVideo.src = data;
myVideo.load();
myVideo.play();
console.log(data)
}
});
var sendmessage = function(message) {
if(message === "ls"){
videoArr.forEach((item) => {
document.getElementById('messages').innerHTML = "" + '<span style="background: white;">' + item + "</span>" + "\n<br />"
+ "" + document.getElementById('messages').innerHTML;
})
}
console.log("chatmessage: " + message);
socket.emit('chatmessage', message);
debugger;
};
</script>
<style>
#messages{
color: rgb(16, 139, 37);
}
#instructions{
color:rgb(16, 139, 37)
}
</style>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ITP TV</title>
</head>
<body>
<div id="main">
<div id="video-container">
<video id="video" width="720" height="480" autoplay muted controls>
<source id="video-player" src="AdriftInTheOcean.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<div id="instructions">
Type: LS, for available files<br>
Type: filename, to play video
</div>
<div id="input-box">
<input type="text" id="message" name="message" value=" ">
<input id="submit-button" type="submit" value="submit" onclick="sendmessage(document.getElementById('message').value)">
<script>
let input = document.getElementById("message");
input.addEventListener('keypress', (event) => {
if(event.key === "Enter"){
event.preventDefault();
document.getElementById('submit-button').click()
document.getElementById("message").value = "";
}
})
</script>
</div>
<div id="messages">
mess with the best, die like the rest
</div>
</div>
</body>
</html>
JAVASCRIPT
// Database to store data
var Datastore = require('nedb');
var db = new Datastore({filename: "data.db", autoload: true});
const express = require("express");
const app = express();
const path = require('path');
var http = require('http');
var fs = require('fs');
// HTTP Portion
var httpServer = http.createServer(app);
const { Server } = require('socket.io');
const io = new Server(httpServer, {});
httpServer.listen(8070);
function requestHandler(req, res) {
// Read index.html
fs.readFile(__dirname + '/index.html',
// Callback function for reading
function (err, data) {
// if there is an error
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
// Otherwise, send the data, the contents of the file
res.writeHead(200);
res.end(data);
}
);
}
app.use('/', express.static(path.join(__dirname, 'public')));
// Register a callback function to run when we have an individual connection
// This is run for each individual user that connects
io.sockets.on('connection',
// We are given a websocket object in our function
function (socket) {
console.log("We have a new client: " + socket.id)
// When this user emits, client side: socket.emit('otherevent',some data);
socket.on('chatmessage', function(data) {
// Data comes in as whatever was sent, including objects
console.log("Received: 'chatmessage' " + data);
// Create the JavaScript Object
var datatosave = {
socketid: socket.id,
message: data
}
// Insert the data into the database
db.insert(datatosave, function (err, newDocs) {
console.log("err: " + err);
console.log("newDocs: " + newDocs);
});
// Send it to all of the clients
io.sockets.emit('chatmessage',data);
});
// When the history is requested, find all of the docs in the database
socket.on('history', function() {
db.find({}, function(err, docs) {
// Loop through the results, send each one as if it were a new chat message
for (var i = 0; i < docs.length; i++) {
socket.emit('chatmessage', docs[i].message);
}
})
});
socket.on('disconnect', function() {
console.log("Client has disconnected " + socket.id);
});
}
);
In thinking about my final project for LiveWeb, my mind jumped back a decade or two to a movie I still watch very frequently…HACKERS. There is a scene in particular that I was thinking about, the tv station scene. At right you can see the clip from the movie. In the scene Zero Cool now known as Crash Override hacks into a tv station to watch what he want to watch. Not necessarily needed in today’s stream centered view experience but novel none the less. While there he is met face to face with, of all things, another hacker- Acid Burn. They fight over what will air for the individual viewing pleasure. Burn eventually wins and boots Crash Override for the network.
So my idea is to create a viewing window with a library of videos around it as well as the ability to “go live” to let users compete for dominance in the space.
After many hours alone, I succumbed to need for help. I sent the up signal and it was answered by none other than the prolific CODING LAB. Partners in help David Currie and Wasif Hyder on two different occasions helped to correct my course and teach me how to change the errors I had made.
The idea for this project remains the same as last week, a tool for relaxation allowing multiple users to control the output. The interactions have strict confines in order to keep chaos from taking over, this is supposed to be a relaxation tool after all.
Users can control the x and y location of an ellipse that is drawn to the canvas. Along with x and y, users can control color, stroke, direction and starting degree of rotation, framerate, and an adjustment variable called “rep”. There are two viewing options inset and full-width as well as the ability to reset the canvas to clear the current drawings.
The heart of the code is really this little block right here:
I was only able to test it with 3 or 4 users at a time, so I’m not sure how many users at a time this will support. There is a lot of data coming through the pipe here. I’m sure there is a better way of doing it, like only sending data when a change is made but I wasn’t able to figure out how to do that right now.
Have fun with it, relax, and let me know if anything breaks.
Two users, one in green-yellow, the other in red.
Two users after some time has past with many changes being made over the course of the draw loop.
First let me say that I am still struggling with the syntax and order of the required documents in order to have an interactive web experience. For instance, when I look at a p5.js sketch it is hard to figure out how to translate it to a standard JavaScript document that works with a server. Where and what gets emitted. If I have a canvas and a set of ui elements that each new user should have on their screen, how do I denote that in the code.
That being said for my midterm project I’m trying to convert the below p5.js sketch so that each new user adds another instance to the canvas and the ui displayed allows the user to control only their own instance.
In this column you will find the code I am working to convert. Of course there is the addition of the server code. I have not included the code for the p5.js library or the p5,sound.min.js library.
// Express is a node module for building HTTP servers
var express = require("express");
var app = express();
// Tell Express to look in the "public" folder for any files first
app.use(express.static("public")); // This is where the HTML, p5.js, sketch.js and so on should be stored
// If the user just goes to the "route" / then run this function
app.get("/", function (req, res) {
res.send("Hello World!");
});
// Here is the actual HTTP server
var http = require("http");
// We pass in the Express object
var httpServer = http.createServer(app);
// Listen on port provided by Glitch
//httpServer.listen(process.env.PORT);
// OR if running your own server choose your own port
httpServer.listen(8080);
// WebSocket Portion
// WebSockets work with the HTTP server
var io = require("socket.io")(httpServer);
// Register a callback function to run when we have an individual connection
// This is run for each individual user that connects
io.sockets.on(
"connection",
// We are given a websocket object in our function
function (socket) {
console.log(socket.id + " has joined the chat.");
socket.on("mouse", function(data) {
//io.emit("mouse", data);
socket.broadcast.emit("mouse", data);
});
socket.on("disconnect", function () {
console.log(socket.id + " has disconnected.");
});
}
);
sketch.js
var socket = io.connect();
socket.on('connect', function() {
console.log("Connected");
});
let x1 = 0;
let y1 = 0;
let col1 = 10;
let strk1 = 1;
let frmRt = 30
let shape1 = false;
let deg1 = 0.33
let rep = 2;
function setup() {
createCanvas(400, 400);
background(0, 0, 0);
angleMode(DEGREES);
colorMode(HSB, 360, 100, 100, 100);
// rectMode(CENTER);
// frameRate(frmRt);
create_ui();
}
function draw() {
frameRate(frmRt);
slider_value('Rep', rep);
slider_value('frmRt', frmRt);
slider_value('x1', x1);
slider_value('y1', y1);
noFill();
translate(width / 2, height / 2);
// push();
// rectMode(CENTER);
if (shape1) {
ellipseMode(CENTER);
push();
// stroke(0, random(0, 85), 0);
// stroke(85, random(0, 85), 85);
strokeWeight(strk1);
stroke(col1, 100, 100, 50);
rotate(x1 / deg1);
// rect(x, y, rep * (random(1, 10)), rep * (random(1, 10)));
// ellipse(t1, t2, 10, t1 + 45);
ellipse(x1, y1, 10, x1 + 45);
// rect(x, y, rep * x + 1, y + 5);
// x = x + 5
pop();
x1 = x1 + rep;
if (x1 > width) {
x1 = 0;
y1 = y1 + rep;
}
} else {}
}
So I’m trying to get some p5.js working in a droplet from digitalocean and guess what….I can’t get it to work. I know the p5.js sketch works, I can run it in the p5 web editor. I’m sure there’s something I’m doing wrong. To be quite honest, I don’t really understand how to structure the different blocks of code and what file they belong in. I’m also not sure what the best way to structure the file in my virtual private server. And can I name these files anything I want? Cause right now I feel like I have a number of files with the same name, I’m sure that could be causing issues. I’ll keep trying to work through it but for now here is the code, be fore warned there is a bunch…
// Express is a node module for building HTTP servers
var express = require("express");
var app = express();
// Tell Express to look in the "public" folder for any files first
app.use(express.static("public")); // This is where the HTML, p5.js, sketch.js and so on should be stored
// If the user just goes to the "route" / then run this function
app.get("/", function (req, res) {
res.send("Hello World!");
});
// Here is the actual HTTP server
var http = require("http");
// We pass in the Express object
var httpServer = http.createServer(app);
// Listen on port provided by Glitch
//httpServer.listen(process.env.PORT);
// OR if running your own server choose your own port
httpServer.listen(8080);
// WebSocket Portion
// WebSockets work with the HTTP server
var io = require("socket.io")(httpServer);
// Register a callback function to run when we have an individual connection
// This is run for each individual user that connects
io.sockets.on(
"connection",
// We are given a websocket object in our function
function (socket) {
console.log(socket.id + " has joined the chat.");
socket.on("mouse", function(data) {
//io.emit("mouse", data);
socket.broadcast.emit("mouse", data);
});
socket.on("disconnect", function () {
console.log(socket.id + " has disconnected.");
});
}
);
I by no means would consider myself someone who is “well versed” as a coder, so the fact that I got this working feels pretty good. It’s nothing special the self-portrait has three array, one for each column, oh yeah I added columns! hahaha. And for the chat I again added columns to center the chat in the window and added a background image. The code for both the self-portrait and the chat are below. If you want to look at either the self-portrait or the chat the links are below as well.
Let’s start by talking about the self portrait that I didn’t get working. The idea was to have an array of images and onclick have the image change to the next in the array, I was also thinking of adding some sound or music that went along with each of the images.
I tried a number of different ways of accomplishing this, however, it never quite worked. I think the closest I came to getting it work was with the code below.
<html>
<head>
<title>lihp idirac</title>
<link rel="icon" type="image/x-icon" href="images/favIcon.ico.jpg">
<script type="text/javascript">
var portImages = new Array();
portImages[0] = "images/Day7of50.jpg";
portImages[1] = "images/Day12of50.jpg";
portImages[2] = "images/PPC_5205.PNG";
portImages[3] = "imagesPPC_5211.PNG";
var currentImage = 0;
var lastImage = portImages.length -1;
/*
window.addEventListener("load", init);
function init() {
console.log("page is loaded");
}
*/
function nextImage(){
if (currentImage == lastImage)
{
currentImage = 0;
document.getElementById('portrait').src = portImages[currentImage];
}
else
{
currentImage++;
document.getElementById('portrait').src = portImages[currentImage];
}
}
</script>
</head>
<body>
<img scr="images/Day7of50.jpg" id="portrait" onclick="nextImage()">
</body>
</html>
I’ll keep working through the issues but for now, here it sits.
Live Media
I think the last “live media” event I engaged in was a “Fan First Friday” produced by Hasbro regarding the GI Joe Classified toy line. Hasbro utilizes YouTube live as their streaming service for events of this nature. The chat feature can be a good thing, however, in this situation it mostly devolves to a lot of complaining. In fact I find it very annoying and turn it off on most occasions. I guess in theory the chat is supposed to make you feel more of a connection to the other viewers and even the members of the live stream. As an avid action figure collector staying up to date with new releases and drop dates is something that makes a difference in the hobby. Finding out information about upcoming releases even as short as an hour late can mean the difference between acquiring the figure and not. Hasbro has only been doing this type of event for the last few years, it used to be that multiple trips to the store were required to find out if figure were available and even then you weren’t guaranteed to find them. In all truth I think this type of event really isn’t missing much, maybe onscreen links, but that’s about it.