This commit is contained in:
Dooho Yi 2022-01-18 17:17:29 +09:00
parent 686848b62a
commit 60ba1dac0d
14 changed files with 452 additions and 711 deletions

BIN
public/audio/clap01.mp3 Normal file

Binary file not shown.

View file

@ -283,14 +283,20 @@ details summary::-webkit-details-marker {
}
.intro {
display: none;
position: relative;
left: 50%;
transform: translate(-50%);
font-size: 15px;
margin-bottom: 50px;
writing-mode: vertical-lr;
text-align: center;
animation-delay: 15s;
animation-name: fadeout;
animation-duration: 5s;
animation-fill-mode: forwards;
}
@keyframes fadeout {
0% {
opacity: 0.7;
}
100% {
opacity: 0;
display: none;
}
}
tr {

View file

@ -1,7 +0,0 @@
#defaultCanvas0 {
display: block;
}
.but {
display: block;
}

View file

@ -1,128 +0,0 @@
// -- https://stackoverflow.com/a/46722645
// history.scrollRestoration = "manual";
// -- https://stackoverflow.com/a/39577640
function dataURLtoBlob(dataURL) {
let array, binary, i, len;
binary = atob(dataURL.split(",")[1]);
array = [];
i = 0;
len = binary.length;
while (i < len) {
array.push(binary.charCodeAt(i));
i++;
}
return new Blob([new Uint8Array(array)], {
type: "image/png",
});
}
var p = [];
var cols = 17;
var rows = 17;
var unit = 15; //px
var sw = 0.4; //px (strokewidth)
var img;
function setup() {
var cnv = createCanvas(cols*(unit+sw)+sw, rows*(unit+sw)+sw);
cnv.parent("p5");
img = createGraphics(cols*(unit+sw)+sw, rows*(unit+sw)+sw);
var but = createButton("clear!");
but.attribute('type', 'button');
but.class('but').parent("p5");
// var sav = createButton("save!");
// sav.class('sav').parent("p5");
for (var i = 0; i < cols*rows; i++) {
p.push(0);
}
but.mousePressed(function () {
for (var i = 0; i < cols*rows; i++) {
p.push(0);
}
img.clear();
});
}
function draw() {
//
clear();
//draw the grid
stroke(255);
strokeWeight(sw);
for (var c = 0; c < cols; c++) {
for (var r = 0; r < rows; r++) {
noFill();
rect(c*(unit+sw)+sw, r*(unit+sw)+sw, unit, unit);
}
}
//
image(img, 0, 0);
//pointer
fill(0, 255, 0);
strokeWeight(0);
//mouse way
circle(mouseX, mouseY, 10);
if (mouseIsPressed && mouseButton === LEFT) {
//find slot under the pointer
var mouseC = int(mouseX/(unit+sw));
var mouseR = int(mouseY/(unit+sw));
if (mouseC < cols && mouseR < rows) p[mouseC*cols + mouseR] = 1;
img.strokeWeight(0);
img.fill(255);
img.rect(mouseC*(unit+sw), mouseR*(unit+sw), unit+sw*2, unit+sw*2);
}
//touch way
if (touches.length > 0) {
circle(touches[0].x, touches[0].y, 10);
//find slot under the pointer
var mouseC = int(touches[0].x/(unit+sw));
var mouseR = int(touches[0].y/(unit+sw));
if (mouseC < cols && mouseR < rows) p[mouseC*cols + mouseR] = 1;
img.strokeWeight(0);
img.fill(255);
img.rect(mouseC*(unit+sw), mouseR*(unit+sw), unit+sw*2, unit+sw*2);
}
}
function submitForm(event) {
//TODO : first check if there is a drawing or not. (pixels)
//
var submit = document.getElementById("submit");
submit.setAttribute('disabled', 'disabled');
//
var form = document.getElementById("form");
var fd = new FormData(form);
//
var dataurl = img.elt.toDataURL();
var pixels = dataURLtoBlob(dataurl);
fd.append("pixels", pixels, "pixels.png");
for(var pair of fd.entries()) {
console.log(pair[0]+ ', '+ pair[1]);
}
//
var request = new XMLHttpRequest();
request.open("POST", "/entry");
request.send(fd);
//
event.preventDefault();
//
alert('감사합니다! Thank you!');
location.reload();
}
const form = document.getElementById('form');
form.addEventListener('submit', submitForm);

View file

