merge parade.html + entry.html

This commit is contained in:
Dooho Yi 2022-11-12 20:57:23 +09:00
parent 3e704559f5
commit 43d96b53b8
5 changed files with 755 additions and 290 deletions

View file

@ -10,27 +10,27 @@ You'll get best use out of this project if you're familiar with basic JavaScript
## What's in this project? ## What's in this project?
`README.md`: Thats this file, where you can tell people what your cool website does and how you built it. ← README.md: Thats this file, where you can tell people what your cool website does and how you built it.
`public/style.css`: The styling rules for the pages in your site. ← public/style.css: The styling rules for the pages in your site.
`server.js`: The **Node.js** server script for your new site. The JavaScript defines the endpoints in the site back-end, one to return the homepage and one to update with the submitted color. Each one sends data to a Handlebars template which builds these parameter values into the web page the visitor sees. ← server.js: The **Node.js** server script for your new site. The JavaScript defines the endpoints in the site back-end, one to return the homepage and one to update with the submitted color. Each one sends data to a Handlebars template which builds these parameter values into the web page the visitor sees.
`package.json`: The NPM packages for your project's dependencies. ← package.json: The NPM packages for your project's dependencies.
`src/`: This folder holds the site template along with some basic data files. ← src/: This folder holds the site template along with some basic data files.
`src/pages/index.hbs`: This is the main page template for your site. The template receives parameters from the server script, which it includes in the page HTML. The page sends the user submitted color value in the body of a request, or as a query parameter to choose a random color. ← src/pages/index.hbs: This is the main page template for your site. The template receives parameters from the server script, which it includes in the page HTML. The page sends the user submitted color value in the body of a request, or as a query parameter to choose a random color.
`src/colors.json`: A collection of CSS color names. We use this in the server script to pick a random color, and to match searches against color names. ← src/colors.json: A collection of CSS color names. We use this in the server script to pick a random color, and to match searches against color names.
`src/seo.json`: When you're ready to share your new site or add a custom domain, change SEO/meta settings in here. ← src/seo.json: When you're ready to share your new site or add a custom domain, change SEO/meta settings in here.
## Try this next 🏗️ ## Try this next 🏗️
Take a look in `TODO.md` for next steps you can try out in your new site! Take a look in TODO.md for next steps you can try out in your new site!
___Want a minimal version of this project to build your own Node.js app? Check out [Blank Node](https://glitch.com/edit/#!/remix/glitch-blank-node)!___ *__Want a minimal version of this project to build your own Node.js app? Check out__* [*__Blank Node__*](https://glitch.com/edit/#!/remix/glitch-blank-node)*__!__*
![Glitch](https://cdn.glitch.com/a9975ea6-8949-4bab-addb-8a95021dc2da%2FLogo_Color.svg?v=1602781328576) ![Glitch](https://cdn.glitch.com/a9975ea6-8949-4bab-addb-8a95021dc2da%2FLogo_Color.svg?v=1602781328576)
@ -38,5 +38,5 @@ ___Want a minimal version of this project to build your own Node.js app? Check o
[Glitch](https://glitch.com) is a friendly community where millions of people come together to build web apps and websites. [Glitch](https://glitch.com) is a friendly community where millions of people come together to build web apps and websites.
- Need more help? [Check out our Help Center](https://help.glitch.com/) for answers to any common questions. * Need more help? [Check out our Help Center](https://help.glitch.com/) for answers to any common questions.
- Ready to make it official? [Become a paid Glitch member](https://glitch.com/pricing) to boost your app with private sharing, more storage and memory, domains and more. * Ready to make it official? [Become a paid Glitch member](https://glitch.com/pricing) to boost your app with private sharing, more storage and memory, domains and more.

View file

@ -62,6 +62,18 @@ body {
height: 100%; height: 100%;
} }
.parade {
position: relative;
width: 100%;
height: 100%;
}
.entry {
position: relative;
width: 100%;
height: 100%;
}
.lang { .lang {
position: fixed; position: fixed;
top: 20px; top: 20px;
@ -71,7 +83,7 @@ body {
} }
.first { .first {
position: fixed; position: absolute;
top: 20px; top: 20px;
right: 18px; right: 18px;
z-index: 2; z-index: 2;
@ -79,7 +91,7 @@ body {
} }
.second { .second {
position: fixed; position: absolute;
top: 20px; top: 20px;
right: 40px; right: 40px;
z-index: 2; z-index: 2;
@ -87,7 +99,7 @@ body {
} }
.third { .third {
position: fixed; position: absolute;
top: 20px; top: 20px;
right: 60px; right: 60px;
z-index: 2; z-index: 2;
@ -110,11 +122,11 @@ audio {
left: 50%; left: 50%;
text-align: center; text-align: center;
} }
.parade { /* .parade {
position: fixed; position: fixed;
bottom: 15px; bottom: 15px;
right: 20px; right: 20px;
} } */
.list-sub { .list-sub {
position: fixed; position: fixed;
top: 36px; top: 36px;
@ -301,7 +313,7 @@ details summary::-webkit-details-marker {
.roomsel button { .roomsel button {
position: absolute; position: absolute;
bottom: 50px; bottom: 80px;
left: 50%; left: 50%;
transform: translate(-50%); transform: translate(-50%);
} }
@ -361,7 +373,7 @@ summary {
.intro { .intro {
top: 40%; top: 35%;
transform: translate(-50%); transform: translate(-50%);
} }
@ -374,8 +386,8 @@ button {
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -30%); transform: translate(-50%, -65%);
height: 600px; /* height: 600px; */
writing-mode: vertical-lr; writing-mode: vertical-lr;
} }

View file

@ -53,8 +53,39 @@ var io = require("socket.io")(fastify.server, {
}); });
//get '/' //get '/'
fastify.get("/", function (request, reply) { fastify.get("/", async function (request, reply) {
reply.view("/src/pages/parade.html", {}); //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) {
let json = await fs.readFile('/media/storage/public/sound-parade/' + item + '/fields.json')
.catch((err) => {
console.error(err);
});
if (json != undefined) {
var fields = JSON.parse(json.toString('utf8'));
folders.push({
foldername: item,
group: fields.group,
title: fields.title,
comment: fields.comment,
});
}
}
// console.log(folders);
//
reply.view("/src/pages/parade.html", {
list: folders,
});
}); });
//get '/live //get '/live

View file

@ -47,31 +47,45 @@
<section> <section>
<h1>흐름을 &nbsp;향하여 &nbsp;걷는</h1> <h1>흐름을 &nbsp;향하여 &nbsp;걷는</h1>
<p> <p>
퍼레이드를 행렬 밖에서 바라본 적이 있나요? 북소리와 함성소리가 멀리서 들리고, 많은 존재들이 외치고, 흐르듯 지나가고, 무리가 등장하고, 멀어지는...... 《흐름을 향하여 걷는》은 사운드 퍼레이드가 열리는 온라인 공간입니다.
</p> </p>
<p> <p>
«흐름을 향하여 걷는»은 온라인 공간에 소리의 행렬을 만드는 사운드 퍼레이드입니다. 누구나 참여할 수 있는 이 퍼레이드는 여러분이 보내주시는 소리가 모여 만들어집니다. 퍼레이드가 진행되는 이 곳, <a href="https://walkingtowardstheflow.xyz">walkingtowardstheflow.xyz</a>는 누구나 소리를 업로드하고 감상할 수 있는 사운드 피드(feed)이자 소리의 행렬이 지나는 길이기도 합니다. 이는 각자의 시공간에 흩어져 살아가는 우리가 고개를 잠깐 돌리기만 하면 함께 걸을 수 있는 흐름이 아주 가까운 곳에 있음을 말합니다.
</p> </p>
<p> <p>
«흐름을 향하여 걷는»은 총 다섯 개의 소리 무리로 이루어집니다. 약속하는 소리들, 말하는 소리들, 몸이 내는 소리들, 주변의 사물들, 그리고 누군가의 소리들이 무리를 지어 각 3분 내외 총 15분 가량 흘러가게 됩니다. 《흐름을 향하여 걷는》은 오프라인 공연으로 함께 하실 수도 있습니다. 11월 27일(일) 공연 당일에는 웹사이트에 모인 소리들이 물리적 공간에 펼쳐집니다. 이 공연은 함께 걷고 멈추며, 흐름에 공감해 주신 분들의 소리를 듣는 참여형 공연입니다.
</p> </p>
<p> <p>
1월 27일(목) 밤, «흐름을 향하여 걷는» 퍼레이드는 라이브 공연과 함께 ‘사유의 밤’ 행사에서 송출될 예정입니다. ‘사유의 밤’은 주한 프랑스대사관 문화과, 주한 리스트 헝가리 문화원, 주한 벨기에 대사관이 주최하고, 유네스코 한국위원회와 프랑스 해외문화진흥원이 후원하여 개최됩니다. 소리는 본질적으로 공기를 진동하는 에너지이며, 이 진동은 우리의 고막 뿐 아니라 온 몸과 피부를 온통 진동하는 촉각적인 접촉입니다. 우리는 소리들의 부드러운 접촉을 통해 그 소리의 발신자들이 부드럽게 우리의 손을 잡아 퍼레이드로 초대하고 있다는 것을 어렵지 않게 눈치챌 수 있습니다.
많은 참여 및 관심 부탁드립니다.
</p> </p>
<p>
소리가 흐르는 길은 영혼이 회귀하는 저 광맥과 같이, 별들이 순회하는 저 은하수와 같이, 언제나 그 자리에 있으면서 당신이 소리를 듣고 있든 그렇지 않든 무관하게 흐르고 있습니다.
</p>
<p>
당신은 혼자이지만 언제나 원하는 순간에 이 흐름을 향해 걸어 들어올 수 있으며, 당신이 원한다면 함께 걷고, 따라걷고, 멈춰서서 바라보고, 당신의 소리, 당신의 만지는 손길들을 이 흐름에 띄워 보낼 수도 있습니다. 우리는 그렇게 손을 잡을 수 있습니다.
</p>
<p>
이 영원한 퍼레이드의 영속성은 우리에게 최후의 안도를 줍니다. 때로는 자신이 위성궤도를 무한히 돌고 있는 우주 부스러기(debris)라는 생각이 들다가도, 그것이 관측되는 순간 더는 외롭거나 잊혀짐이 아니라 기억됨이 됩니다.
</p>
<p>
소리 모집에 많은 참여 부탁드립니다.<br>
*혐오표현은 《흐름을 향하여 걷는》에 모인 사람들이 보호해야 할 표현의 자유에 포함되지 않으므로 삭제될 수 있습니다.
</p>
<br>
<div class="info"> <div class="info">
<p> <p>
소리 모집<br/> 소리 모집<br/>
2022년 1월 17일(월)2022년 1월 26일(수) 2022년 11월 13일(일)2022년 11월 26일(토)
</p> </p>
<p> <p>
라이브 공연<br/> 퍼포먼스<br/>
2022년 1월 27일(목)<br> 2022년 11월 27일(일), 16:00
20:45-21:00 (KST), 12:45-13:00 (CET)<br/>
</p> </p>
<p> <p>
장소<br/> 장소<br/>
<a href="https://walkingtowardstheflow.xyz">walkingtowardstheflow.xyz</a><br><a href="https://www.youtube.com/c/franceencoree">주한프랑스대사관 문화과 유튜브 채널</a> <a
서울시립미술관 서소문본관 1층 로비, 2층 러닝스테이션, 옥상정원
</p> </p>
<p> <p>
작가<br/> 작가<br/>

View file

@ -1,295 +1,703 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>흐름을 향하여 걷는</title> <title>흐름을 향하여 걷는</title>
<link rel="stylesheet" href="/default.css" /> <link rel="stylesheet" href="/default.css" />
<style> <style>
html, html,
body { body {
overflow: hidden; overflow-x: 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/Tone-14.8.36.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" />
</head>
<body> #defaultCanvas0 {
<div class="bg"></div> display: block;
<div class="content"> }
</div>
<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); .clear {
var n = 0; display: block;
var fr = 20; }
var arr = [];
var looper;
var score;
var logo;
var silence;
var clap;
//promisify -> new Tone.Player img {
function AudioImport(url) { width: 100%;
return new Promise((resolve, reject) => { max-width: 500px;
var audio = new Tone.Player(url, () => resolve(audio)); }
});
}
async function setup() { #p5 {
noCanvas(); display: inline-block;
if (windowWidth > 1500 && windowWidth > windowHeight) { }
fr = 30;
} else {
fr = 20;
}
frameRate(fr);
//p5 'draw()' doesn't work if user is not looking at the tab. .tools {
noLoop(); padding: 1em 1em;
// --> use custom looper. display: inline-block;
} vertical-align: top;
}
// .penselect {
var myroom = -1; margin: 1em 0em;
var intro; }
var ready; </style>
// <script src="/js/p5-v1.1.9.min.js"></script>
socket.on("connect", async function() { <script src="/js/socket-v2.3.0.io.slim.js"></script>
console.log("connected!"); <script src="/js/Tone-14.8.36.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" />
</head>
// <body>
silence = (await AudioImport("./audio/_silence.wav")).toDestination(); <div class="bg"></div>
clap = (await AudioImport("./audio/clap01.mp3")).toDestination(); <div class="parade"></div>
<div class="entry">
<div class="first"><a href="/en/entry">EN</a></div>
<div class="second"><a href="/" target="_blank">퍼레이드</a></div>
<div class="notice">
<section>
<h1>흐름을 &nbsp;향하여 &nbsp;걷는</h1>
<p>
《흐름을 향하여 걷는》은 사운드 퍼레이드가 열리는 온라인 공간입니다.
</p>
<p>
퍼레이드가 진행되는 이 곳, <a href="https://walkingtowardstheflow.xyz">walkingtowardstheflow.xyz</a>는 누구나 소리를 업로드하고 감상할 수 있는 사운드 피드(feed)이자 소리의 행렬이 지나는 길이기도 합니다. 이는 각자의 시공간에 흩어져 살아가는 우리가 고개를 잠깐 돌리기만 하면 함께 걸을 수 있는 흐름이 아주 가까운 곳에 있음을 말합니다.
</p>
<p>
《흐름을 향하여 걷는》은 오프라인 공연으로 함께 하실 수도 있습니다. 11월 27일(일) 공연 당일에는 웹사이트에 모인 소리들이 물리적 공간에 펼쳐집니다. 이 공연은 함께 걷고 멈추며, 흐름에 공감해 주신 분들의 소리를 듣는 참여형 공연입니다.
</p>
<p>
소리는 본질적으로 공기를 진동하는 에너지이며, 이 진동은 우리의 고막 뿐 아니라 온 몸과 피부를 온통 진동하는 촉각적인 접촉입니다. 우리는 소리들의 부드러운 접촉을 통해 그 소리의 발신자들이 부드럽게 우리의 손을 잡아 퍼레이드로 초대하고 있다는 것을 어렵지 않게 눈치챌 수 있습니다.
</p>
<p>
소리가 흐르는 길은 영혼이 회귀하는 저 광맥과 같이, 별들이 순회하는 저 은하수와 같이, 언제나 그 자리에 있으면서 당신이 소리를 듣고 있든 그렇지 않든 무관하게 흐르고 있습니다.
</p>
<p>
당신은 혼자이지만 언제나 원하는 순간에 이 흐름을 향해 걸어 들어올 수 있으며, 당신이 원한다면 함께 걷고, 따라걷고, 멈춰서서 바라보고, 당신의 소리, 당신의 만지는 손길들을 이 흐름에 띄워 보낼 수도 있습니다. 우리는 그렇게 손을 잡을 수 있습니다.
</p>
<p>
이 영원한 퍼레이드의 영속성은 우리에게 최후의 안도를 줍니다. 때로는 자신이 위성궤도를 무한히 돌고 있는 우주 부스러기(debris)라는 생각이 들다가도, 그것이 관측되는 순간 더는 외롭거나 잊혀짐이 아니라 기억됨이 됩니다.
</p>
<p>
소리 모집에 많은 참여 부탁드립니다.<br />
*혐오표현은 《흐름을 향하여 걷는》에 모인 사람들이 보호해야 할 표현의 자유에 포함되지 않으므로 삭제될 수 있습니다.
</p>
<br>
<div class="info">
<p>
소리 모집<br />
2022년 11월 13일(일)2022년 11월 26일(토)
</p>
<p>
퍼포먼스<br />
2022년 11월 27일(일), 16:00
</p>
<p>
장소<br />
서울시립미술관 서소문본관 1층 로비, 2층 러닝스테이션, 옥상정원
</p>
<p>
작가<br />
<a href="https://dianaband.info" target="_blank">다이애나밴드</a> X <a href="https://cgyoon.kr/"
target="_blank">윤충근</a> (문의: wonjung24@gmail.com)
</p>
<p>
퍼레이드 구성<br />
무리0 약속들 — 무리1 깃발들 — 무리2 신체들 — 무리3 사물들 — 무리4 누구들
</p>
</div>
</section>
<section class="participation">
<h1>참여 방법</h1>
<ol>
<li>1. 무리의 특성에 따라 녹음기기나 핸드폰으로 30초 가량의 소리를 녹음해주세요.
<ol class="category">
<li>• 무리1 깃발들 — 좋아하는 것, 가치에 대해 다섯 번 외쳐주세요.</li>
<li>• 무리2 신체들 — 몸에서 나는 소리를 녹음해 보아요. 박수, 휘파람도 좋아요.</li>
<li>• 무리3 사물들 — 주변 사물들의 소리를 찾아 주세요. 뽁뽁이 소리, 구슬 소리</li>
<li>• 무리4 누구들 — 누구의 소리를 모아주세요. 반려동물, 물 소리, 산책의 장소</li>
</ol>
</li>
<li>2. 녹음한 소리 파일을 업로드해주세요.</li>
<li>3. 소리의 제목과 묘사을 입력한 뒤, 소리의 모양을 그려 제출해주세요.</li>
</ol>
</section>
<section>
<h1>소리 제출</h1>
<form id="form" method="POST" enctype="multipart/form-data">
<ul class="submit">
<li>
<h3>1. 소리 유형</h3>
<ul>
<li>
<input type="radio" name="group" autocomplete="off" value="flag" /> 무리1 깃발들
</li>
<li>
<input type="radio" name="group" autocomplete="off" value="body" /> 무리2 신체들
</li>
<li>
<input type="radio" name="group" autocomplete="off" value="object" /> 무리3 사물들
</li>
<li>
<input type="radio" name="group" autocomplete="off" value="any" required /> 무리4 누구들
</li>
</ul>
</li>
<li>
<h3>2. 소리 파일</h3>
<input type="file" name="audiofile" autocomplete="off" required />
</li>
<li>
<h3>3. 소리 제목</h3>
<input id="title" name="title" type="text" autocomplete="off" required />
</li>
<li>
<h3>4. 소리 묘사</h3>
<input id="comment" name="comment" type="text" autocomplete="off" required />
</li>
<!-- pixels.png ~ made with p5.js -->
<li class="noscroll">
<h3>5. 소리 모양</h3>
<div>
<div id="p5">
</div>
<div class="tools">
<div>
<input class="penselect" type="radio" value="pencil" name="penselect" id="penselect-pencil"
autocomplete="off" checked>
<label for="penselect-pencil">연필</label>
</div>
<div>
<input class="penselect" type="radio" value="erasor" name="penselect" id="penselect-erasor"
autocomplete="off">
<label for="penselect-erasor">지우개</label>
</div>
</div>
</div>
<button type="button" class="clear">다시그리기!</button>
</li>
<li>
<h3>6. 비밀 번호</h3>
<input id="pass" name="pass" type="text" maxlength="2" pattern="^\d{2}$" title="암호는 숫자x2개로 해주세요."
required />
<small>두 자리 숫자를 입력해주세요. 업로드한 소리를 삭제할 때 쓰입니다.</small>
</li>
<li>
<input id="submit" type="submit" value="보내기!" />
</li>
</ul>
<p>
↓ 
</p>
</form>
</section>
<section>
<h1>소리 목록</h1>
<p>제출해주신 소리는 아래 목록에 시간순으로 쌓입니다. 각각의 모양을 클릭하면, 모양에 해당하는 소리를 듣고 소리에 대한 정보를 확인할 수 있습니다.</p>
{{#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="preview" type="button"
onclick="javascript:window.open('/preview/{{this.foldername}}', '_blank');">미리보기</button>
<button class="delete" type="button" onclick="del(this)">삭제</button>
</details>
</div>
{{/each}}
</section>
</div><!-- div class="notice" -->
</div><!-- div class="entry" -->
//TESTING... fixed to room 1. <script>
// myroom = 1; // // force https
// var http_confirm = location.href.split(":")[0];
// if (http_confirm == "http") {
// window.location.replace("https://" + location.host);
// }
if (myroom == -1 && selectAll(".roomsel").length == 0) { var socket = io(location.host);
//initial connection -> ask the room number. var n = 0;
var fr = 20;
var arr = [];
var looper;
var score;
var logo;
var silence;
var clap;
var roomsel = createDiv(); //promisify -> new Tone.Player
roomsel.class("roomsel"); function AudioImport(url) {
var b = createButton("시작하기 Start!", 1); return new Promise((resolve, reject) => {
var d = createDiv("<a href='/entry'>흐름을&nbsp; 향하여&nbsp; 걷는 &nbsp;&nbsp;Walking towards the Flow</a>"); var audio = new Tone.Player(url, () => resolve(audio));
d.class("title"); });
b.mouseClicked(function() { }
silence.start();
clap.start();
myroom = parseInt(this.value());
socket.emit("room", myroom, function(res) { //**ENTRY begin >>>
if (res) { // -- https://stackoverflow.com/a/39577640
console.log("entered the room -> " + myroom); function dataURLtoBlob(dataURL) {
createP(str(myroom)); let array, binary, i, len;
// setTimeout(function() { binary = atob(dataURL.split(",")[1]);
// ready = createP("퍼레이드 시작합니다!!"); array = [];
// ready.position( i = 0;
// windowWidth / 2 - windowWidth / 10, len = binary.length;
// windowHeight / 2 while (i < len) {
// ); array.push(binary.charCodeAt(i));
// }, 1000); i++;
} else { }
console.log("rejected!"); return new Blob([new Uint8Array(array)], {
} type: "image/png",
}); });
}
function submitForm(event) {
setTimeout(() => { //TODO : first check if there is a drawing or not. (pixels)
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(d);
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.3; //30% //
var fading_factor = 0.5; //50% var submit = document.getElementById("submit");
socket.on("post", async function(post) { submit.setAttribute('disabled', 'disabled');
select("html").style('cursor', 'progress');
console.log(post); //
var list = await new Promise((resolve, reject) => { var form = document.getElementById("form");
loadJSON("/entries", (json) => resolve(json)); var fd = new FormData(form);
})
console.log(list);
// var object = post.object; //
var object = { var unit = 45; //mask&override 'unit' -> for crispy png.
"id": 1, var img2 = createGraphics(cols * unit + 2, rows * unit + 2);
"type": "abc", img2.clear();
"src": "https://p.dianaband.info/public/sound-parade/" + list[post] + "/pixels.png", img2.strokeWeight(0);
"audio": "https://p.dianaband.info/public/sound-parade/" + list[post] + "/audio.mp3", img2.fill(255);
"alt": "알트", for (var c = 0; c < cols; c++) {
"size": { for (var r = 0; r < rows; r++) {
"base": 40, if (p[c * cols + r] == 1) {
"random": 20 img2.rect(c * unit + 1, r * unit + 1, unit, unit);
}, }
"y": { }
"base": 20, }
"random": 10 var dataurl = img2.elt.toDataURL();
}, var pixels = dataURLtoBlob(dataurl);
"showtime": 20000 fd.append("pixels", pixels, "pixels.png");
};
console.log(object);
var img = createImg(object.src, object.alt, "", async function(im) { for (var pair of fd.entries()) {
//로딩이 끝나면, start! console.log(pair[0] + ', ' + pair[1]);
var pv = new Tone.PanVol(0, -99).toDestination(); }
var snd = await AudioImport(object.audio); // NOTE: url with spaces didn't work here.
snd.connect(pv).start();
snd.loop = true;
//로딩이 끝나면, show! //
im.show(); var request = new XMLHttpRequest();
request.open("POST", "/entry");
request.onload = () => {
alert('감사합니다!');
location.reload();
//location.assign("/submit");
}
request.send(fd);
//그림의 크기와 초기 위치 ==> 가로 보기인 경우 //
var width = 0; event.preventDefault();
if (windowWidth > windowHeight) { }
width = (windowHeight * (object.size.base * 1.4 + object.size.random * Math.random())) / 100; // 좀더 크게 + 40% (ratio) const form = document.getElementById('form');
im.size(width, AUTO); form.addEventListener('submit', submitForm);
im.position( //// ---- for 'list' rendering ----
windowWidth * (1 + fading_factor),
(windowHeight * (object.y.base + object.y.random * Math.random()) * 0.5) / 100 // 좀더 위로 위로 - 50% (ratio)
);
//그림의 크기와 초기 위치 ==> 세로 보기인 경우 function del(that) {
} else { console.log();
let text;
let pass = prompt("패스워드를 맞춰보세요!", "숫자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개...");
}
}
width = (windowHeight * (object.size.base + object.size.random * Math.random())) / 100; // json에서 정한 크기 그대로. (ratio) var p = [];
im.size(width, AUTO); var cols = 17;
var rows = 17;
var unit = 15; //px
var img;
var penselect = "pencil";
var scrollable = true;
// <<< end of **ENTRY
im.position( async function setup() {
windowWidth * (1 + fading_factor),
(windowHeight * (object.y.base + object.y.random * Math.random())) / 100 // json에서 정한 위치 그대로. (ratio)
);
}
//추가 정보들 //**PARADE
im.attribute("data-type", object.type); noCanvas();
im.attribute("data-showtime", object.showtime / 1000); //milli-sec. -> seconds. if (windowWidth > 1500 && windowWidth > windowHeight) {
fr = 30;
} else {
fr = 20;
}
frameRate(fr);
//'아이콘' 들은 애니메이션을 시켜줘야 함... //p5 'draw()' doesn't work if user is not looking at the tab.
if (object.type == "icon") { //noLoop(); // <-- BUT, we want 1 for ENTRY graphics!
// // --> use custom looper.
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에 추가. //**ENTRY
var bundle = { var cnv = createCanvas(cols * unit + 2, rows * unit + 2);
ref: object, cnv.parent("p5");
img: im, img = createGraphics(cols * unit + 2, rows * unit + 2);
sound: snd, document.querySelectorAll('.penselect').forEach(item => item.onclick = () => {
panvol: pv, penselect = document.querySelector('input[name="penselect"]:checked').value;
width: width });
}; //
arr.push(bundle); for (var i = 0; i < cols * rows; i++) p.push(0);
}); document.querySelectorAll('.clear').forEach(item => item.onclick = () => {
for (let a = 0; a < p.length; a++) p[a] = 0;
});
}
//첨에는 hide //**ENTRY begin >>>
img.hide(); function draw() {
//clear
clear();
}); //draw the grid
stroke(255);
strokeWeight(0.2);
for (var c = 0; c < cols; c++) {
for (var r = 0; r < rows; r++) {
noFill();
rect(c * unit + 1, r * unit + 1, unit, unit);
}
}
//p5 'draw()' doesn't work if user is not looking at the tab. //pointer
// --> custom looper is ok. fill(0, 255, 0);
var looper; strokeWeight(0);
(looper = function(timeout) {
setTimeout(async function() {
// //mouse way
for (var i = arr.length - 1; i >= 0; i -= 1) { circle(mouseX, mouseY, 10);
var bundle = arr[i]; if (mouseIsPressed && mouseButton === LEFT) {
var img = bundle.img; //find slot under the pointer
var showtime = parseFloat(img.attribute("data-showtime")); var mouseC = int(mouseX / unit);
var type = img.attribute("data-type"); var mouseR = int(mouseY / unit);
var x = img.position().x; if (mouseC >= 0 && mouseC < cols && mouseR >= 0 && mouseR < rows) {
var y = img.position().y; if (penselect == "pencil") p[mouseC * cols + mouseR] = 1;
y = y + random(-1, 1); else if (penselect == "erasor") p[mouseC * cols + mouseR] = 0;
x = x - windowWidth / (fr * showtime); }
}
// //touch way
if (type == "icon") { if (touches.length > 0) {
img.style("z-index", "-1"); circle(touches[0].x, touches[0].y, 10);
} //find slot under the pointer
3; var mouseC = int(touches[0].x / unit);
var mouseR = int(touches[0].y / unit);
if (mouseC >= 0 && mouseC < cols && mouseR >= 0 && mouseR < rows) {
// if (scrollable == true) {
// scrollable = false;
// // firefox browser @ my android phone -> url bar auto-hiding kills drawing experience.
// // --> https://stackoverflow.com/a/63221105
// document.body.style.marginTop = `-${window.pageYOffset}px`;
// document.body.style.position = 'fixed';
// document.body.style.overflowY = 'scroll';
// }
if (penselect == "pencil") p[mouseC * cols + mouseR] = 1;
else if (penselect == "erasor") p[mouseC * cols + mouseR] = 0;
} else {
// if (scrollable == false) {
// scrollable = true;
// // firefox browser @ my android phone -> url bar auto-hiding kills drawing experience.
// // --> https://stackoverflow.com/a/63221105
// document.body.style.position = '';
// document.body.style.overflowY = '';
// if (document.body.style.marginTop) {
// const scrollTop = -parseInt(document.body.style.marginTop, 10);
// document.body.style.marginTop = '';
// window.scrollTo(window.pageXOffset, scrollTop);
// }
// }
}
}
img.position(x, y); //draw img
var pan = (x / windowWidth) * 2 - 1; image(img, 0, 0);
img.clear();
img.strokeWeight(0);
img.fill(255);
for (var c = 0; c < cols; c++) {
for (var r = 0; r < rows; r++) {
if (p[c * cols + r] == 1) {
img.rect(c * unit + 1, r * unit + 1, unit, unit);
}
}
}
}
// <<< end of **ENTRY
//panning //
var snd = bundle.sound; var myroom = -1;
var pv = bundle.panvol; var intro;
if (x >= -bundle.width && x < windowWidth) { var ready;
pan = ((x + bundle.width) / (windowWidth + bundle.width)) * 2 - 1; //
pv.pan.value = pan; socket.on("connect", async function () {
pv.volume.value = 0;//(dB) console.log("connected!");
} else {
var range;
var knob;
if (x >= windowWidth) {
range = windowWidth * fading_factor
knob = x - windowWidth;
pv.pan.value = 1;
pv.volume.value = knob / range * -20;
} else if (x < -bundle.width) {
range = windowWidth * fading_factor
knob = (x + bundle.width) * -1;
pv.pan.value = -1;
pv.volume.value = knob / range * -20;
}
}
//remove with sound fade-out //
var exit_x = -bundle.width - windowWidth * fading_factor; silence = (await AudioImport("./audio/_silence.wav")).toDestination();
if (x < exit_x) { clap = (await AudioImport("./audio/clap01.mp3")).toDestination();
img.remove();
snd.stop();
delete snd;
delete pv;
arr.splice(i, 1);
}
}
//
looper(1000/fr); //TESTING... fixed to room 1.
}, timeout); // myroom = 1;
})(1000/fr);
if (myroom == -1 && selectAll(".roomsel").length == 0) {
//initial connection -> ask the room number.
var roomsel = createDiv();
selectAll(".parade")[0].child(roomsel);
roomsel.class("roomsel");
///
var b = createButton("시작하기 Start!", "1");
var d = createDiv("<a href='/entry'>흐름을&nbsp; 향하여&nbsp; 걷는 &nbsp;&nbsp;Walking towards the Flow</a>");
d.class("title");
b.mouseClicked(function () {
silence.start();
clap.start();
myroom = parseInt(this.value());
socket.emit("room", myroom, function (res) {
if (res) {
console.log("entered the room -> " + myroom);
// myroom-indicator
// var tag = createP(str(myroom));
// selectAll(".parade")[0].child(tag);
//
// 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(d);
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.3; //30%
var fading_factor = 0.5; //50%
socket.on("post", async function (post) {
console.log(post);
var list = await new Promise((resolve, reject) => {
loadJSON("/entries", (json) => resolve(json));
})
console.log(list);
// var object = post.object;
var object = {
"id": 1,
"type": "abc",
"src": "https://p.dianaband.info/public/sound-parade/" + list[post] + "/pixels.png",
"audio": "https://p.dianaband.info/public/sound-parade/" + 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, "", async function (im) {
//로딩이 끝나면, start!
var pv = new Tone.PanVol(0, -99).toDestination();
var snd = await AudioImport(object.audio); // NOTE: url with spaces didn't work here.
snd.connect(pv).start();
snd.loop = true;
//로딩이 끝나면, 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,
panvol: pv,
width: width
};
arr.push(bundle);
});
//첨에는 hide
img.hide();
});
//p5 'draw()' doesn't work if user is not looking at the tab.
// --> custom looper is ok.
var looper;
(looper = function (timeout) {
setTimeout(async function () {
//
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;
var pv = bundle.panvol;
if (x >= -bundle.width && x < windowWidth) {
pan = ((x + bundle.width) / (windowWidth + bundle.width)) * 2 - 1;
pv.pan.value = pan;
pv.volume.value = 0;//(dB)
} else {
var range;
var knob;
if (x >= windowWidth) {
range = windowWidth * fading_factor
knob = x - windowWidth;
pv.pan.value = 1;
pv.volume.value = knob / range * -20;
} else if (x < -bundle.width) {
range = windowWidth * fading_factor
knob = (x + bundle.width) * -1;
pv.pan.value = -1;
pv.volume.value = knob / range * -20;
}
}
//remove with sound fade-out
var exit_x = -bundle.width - windowWidth * fading_factor;
if (x < exit_x) {
img.remove();
snd.stop();
delete snd;
delete pv;
arr.splice(i, 1);
}
}
//
looper(1000 / fr);
}, timeout);
})(1000 / fr);
// function randomvoiceplay() { // function randomvoiceplay() {
// (looper = function(timeout) { // (looper = function(timeout) {
@ -299,7 +707,7 @@
// }, timeout); // }, timeout);
// })(8000); // })(8000);
// } // }
</script> </script>
</body> </body>
</html> </html>