init
BIN
assets/audio/Amphibians.mp3
Normal file
BIN
assets/audio/Asteroids.mp3
Normal file
BIN
assets/audio/Down Polypore Wood.mp3
Normal file
BIN
assets/audio/Ritual Dance of The Cavern Walls Cult.mp3
Normal file
BIN
assets/audio/Sneaking Out Alone.mp3
Normal file
BIN
assets/audio/Tatari.mp3
Normal file
BIN
assets/audio/buranko.mp3
Normal file
BIN
assets/audio/new jersey again.mp3
Normal file
272
assets/css/style.css
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
body {
|
||||
background-color: #E7D5B1;
|
||||
/* background-color: #8EA7C8; */
|
||||
background-image: url("https://www.transparenttextures.com/patterns/asfalt-dark.png");
|
||||
font-family: monospace;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.outer-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 720px;
|
||||
margin: auto;
|
||||
margin: 0 auto 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: relative;
|
||||
z-index: -1;
|
||||
max-width: 720px;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: #f8f8ff;
|
||||
border: inset 8px black;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
margin: 20px;
|
||||
min-width: 680px;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.enter-indicator {
|
||||
position: absolute;
|
||||
font-size: 14px;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
margin: 5px;
|
||||
animation: blink 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.window-container {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
margin: 20px;
|
||||
border: solid 3px #dbe0e7;
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.window-bar {
|
||||
position: relative;
|
||||
background: #57C785;
|
||||
background: linear-gradient(90deg, rgba(87, 199, 133, 1) 19%, rgba(191, 83, 237, 1) 100%);
|
||||
font-family: monospace;
|
||||
font-size: 20px;
|
||||
border-bottom: solid 3px #dbe0e7;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 3px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
border-radius: 0%;
|
||||
border-top: white;
|
||||
border-left: white;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
#term {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
overflow-wrap: break-word;
|
||||
display: none;
|
||||
background-color: #272E33;
|
||||
color: #A7C080;
|
||||
font-family: monospace;
|
||||
font-size: 18px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.prompt-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.prompt-container label {
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
|
||||
.prompt-container input[type="text"] {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#term input {
|
||||
float: left;
|
||||
color: #A7C080;
|
||||
font-family: monospace;
|
||||
font-size: 18px;
|
||||
min-width: 90%;
|
||||
background-color: #272E33;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
#term input:focus {
|
||||
width: 100%;
|
||||
background-color: #272E33;
|
||||
border: 0;
|
||||
outline:none!important;
|
||||
}
|
||||
|
||||
.music-inner-container {
|
||||
background: #a3acbe;
|
||||
position: relative;
|
||||
height: inherit;
|
||||
box-sizing: border-box;
|
||||
font-family: monospace;
|
||||
font-size: 20px;
|
||||
padding: 10px;
|
||||
overflow: auto!important;
|
||||
}
|
||||
|
||||
#album-thumb {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.audio-controls {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
#album-thumb img {
|
||||
border: solid 3px #dbe0e7;
|
||||
margin-top: 10px;
|
||||
width: 200px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#games-container {
|
||||
background: #a3acbe;
|
||||
}
|
||||
|
||||
.games-inner-container {
|
||||
position: relative;
|
||||
height: inherit;
|
||||
box-sizing: border-box;
|
||||
font-family: monospace;
|
||||
font-size: 20px;
|
||||
padding: 10px;
|
||||
overflow: auto!important;
|
||||
}
|
||||
|
||||
.games-inner-container img {
|
||||
width: 200px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.games-inner-container h3 {
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.single-game-container {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.single-game-container:hover {
|
||||
border: solid 4px black;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.game-thumbnail-container {
|
||||
flex: 25%;
|
||||
}
|
||||
|
||||
.game-description-container {
|
||||
flex: 75%;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.clearfix::after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
|
||||
table {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td, th {
|
||||
border: 1px solid #dddddd;
|
||||
text-align: left;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
0% { box-shadow: 0 0 -28px 13px #ff0000; }
|
||||
40% { box-shadow: 0 0 15px 13px #ff0000; }
|
||||
60% { box-shadow: 0 0 15px 13px #ff0000; }
|
||||
100% { box-shadow: 0 0 -28px 13px #ff0000; }
|
||||
}
|
||||
|
||||
.indicator {
|
||||
display: none;
|
||||
background-color: yellow;
|
||||
border-radius: 50%;
|
||||
margin: 0 auto;
|
||||
height: 0px;
|
||||
width: 0px;
|
||||
animation: glow 3s infinite;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#resume-indicator {
|
||||
top: 310px;
|
||||
left: 368px;
|
||||
}
|
||||
|
||||
#portfolio-indicator {
|
||||
top: 20px;
|
||||
left: 140px;
|
||||
}
|
||||
|
||||
#computer-indicator {
|
||||
top: 260px;
|
||||
left: 260px;
|
||||
}
|
||||
|
||||
#tv-indicator {
|
||||
top: 20px;
|
||||
left: 700px;
|
||||
}
|
||||
|
||||
#guitar-indicator {
|
||||
top: 570px;
|
||||
left: 60px;
|
||||
}
|
||||
BIN
assets/img/endesga-36-1x.png
Normal file
|
After Width: | Height: | Size: 213 B |
BIN
assets/img/sprites/sprite-map-1.ase
Normal file
BIN
assets/img/sprites/sprite-map-1.jpg
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
assets/img/sprites/sprite-map-1.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
assets/img/sprites/test-sprite.png
Normal file
|
After Width: | Height: | Size: 134 B |
BIN
assets/img/thumbnails/amphi.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
assets/img/thumbnails/asteroids.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
assets/img/thumbnails/nj.jpg
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
assets/img/thumbnails/pong.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/img/thumbnails/scoundrel.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
assets/img/thumbnails/shrinkinminkin.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
assets/img/thumbnails/sokobanya.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/img/thumbnails/tatari.jpg
Normal file
|
After Width: | Height: | Size: 72 KiB |
144
assets/js/app.js
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
var _listener
|
||||
var TO_RADIANS = Math.PI/180;
|
||||
|
||||
var terminalMode = false
|
||||
var spriteSize = 16 * 5
|
||||
var spriteMap = new Image()
|
||||
spriteMap.src = './assets/img/sprites/sprite-map-1.png'
|
||||
|
||||
var canvasOffset = 9
|
||||
var canvas = document.getElementById("canvas")
|
||||
var ctx = canvas.getContext("2d")
|
||||
|
||||
canvas.width = spriteSize * canvasOffset
|
||||
canvas.height = canvas.width
|
||||
|
||||
var audio = null
|
||||
|
||||
var terminal = new Terminal()
|
||||
var games = new Games()
|
||||
var music = new Music()
|
||||
var dialog = new Dialog()
|
||||
var indicator = new Indicator()
|
||||
var player = new Player(1, 1, 'down')
|
||||
|
||||
window.addEventListener("resize", function() {
|
||||
terminal.resize();
|
||||
games.resize();
|
||||
})
|
||||
|
||||
function renderRoom() {
|
||||
// render wall
|
||||
for (let i = 0; i < canvasOffset; i++) {
|
||||
new Renderer(2, 1, i, 0)
|
||||
}
|
||||
|
||||
// Render Wood Floor
|
||||
for (let i = 0; i < canvasOffset; i++) {
|
||||
for (let j = 1; j < canvasOffset; j++) {
|
||||
new Renderer(1, 0, i, j)
|
||||
}
|
||||
}
|
||||
|
||||
// Render Rug row 1
|
||||
new Renderer(2, 0, 1, 2)
|
||||
new Renderer(3, 0, 2, 2)
|
||||
new Renderer(3, 0, 3, 2)
|
||||
new Renderer(3, 0, 4, 2)
|
||||
new Renderer(3, 0, 5, 2)
|
||||
new Renderer(3, 0, 6, 2)
|
||||
new Renderer(2, 0, 7, 2, 90)
|
||||
// Render Rug row 1
|
||||
new Renderer(3, 0, 1, 3, 270)
|
||||
new Renderer(4, 0, 2, 3)
|
||||
new Renderer(4, 0, 3, 3)
|
||||
new Renderer(5, 0, 4, 3)
|
||||
new Renderer(5, 0, 5, 3)
|
||||
new Renderer(5, 0, 6, 3)
|
||||
new Renderer(3, 0, 7, 3, 90)
|
||||
// Render Rug row 2
|
||||
new Renderer(3, 0, 1, 4, 270)
|
||||
new Renderer(5, 0, 2, 4)
|
||||
new Renderer(5, 0, 3, 4)
|
||||
new Renderer(5, 0, 4, 4)
|
||||
new Renderer(5, 0, 5, 4)
|
||||
new Renderer(5, 0, 6, 4)
|
||||
new Renderer(3, 0, 7, 4, 90)
|
||||
// Render Rug row 3
|
||||
new Renderer(3, 0, 1, 5, 270)
|
||||
new Renderer(5, 0, 2, 5)
|
||||
new Renderer(5, 0, 3, 5)
|
||||
new Renderer(5, 0, 4, 5)
|
||||
new Renderer(5, 0, 5, 5)
|
||||
new Renderer(5, 0, 6, 5)
|
||||
new Renderer(3, 0, 7, 5, 90)
|
||||
// Render Rug row
|
||||
new Renderer(3, 0, 1, 6, 270)
|
||||
new Renderer(5, 0, 2, 6)
|
||||
new Renderer(5, 0, 3, 6)
|
||||
new Renderer(5, 0, 4, 6)
|
||||
new Renderer(5, 0, 5, 6)
|
||||
new Renderer(4, 0, 6, 6)
|
||||
new Renderer(3, 0, 7, 6, 90)
|
||||
// Render Rug row 4
|
||||
new Renderer(2, 0, 1, 7, 270)
|
||||
new Renderer(3, 0, 2, 7, 180)
|
||||
new Renderer(3, 0, 3, 7, 180)
|
||||
new Renderer(3, 0, 4, 7, 180)
|
||||
new Renderer(3, 0, 5, 7, 180)
|
||||
new Renderer(3, 0, 6, 7, 180)
|
||||
new Renderer(2, 0, 7, 7, 180)
|
||||
|
||||
// render TV
|
||||
new Renderer(6, 0, 7, 0)
|
||||
new Renderer(7, 0, 8, 0)
|
||||
new Renderer(6, 1, 7, 1)
|
||||
new Renderer(7, 1, 8, 1)
|
||||
|
||||
// render bookshelves
|
||||
new Renderer(1, 1, 0, 0)
|
||||
new Renderer(1, 1, 1, 0)
|
||||
|
||||
// render computer
|
||||
new Renderer(0, 8, 2, 4)
|
||||
new Renderer(1, 8, 3, 4)
|
||||
new Renderer(2, 8, 4, 4)
|
||||
new Renderer(3, 8, 5, 4)
|
||||
|
||||
// render maomao
|
||||
new Renderer(4, 1, 6, 6)
|
||||
|
||||
// render window
|
||||
new Renderer(3, 1, 4, 0)
|
||||
|
||||
//render player
|
||||
player.render()
|
||||
|
||||
// render second half of computer
|
||||
new Renderer(0, 7, 2, 3)
|
||||
new Renderer(1, 7, 3, 3)
|
||||
new Renderer(2, 7, 4, 3)
|
||||
new Renderer(3, 7, 5, 3)
|
||||
|
||||
// render guitar
|
||||
new Renderer(3, 2, 0, 7)
|
||||
new Renderer(3, 3, 0, 8)
|
||||
new Renderer(4, 2, 1, 8)
|
||||
|
||||
}
|
||||
|
||||
dialog.startIntroDialogSequence()
|
||||
|
||||
function gameLoop() {
|
||||
renderRoom()
|
||||
document.removeEventListener("keydown", _listener);
|
||||
if (terminalMode) {
|
||||
terminal.getKeystroke();
|
||||
} else {
|
||||
this.getKeystroke();
|
||||
}
|
||||
}
|
||||
|
||||
spriteMap.onload = function() {
|
||||
setInterval(gameLoop, 33);
|
||||
}
|
||||
33
assets/js/constants.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
var boundaries = [
|
||||
// computer
|
||||
[2, 3],
|
||||
[3, 3],
|
||||
[4, 3],
|
||||
[5, 3],
|
||||
//guitar
|
||||
[1, 7],
|
||||
[0, 7],
|
||||
//maomao
|
||||
[6, 5]
|
||||
]
|
||||
|
||||
var computerInteractionZones = [
|
||||
[2, 4],
|
||||
[3, 4]
|
||||
]
|
||||
|
||||
var gamesInteractionZones = [
|
||||
[7, 0],
|
||||
[8, 0]
|
||||
]
|
||||
|
||||
var musicInteractionZones = [
|
||||
[0, 6],
|
||||
[1, 6],
|
||||
[2, 7]
|
||||
]
|
||||
|
||||
var resumeInteractionZones = [
|
||||
[4, 4],
|
||||
[4, 2]
|
||||
]
|
||||
54
assets/js/dialog.js
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
class Dialog {
|
||||
constructor() {
|
||||
this.dialogElem = document.getElementById('dialog')
|
||||
this.dialogTextElem = document.getElementById('dialog-text')
|
||||
|
||||
this.currentDialogIndex = 0
|
||||
this.dialogOrder = ['intro', 'controls', 'resume']
|
||||
|
||||
this.dialogMap = {
|
||||
'intro': 'Hello! Welcome to my Interactive Portfolio!<br>Press <b>ENTER</b> to continue, or click the links below for quick access to my Resume & Projects.',
|
||||
'controls': 'Use <b>ARROW KEYS</b> or <b>WASD</b> or <b>VIM</b> keys (HJKL) to move around. <br>Press the <b>ENTER</b> key to interact with what you see on the screen.<br><br>',
|
||||
'resume': 'Walk over to the <b>DESK</b> and click on my <b>RESUME</b>.<br> The <b>RESUME</b> is marked by the flashing red indicator light<br>.',
|
||||
'portfolio': 'Thanks for looking at my Resume!<br>Check out my <b>PORTFOLIO</b> by clicking on the <b>BOOKSHELF</br>.'
|
||||
}
|
||||
|
||||
this.resumeIndicator = document.getElementById('resume-indicator')
|
||||
}
|
||||
|
||||
dialogListener(event) {
|
||||
console.log(event)
|
||||
if (event.key === 'Enter') {
|
||||
event.currentTarget.self.startIntroDialogSequence()
|
||||
}
|
||||
}
|
||||
|
||||
startIntroDialogSequence() {
|
||||
document.removeEventListener("keydown", this.dialogListener);
|
||||
console.log('hit')
|
||||
if (this.currentDialogIndex > this.dialogOrder.length - 1) {
|
||||
this.dialogElem.style.display = 'none'
|
||||
|
||||
} else {
|
||||
var dialog = this.dialogMap[this.dialogOrder[this.currentDialogIndex]]
|
||||
this.display(dialog)
|
||||
|
||||
if (this.dialogOrder[this.currentDialogIndex] in indicator.indicatorMap) {
|
||||
indicator.show(this.dialogOrder[this.currentDialogIndex])
|
||||
}
|
||||
|
||||
this.currentDialogIndex++
|
||||
|
||||
var self = this
|
||||
document.addEventListener('keydown', this.dialogListener)
|
||||
document.self = self
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
display(dialog) {
|
||||
this.dialogElem.style.display = 'block'
|
||||
this.dialogTextElem.innerHTML = this.dialogMap[this.dialogOrder[this.currentDialogIndex]]
|
||||
}
|
||||
|
||||
}
|
||||
23
assets/js/games.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
class Games {
|
||||
constructor() {
|
||||
this.gamesContainer = document.getElementById("games-container")
|
||||
this.gamesInnerContainer = document.getElementById("games")
|
||||
}
|
||||
|
||||
show() {
|
||||
this.resize()
|
||||
this.gamesContainer.style.display = 'block'
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.gamesContainer.style.display = 'none'
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.gamesContainer.style.width = canvas.getBoundingClientRect().width - 40 + 'px';
|
||||
this.gamesContainer.style.height = canvas.getBoundingClientRect().height - 40 + 'px';
|
||||
this.gamesContainer.style.minHeight = canvas.getBoundingClientRect().width - 40 + 'px';
|
||||
|
||||
this.gamesInnerContainer.style.height = canvas.getBoundingClientRect().height - 77 + 'px';
|
||||
}
|
||||
}
|
||||
33
assets/js/indicator.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
class Indicator {
|
||||
constructor() {
|
||||
this.resumeIndicator = document.getElementById('resume-indicator')
|
||||
this.portfolioIndicator = document.getElementById('portfolio-indicator')
|
||||
this.computerIndicator = document.getElementById('computer-indicator')
|
||||
this.tvIndicator = document.getElementById('tv-indicator')
|
||||
this.guitarIndicator = document.getElementById('guitar-indicator')
|
||||
|
||||
this.resumeIndicatorShown = false
|
||||
this.portfolioIndicatorShown = false
|
||||
this.computerIndicatorShown = false
|
||||
this.tvIndicatorShown = false
|
||||
this.guitarIndicatorShown = false
|
||||
|
||||
this.indicatorMap = {
|
||||
'resume': this.resumeIndicator,
|
||||
'portfolio': this.portfolioIndicator,
|
||||
'computer': this.computerIndicator,
|
||||
'tv': this.tvIndicator,
|
||||
'guitar': this.guitarIndicator
|
||||
}
|
||||
}
|
||||
|
||||
show(indicatorName) {
|
||||
console.log(indicatorName)
|
||||
this.indicatorMap[indicatorName].style.display = 'block'
|
||||
}
|
||||
|
||||
hide(indicatorName) {
|
||||
this.indicatorMap[indicatorName].style.display = 'none'
|
||||
}
|
||||
|
||||
}
|
||||
61
assets/js/keystroke.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
function getKeystroke() {
|
||||
_listener = function (event) {
|
||||
if (
|
||||
["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].indexOf(
|
||||
event.code,
|
||||
) > -1
|
||||
) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (event.key === "h" || event.key === "a" || event.key === "ArrowLeft") {
|
||||
player.move('left')
|
||||
} else if (
|
||||
event.key === "j" ||
|
||||
event.key === "s" ||
|
||||
event.key === "ArrowDown"
|
||||
) {
|
||||
player.move('down')
|
||||
} else if (
|
||||
event.key === "k" ||
|
||||
event.key === "w" ||
|
||||
event.key === "ArrowUp"
|
||||
) {
|
||||
player.move('up')
|
||||
} else if (
|
||||
event.key === "l" ||
|
||||
event.key === "d" ||
|
||||
event.key === "ArrowRight"
|
||||
) {
|
||||
player.move('right')
|
||||
} else if (
|
||||
event.key === "Enter" &&
|
||||
!terminal.active
|
||||
) {
|
||||
var playerPosition = [player.canvasX, player.canvasY]
|
||||
if (player.direction === 'up') {
|
||||
if (computerInteractionZones.some(a => playerPosition.every((v, i) => v === a[i]))) {
|
||||
terminal.show();
|
||||
}
|
||||
if (gamesInteractionZones.some(a => playerPosition.every((v, i) => v === a[i]))) {
|
||||
games.show();
|
||||
}
|
||||
}
|
||||
|
||||
if (player.direction === 'down' || player.direction === 'left') {
|
||||
if (musicInteractionZones.some(a => playerPosition.every((v, i) => v === a[i]))) {
|
||||
music.show();
|
||||
}
|
||||
}
|
||||
|
||||
if (player.direction === 'down' || player.direction === 'up') {
|
||||
if (resumeInteractionZones.some(a => playerPosition.every((v, i) => v === a[i]))) {
|
||||
indicator.hide('resume');
|
||||
indicator.resumeIndicatorShown = true;
|
||||
// show resume
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
document.addEventListener("keydown", _listener);
|
||||
}
|
||||
116
assets/js/music.js
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
class Music extends Window {
|
||||
constructor() {
|
||||
super('music')
|
||||
this.albumCoverElem = document.getElementById("album-art")
|
||||
this.currentlyPlayingElem = document.getElementById("currently-playing")
|
||||
this.currentSong = null
|
||||
|
||||
this.songOrder = [
|
||||
'Down Polypore Wood',
|
||||
'Sneaking Out Alone',
|
||||
'Ritual Dance of The Cavern Walls Cult',
|
||||
'Tatari',
|
||||
'Buranko',
|
||||
'New Jersey Again',
|
||||
'Asteroids'
|
||||
]
|
||||
|
||||
this.songMap = {
|
||||
'Down Polypore Wood': {
|
||||
'audio': 'Down Polypore Wood.mp3',
|
||||
'thumb': 'shrinkinminkin.jpg'
|
||||
},
|
||||
'Sneaking Out Alone': {
|
||||
'audio': 'Sneaking Out Alone.mp3',
|
||||
'thumb': 'shrinkinminkin.jpg'
|
||||
},
|
||||
'Ritual Dance of The Cavern Walls Cult': {
|
||||
'audio': 'Ritual Dance of The Cavern Walls Cult.mp3',
|
||||
'thumb': 'shrinkinminkin.jpg'
|
||||
},
|
||||
'Tatari': {
|
||||
'audio': 'Tatari.mp3',
|
||||
'thumb': 'tatari.jpg'
|
||||
},
|
||||
'Buranko': {
|
||||
'audio': 'buranko.mp3',
|
||||
'thumb': 'tatari.jpg'
|
||||
},
|
||||
'New Jersey Again': {
|
||||
'audio': 'new jersey again.mp3',
|
||||
'thumb': 'nj.jpg'
|
||||
},
|
||||
'Asteroids': {
|
||||
'audio': 'Asteroids.mp3',
|
||||
'thumb': 'amphi.jpg'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
resume() {
|
||||
if (!this.currentSong) {
|
||||
this.play(this.songOrder[0])
|
||||
}
|
||||
audio.play()
|
||||
}
|
||||
|
||||
play(songName=null) {
|
||||
if (this.currentSong) {
|
||||
audio.pause()
|
||||
}
|
||||
|
||||
if (!songName && !this.currentSong) {
|
||||
songName = this.songOrder[0]
|
||||
}
|
||||
|
||||
this.currentSong = songName
|
||||
audio = new Audio(this.getSongFilepath(songName))
|
||||
audio.play()
|
||||
|
||||
var self = this
|
||||
audio.addEventListener('ended', function() {
|
||||
self.next(self.currentSong)
|
||||
})
|
||||
|
||||
this.albumCoverElem.src = this.getAlbumArtFilepath(songName)
|
||||
this.currentlyPlayingElem.innerHTML = this.currentSong
|
||||
}
|
||||
|
||||
getSongFilepath(songName) {
|
||||
return `./assets/audio/${this.songMap[songName]['audio']}`
|
||||
}
|
||||
|
||||
getAlbumArtFilepath(songName) {
|
||||
return `./assets/img/thumbnails/${this.songMap[songName]['thumb']}`
|
||||
}
|
||||
|
||||
next() {
|
||||
if (this.currentSong) {
|
||||
var currentSongIndex = this.songOrder.indexOf(this.currentSong)
|
||||
var nextSongIndex = currentSongIndex + 1
|
||||
|
||||
if (nextSongIndex > this.songOrder.length - 1) {
|
||||
nextSongIndex = 0
|
||||
}
|
||||
|
||||
this.play(this.songOrder[nextSongIndex])
|
||||
}
|
||||
}
|
||||
|
||||
prev() {
|
||||
if (this.currentSong) {
|
||||
var currentSongIndex = this.songOrder.indexOf(this.currentSong)
|
||||
var nextSongIndex = currentSongIndex - 1
|
||||
|
||||
if (nextSongIndex < 0) {
|
||||
nextSongIndex = this.songOrder.length - 1
|
||||
}
|
||||
|
||||
this.play(this.songOrder[nextSongIndex])
|
||||
}
|
||||
}
|
||||
|
||||
pause() {
|
||||
audio.pause()
|
||||
}
|
||||
}
|
||||
72
assets/js/player.js
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
class Player {
|
||||
constructor(x, y, direction) {
|
||||
this.canvasX = x
|
||||
this.canvasY = y
|
||||
|
||||
this.direction = direction
|
||||
|
||||
this.spriteWidth = spriteSize
|
||||
this.spriteHeight = spriteSize * 2
|
||||
|
||||
this.animationCycle = [0, 1, 0, 2]
|
||||
this.animationCycleIndex = 0
|
||||
this.spriteMapXAnimationOffset = 0
|
||||
|
||||
this.directionSpriteYMap = {
|
||||
'down': 2,
|
||||
'right': 4,
|
||||
'up': 6,
|
||||
'left': 8,
|
||||
}
|
||||
}
|
||||
|
||||
move(direction) {
|
||||
this.direction = direction
|
||||
var nextPosition
|
||||
if (direction === 'left' && this.canvasX - 1 >= 0) {
|
||||
nextPosition = [this.canvasX - 1, this.canvasY]
|
||||
if (!this.isBoundary(nextPosition)) {
|
||||
this.canvasX -= 1;
|
||||
}
|
||||
}
|
||||
if (direction === 'right' && this.canvasX + 1 < canvas.width/spriteSize) {
|
||||
nextPosition = [this.canvasX + 1, this.canvasY]
|
||||
if (!this.isBoundary(nextPosition)) {
|
||||
this.canvasX += 1;
|
||||
}
|
||||
}
|
||||
if (direction === 'up' && this.canvasY - 1 >= 0) {
|
||||
nextPosition = [this.canvasX, this.canvasY - 1]
|
||||
if (!this.isBoundary(nextPosition)) {
|
||||
this.canvasY -= 1;
|
||||
}
|
||||
}
|
||||
if (direction === 'down' && this.canvasY + 2 < canvas.height/spriteSize){
|
||||
nextPosition = [this.canvasX, this.canvasY + 1]
|
||||
if (!this.isBoundary(nextPosition)) {
|
||||
this.canvasY += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isBoundary(nextPosition) {
|
||||
return boundaries.some(a => nextPosition.every((v, i) => v === a[i]));
|
||||
}
|
||||
|
||||
render() {
|
||||
this.spriteMapX = this.spriteWidth * 5
|
||||
this.spriteMapY = this.directionSpriteYMap[this.direction] * spriteSize
|
||||
|
||||
ctx.drawImage(
|
||||
spriteMap,
|
||||
this.spriteMapX + this.spriteMapXAnimationOffset,
|
||||
this.spriteMapY,
|
||||
this.spriteWidth,
|
||||
this.spriteHeight,
|
||||
spriteSize * this.canvasX,
|
||||
spriteSize * this.canvasY,
|
||||
this.spriteWidth,
|
||||
this.spriteHeight,
|
||||
)
|
||||
}
|
||||
}
|
||||
23
assets/js/portfolio.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
class Portfolio {
|
||||
constructor() {
|
||||
this.container = document.getElementById("portfolio-container")
|
||||
this.innerContainer = document.getElementById("portfolio")
|
||||
}
|
||||
|
||||
show() {
|
||||
this.resize()
|
||||
this.container.style.display = 'block'
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.container.style.display = 'none'
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.container.style.width = canvas.getBoundingClientRect().width - 40 + 'px';
|
||||
this.container.style.height = canvas.getBoundingClientRect().height - 40 + 'px';
|
||||
this.container.style.minHeight = canvas.getBoundingClientRect().width - 40 + 'px';
|
||||
|
||||
this.innerContainer.style.height = canvas.getBoundingClientRect().height - 77 + 'px';
|
||||
}
|
||||
}
|
||||
52
assets/js/renderer.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
class Renderer {
|
||||
constructor(spriteX, spriteY, canvasX, canvasY, rotation=0) {
|
||||
this.spriteX = spriteX
|
||||
this.spriteY = spriteY
|
||||
this.canvasX = canvasX
|
||||
this.canvasY = canvasY
|
||||
this.rotation = rotation
|
||||
|
||||
if (this.rotation === 0) {
|
||||
this.render()
|
||||
} else {
|
||||
this.rotateRender()
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
ctx.drawImage(
|
||||
spriteMap,
|
||||
spriteSize * this.spriteX,
|
||||
spriteSize * this.spriteY,
|
||||
spriteSize,
|
||||
spriteSize,
|
||||
spriteSize * this.canvasX,
|
||||
spriteSize * this.canvasY,
|
||||
spriteSize,
|
||||
spriteSize
|
||||
)
|
||||
}
|
||||
|
||||
rotateRender() {
|
||||
ctx.save()
|
||||
|
||||
ctx.translate(
|
||||
spriteSize * this.canvasX + (spriteSize / 2),
|
||||
spriteSize * this.canvasY + (spriteSize / 2)
|
||||
)
|
||||
ctx.rotate(this.rotation * TO_RADIANS)
|
||||
|
||||
ctx.drawImage(
|
||||
spriteMap,
|
||||
spriteSize * this.spriteX,
|
||||
spriteSize * this.spriteY,
|
||||
spriteSize,
|
||||
spriteSize,
|
||||
-(spriteSize/2),
|
||||
-(spriteSize/2),
|
||||
spriteSize,
|
||||
spriteSize)
|
||||
|
||||
ctx.restore()
|
||||
}
|
||||
}
|
||||
5
assets/js/resume.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class Resume extends Window {
|
||||
constructor() {
|
||||
super('resume')
|
||||
}
|
||||
}
|
||||
197
assets/js/terminal.js
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
class Terminal {
|
||||
constructor() {
|
||||
this.terminalElem = document.getElementById("term")
|
||||
this.terminalContainerElem = document.getElementById("term-container")
|
||||
this.promptContainerElem = document.getElementById("prompt-container")
|
||||
this.promptsAndResponses = []
|
||||
this.commands = []
|
||||
this.commandPosition = this.commands.length
|
||||
this.currentPrompt = null
|
||||
this.active = false;
|
||||
this.initialized = false;
|
||||
}
|
||||
|
||||
show() {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
this.initialize()
|
||||
} else {
|
||||
this.terminalElem.style.display = "block"
|
||||
this.terminalContainerElem.style.display = "block"
|
||||
if (this.currentPrompt) {
|
||||
this.currentPrompt.focus()
|
||||
}
|
||||
}
|
||||
terminalMode = true;
|
||||
}
|
||||
|
||||
hide () {
|
||||
this.terminalElem.style.display = "none"
|
||||
this.terminalContainerElem.style.display = "none"
|
||||
terminalMode = false;
|
||||
}
|
||||
|
||||
createPrompt() {
|
||||
this.commandPosition = this.commands.length
|
||||
|
||||
var promptContainerElem = document.createElement("div")
|
||||
promptContainerElem.classList.add("prompt-container")
|
||||
|
||||
var label = document.createElement("label")
|
||||
label.innerHTML = '>>>'
|
||||
|
||||
var prompt = document.createElement("input")
|
||||
prompt.setAttribute("autofocus", true)
|
||||
|
||||
var self = this
|
||||
prompt.addEventListener("keypress", function(event) {
|
||||
|
||||
if (event.key === "Enter") {
|
||||
if (terminalMode && this.value !== ''){
|
||||
event.preventDefault();
|
||||
this.disabled = true;
|
||||
self.handlePrompt(this.value);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var clearFixDiv = document.createElement("div")
|
||||
clearFixDiv.classList.add("clearfix")
|
||||
|
||||
promptContainerElem.appendChild(label);
|
||||
promptContainerElem.appendChild(prompt);
|
||||
this.terminalElem.appendChild(promptContainerElem);
|
||||
|
||||
prompt.focus()
|
||||
this.currentPrompt = prompt
|
||||
this.promptsAndResponses.push(promptContainerElem)
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.resize()
|
||||
this.show();
|
||||
this.createPrompt();
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.terminalElem.style.width = canvas.getBoundingClientRect().width - 40 + 'px';
|
||||
this.terminalElem.style.height = canvas.getBoundingClientRect().height - 80 + 'px';
|
||||
this.terminalElem.style.minHeight = canvas.getBoundingClientRect().width - 80 + 'px';
|
||||
}
|
||||
|
||||
handlePrompt(promptText) {
|
||||
this.commands.push(promptText);
|
||||
this.determineResult(promptText);
|
||||
this.createPrompt();
|
||||
}
|
||||
|
||||
determineResult(promptText) {
|
||||
var returnText
|
||||
if (promptText === 'help') {
|
||||
returnText = `Documented Commands:<br>
|
||||
========================================<br>
|
||||
help     Shows the help screen<br>
|
||||
about    Provides background of the terminal<br>
|
||||
clear    Clears the terminal<br>
|
||||
echo     Display a line of text<br>
|
||||
exit     Exits the terminal<br>
|
||||
history  Prints command history<br>
|
||||
<br>
|
||||
Terminal Functionality:<br>
|
||||
========================================<br>
|
||||
Up Arrow - cycle through commands<br>
|
||||
Down Arrow - cycle through commands<br>
|
||||
Ctrl+c - discard current prompt<br>
|
||||
Ctrl+d - exit<br>
|
||||
`
|
||||
|
||||
} else if (promptText.split(" ")[0] == 'echo') {
|
||||
promptText = promptText.replaceAll('"', '')
|
||||
promptText = promptText.split(' ').slice(1)
|
||||
returnText = promptText.join(' ')
|
||||
} else if (promptText === 'history') {
|
||||
|
||||
returnText = this.commands.join('<br>')
|
||||
|
||||
} else if (promptText == 'exit') {
|
||||
this.hide()
|
||||
|
||||
} else if (promptText == 'about') {
|
||||
returnText = 'I built this terminal emulator in JavaScript. While the functionality is quite simple, I wanted to showcase my love for linux and working in the terminal. All actions that can be done in the main world like: looking at my portfolio, downloading my resume, or playing one of the games I made can be done through this terminal. <br><br> I also added some quality of life commands like clear, exit, echo and more for the fun of it. That\'s right! This is what I do for fun :)'
|
||||
|
||||
} else if (promptText == 'clear') {
|
||||
this.clear()
|
||||
|
||||
} else if (['vim', 'nvim', 'nano', 'ed'].includes(promptText)) {
|
||||
returnText = 'Did you really think I coded a text editor in here!?'
|
||||
|
||||
} else {
|
||||
returnText = 'Unkown command, please type "help" for options'
|
||||
|
||||
}
|
||||
|
||||
if (returnText) {
|
||||
var responseElem = document.createElement('span')
|
||||
responseElem.innerHTML = returnText
|
||||
this.terminalElem.appendChild(responseElem)
|
||||
this.promptsAndResponses.push(responseElem)
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
for (let i = 0; i < this.promptsAndResponses.length; i++) {
|
||||
this.promptsAndResponses[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
getKeystroke() {
|
||||
var self = this
|
||||
_listener = function (event) {
|
||||
console.log(event.code)
|
||||
if (
|
||||
["ArrowUp", "ArrowDown", "ControlLeft"].indexOf(event.code,) > -1
|
||||
) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (event.ctrlKey && event.key === 'd') {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (event.key === "ArrowUp") {
|
||||
if (self.commands.length > 0) {
|
||||
var nextCommandPosition = self.commandPosition - 1
|
||||
|
||||
if (nextCommandPosition < 0) {
|
||||
nextCommandPosition = self.commands.length - 1
|
||||
}
|
||||
|
||||
self.currentPrompt.value = self.commands[nextCommandPosition]
|
||||
self.commandPosition = nextCommandPosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.key === "ArrowDown") {
|
||||
if (self.commands.length > 0) {
|
||||
var nextCommandPosition = self.commandPosition + 1
|
||||
|
||||
if (nextCommandPosition > self.commands.length - 1) {
|
||||
nextCommandPosition = 0
|
||||
}
|
||||
|
||||
self.currentPrompt.value = self.commands[nextCommandPosition]
|
||||
self.commandPosition = nextCommandPosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.ctrlKey && event.key === 'c') {
|
||||
self.createPrompt()
|
||||
}
|
||||
|
||||
if (event.ctrlKey && event.key === 'd') {
|
||||
self.hide()
|
||||
}
|
||||
}
|
||||
document.addEventListener("keydown", _listener);
|
||||
}
|
||||
}
|
||||
22
assets/js/window.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
class Window {
|
||||
constructor(id) {
|
||||
this.container = document.getElementById(`${id}-container`)
|
||||
this.innerContainer = document.getElementById(id)
|
||||
}
|
||||
|
||||
show() {
|
||||
this.resize()
|
||||
this.container.style.display = 'block'
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.container.style.display = 'none'
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.container.style.width = canvas.getBoundingClientRect().width - 40 + 'px';
|
||||
this.container.style.height = canvas.getBoundingClientRect().height - 40 + 'px';
|
||||
this.container.style.minHeight = canvas.getBoundingClientRect().width - 40 + 'px';
|
||||
this.innerContainer.style.height = canvas.getBoundingClientRect().height - 77 + 'px';
|
||||
}
|
||||
}
|
||||
248
index.html
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Dominic DiTaranto - Portfolio</title>
|
||||
<link rel="stylesheet" href="./assets/css/style.css">
|
||||
|
||||
<script type="text/javascript" src="./assets/js/renderer.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/constants.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/player.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/window.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/terminal.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/games.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/music.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/resume.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/portfolio.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/dialog.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/indicator.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/keystroke.js" defer></script>
|
||||
<script type="text/javascript" src="./assets/js/app.js" defer></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="outer-container">
|
||||
<div class="container">
|
||||
<h1 style="margin-bottom: -3px;">Dominic DiTaranto</h1>
|
||||
Software Developer & Architect
|
||||
</div>
|
||||
<div class="container">
|
||||
<canvas id="canvas"></canvas>
|
||||
|
||||
<span class="indicator" id='resume-indicator'></span>
|
||||
<span class="indicator" id='portfolio-indicator'></span>
|
||||
<span class="indicator" id='computer-indicator'></span>
|
||||
<span class="indicator" id='tv-indicator'></span>
|
||||
<span class="indicator" id='guitar-indicator'></span>
|
||||
|
||||
|
||||
<div class="dialog" id="dialog">
|
||||
<span id="dialog-text"></span>
|
||||
<div class="enter-indicator">PRESS ENTER</div>
|
||||
</div>
|
||||
|
||||
<!-- Terminal -->
|
||||
<div class="window-container" id="term-container">
|
||||
<div class="window-bar">
|
||||
<div style="float:inline-start;">
|
||||
💻 Terminal
|
||||
</div>
|
||||
<div style="float:inline-end;">
|
||||
<button class="close-button" onclick="terminal.hide()">X</button>
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
<div id="term">
|
||||
DD-Term 1.0.0 (main, Dec 14 2025, 23:35:36) on javascript <br>
|
||||
Type "help" for more information.<br>
|
||||
<div id="prompt-container" class="prompt-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resume -->
|
||||
<div class="window-container" id="resume-container">
|
||||
<div class="window-bar">
|
||||
<div style="float:inline-start;">
|
||||
📄 Resume
|
||||
</div>
|
||||
<div style="float:inline-end;">
|
||||
<button class="close-button" onclick="resume.hide()">X</button>
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
<div id="resume">
|
||||
Resume placeholder
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Portfolio -->
|
||||
<div class="window-container" id="portfolio-container">
|
||||
<div class="window-bar">
|
||||
<div style="float:inline-start;">
|
||||
💼 Portfolio
|
||||
</div>
|
||||
<div style="float:inline-end;">
|
||||
<button class="close-button" onclick="portfolio.hide()">X</button>
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
<div id="portfolio">
|
||||
Portfolio placeholder
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Music -->
|
||||
<div class="window-container" id="music-container">
|
||||
<div class="window-bar">
|
||||
<div style="float:inline-start;">
|
||||
🎸 Music
|
||||
</div>
|
||||
<div style="float:inline-end;">
|
||||
<button class="close-button" onclick="music.hide()">X</button>
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
<div id="music" class="music-inner-container">
|
||||
<center>
|
||||
<div id="album-thumb">
|
||||
<img id="album-art" src="./assets/img/thumbnails/shrinkinminkin.jpg" alt=""><br>
|
||||
<div class="audio-controls">
|
||||
<span onclick="music.prev()">⏮</span>
|
||||
<span onclick="music.resume()">▶</span>
|
||||
<span onclick="music.pause()">⏸</span>
|
||||
<span onclick="music.next()">⏭</span>
|
||||
</div>
|
||||
Currently Playing: <span id="currently-playing">None</span>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
</div>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Song</th>
|
||||
<th>Artist</th>
|
||||
<th>Album</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Down Polypore Wood</td>
|
||||
<td>shrinkin-minkin</td>
|
||||
<td>Tyrannizing Harmonics</td>
|
||||
<td><a href="#" onclick="music.play('Down Polypore Wood')">play</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sneaking Out Alone</td>
|
||||
<td>shrinkin-minkin</td>
|
||||
<td>Tyrannizing Harmonics</td>
|
||||
<td><a href="#" onclick="music.play('Sneaking Out Alone')">play</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ritual Dance of The...</td>
|
||||
<td>shrinkin-minkin</td>
|
||||
<td>Tyrannizing Harmonics</td>
|
||||
<td><a href="#" onclick="music.play('Ritual Dance of The Cavern Walls Cult')">play</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tatari</td>
|
||||
<td>Dominic Ditaranto</td>
|
||||
<td>Tatari</td>
|
||||
<td><a href="#" onclick="music.play('Tatari')">play</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Buranko</td>
|
||||
<td>Dominic Ditaranto</td>
|
||||
<td>Tatari</td>
|
||||
<td><a href="#" onclick="music.play('Buranko')">play</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Jersey Again</td>
|
||||
<td>Dominic Ditaranto</td>
|
||||
<td>Chicago-New Jersey</td>
|
||||
<td><a href="#" onclick="music.play('New Jersey Again')">play</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Asteroids</td>
|
||||
<td>Dominic Ditaranto</td>
|
||||
<td>Amphibians And Asteroids</td>
|
||||
<td><a href="#" onclick="music.play('Asteroids')">play</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<span style="font-size: 12px;">
|
||||
I am the singer, guitarist and composer for the band <a href="https://shrinkinminkin.com/" target="_blank">shrinkin-minkin</a> <br>All songs by Dominic DiTaranto are from my <a href="https://dominicditaranto.bandcamp.com/" target="_blank">solo project</a>
|
||||
</span>
|
||||
</center>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Games -->
|
||||
<div class="window-container" id="games-container">
|
||||
<div class="window-bar">
|
||||
<div style="float:inline-start;">
|
||||
🕹️ Games
|
||||
</div>
|
||||
<div style="float:inline-end;">
|
||||
<button class="close-button" onclick="games.hide()">X</button>
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
<div id="games" class="games-inner-container">
|
||||
Take a break and enjoy the games I have made!
|
||||
<br>
|
||||
<br>
|
||||
<div class="single-game-container" onclick="window.open('https://asteroids.domdit.com', '_blank')">
|
||||
<div class="game-thumbnail-container">
|
||||
<img src="./assets/img/thumbnails/asteroids.png" alt="">
|
||||
</div>
|
||||
<div class="game-description-container">
|
||||
<u><h3>Asteroids</h3></u>
|
||||
<b>Description:</b> Asteroids port with a few extra features like power ups and a space ship that shoots homing missiles at you. <br><br>
|
||||
<b>Technology:</b> p5.js, JavaScript
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
|
||||
<div class="single-game-container" onclick="window.open('https://sokobanya.domdit.com', '_blank')">
|
||||
<div class="game-thumbnail-container">
|
||||
<img src="./assets/img/thumbnails/sokobanya.png" alt="">
|
||||
</div>
|
||||
<div class="game-description-container">
|
||||
<u><h3>Sokobanya</h3></u>
|
||||
<b>Description:</b> A puzzle game where you are an old man pushing coal onto burners to keep your sauna hot! <br><br>
|
||||
<b>Technology:</b> JavaScript
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
|
||||
<div class="single-game-container" onclick="window.open('https://git.domdit.com/dominic/scoundrel', '_blank')">
|
||||
<div class="game-thumbnail-container">
|
||||
<img src="./assets/img/thumbnails/scoundrel.png" alt="">
|
||||
</div>
|
||||
<div class="game-description-container">
|
||||
<u><h3>Scoundrel</h3></u>
|
||||
<b>Description:</b> TUI port of the rogue-like card game. I was inspired by Balatro to code a card game for the terminal.<br><br>
|
||||
<b>Technology:</b> Python
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
|
||||
<div class="single-game-container" onclick="window.open('https://pong.domdit.com', '_blank')">
|
||||
<div class="game-thumbnail-container">
|
||||
<img src="./assets/img/thumbnails/pong.png" alt="">
|
||||
</div>
|
||||
<div class="game-description-container">
|
||||
<u><h3>Pong</h3></u>
|
||||
<b>Description:</b> You know I had to do it. One of my first coding projects, PONG!<br><br>
|
||||
<b>Technology:</b> p5.js, JavaScript
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||