@ -1,4 +0,0 @@
html,
body {
overflow: hidden;
}

View file

@ -1,238 +0,0 @@
// // force https
// var http_confirm = location.href.split(":")[0];
// if (http_confirm == "http") {
// window.location.replace("https://" + location.host);
// }
var socket = io(location.host);
var n = 0;
var fr = 20;
var arr = [];
var looper;
var score;
let logo;
var silence;
function preload() {
silence = loadSound("./audio/_silence.wav");
}
function setup() {
noCanvas();
if (windowWidth > 1500 && windowWidth > windowHeight) {
fr = 30;
} else {
fr = 20;
}
frameRate(fr);
}
//
var myroom = -1;
var intro;
var ready;
//
socket.on("connect", function() {
console.log("connected!");
//
//TESTING... fixed to room 1.
// myroom = 1;
if (myroom == -1 && selectAll(".roomsel").length == 0) {
//initial connection -> ask the room number.
intro = createP("《흐름을 향하여 걷는》 ...");
intro.style("font-size", windowHeight / 30 + "pt");
intro.class("intro");
var roomsel = createDiv();
roomsel.class("roomsel");
var b = createButton("시작하기!", 1);
b.mouseClicked(function() {
silence.play();
myroom = parseInt(this.value());
socket.emit("room", myroom, function(res) {
if (res) {
console.log("entered the room -> " + myroom);
createP(str(myroom));
// setTimeout(function() {
// ready = createP("퍼레이드 시작합니다!!");
// ready.position(
// windowWidth / 2 - windowWidth / 10,
// windowHeight / 2
// );
// }, 1000);
} else {
console.log("rejected!");
}
});
setTimeout(function() {
selectAll(".roomsel").forEach(function(item) {
item.remove();
});
selectAll(".intro").forEach(function(item) {
item.remove();
});
}, 1000);
});
roomsel.child(b);
} else {
//re-connection -> just connect to remembered room!
socket.emit("room", myroom, function(res) {
if (res) {
console.log("entered the room -> " + myroom);
} else {
console.log("rejected!");
}
});
}
});
socket.on("post", async function(post) {
console.log(post);
var resp = await new Promise((resolve, reject) => {
loadJSON("/entries", (json) => resolve(json));
})
console.log(resp.list);
// var object = post.object;
var object = {
"id": 1,
"type": "abc",
"src": "https://p.dianaband.info/public/sound-parade/" + resp.list[post] + "/pixels.png",
"audio": "https://p.dianaband.info/public/sound-parade/" + resp.list[post] + "/audio.mp3",
"alt": "알트",
"size": { "base": 40, "random": 20 },
"y": { "base": 20, "random": 10 },
"showtime": 30000
};
console.log(object);
var img = createImg(object.src, object.alt, "", function(im) {
var sound = loadSound(object.audio, function(snd) {
//로딩이 끝나면, play!
snd.loop();
//로딩이 끝나면, show!
im.show();
//그림의 크기와 초기 위치 ==> 가로 보기인 경우
var width = 0;
if (windowWidth > windowHeight) {
width = (windowHeight * (object.size.base * 1.4 + object.size.random * Math.random())) / 100; // 좀더 크게 + 40% (ratio)
im.size(width, AUTO);
im.position(
windowWidth * 1.5, // +150% 에서 생성되어서 접근 (sound fade-in)
(windowHeight * (object.y.base + object.y.random * Math.random()) * 0.5) / 100 // 좀더 위로 위로 - 50% (ratio)
);
//그림의 크기와 초기 위치 ==> 세로 보기인 경우
} else {
width = (windowHeight * (object.size.base + object.size.random * Math.random())) / 100; // json에서 정한 크기 그대로. (ratio)
im.size(width, AUTO);
im.position(
windowWidth * 1.5, // +150% 에서 생성되어서 접근 (sound fade-in)
(windowHeight * (object.y.base + object.y.random * Math.random())) / 100 // json에서 정한 위치 그대로. (ratio)
);
}
//추가 정보들
im.attribute("data-type", object.type);
im.attribute("data-showtime", object.showtime / 1000); //milli-sec. -> seconds.
//'아이콘' 들은 애니메이션을 시켜줘야 함...
if (object.type == "icon") {
//
im.class("rotate");
im.style("animation-duration", object.rotate + "s");
var orgs = im.style("transform-origin").split(" ");
var str = parseFloat(orgs[0]) + object.pivot.x + "px";
str = str + " " + parseFloat(orgs[1]) + object.pivot.y + "px";
im.style("transform-origin", str);
//
}
//로딩이 다 되면, rendering array에 추가.
var bundle = {
ref: object,
img: im,
sound: snd,
width: width
};
arr.push(bundle);
});
});
//첨에는 hide
img.hide();
});
function draw() {
for (var i = arr.length - 1; i >= 0; i -= 1) {
var bundle = arr[i];
var img = bundle.img;
var showtime = parseFloat(img.attribute("data-showtime"));
var type = img.attribute("data-type");
var x = img.position().x;
var y = img.position().y;
y = y + random(-1, 1);
x = x - windowWidth / (fr * showtime);
//
if (type == "icon") {
img.style("z-index", "-1");
}
3;
img.position(x, y);
var pan = (x / windowWidth) * 2 - 1;
//panning
var snd = bundle.sound;
if (x >= -bundle.width && x < windowWidth) {
pan = ((x + bundle.width) / (windowWidth + bundle.width)) * 2 - 1;
snd.pan(pan);
snd.setVolume(1);
} else {
var range;
var knob;
if (x >= windowWidth) {
range = windowWidth / 2;
knob = x - windowWidth;
snd.pan(1);
snd.setVolume(1 - knob / range);
} else if (x < -bundle.width) {
range = windowWidth / 2;
knob = (x + bundle.width) * -1;
snd.pan(-1);
snd.setVolume(1 - knob / range);
}
}
//remove at -50% (sound fade-out)
var exit_x = -bundle.width - windowWidth/2;
if (x < exit_x) {
img.remove();
snd.stop();
delete snd;
arr.splice(i, 1);
}
}
}
// function randomvoiceplay() {
// (looper = function(timeout) {
// setTimeout(function() {
// voice[int(random(19))].play();
// looper(random(8000, 12000));
// }, timeout);
// })(8000);
// }

