diff --git a/src/bg-eyecandy/css/parallax-bg.css b/src/bg-eyecandy/css/parallax-bg.css index c72f2b1dcd0905b17fb71b1088c3239f221a3a97..02cb65a5c499fe138e7f8f32eca783e6f302bb58 100644 --- a/src/bg-eyecandy/css/parallax-bg.css +++ b/src/bg-eyecandy/css/parallax-bg.css @@ -1,23 +1,20 @@ html { - min-height: 100vh; -} + min-height: 100vh; } body { height: 100%; - position: relative; -} + position: relative; } .eyecandy-parallax header, .eyecandy-full header { position: fixed; width: 100%; z-index: 1; - overflow: hidden; -} + overflow: hidden; } + .eyecandy-parallax main, .eyecandy-full main { margin-top: 16em; mask-image: linear-gradient(180deg, transparent 0em, transparent 320px, black 360px); - mask-position-y: -480px; -} + mask-position-y: -480px; } .rc3-bg-L01 { background-image: url("img/01_FG_Pixels_still.gif"); @@ -28,8 +25,7 @@ body { right: 0; bottom: 0; position: absolute; - z-index: -6; -} + z-index: -6; } .rc3-bg-L03 { background-image: url("img/RC3_vignette.png"); @@ -40,64 +36,54 @@ body { background-repeat: no-repeat; background-size: 100% 100%; height: 100vh; - width: 100vw; -} + width: 100vw; } .rc3-bg-L05-collages { -position: absolute; -height: 100%; width: 100%; - z-index: -5; -} + z-index: -5; } .rc3-bg-L05-container { position: relative; - background-image: url("img/RC3_vignette_debug.png"); -} + background-image: url("img/RC3_vignette_debug.png"); } .rc3-bg-L05-collages > * > * { background-image: url("img/05_collage_1_bust_vr-goggles_L_halfres_still_V01.png"); content: ""; background-repeat: no-repeat; opacity: 70%; - height: 300px; -} + height: 300px; } .rc3-bg-L05--googles-R { background-image: url("img/05_collage_1_bust_vr-goggles_L_halfres_still_V01.png"); height: 250px; width: 250px; position: absolute; - right: -125px; -} + right: -125px; } .rc3-bg-L05--hand-L { background-image: url("img/05_Collage_2_robothand_nib_L_halfres_still_V01.png"); height: 200px; width: 300px; position: absolute; - left: -100px; -} + left: -100px; } .rc3-bg-L05--baby-R { background-image: url("img/05_Collage_3_baby_ethernet_R_halfres_still_V01.png"); height: 300px; width: 300px; position: absolute; - right: -150px; -} + right: -150px; } .rc3-bg-L05--pos-1 { - top: 20vh; -} + top: 20vh; } .rc3-bg-L05--pos-2 { - top: 80vh; -} + top: 80vh; } .rc3-bg-L05--pos-3 { - top: 140vh; -} + top: 140vh; } .rc3-bg-L06 { background-image: url("img/06_BG_Pixels_still.gif"); @@ -109,8 +95,7 @@ body { right: 0; bottom: 0; position: absolute; - z-index: -6; -} + z-index: -6; } .rc3-bg-L07 { background-image: url("img/07_Grid.png"); @@ -122,8 +107,7 @@ body { height: 100%; height: 100vh; width: 100%; - width: 100vw; -} + width: 100vw; } .rc3-bg-L08 { background-image: url("img/08_VCR_Overlay.png"); @@ -135,8 +119,7 @@ body { height: 100%; height: 100vh; width: 100%; - width: 100vw; -} + width: 100vw; } .rc3-bg-L09 { background-image: linear-gradient(to left top, #f035e8, #4d7ffa); @@ -145,9 +128,8 @@ body { right: 0; bottom: 0; position: absolute; - z-index: -9; - mix-blend-mode: color; -} + z-index: -09; + mix-blend-mode: color; } .rc3-bg-L10 { background-image: url("img/10_Background_desktop_01.jpg"); @@ -158,24 +140,22 @@ body { position: fixed; z-index: -10; height: 105%; - width: 100%; -} + width: 100%; } .eyecandy-full .rc3-bg-L01 { - background-image: url("img/01_FG_Pixels.gif"); -} + background-image: none; } + .eyecandy-full .rc3-bg-L06 { - background-image: url("img/06_BG_Pixels.gif"); -} + background-image: none; } + .eyecandy-full .rc3-bg-L05--googles-R { - background-image: url("img/05_collage_1_bust_vr-goggles_L_halfres_ani_V01.gif"); -} + background-image: url("img/05_collage_1_bust_vr-goggles_L_halfres_ani_V01.gif"); } + .eyecandy-full .rc3-bg-L05--hand-L { - background-image: url("img/05_Collage_2_robothand_nib_L_halfres_ani_V01.gif"); -} + background-image: url("img/05_Collage_2_robothand_nib_L_halfres_ani_V01.gif"); } + .eyecandy-full .rc3-bg-L05--baby-R { - background-image: url("img/05_Collage_3_baby_ethernet_R_halfres_ani_V01.gif"); -} + background-image: url("img/05_Collage_3_baby_ethernet_R_halfres_ani_V01.gif"); } #debug { position: fixed; @@ -185,5 +165,4 @@ body { height: 2em; width: 50%; background-color: white; - color: black; -} + color: black; } diff --git a/src/bg-eyecandy/css/parallax-bg.scss b/src/bg-eyecandy/css/parallax-bg.scss index 0b22315c8a13a0c933c36bc72a70d74977a4809e..9d74e46b8a8d2bbf3475ee3f100211524afd0ce3 100644 --- a/src/bg-eyecandy/css/parallax-bg.scss +++ b/src/bg-eyecandy/css/parallax-bg.scss @@ -188,11 +188,13 @@ $gradient-yellowgreen: #b2ff7c; .eyecandy-full { .rc3-bg-L01 { - background-image: url("img/01_FG_Pixels.gif"); + // use js particles + background-image: none; } // BG-Pixel .rc3-bg-L06 { - background-image: url("img/06_BG_Pixels.gif"); + // use js particles + background-image: none; } .rc3-bg-L05--googles-R { diff --git a/src/bg-eyecandy/index.html b/src/bg-eyecandy/index.html index e602a5d0c9bfc6b9e90b1ab6a7c234e7ede9c4ab..f299ea2e3499a1b772355b42069e88039db3ca1d 100644 --- a/src/bg-eyecandy/index.html +++ b/src/bg-eyecandy/index.html @@ -1,42 +1,120 @@ <!DOCTYPE html> -<html class="js" lang="de"><head> -<meta http-equiv="content-type" content="text/html; charset=UTF-8"> - <meta charset="utf-8"> - <link rel="stylesheet" href="css/rc3.css"> - <link rel="stylesheet" href="css/parallax-bg.css"> - <link rel="icon" href="http://localhost:8000/static/plainui/img/favicon.ico" type="image/x-icon"> - <title>Remote Chaos Experience - Event Boiling Mind</title> - <meta name="viewport" content="width=device-width, initial-scale=1"> - - <script> - document.addEventListener('DOMContentLoaded', (e) => { - document.querySelector('html').classList.remove('no-js'); - document.querySelector('html').classList.add('js'); - initParallax() - }); - </script> - - </head> - <!-- +<html class="js" lang="de"> + +<head> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <meta charset="utf-8"> + <link rel="stylesheet" href="css/rc3.css"> + <link rel="stylesheet" href="css/parallax-bg.css"> + <link rel="icon" href="http://localhost:8000/static/plainui/img/favicon.ico" type="image/x-icon"> + <title>Remote Chaos Experience - Event Boiling Mind</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <script src="particles.js"></script> + <script> + document.addEventListener('DOMContentLoaded', (e) => { + document.querySelector('html').classList.remove('no-js'); + document.querySelector('html').classList.add('js'); + initParallax(); + initParticles(); + }); + + function initParticles() { + const body = document.querySelector('body'); + if (!body.classList.contains('eyecandy-full')) { + return; + } + var fgParticleConfig = { + scene: { + // Id of the canvas to render to + canvasId: 'fg-particles', + // Id of the content container, we're using it to get the + // rendering height and it's the anchor to get the y offset + // to simulate scrolling. + contentId: 'content', + fps: 24, + depth: 2.5, + }, + particles: { + amount: 50, + color: 'white', + size: 40, + speed: 0.5, + lifespan: 12000 // in milliseconds + } + } + var bgParticleConfig = { + scene: { + // Id of the canvas to render to + canvasId: 'bg-particles', + // Id of the content container, we're using it to get the + // rendering height and it's the anchor to get the y offset + // to simulate scrolling. + contentId: 'content', + fps: 16, + depth: 0.08, + }, + particles: { + amount: 150, + color: 'white', + size: 7, + speed: 0.2, + lifespan: 8000 // in milliseconds + } + } + + var animation = Particles([ + fgParticleConfig, + bgParticleConfig, + ]) + animation.run() + window.addEventListener('resize', animation.onScreenSizeChange) + } + </script> + <style> + .static { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100vh; + } + + .full-bg { + width: 100%; + height: 100vh; + background-size: 100% 100%; + background-repeat: no-repeat; + background-position: center center; + content: ""; + } + </style> +</head> +<!-- css-classes: - eyecandy - eyecandy-parallax - eyecandy-full --> - <body class="eyecandy-parallax"> - <div class=""> -<div class="rc3-bg-L10"></div> -<div class="rc3-bg-L09"></div> -<div class="rc3-bg-L08"></div> -<div class="rc3-bg-L07"></div> -<div class="rc3-bg-L06"></div> -<div class="rc3-bg-L05-collages "> - <div class="container rc3-bg-L05-container"> - <div class="rc3-bg-L05--googles-R rc3-bg-L05--pos-1"></div> - <div class="rc3-bg-L05--hand-L rc3-bg-L05--pos-2"></div> - <!--<div class="rc3-bg-L05-collage--03-baby"></div>--> - </div> -</div> + +<body class="eyecandy-full"> + <div class=""> + + + <div class="rc3-bg-L10"></div> + <div class="rc3-bg-L09"></div> + <div class="rc3-bg-L08"></div> + <div class="rc3-bg-L07"></div> + <div class="rc3-bg-L06"></div> + <canvas id="bg-particles" class="static full-bg particles"></canvas> + <div class="rc3-bg-L05-collages "> + <div class="container rc3-bg-L05-container"> + <div class="rc3-bg-L05--googles-R rc3-bg-L05--pos-1"></div> + <div class="rc3-bg-L05--hand-L rc3-bg-L05--pos-2"></div> + <!--<div class="rc3-bg-L05-collage--03-baby"></div>--> + </div> + </div> <ul class="sr-only"> <li> @@ -53,314 +131,375 @@ -<header id="header" > -<!-- Had to add an extra div for centering --> - <div class="rc3-header container mb-3 mt-6"> - <a class="rc3-logo" href="http://localhost:8000/index"> - <img src="02a_Logo_web_200px_still.png" alt="Remote Chaos Experience logo" title="Remote Chaos Experience logo"> -</a> - <nav class="rc3-header__main"> - <a class="btn btn-transparent rc3-header__main-linkbox" href="http://localhost:8000/world" title="world"> - world - </a> - <a class="btn btn-transparent rc3-header__main-linkbox" href="http://localhost:8000/index" title="Plattform"> - Plattform - </a> - <a class="btn btn-transparent rc3-header__main-linkbox" href="http://localhost:8000/static/start/" title="info"> - info - </a> - <form class="rc3-header__main-search input-group" method="POST" action="/search" role="search"> - <input type="hidden" name="csrfmiddlewaretoken" value="TSp4QUYtpnFaqqxPB1Hk1lOw5IS1aYyQfKO00clnOhI3YYmnKSClK3Jt6btj7dkQ"> - <input class="form-control col rc3-header__main-search-input" name="q" type="text" placeholder="suchen"> - <button class="rc3-header__main-search-btn input-group-append btn btn-transparent"> - <svg width="1em" height="1em" viewBox="0 0 16 16" class=" bi bi-search" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> - <title>suchen</title> - <path fill-rule="evenodd" d="M10.442 10.442a1 1 0 0 1 1.415 0l3.85 3.85a1 1 0 0 1-1.414 1.415l-3.85-3.85a1 1 0 0 1 0-1.415z"></path> - <path fill-rule="evenodd" d="M6.5 12a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM13 6.5a6.5 6.5 0 1 1-13 0 6.5 6.5 0 0 1 13 0z"></path> - </svg> - </button> - </form> - </nav> - <div class="rc3-header__additional"> - <a class="btn rc3-header__additional-linkbox btn-transparent" href="http://localhost:8000/me" title="Profil"> - <figure class="rc3-avatar"> - - <img class="rc3-avatar__none" src="rc3-no-avatar-plattform-active.jpeg" alt="Avatar Bild"> - - </figure> - </a> - <a class="btn rc3-header__additional-linkbox btn-transparent" href="http://localhost:8000/my_fahrplan"> - Mein Plan - </a> - <div class="rc3-header__additional-box-2x1"> - <a class="btn btn-transparent rc3-header__additional-linkbox" href="http://localhost:8000/logout" title="logout"> - logout - </a> - - <a class="btn rc3-header__additional-linkbox btn-transparent" href="http://localhost:8000/board" title="board"> - board - </a> - </div> - <a class="btn btn-block rc3-header__additional-linkbox btn-transparent" href="http://localhost:8000/pm/inbox" title="Messages"> - Nach richten - </a> - <a class="btn rc3-header__additional-linkbox btn-transparent" href="http://localhost:8000/fahrplan" title="Fahrplan"> - Fahr plan - </a> - - <form class="rc3-header__additional-box-2x1 rc3-header__nomob" method="POST" action="/modify_language"> - <input type="hidden" name="csrfmiddlewaretoken" value="bpLSLkPpJyxPJ9WkIGrpVXTaR9aJ0hrAxhaOVCcj8sAIhHLSRxmqEFO7SCL1XwdA"> - <input type="hidden" name="next" value="/event/rc3-11560-boiling_mind/"> - <button class="btn rc3-header__additional-button btn-transparent" name="language" value="de"> - de - </button> - <button class="btn rc3-header__additional-button btn-transparent" name="language" value="en"> - en - </button> - </form> - </div> -</div> - -</header> - - - -<main class="container" id="content"> - -<article class="mt-10 rc3-bg-image-01"> - <div class="row w-100 my-11"> - <div class="col"> - <h1 class="mb-xl-0" title="Boiling Mind">Boiling Mind</h1> - </div> - - <div class="col-sm-auto text-righ align-self-center"> - - <a href="http://localhost:8000/event/rc3-11560-boiling_mind/" class="ml-2 btn-icon-big btn btn-transparent" title="dies teilen" target="_blank"> - <svg width="1rem" height="1rem" viewBox="0 0 16 16" class="bi bi-share" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> - <path fill-rule="evenodd" d="M13.5 1a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zM11 2.5a2.5 2.5 0 1 1 .603 1.628l-6.718 3.12a2.499 2.499 0 0 1 0 1.504l6.718 3.12a2.5 2.5 0 1 1-.488.876l-6.718-3.12a2.5 2.5 0 1 1 0-3.256l6.718-3.12A2.5 2.5 0 0 1 11 2.5zm-8.5 4a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zm11 5.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3z"></path> - </svg> - </a> - - - - <form action="/modify_favorites" class="d-inline-block" method="POST"> - <input type="hidden" name="csrfmiddlewaretoken" value="bpLSxOKkhsIJlJP6k1O4PKcoexvmghezxhaOH67eGmLCThEEtSJ5ys7lf06Edw0z"> - <input type="hidden" name="next" value="/event/rc3-11560-boiling_mind/#fav_b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e"> - <input type="hidden" name="id" value="b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e"><input type="hidden" name="type" value="event"><input type="hidden" name="mode" value="add"> - <button type="submit" id="fav_b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e" class="ml-2 btn-icon-big btn btn-transparent" title="zu Favoriten hinzufügen"> - <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-heart" viewBox="0 0 16 16"> - <path fill-rule="evenodd" d="M8 2.748l-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01L8 2.748zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143c.06.055.119.112.176.171a3.12 3.12 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15z"></path> - </svg> - </button> - </form> - - - - <form action="/modify_personal_calendar" class="d-inline-block" method="POST"> - <input type="hidden" name="csrfmiddlewaretoken" value="CTcQzPH9yu3D51rLlYQTbCCR4iVBhJ7yYLBMJ743Xo6wDzgjuPLUUkxO5LwTeYTy"> - <input type="hidden" name="next" value="/event/rc3-11560-boiling_mind/#sch_b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e"> - <input type="hidden" name="id" value="b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e"><input type="hidden" name="mode" value="add"> - <button type="submit" id="sch_b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e" class="ml-2 btn-icon-big btn btn-transparent" title="zu Zeitplan hinzufügen"> - <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-calendar2-week" viewBox="0 0 16 16"> - <path fill-rule="evenodd" d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM2 2a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H2z"></path> - <path d="M2.5 4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5H3a.5.5 0 0 1-.5-.5V4zM11 7.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm-3 0a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm-5 3a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm3 0a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1z"></path> - </svg> - </button> - </form> - - - - - <a href="http://localhost:8000/report?kind=url&kind_data=/event/rc3-11560-boiling_mind/&next=/event/rc3-11560-boiling_mind/" class="ml-2 btn-icon-big btn btn-transparent" title="dies melden"> - <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-exclamation-diamond-fill" viewBox="0 0 16 16"> - <path fill-rule="evenodd" d="M9.05.435c-.58-.58-1.52-.58-2.1 0L.436 6.95c-.58.58-.58 1.519 0 2.098l6.516 6.516c.58.58 1.519.58 2.098 0l6.516-6.516c.58-.58.58-1.519 0-2.098L9.05.435zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"></path> - </svg> - </a> - - </div> - - </div> - - - - - <div class="rc3-event-info border border-1 border-white"> - <h3 class="flex-row align-items-center justify-content-center bg-info p-3 text-dark h3 mb-lg-0"> - Event Start: - 1 Woche, 1 Tag von jetzt an - </h3> - <h3 class="rc3-event-info__title-info flex-row align-items-center justify-content-center bg-info p-3 text-white h3 mb-lg-0">Event Information</h3> - <figure class="p-0 mb-lg-0"> - - <img class="w-100 d-block" src="rc3-assembly-event-04.png" alt="Boiling Mind" title="Boiling Mind"> - - </figure> - <dl class="grid-list mb-0"> - <dt class="grid-list__item grid-list__item--title">Zeit</dt> - <dd class="grid-list__item grid-list__item--text"> - - 27. Dezember 2021 13:00 - - - 27. Dezember 2021 13:40 - - - </dd> - <dt class="grid-list__item grid-list__item--title">Speaker</dt> - <dd class="grid-list__item grid-list__item--text"> - - Noch keine Speaker bekannt gegeben - - </dd> - <dt class="grid-list__item grid-list__item--title">Track</dt> - <dd class="grid-list__item grid-list__item--text"> - - Art & Culture - - </dd> - <dt class="grid-list__item grid-list__item--title">Sprache</dt> - <dd class="grid-list__item grid-list__item--text"> - - en - - </dd> - <dt class="grid-list__item grid-list__item--title">Raum</dt> - <dd class="grid-list__item grid-list__item--text"> - - <a href="http://localhost:8000/room/rc2/" title="rC2" class=""> - rC2 + <header id="header"> + <!-- Had to add an extra div for centering --> + <div class="rc3-header container mb-3 mt-6"> + <a class="rc3-logo" href="http://localhost:8000/index"> + <img src="02a_Logo_web_200px_still.png" alt="Remote Chaos Experience logo" + title="Remote Chaos Experience logo"> </a> - - </dd> - <dt class="grid-list__item grid-list__item--title">Host</dt> - <dd class="grid-list__item grid-list__item--text"> - - <a href="http://localhost:8000/assembly/ccc/">CCC</a> - - </dd> - </dl> - </div> - - <hr class="my-8"> - - <section class="rc3-markdown border bg-opaque p-3"><p>The role of -the audience in stage performances is changing from passive spectators -to contributors making the performance interactive by using different -techniques. In this talk, we investigate the connection of audience -physiological data to the experienced performance in three performance -events with a total of 98 participants. We identified memorable -performance moments by assessing, Electrodermal Activity (EDA) showing -that the audience’s responses match the choreographer’s intention. -Through Heart Rate Variability (HRV) features related to parasympathetic - activity, we identified dramatic shifts that are connected to the -choreographic development of the performance. Our results show how the -audience's physiological responses are linked to the choreographic -development of the performance. Based on the findings, we contribute a -discussion of the registered physiological phenomena and implications of - the audience’s responses analysis to performance and choreography -design in general. Furthermore, we walk through the dataset collected -from the performance events. </p> -<p>Each performance lives from the interplay between audience and -artists. Even if performers follow a precise script, each rendition is -different partly due to audience reactions. Performers often describe it - as an invisible link between then and the spectators, involving the -audience in co-creating art. </p> -<p>The stage design and described setup came out of a collaboration -between the performing artists, designers and researchers in a -semi-democratic process.</p> -<p>Both researchers and artists contributed to developing the concept -during the iterative process to balance research and artistic interests. - This process was mainly led by artists, especially the choreographer. -Besides the predetermined story and design, the choreographer also -created some improvisational sections where dancers could interact with -stage elements affected by audience physiological response.</p> -<p>The main contributions of this talk are as follows: -(1) We present the concept of "bringing the audience on stage" by -mapping physiological signals from audience members to stage elements to - amplify the connection between artists and the audience. We detail -information about the design process, focusing on sensing heart rate and - electrodermal activity (EDA), as well as how these signals are -translated to the onstage elements through sonification and -visualizations. -(2) We describe an open integrated wearable system that consists of a -wrist band, back-end processing, and output. Our proposed system enables - the capturing and translating of physiological signals into stage -design elements. -(3) We realized our proposed concept as a proof-of-concept with the -performance "Boiling Mind". The performance involved dancers, -choreographers, researchers, visual and sound designers in the process. -It was performed three times in front of an audience of 57, 37 and 45 -people. In each performance, around 30 audience members wore the -wearable wrist bands.</p> -<p>The hardware used for the performance piece as well as the data -recorded will be open sourced and will be made avaialable to download.</p></section> - - <hr class="my-8"> - - <aside class="row mx-0"> - <div class="col-12 col-lg-6 mb-5 mb-lg-0 d-flex flex-column flex-nowrap"> - <h4 class="h2 mb-5">Tags</h4> - - <div class="border flex-grow-1 px-6 pt-6 pb-5 d-flex flex-row flex-wrap justify-content-center align-items-center"> - <p class="my-6">Nicht getaggt.</p> - </div> - - </div> - <div class="col-12 col-lg-6 d-flex flex-column flex-nowrap"> - - <h4 class="h2 mb-5">Anhänge</h4> - -<div class="border p-6 flex-grow-1 d-flex flex-column justify-content-center align-items-center "> - - <div class="border border-secondary p-3 pl-6 w-100 d-flex flex-row flex-wrap justify-content-center align-items-center"> - <p>Keine Einträge vorhanden.</p> - </div> - -</div> - </div> - </aside> - - <hr class="my-8"> - - <h2>recommendations</h2> - <div class="border p-6"> - - <p>Keine Einträge vorhanden.</p> - - </div> - - <hr class="my-11 border-top-0"> -</article> - - - </main> + <nav class="rc3-header__main"> + <a class="btn btn-transparent rc3-header__main-linkbox" href="http://localhost:8000/world" + title="world"> + world + </a> + <a class="btn btn-transparent rc3-header__main-linkbox" href="http://localhost:8000/index" + title="Plattform"> + Plattform + </a> + <a class="btn btn-transparent rc3-header__main-linkbox" + href="http://localhost:8000/static/start/" title="info"> + info + </a> + <form class="rc3-header__main-search input-group" method="POST" action="/search" role="search"> + <input type="hidden" name="csrfmiddlewaretoken" + value="TSp4QUYtpnFaqqxPB1Hk1lOw5IS1aYyQfKO00clnOhI3YYmnKSClK3Jt6btj7dkQ"> + <input class="form-control col rc3-header__main-search-input" name="q" type="text" + placeholder="suchen"> + <button class="rc3-header__main-search-btn input-group-append btn btn-transparent"> + <svg width="1em" height="1em" viewBox="0 0 16 16" class=" bi bi-search" + fill="currentColor" xmlns="http://www.w3.org/2000/svg"> + <title>suchen</title> + <path fill-rule="evenodd" + d="M10.442 10.442a1 1 0 0 1 1.415 0l3.85 3.85a1 1 0 0 1-1.414 1.415l-3.85-3.85a1 1 0 0 1 0-1.415z"> + </path> + <path fill-rule="evenodd" + d="M6.5 12a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM13 6.5a6.5 6.5 0 1 1-13 0 6.5 6.5 0 0 1 13 0z"> + </path> + </svg> + </button> + </form> + </nav> + <div class="rc3-header__additional"> + <a class="btn rc3-header__additional-linkbox btn-transparent" href="http://localhost:8000/me" + title="Profil"> + <figure class="rc3-avatar"> + + <img class="rc3-avatar__none" src="rc3-no-avatar-plattform-active.jpeg" + alt="Avatar Bild"> + + </figure> + </a> + <a class="btn rc3-header__additional-linkbox btn-transparent" + href="http://localhost:8000/my_fahrplan"> + Mein Plan + </a> + <div class="rc3-header__additional-box-2x1"> + <a class="btn btn-transparent rc3-header__additional-linkbox" + href="http://localhost:8000/logout" title="logout"> + logout + </a> + + <a class="btn rc3-header__additional-linkbox btn-transparent" + href="http://localhost:8000/board" title="board"> + board + </a> + </div> + <a class="btn btn-block rc3-header__additional-linkbox btn-transparent" + href="http://localhost:8000/pm/inbox" title="Messages"> + Nach richten + </a> + <a class="btn rc3-header__additional-linkbox btn-transparent" + href="http://localhost:8000/fahrplan" title="Fahrplan"> + Fahr plan + </a> + + <form class="rc3-header__additional-box-2x1 rc3-header__nomob" method="POST" + action="/modify_language"> + <input type="hidden" name="csrfmiddlewaretoken" + value="bpLSLkPpJyxPJ9WkIGrpVXTaR9aJ0hrAxhaOVCcj8sAIhHLSRxmqEFO7SCL1XwdA"> + <input type="hidden" name="next" value="/event/rc3-11560-boiling_mind/"> + <button class="btn rc3-header__additional-button btn-transparent" name="language" + value="de"> + de + </button> + <button class="btn rc3-header__additional-button btn-transparent" name="language" + value="en"> + en + </button> + </form> + </div> + </div> + + </header> + + + + <main class="container" id="content"> + + <article class="mt-10 rc3-bg-image-01"> + <div class="row w-100 my-11"> + <div class="col"> + <h1 class="mb-xl-0" title="Boiling Mind">Boiling Mind</h1> + </div> + + <div class="col-sm-auto text-righ align-self-center"> + + <a href="http://localhost:8000/event/rc3-11560-boiling_mind/" + class="ml-2 btn-icon-big btn btn-transparent" title="dies teilen" target="_blank"> + <svg width="1rem" height="1rem" viewBox="0 0 16 16" class="bi bi-share" + fill="currentColor" xmlns="http://www.w3.org/2000/svg"> + <path fill-rule="evenodd" + d="M13.5 1a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zM11 2.5a2.5 2.5 0 1 1 .603 1.628l-6.718 3.12a2.499 2.499 0 0 1 0 1.504l6.718 3.12a2.5 2.5 0 1 1-.488.876l-6.718-3.12a2.5 2.5 0 1 1 0-3.256l6.718-3.12A2.5 2.5 0 0 1 11 2.5zm-8.5 4a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zm11 5.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3z"> + </path> + </svg> + </a> + + + + <form action="/modify_favorites" class="d-inline-block" method="POST"> + <input type="hidden" name="csrfmiddlewaretoken" + value="bpLSxOKkhsIJlJP6k1O4PKcoexvmghezxhaOH67eGmLCThEEtSJ5ys7lf06Edw0z"> + <input type="hidden" name="next" + value="/event/rc3-11560-boiling_mind/#fav_b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e"> + <input type="hidden" name="id" value="b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e"><input + type="hidden" name="type" value="event"><input type="hidden" name="mode" + value="add"> + <button type="submit" id="fav_b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e" + class="ml-2 btn-icon-big btn btn-transparent" title="zu Favoriten hinzufügen"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" + class="bi bi-heart" viewBox="0 0 16 16"> + <path fill-rule="evenodd" + d="M8 2.748l-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01L8 2.748zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143c.06.055.119.112.176.171a3.12 3.12 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15z"> + </path> + </svg> + </button> + </form> + + + + <form action="/modify_personal_calendar" class="d-inline-block" method="POST"> + <input type="hidden" name="csrfmiddlewaretoken" + value="CTcQzPH9yu3D51rLlYQTbCCR4iVBhJ7yYLBMJ743Xo6wDzgjuPLUUkxO5LwTeYTy"> + <input type="hidden" name="next" + value="/event/rc3-11560-boiling_mind/#sch_b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e"> + <input type="hidden" name="id" value="b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e"><input + type="hidden" name="mode" value="add"> + <button type="submit" id="sch_b4cb2164-52b4-4f81-a3cc-8d6b60e7e99e" + class="ml-2 btn-icon-big btn btn-transparent" title="zu Zeitplan hinzufügen"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" + class="bi bi-calendar2-week" viewBox="0 0 16 16"> + <path fill-rule="evenodd" + d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM2 2a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H2z"> + </path> + <path + d="M2.5 4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5H3a.5.5 0 0 1-.5-.5V4zM11 7.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm-3 0a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm-5 3a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm3 0a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1z"> + </path> + </svg> + </button> + </form> + + + + + <a href="http://localhost:8000/report?kind=url&kind_data=/event/rc3-11560-boiling_mind/&next=/event/rc3-11560-boiling_mind/" + class="ml-2 btn-icon-big btn btn-transparent" title="dies melden"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" + class="bi bi-exclamation-diamond-fill" viewBox="0 0 16 16"> + <path fill-rule="evenodd" + d="M9.05.435c-.58-.58-1.52-.58-2.1 0L.436 6.95c-.58.58-.58 1.519 0 2.098l6.516 6.516c.58.58 1.519.58 2.098 0l6.516-6.516c.58-.58.58-1.519 0-2.098L9.05.435zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"> + </path> + </svg> + </a> + + </div> + + </div> + + + + + <div class="rc3-event-info border border-1 border-white"> + <h3 class="flex-row align-items-center justify-content-center bg-info p-3 text-dark h3 mb-lg-0"> + Event Start: + 1 Woche, 1 Tag von jetzt an + </h3> + <h3 + class="rc3-event-info__title-info flex-row align-items-center justify-content-center bg-info p-3 text-white h3 mb-lg-0"> + Event Information</h3> + <figure class="p-0 mb-lg-0"> + + <img class="w-100 d-block" src="rc3-assembly-event-04.png" alt="Boiling Mind" + title="Boiling Mind"> + + </figure> + <dl class="grid-list mb-0"> + <dt class="grid-list__item grid-list__item--title">Zeit</dt> + <dd class="grid-list__item grid-list__item--text"> + + 27. Dezember 2021 13:00 + + - 27. Dezember 2021 13:40 + + + </dd> + <dt class="grid-list__item grid-list__item--title">Speaker</dt> + <dd class="grid-list__item grid-list__item--text"> + + Noch keine Speaker bekannt gegeben + + </dd> + <dt class="grid-list__item grid-list__item--title">Track</dt> + <dd class="grid-list__item grid-list__item--text"> + + Art & Culture + + </dd> + <dt class="grid-list__item grid-list__item--title">Sprache</dt> + <dd class="grid-list__item grid-list__item--text"> + + en + + </dd> + <dt class="grid-list__item grid-list__item--title">Raum</dt> + <dd class="grid-list__item grid-list__item--text"> + + <a href="http://localhost:8000/room/rc2/" title="rC2" class=""> + rC2 + </a> + + </dd> + <dt class="grid-list__item grid-list__item--title">Host</dt> + <dd class="grid-list__item grid-list__item--text"> + + <a href="http://localhost:8000/assembly/ccc/">CCC</a> + + </dd> + </dl> + </div> + + <hr class="my-8"> + + <section class="rc3-markdown border bg-opaque p-3"> + <p>The role of + the audience in stage performances is changing from passive spectators + to contributors making the performance interactive by using different + techniques. In this talk, we investigate the connection of audience + physiological data to the experienced performance in three performance + events with a total of 98 participants. We identified memorable + performance moments by assessing, Electrodermal Activity (EDA) showing + that the audience’s responses match the choreographer’s intention. + Through Heart Rate Variability (HRV) features related to parasympathetic + activity, we identified dramatic shifts that are connected to the + choreographic development of the performance. Our results show how the + audience's physiological responses are linked to the choreographic + development of the performance. Based on the findings, we contribute a + discussion of the registered physiological phenomena and implications of + the audience’s responses analysis to performance and choreography + design in general. Furthermore, we walk through the dataset collected + from the performance events. </p> + <p>Each performance lives from the interplay between audience and + artists. Even if performers follow a precise script, each rendition is + different partly due to audience reactions. Performers often describe it + as an invisible link between then and the spectators, involving the + audience in co-creating art. </p> + <p>The stage design and described setup came out of a collaboration + between the performing artists, designers and researchers in a + semi-democratic process.</p> + <p>Both researchers and artists contributed to developing the concept + during the iterative process to balance research and artistic interests. + This process was mainly led by artists, especially the choreographer. + Besides the predetermined story and design, the choreographer also + created some improvisational sections where dancers could interact with + stage elements affected by audience physiological response.</p> + <p>The main contributions of this talk are as follows: + (1) We present the concept of "bringing the audience on stage" by + mapping physiological signals from audience members to stage elements to + amplify the connection between artists and the audience. We detail + information about the design process, focusing on sensing heart rate and + electrodermal activity (EDA), as well as how these signals are + translated to the onstage elements through sonification and + visualizations. + (2) We describe an open integrated wearable system that consists of a + wrist band, back-end processing, and output. Our proposed system enables + the capturing and translating of physiological signals into stage + design elements. + (3) We realized our proposed concept as a proof-of-concept with the + performance "Boiling Mind". The performance involved dancers, + choreographers, researchers, visual and sound designers in the process. + It was performed three times in front of an audience of 57, 37 and 45 + people. In each performance, around 30 audience members wore the + wearable wrist bands.</p> + <p>The hardware used for the performance piece as well as the data + recorded will be open sourced and will be made avaialable to download.</p> + </section> + + <hr class="my-8"> + + <aside class="row mx-0"> + <div class="col-12 col-lg-6 mb-5 mb-lg-0 d-flex flex-column flex-nowrap"> + <h4 class="h2 mb-5">Tags</h4> + + <div + class="border flex-grow-1 px-6 pt-6 pb-5 d-flex flex-row flex-wrap justify-content-center align-items-center"> + <p class="my-6">Nicht getaggt.</p> + </div> + + </div> + <div class="col-12 col-lg-6 d-flex flex-column flex-nowrap"> + + <h4 class="h2 mb-5">Anhänge</h4> + + <div + class="border p-6 flex-grow-1 d-flex flex-column justify-content-center align-items-center "> + + <div + class="border border-secondary p-3 pl-6 w-100 d-flex flex-row flex-wrap justify-content-center align-items-center"> + <p>Keine Einträge vorhanden.</p> + </div> + + </div> + </div> + </aside> + + <hr class="my-8"> + + <h2>recommendations</h2> + <div class="border p-6"> + + <p>Keine Einträge vorhanden.</p> + + </div> + + <hr class="my-11 border-top-0"> + </article> + + + </main> <footer id="footer" class="mt-auto border-top border-primary py-3 py-xl-5"> <ul class="container nav p-0 justify-content-center"> <li> <a class="nav-link text-white" title="Kontakt" href="https://legal.rc3.world/">Kontakt</a> </li> <li> - <a class="nav-link text-white" title="Datenschutzerklärung" href="https://legal.rc3.world/">Datenschutzerklärung</a> + <a class="nav-link text-white" title="Datenschutzerklärung" + href="https://legal.rc3.world/">Datenschutzerklärung</a> </li> <li> - <a class="nav-link text-white" title="Über die rC3" href="https://howto.rc3.world/">Über die rC3</a> + <a class="nav-link text-white" title="Über die rC3" href="https://howto.rc3.world/">Über die + rC3</a> </li> <li> <a class="nav-link text-white" title="Impressum" href="https://legal.rc3.world/">Impressum</a> </li> <li> - <a class="nav-link text-white" title="Spielregeln" href="https://howto.rc3.world/rules.html">Spielregeln</a> + <a class="nav-link text-white" title="Spielregeln" + href="https://howto.rc3.world/rules.html">Spielregeln</a> </li> </ul> </footer> </div> </div> - <div class="rc3-bg-L03"></div> - <div class="rc3-bg-L01"></div> -<!-- <div id="debug"></div> --> - <script> + <div class="rc3-bg-L03"></div> + <div class="rc3-bg-L01"> + </div> + <canvas id="fg-particles" class="static full-bg particles"></canvas> + + <!-- <div id="debug"></div> --> + <script> function initParallax() { if (!('querySelector' in document) - || !('requestAnimationFrame' in window)) { + || !('requestAnimationFrame' in window)) { return; } const body = document.querySelector('body'); @@ -380,38 +519,40 @@ recorded will be open sourced and will be made avaialable to download.</p></sect const maxScroll = height - window.innerHeight; const setTransform = (el, factor) => { if (el) { - el.style.transform ="translate3D(0,"+ window.scrollY * factor + "px,0)" + el.style.transform = "translate3D(0," + window.scrollY * factor + "px,0)" } } const setBgPosition = (el, factor) => { if (el) { - el.style.backgroundPositionY =window.scrollY * factor + "px" + el.style.backgroundPositionY = window.scrollY * factor + "px" } } function step() { if (!lastPos) - lastPos = window.scrollY; + lastPos = window.scrollY; if (lastPos !== window.scrollY) { scrollFactor = window.scrollY / height if (debug) { - debug.innerText = window.scrollY +" / " + height + " / " + maxScroll + " / " + window.innerHeight; + debug.innerText = window.scrollY + " / " + height + " / " + maxScroll + " / " + window.innerHeight; } - setBgPosition(layer01,-1.2); - setTransform(layer05,0.8); - setBgPosition(layer06,0.5); - setTransform(layer10,-0.02); + setBgPosition(layer01, -1.2); + setTransform(layer05, 0.8); + setBgPosition(layer06, 0.5); + setTransform(layer10, -0.02); // Move mask for header if (main) { - main.style.maskPositionY = window.scrollY-320 + "px"; + main.style.maskPositionY = window.scrollY - 320 + "px"; } } lastPos = window.scrollY; window.requestAnimationFrame(step); - } - window.requestAnimationFrame(step); } - </script> - </body></html> + window.requestAnimationFrame(step); + } + </script> +</body> + +</html> \ No newline at end of file diff --git a/src/bg-eyecandy/particles.js b/src/bg-eyecandy/particles.js new file mode 100644 index 0000000000000000000000000000000000000000..232721bfe749afa06365927ca4be5fb439498920 --- /dev/null +++ b/src/bg-eyecandy/particles.js @@ -0,0 +1,337 @@ +/* + * Particles.js + * + * Particle emitter and renderer. + * + * TODO: Gleichmäßige Particle verteilung + * TODO: Pulse Animation anpassen (easing) + */ + + +// +// Helper +// + + +function randomValue(min, max) { + var value = (Math.random() * (+max - +min) + +min) + // Prevent values that can be possible boring + return (value === 0 || value === 1) + ? randomValue(min, max) + : value +} + +function getNodeYOffset(node) { + var dimensions = node.getBoundingClientRect() + return (dimensions) ? dimensions.y : 0 +} + +function getNodeHeight(node) { + var dimensions = node.getBoundingClientRect() + return (dimensions) ? dimensions.height : window.innerHeight +} + + +// +// Data +// + + +function Point2D(x, y) { + return { x, y } +} + +function MinMax(min, max) { + return { min, max } +} + +function MaxValue(value, max) { + return { value, max } +} + +function RandomPoint2D(minMaxX, minMaxY) { + var x = randomValue(minMaxX.min, minMaxX.max) + var y = randomValue(minMaxY.min, minMaxY.max) + return Point2D( x, y ) +} + +function Particle({ position, direction, size, color }) { + return { position, direction, size, color } +} + + +// +// Transformations | Actions +// + + +function Update(scene, particle) { + // Cache object access -> Performance + var width = scene.width + var height = scene.height + var color = particle.color + var particleSize = particle.size + var particleSizeValue = particleSize.value + var particleSizeBound = particleSize.bound + var particleSizeBoundMin = particleSizeBound.min + var particleSizeBoundMax = particleSizeBound.max + var particleSizeStep = particleSize.step + var particleSizeDirection = particleSize.direction + var particlePosition = particle.position + var particlePositionX = particlePosition.x + var particlePositionY = particlePosition.y + var particleDirection = particle.direction + var particleDirectionX = particleDirection.x + var particleDirectionY = particleDirection.y + + // Animate the pulse effect of the particle + // + var isMaxSize = particleSizeValue > particleSizeBoundMax + var isMinSize = particleSizeValue < particleSizeBoundMin + var sizeDirection = + (isMaxSize || isMinSize) + ? -particleSizeDirection + : particleSizeDirection + var sizeValue = + particleSizeValue + particleSizeStep * sizeDirection + + // Animate the movement of the particle + // + var sizeOffset = sizeValue * 0.5 + var top = particlePositionY + sizeOffset + var bottom = particlePositionY - sizeOffset + var left = particlePositionX - sizeOffset + var right = particlePositionX + sizeOffset + + var isRightEdge = (left > (width+1)) + var isLeftEdge = (right < -1) + var isTopEdge = (bottom < -1) + var isBottomEdge = (top > (height+1)) + + var positionX = + (isRightEdge) + ? -sizeOffset + : (isLeftEdge) + ? width + sizeOffset + : particlePositionX + particleDirectionX + var positionY = + (isBottomEdge) + ? -sizeOffset + : (isTopEdge) + ? height + sizeOffset + : particlePositionY + particleDirectionY + return { + position: { + x: positionX, + y: positionY, + }, + direction: particleDirection, + size: { + value: sizeValue, + bound: particleSizeBound, + step: particleSizeStep, + direction: sizeDirection + }, + color: color + } +} + +function Draw(scene, particle) { + // Cache object access + var particlePosition = particle.position + var particlePositionX = particlePosition.x + var particlePositionY = particlePosition.y + + // Draw calculations -- + var yOffset = scene.yOffset * scene.depthScale + var size = particle.size.value + var drawOffset = size * 0.5 + var x = particlePositionX - drawOffset + var y = yOffset + (particlePositionY - drawOffset) + + var ctx = scene.ctx + // var isVisible = (size > 0 && y < window.innerHeight && y > 0) + var isVisible = (size > 0) + + // Draw + if (isVisible) { + ctx.fillStyle = particle.color + // Round to full integer to prevent subpixel rendering + // - The ~~ operator is equivalent to Math.trunc() but faster. + // ctx.fillRect(~~x, ~~y, size, size) + ctx.fillRect(x, y, size, size) + } +} + +function Clear(scene) { + scene.ctx.clearRect(0, 0, scene.width, scene.height) +} + +function Render(scene, particles) { + Clear(scene) + particles.forEach( + function doDraw(particle) { + Draw(scene, particle) + } + ) +} + +function Animate(scene, particles) { + var updatedParticles = [], + fpsInterval = scene.fpsInterval, + now = performance.now(), + then = scene.then, + elapsed = now - then, + tolerance = 0.1 + + // Just render when we're reaching the configured fps + if (elapsed >= (scene.fpsInterval - tolerance)) { + scene.yOffset = getNodeYOffset(scene.anchorNode) + scene.then = now - (elapsed % fpsInterval) + Render(scene, particles) + } + + // Update particle positions for the next render call + updatedParticles = particles.map(function doUpdate(p) { + return Update(scene, p) + }) + + // Function to animate the next frame + return function nextFrame() { + return Animate( + scene, + updatedParticles + ) + } +} + +function CreateScene({ canvasId, contentId, depth, fps }) { + var contentNode = document.getElementById(contentId), + height = getNodeHeight(contentNode), + width = window.innerWidth, + fpsInterval = 1000 / fps, + yOffset = 0, + canvas = document.getElementById(canvasId), + ctx = canvas.getContext('2d'), + depthScaledHeight = height * (depth+1) + + ctx.canvas.width = width + ctx.canvas.height = window.innerHeight + + return { + width, + height: depthScaledHeight, + yOffset, + depthScale: depth, + ctx, + fps, + fpsInterval, + then: performance.now(), + anchorNode: contentNode + } +} + + +function CreateParticles(scene, { + amount, + color, + size, + speed, + lifespan, +}) { + return Array.from( + { length: amount }, + function createParticle() { + return Particle({ + position: + RandomPoint2D( + MinMax(0, (scene.width - (size * 2))), + MinMax(0, (scene.height - (size * 2))), + ), + direction: + RandomPoint2D( + MinMax(-speed, speed), + MinMax(-speed, speed) + ), + size: { + value: randomValue(-size, size), + bound: MinMax(-size, size), + step: size / ((lifespan) / scene.fps), + direction: + // 50% Chance for the particle floating in one + // direction or the other. + (randomValue(0, 100) < 50) + ? -1 + : +1, + }, + color + }) + } + ) +} + + +// +// Api +// + + +function Particles(configs) { + + var particles = [] + var isRunning = false + var throttled = false + var delay = 25 + var rafId = undefined + + function animate(rendererList) { + if (isRunning) { + rafId = requestAnimationFrame(function doRaf() { + animate( + rendererList.map(function doRender(render) { + return render() + }) + ) + }) + } + } + + function init() { + particles = configs.map(function (particleConfig) { + var scene = CreateScene(particleConfig.scene) + var particles = CreateParticles(scene, particleConfig.particles) + return Animate(scene, particles) + }) + return particles + } + + function run() { + if (particles.length === 0) { + particles = init() + } + isRunning = true + animate(particles) + } + + function stop() { + isRunning = false + cancelAnimationFrame(rafId) + } + + return { + init: init, + run: run, + stop: stop, + onScreenSizeChange: function onResize() { + stop() + if (!throttled) { + throttled = true + setTimeout(function () { + particles = init() + run() + throttled = false + }, delay) + } + } + } +} \ No newline at end of file