125
server.js
View file

@ -57,94 +57,48 @@ fastify.get("/", function (request, reply) {
reply.view("/src/pages/parade.html", {});
});
//get '/entry', '/entry/'
["/entry", "/entry/"].forEach(function(item) {
fastify.get(item, function (request, reply) {
reply.view("/src/pages/entry.html", {});
//get '/entry', '/entry/', '/en/entry', '/en/entry/'
["/entry", "/entry/", "/en/entry", "/en/entry/"].forEach(function(item) {
fastify.get(item, async function (request, reply) {
//console.log(request.url);
let url = request.url.replace(/\/$/, '');
//get list
let list = await fs.readdir('/media/storage/public/sound-parade/');
list.reverse();
// console.log(list);
let folders = [];
for (const item of list) {
var fields = JSON.parse((await fs.readFile('/media/storage/public/sound-parade/' + item + '/fields.json')).toString('utf8'));
folders.push({
foldername: item,
group: fields.group,
title: fields.title,
comment: fields.comment,
});
}
// console.log(folders);
//
if (url == "/entry") {
reply.view("/src/pages/entry.html", {
list: folders,
});
} else if (url == "/en/entry") {
reply.view("/src/pages/entry.en.html", {
list: folders,
});
}
});
});
// --> https://stackoverflow.com/a/40899275
// all the regex didn't work for me -- a 'last resort' method
//get '/submit', '/submit/'
["/submit", "/submit/"].forEach(function(item) {
fastify.get(item, function (request, reply) {
reply.view("/src/pages/submit.html", {});
});
});
//get '/en/entry', '/en/entry/'
["/en/entry", "/en/entry/"].forEach(function(item) {
fastify.get(item, function (request, reply) {
reply.view("/src/pages/entry.en.html", {});
});
});
//get '/en/submit', '/en/submit/'
["/en/submit", "/en/submit/"].forEach(function(item) {
fastify.get(item, function (request, reply) {
reply.view("/src/pages/submit.en.html", {});
});
});
//get '/list', '/list/'
["/list", "/list/"].forEach(function(item) {
fastify.get(item, async function (request, reply) {
//get list
let list = await fs.readdir('/media/storage/public/sound-parade/');
list.reverse();
// console.log(list);
let folders = [];
for (const item of list) {
var fields = JSON.parse((await fs.readFile('/media/storage/public/sound-parade/' + item + '/fields.json')).toString('utf8'));
folders.push({
foldername: item,
group: fields.group,
title: fields.title,
comment: fields.comment,
});
}
// console.log(folders);
reply.view("/src/pages/list.html", {
list: folders,
});
});
});
//get '/en/list', '/en/list/'
["/en/list", "/en/list/"].forEach(function(item) {
fastify.get(item, async function (request, reply) {
//get list
let list = await fs.readdir('/media/storage/public/sound-parade/');
list.reverse();
// console.log(list);
let folders = [];
for (const item of list) {
var fields = JSON.parse((await fs.readFile('/media/storage/public/sound-parade/' + item + '/fields.json')).toString('utf8'));
folders.push({
foldername: item,
group: fields.group,
title: fields.title,
comment: fields.comment,
});
}
// console.log(folders);
reply.view("/src/pages/list.en.html", {
list: folders,
});
});
});
//get '/entries'
fastify.get("/entries", async function (request, reply) {
@ -180,11 +134,6 @@ fastify.get("/delete/:foldername/:pass", async function (request, reply) {
reply.send({ result: res });
});
// //get '/folder:foldername'
// fastify.get("/folder/:foldername", async function (request, reply) {
// reply.send({ foldername: foldername });
// });
//post on '/entry'
fastify.post("/entry", async function (request, reply) {

View file

@ -5,6 +5,20 @@
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>Walking Towards the Flow | entry</title>
<link rel="stylesheet" href="/default.css" />
<style>
#defaultCanvas0 {
display: block;
}
.but {
display: block;
}
img {
width: 100%;
max-width: 500px;
}
</style>
<link rel="stylesheet" href="/entry.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
@ -47,7 +61,7 @@
</p>
<p>
Parade Composition<br/>
Flock0 promises — Flock1 flags — Flock2 bodies — Flock3 objects — Flock4 Whoness
Flock0 promises — Flock1 flags — Flock2 bodies — Flock3 objects — Flock4 someone
</p>
<p>
Inquiry<br/>
@ -61,9 +75,9 @@
<li>1. Record the sound for about 30 seconds with a recording device or phone according to the characteristics of the flock.
<ol class="category">
<li>• Flock1 flags — Speak out five times about what you like or value.</li>
<li>• Flock2 bodies —Record the sound of your body. Applause and whistling.</li>
<li>• Flock3 objects — find the sound of things around you. Bubble wrap sound, Beads sound.</li>
<li>Whoness —Collect the sound of others. animal, sound of water, place to take a walk.</li>
<li>• Flock2 bodies — Record the sound of your body. Applause and whistling.</li>
<li>• Flock3 objects — Find the sound of things around you. Bubble wrap sound, Beads sound.</li>
<li>Flock4 someone — Collect the sound of others. animal, sound of water, place to take a walk.</li>
</ol>
</li>
<li>2. Upload the recorded sound file.</li>
@ -74,21 +88,23 @@
<h2>Sound Submission</h2>
<form id="form" method="POST" enctype="multipart/form-data">
<ul class="submit">
<h3>1. Sound Type</h3>
<ul>
<li>
<input type="radio" name="group" autocomplete="off" value="flag" /> Flock1 flags
</li>
<li>
<input type="radio" name="group" autocomplete="off" value="body" /> Flock2 bodies
</li>
<li>
<input type="radio" name="group" autocomplete="off" value="object" /> Flock3 objects
</li>
<li>
<input type="radio" name="group" autocomplete="off" value="any" required /> Flock4 Whoness
</li>
</ul>
<li>
<h3>1. Sound Type</h3>
<ul>
<li>
<input type="radio" name="group" autocomplete="off" value="flag" /> Flock1 flags
</li>
<li>
<input type="radio" name="group" autocomplete="off" value="body" /> Flock2 bodies
</li>
<li>
<input type="radio" name="group" autocomplete="off" value="object" /> Flock3 objects
</li>
<li>
<input type="radio" name="group" autocomplete="off" value="any" required /> Flock4 someone
</li>
</ul>
</li>
<li>
<h3>2. Sound File</h3>
<input type="file" name="audiofile" autocomplete="off" required />
@ -108,7 +124,7 @@
</div>
</li>
<li>
<h3>6. passward 2 numbers. It's required if you delete it.</h3>
<h3>6. passward is 2-digit numbers. It's required if you delete it.</h3>
<input id="pass" name="pass" type="text" maxlength="2" pattern="^\d{2}$" title="암호는 숫자x2개로 해주세요." required />
</li>
<li>
@ -117,6 +133,25 @@
</ul>
</form>
</section>
<section>
<h2>Sound &nbsp;List</h2>
{{#each list}}
<div class="items" foldername="{{this.foldername}}">
<details>
<summary><img class="drawing" src="https://p.dianaband.info/public/sound-parade/{{this.foldername}}/pixels.png" /></summary>
<audio class="sound" preload="none" controls>
<source src="https://p.dianaband.info/public/sound-parade/{{this.foldername}}/audio.mp3" type="audio/mpeg">
</audio>
<ul class="soundinfo"><hr>
<li>Group | <div class="group">{{this.group}}</div></li><hr>
<li>Title | <div class="title">{{this.title}}</div></li><hr>
<li>Desc. | <div class="comment">{{this.comment}}</div></li><hr>
</ul>
<button class="delete" type="button" onclick="del(this)">Delete</button>
</details>
</div>
{{/each}}
</section>
</div><!-- div class="notice" -->
</div><!-- div class="content" -->
<script>
@ -219,6 +254,7 @@
//
var submit = document.getElementById("submit");
submit.setAttribute('disabled', 'disabled');
select("html").style('cursor', 'progress');
//
var form = document.getElementById("form");
@ -238,8 +274,8 @@
request.open("POST", "/entry");
request.onload = () => {
alert('Thank you!');
//location.reload();
location.assign("/en/submit");
location.reload();
//location.assign("/en/submit");
}
request.send(fd);
@ -249,6 +285,37 @@
const form = document.getElementById('form');
form.addEventListener('submit', submitForm);
//// ---- for 'list' rendering ----
function del(that) {
console.log();
let text;
let pass = prompt("Please enter password!", "2-digit numbers");
if (/^\d{2}$/.test(pass)) {
var target = that.parentElement.parentElement.getAttribute('foldername');
const trydelete = async () => {
const response = await fetch('/delete/' + target + '/' + pass);
if (response.ok) {
const json = await response.json();
return Promise.resolve(json);
} else {
return Promise.reject('no response.');
}
}
trydelete().then((resp) => {
if (resp.result) {
alert("Delete Success!");
location.reload();
} else {
alert("Delete Failed-");
}
}).catch(console.log);
} else {
alert("Reminder: Password was 2-digit numbers...");
}
}
</script>
</body>
</html>

View file

@ -5,6 +5,20 @@
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>흐름을 향하여 걷는 | 소개</title>
<link rel="stylesheet" href="/default.css" />
<style>
#defaultCanvas0 {
display: block;
}
.but {
display: block;
}
img {
width: 100%;
max-width: 500px;
}
</style>
<link rel="stylesheet" href="/entry.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
@ -122,7 +136,23 @@
</form>
</section>
<section>
<h2><a href="/list">소리 목록</a></h2>
<h2>소리 목록</h2>
{{#each list}}
<div class="items" foldername="{{this.foldername}}">
<details>
<summary><img class="drawing" src="https://p.dianaband.info/public/sound-parade/{{this.foldername}}/pixels.png" /></summary>
<audio class="sound" preload="none" controls>
<source src="https://p.dianaband.info/public/sound-parade/{{this.foldername}}/audio.mp3" type="audio/mpeg">
</audio>
<ul class="soundinfo"><hr>
<li>유형 | <div class="group">{{this.group}}</div></li><hr>
<li>제목 | <div class="title">{{this.title}}</div></li><hr>
<li>묘사 | <div class="comment">{{this.comment}}</div></li><hr>
</ul>
<button class="delete" type="button" onclick="del(this)">삭제</button>
</details>
</div>
{{/each}}
</section>
</div><!-- div class="notice" -->
</div><!-- div class="content" -->
@ -226,6 +256,7 @@
//
var submit = document.getElementById("submit");
submit.setAttribute('disabled', 'disabled');
select("html").style('cursor', 'progress');
//
var form = document.getElementById("form");
@ -245,8 +276,8 @@
request.open("POST", "/entry");
request.onload = () => {
alert('감사합니다!');
//location.reload();
location.assign("/submit");
location.reload();
//location.assign("/submit");
}
request.send(fd);
@ -256,6 +287,36 @@
const form = document.getElementById('form');
form.addEventListener('submit', submitForm);
//// ---- for 'list' rendering ----
function del(that) {
console.log();
let text;
let pass = prompt("Please enter password!", "숫자2개");
if (/^\d{2}$/.test(pass)) {
var target = that.parentElement.parentElement.getAttribute('foldername');
const trydelete = async () => {
const response = await fetch('/delete/' + target + '/' + pass);
if (response.ok) {
const json = await response.json();
return Promise.resolve(json);
} else {
return Promise.reject('no response.');
}
}
trydelete().then((resp) => {
if (resp.result) {
alert("지우기 성공!");
location.reload();
} else {
alert("지우기 실패-");
}
}).catch(console.log);
} else {
alert("암호는 숫자2개...");
}
}
</script>
</body>
</html>

View file

@ -1,68 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Walking Towards the Flow | list</title>
<link rel="stylesheet" href="/default.css" />
<link rel="stylesheet" href="/list.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@500&display=swap" rel="stylesheet" />
</head>
<body>
<div class="bg"></div>
<div class="popup"></div>
<div class="content">
<div class="first"><a href="/list">KR</a></div>
<div class="content" id="list">
<div class="second"><a href="/">Home</a></div>
<div class="content" id="list">
<div class="notice">
<h1>Sound &nbsp;List</h1>
{{#each list}}
<div class="items" foldername="{{this.foldername}}">
<img class="drawing" src="https://p.dianaband.info/public/sound-parade/{{this.foldername}}/pixels.png" />
<div class="group">{{this.group}}</div>
<div class="title">{{this.title}}</div>
<div class="comment">{{this.comment}}</div>
<audio class="sound" preload="none" controls>
<source src="https://p.dianaband.info/public/sound-parade/{{this.foldername}}/audio.mp3" type="audio/mpeg">
</audio>
<button class="delete" type="button" onclick="del(this)">삭제x</button>
</div>
{{/each}}
</div>
</div>
<script>
function del(that) {
console.log();
let text;
let pass = prompt("Please enter password!", "숫자2개");
if (/^\d{2}$/.test(pass)) {
var target = that.parentElement.getAttribute('foldername');
const trydelete = async () => {
const response = await fetch('/delete/' + target + '/' + pass);
if (response.ok) {
const json = await response.json();
return Promise.resolve(json);
} else {
return Promise.reject('no response.');
}
}
trydelete().then((resp) => {
if (resp.result) {
alert("지우기 성공!");
location.reload();
} else {
alert("지우기 실패-");
}
}).catch(console.log);
} else {
alert("암호는 숫자2개...");
}
}
</script>
</body>
</html>

View file

@ -1,71 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>흐름을 향하여 걷는 | 소리 목록</title>
<link rel="stylesheet" href="/default.css" />
<link rel="stylesheet" href="/list.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@500&display=swap" rel="stylesheet" />
</head>
<body>
<div class="bg"></div>
<div class="popup"></div>
<div class="content">
<div class="first"><a href="/en/list">EN</a></div>
<div class="second"><a href="/"></a></div>
<div class="content" id="list">
<div class="notice">
<h1>소리 &nbsp;목록</h1>
{{#each list}}
<div class="items" foldername="{{this.foldername}}">
<details>
<summary><img class="drawing" src="https://p.dianaband.info/public/sound-parade/{{this.foldername}}/pixels.png" /></summary>
<audio class="sound" preload="none" controls>
<source src="https://p.dianaband.info/public/sound-parade/{{this.foldername}}/audio.mp3" type="audio/mpeg">
</audio>
<ul class="soundinfo"><hr>
<li>유형 | <div class="group">{{this.group}}</div></li><hr>
<li>제목 | <div class="title">{{this.title}}</div></li><hr>
<li>묘사 | <div class="comment">{{this.comment}}</div></li><hr>
</ul>
<button class="delete" type="button" onclick="del(this)">삭제</button>
</details>
</div>
{{/each}}
</div>
</div>
<script>
function del(that) {
console.log();
let text;
let pass = prompt("Please enter password!", "숫자2개");
if (/^\d{2}$/.test(pass)) {
var target = that.parentElement.getAttribute('foldername');
const trydelete = async () => {
const response = await fetch('/delete/' + target + '/' + pass);
if (response.ok) {
const json = await response.json();
return Promise.resolve(json);
} else {
return Promise.reject('no response.');
}
}
trydelete().then((resp) => {
if (resp.result) {
alert("지우기 성공!");
location.reload();
} else {
alert("지우기 실패-");
}
}).catch(console.log);
} else {
alert("암호는 숫자2개...");
}
}
</script>
</body>
</html>

View file

@ -5,14 +5,260 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>흐름을 향하여 걷는</title>
<link rel="stylesheet" href="/default.css" />
<link rel="stylesheet" href="/parade.css" />
<style>
html,
body {
overflow: hidden;
}
</style>
<script src="/js/p5-v1.1.9.min.js"></script>
<script src="/js/socket-v2.3.0.io.slim.js"></script>
<script src="/js/p5-v0.3.11.sound.min.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@500&display=swap" rel="stylesheet" />
<script src="/parade.js"></script>
<script>
// // force https
// var http_confirm = location.href.split(":")[0];
// if (http_confirm == "http") {
// window.location.replace("https://" + location.host);
// }
var socket = io(location.host);
var n = 0;
var fr = 20;
var arr = [];
var looper;
var score;
let logo;
var silence;
var clap;
function preload() {
silence = loadSound("./audio/_silence.wav");
clap = loadSound("./audio/clap01.mp3");
}
function setup() {
noCanvas();
if (windowWidth > 1500 && windowWidth > windowHeight) {
fr = 30;
} else {
fr = 20;
}
frameRate(fr);
}
//
var myroom = -1;
var intro;
var ready;
//
socket.on("connect", function() {
console.log("connected!");
//
//TESTING... fixed to room 1.
// myroom = 1;
if (myroom == -1 && selectAll(".roomsel").length == 0) {
//initial connection -> ask the room number.
var roomsel = createDiv();
roomsel.class("roomsel");
var b = createButton("시작하기!", 1);
b.mouseClicked(function() {
silence.play();
clap.play();
myroom = parseInt(this.value());
socket.emit("room", myroom, function(res) {
if (res) {
console.log("entered the room -> " + myroom);
createP(str(myroom));
// setTimeout(function() {
// ready = createP("퍼레이드 시작합니다!!");
// ready.position(
// windowWidth / 2 - windowWidth / 10,
// windowHeight / 2
// );
// }, 1000);
} else {
console.log("rejected!");
}
});
setTimeout(() => {
selectAll(".roomsel").forEach(item => {
item.remove();
// 1 second popup '.intro' div
intro = createDiv("«흐름을 향하여 걷는»은 온라인 공간에 소리의 행렬을 만드는 사운드 퍼레이드입니다. 누구나 참여할 수 있는 이 퍼레이드는 여러분이 보내주시는 소리가 모여 만들어집니다.<br>소리가 들리지 않는다면, 볼륨을 확인해주시고, 스마트폰 환경에서는 진동해제해주세요. <br><br> «Walking Toward the Flow» is a sound parade that creates a procession of sounds in the online space. Anyone can participate. This parade is made by collecting the sounds you sent.<br>If there is no sound, check the volume and turn off the vibration in the smartphone environment.");
intro.class("notice intro"); //-> fadeout & disapear by css animation style.
});
}, 1000);
});
roomsel.child(b);
} else {
//re-connection -> just connect to remembered room!
socket.emit("room", myroom, function(res) {
if (res) {
console.log("entered the room -> " + myroom);
} else {
console.log("rejected!");
}
});
}
});
var fading_factor = 0.2; //20%
//var fading_factor = 0.5; //50%
socket.on("post", async function(post) {
console.log(post);
var resp = await new Promise((resolve, reject) => {
loadJSON("/entries", (json) => resolve(json));
})
console.log(resp.list);
// var object = post.object;
var object = {
"id": 1,
"type": "abc",
"src": "https://p.dianaband.info/public/sound-parade/" + resp.list[post] + "/pixels.png",
"audio": "https://p.dianaband.info/public/sound-parade/" + resp.list[post] + "/audio.mp3",
"alt": "알트",
"size": { "base": 40, "random": 20 },
"y": { "base": 20, "random": 10 },
"showtime": 20000
};
console.log(object);
var img = createImg(object.src, object.alt, "", function(im) {
var sound = loadSound(object.audio, function(snd) {
//로딩이 끝나면, play!
snd.loop();
//로딩이 끝나면, show!
im.show();
//그림의 크기와 초기 위치 ==> 가로 보기인 경우
var width = 0;
if (windowWidth > windowHeight) {
width = (windowHeight * (object.size.base * 1.4 + object.size.random * Math.random())) / 100; // 좀더 크게 + 40% (ratio)
im.size(width, AUTO);
im.position(
windowWidth * (1 + fading_factor),
(windowHeight * (object.y.base + object.y.random * Math.random()) * 0.5) / 100 // 좀더 위로 위로 - 50% (ratio)
);
//그림의 크기와 초기 위치 ==> 세로 보기인 경우
} else {
width = (windowHeight * (object.size.base + object.size.random * Math.random())) / 100; // json에서 정한 크기 그대로. (ratio)
im.size(width, AUTO);
im.position(
windowWidth * (1 + fading_factor),
(windowHeight * (object.y.base + object.y.random * Math.random())) / 100 // json에서 정한 위치 그대로. (ratio)
);
}
//추가 정보들
im.attribute("data-type", object.type);
im.attribute("data-showtime", object.showtime / 1000); //milli-sec. -> seconds.
//'아이콘' 들은 애니메이션을 시켜줘야 함...
if (object.type == "icon") {
//
im.class("rotate");
im.style("animation-duration", object.rotate + "s");
var orgs = im.style("transform-origin").split(" ");
var str = parseFloat(orgs[0]) + object.pivot.x + "px";
str = str + " " + parseFloat(orgs[1]) + object.pivot.y + "px";
im.style("transform-origin", str);
//
}
//로딩이 다 되면, rendering array에 추가.
var bundle = {
ref: object,
img: im,
sound: snd,
width: width
};
arr.push(bundle);
});
});
//첨에는 hide
img.hide();
});
function draw() {
for (var i = arr.length - 1; i >= 0; i -= 1) {
var bundle = arr[i];
var img = bundle.img;
var showtime = parseFloat(img.attribute("data-showtime"));
var type = img.attribute("data-type");
var x = img.position().x;
var y = img.position().y;
y = y + random(-1, 1);
x = x - windowWidth / (fr * showtime);
//
if (type == "icon") {
img.style("z-index", "-1");
}
3;
img.position(x, y);
var pan = (x / windowWidth) * 2 - 1;
//panning
var snd = bundle.sound;
if (x >= -bundle.width && x < windowWidth) {
pan = ((x + bundle.width) / (windowWidth + bundle.width)) * 2 - 1;
snd.pan(pan);
snd.setVolume(1);
} else {
var range;
var knob;
if (x >= windowWidth) {
range = windowWidth * fading_factor
knob = x - windowWidth;
snd.pan(1);
snd.setVolume(1 - knob / range);
} else if (x < -bundle.width) {
range = windowWidth * fading_factor
knob = (x + bundle.width) * -1;
snd.pan(-1);
snd.setVolume(1 - knob / range);
}
}
//remove with sound fade-out
var exit_x = -bundle.width - windowWidth*fading_factor;
if (x < exit_x) {
img.remove();
snd.stop();
delete snd;
arr.splice(i, 1);
}
}
}
// function randomvoiceplay() {
// (looper = function(timeout) {
// setTimeout(function() {
// voice[int(random(19))].play();
// looper(random(8000, 12000));
// }, timeout);
// })(8000);
// }
</script>
</head>
<body>
<div class="bg"></div>

View file

@ -1,36 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Walking Towards the Flow | entry</title>
<link rel="stylesheet" href="/default.css" />
<link rel="stylesheet" href="/entry.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@500&display=swap" rel="stylesheet" />
</head>
<body>
<div class="bg"></div>
<div class="notice">
<section>
<h1>Walking &nbsp;Towards &nbsp;the Flow</h1>
<p>
Submission complete!
</p>
<div class="content">
<div class="sub">
<a href="/en/entry">≪ ENTRY</a>
</div>
<div class="list2">
<a href="/en/list">▤ LIST</a>
</div>
<div class="parade">
<a href="/" target="_blank">PARADE ≫</a>
</div>
</div>
</section>
</div>
</body>
</html>

View file

@ -1,36 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>흐름을 향하여 걷는 | 입장</title>
<link rel="stylesheet" href="/default.css" />
<link rel="stylesheet" href="/entry.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@500&display=swap" rel="stylesheet" />
</head>
<body>
<div class="bg"></div>
<div class="notice">
<section>
<h1>흐름을 &nbsp;향하여 &nbsp;걷는</h1>
<p>
제출되었습니다
</p>
<div class="content">
<div class="sub">
<a href="/entry">≪ 소리 모집</a>
</div>
<div class="list2">
<a href="/list">▤ 소리 목록</a>
</div>
<div class="parade">
<a href="/" target="_blank">퍼레이드 ≫</a>
</div>
</div>
</section>
</div>
</body>
</html>