This commit is contained in:
hubourge
2024-08-24 19:57:53 +02:00
68 changed files with 2825 additions and 154 deletions

View File

@ -2,8 +2,16 @@ FROM debian:bullseye
RUN apt update
RUN apt upgrade -y
RUN apt install gnupg curl -y
RUN echo "deb http://ppa.launchpad.net/deadsnakes/ppa/ubuntu focal main" | tee /etc/apt/sources.list.d/deadsnakes-ppa.list
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6A755776
RUN apt update
RUN apt upgrade -y
RUN apt install -y python3.12 postgresql-client
RUN curl https://bootstrap.pypa.io/get-pip.py -o /root/get-pip.py
RUN python3.12 /root/get-pip.py
RUN apt install -y python3 python3-pip postgresql-client
RUN pip3 install requests django psycopg "channels[daphne]"
ARG DB_HOST=;
@ -18,19 +26,19 @@ ENV PYTHONUNBUFFERED=1
ENV UID_42=${UID_42}
ENV SECRET_42=${SECRET_42}
COPY start.sh /root/start.sh
RUN mkdir -p /var/www/djangoserver/
RUN mkdir -p /var/www/djangoserver/static/
COPY file/server /var/www/djangoserver/server
RUN chmod 755 /var/www/djangoserver/
RUN chown -R www-data:www-data /var/www/djangoserver/
RUN sed -i "s/VAR_DB_HOST/$DB_HOST/" /var/www/djangoserver/server/server/settings.py
RUN sed -i "s/VAR_DB_NAME/$DB_NAME/" /var/www/djangoserver/server/server/settings.py
RUN sed -i "s/VAR_DB_USERNAME/$DB_USERNAME/" /var/www/djangoserver/server/server/settings.py
RUN sed -i "s/VAR_DB_PASSWORD/$DB_PASSWORD/" /var/www/djangoserver/server/server/settings.py
WORKDIR /var/www/djangoserver
STOPSIGNAL SIGKILL
RUN mkdir -p /var/www/djangoserver/static/
COPY file/server /var/www/djangoserver/server
RUN chmod 755 /var/www/djangoserver/ && chown -R www-data:www-data /var/www/djangoserver/
RUN sed -i "s/VAR_DB_HOST/$DB_HOST/" /var/www/djangoserver/server/server/settings.py && \
sed -i "s/VAR_DB_NAME/$DB_NAME/" /var/www/djangoserver/server/server/settings.py && \
sed -i "s/VAR_DB_USERNAME/$DB_USERNAME/" /var/www/djangoserver/server/server/settings.py && \
sed -i "s/VAR_DB_PASSWORD/$DB_PASSWORD/" /var/www/djangoserver/server/server/settings.py
COPY start.sh /root/start.sh
ENTRYPOINT ["sh", "/root/start.sh"]

View File

@ -123,6 +123,12 @@ USE_TZ = True
STATIC_URL = 'static/'
STATIC_DIRS = [
BASE_DIR/ "static"
]
STATIC_ROOT = BASE_DIR / 'staticfiles'
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

View File

@ -0,0 +1,127 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Chat</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' href='/static/style/home.css'>
<link rel='stylesheet' type='text/css' href='/static/style/liveChat.css'>
<link rel='stylesheet' type='text/css' href='/static/style/notification.css'>
<link rel='stylesheet' type='text/css' href='/static/style/loginPage.css'>
<script type="module" src='/static/main.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=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
</head>
<body>
<div id="divNotification">
</div>
<div id="topBar">
<h1>PTME</h1>
<div id="topButton">
<p>HOME</p>
<p>PROJECT</p>
<p>NEWS</p>
</div>
<div id="loginButton">
<p>LOGIN</p>
</div>
</div>
<div id="loginPopup" class="popup">
<div class="container">
<div class="left-side"></div>
<div class="right-side">
<h1>Access to a new WORLD</h1>
<form>
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="Email">
<label for="password">Password</label>
<input type="password" id="password" name="password" placeholder="Password">
<button type="submit" class="login-btn">Login</button>
<div class="new-player">
New player? <a href="#">Create an account</a>
</div>
<div class="divider">
<span></span>
<p>Or</p>
<span></span>
</div>
<button type="button" class="login-42-btn">Log with <span>42</span></button>
</form>
</div>
</div>
</div>
<div id="chatButton">
<p>CHAT</p>
</div>
<div id="chatDiv">
<div id="topChatHome">
<h1>Chat</h1>
<div id="topChatCross">
<h2>X</h2>
</div>
</div>
</div>
<section class="homeSection">
</section>
<section class="homeSection relative">
<img id="firstBall" src="static/style/ball3D2.png">
<img id="secondBall" src="static/style/ball3D3.png">
<div class="relative">
<p id="firstText">Lorem ipsum dolor sit amet consectetur adipisicing elit. Officia totam cupiditate magni unde expedita molestiae eum aliquam fugit voluptatibus omnis! Dolores, ipsa inventore necessitatibus numquam aspernatur in perferendis id voluptas?</p>
<p id="secondText">Lorem ipsum dolor sit amet consectetur adipisicing elit. Officia totam cupiditate magni unde expedita molestiae eum aliquam fugit voluptatibus omnis! Dolores, ipsa inventore necessitatibus numquam aspernatur in perferendis id voluptas?</p>
</div>
</section>
<section class="homeSection">
<div class="team">
<div class="team-member">
<img src="/static/style/tomoron.png" alt="Tom" class="team-photo">
<h2>Tom, tomoron</h2>
<p>Partie Backend</p>
<div class="info">
<p>Tom est spécialisé en développement backend et travaille principalement avec Node.js et MongoDB.</p>
</div>
</div>
<div class="team-member">
<img src="/static/style/madegryc.png" alt="Mathis" class="team-photo">
<h2>Mathis, madegryc</h2>
<p>Partie Frontend / Design</p>
<div class="info">
<p>Tom est spécialisé en développement backend et travaille principalement avec Node.js et MongoDB.</p>
</div>
</div>
<div class="team-member">
<img src="/static/style/edbernard.png" alt="Eddy" class="team-photo">
<h2>Eddy, edbernar</h2>
<p>Partie Midend</p>
<div class="info">
<p>Tom est spécialisé en développement backend et travaille principalement avec Node.js et MongoDB.</p>
</div>
</div>
<div class="team-member">
<img src="/static/style/hubourge.png" alt="Hugo" class="team-photo">
<h2>Hugo, hubourge</h2>
<p>Partie jeu</p>
<div class="info">
<p>Tom est spécialisé en développement backend et travaille principalement avec Node.js et MongoDB.</p>
</div>
</div>
</div>
</section>
<footer>
<div class="footer-content">
<div class="footer-left">
<h1>PTME</h1>
<p>ft_transcendance project<br>for 42 shcool</p>
</div>
<div class="footer-right">
<p>2024</p>
</div>
</footer>
</body>
</html>

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/09 08:08:00 by edbernar #+# #+# #
# Updated: 2024/08/22 19:13:09 by tomoron ### ########.fr #
# Updated: 2024/08/24 01:11:45 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -19,42 +19,42 @@ pattern = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_]).+$'
# {'username': 'Kumita', 'mail': 'eddydhj@gmail.com', 'password': '3b19482535d1ab2f4e3c629c4e3e5e2d6af0a5f5280be190726a4c3be518a475'}
async def createAccount(socket, content):
def createAccount(socket, content):
try:
content["mail"] = content["mail"].lower()
if (content["mail"].find('@') == -1 or content["mail"].find('.') == -1):
await socket.sendError("Invalid mail", 9006)
socket.sendError("Invalid mail", 9006)
return
if (content["username"].find(' ') != -1):
await socket.sendError("Username must not contain spaces", 9007)
socket.sendError("Username must not contain spaces", 9007)
return
if (len(content["username"]) < 3):
await socket.sendError("Username must be at least 3 characters long", 9008)
socket.sendError("Username must be at least 3 characters long", 9008)
return
if (len(content["username"]) > 20):
await socket.sendError("Username must be at most 20 characters long", 9009)
socket.sendError("Username must be at most 20 characters long", 9009)
return
if (content["username"].find(' ') != -1):
await socket.sendError("Username must not contain spaces", 9011)
socket.sendError("Username must not contain spaces", 9011)
return
if (content["username"].isalnum() == False):
await socket.sendError("Username must contain only letters and numbers", 9012)
socket.sendError("Username must contain only letters and numbers", 9012)
return
if (len(content["password"]) < 8):
await socket.sendError("Password must be at least 8 characters long", 9013)
socket.sendError("Password must be at least 8 characters long", 9013)
return
if (bool(re.match(pattern, content["password"]))):
await socket.sendError("Password must contain at least one lowercase letter, one uppercase letter and one special character", 9014)
socket.sendError("Password must contain at least one lowercase letter, one uppercase letter and one special character", 9014)
return
if (content["password"].find(content["username"]) != -1):
await socket.sendError("Password must not contain the username", 9015)
socket.sendError("Password must not contain the username", 9015)
return
# |Tom| Au lieu d'utiliser userList, faire une requête à la base de donnée pour savoir si on a un utilisateur avec cet email ou cet username
if (content["mail"] in userList):
await socket.sendError("Mail already used", 9016)
socket.sendError("Mail already used", 9016)
return
if (content["username"] in userList):
await socket.sendError("Username already used", 9017)
socket.sendError("Username already used", 9017)
return
content["token"] = generateToken()
while (True):
@ -62,9 +62,12 @@ async def createAccount(socket, content):
if (content["id"] not in userList):
break
userList.append(content)
await socket.send({"type": "create_account", "content": "Account created"})
socket.send(text_data=json.dumps({"type": "create_account", "content": "Account created"}))
socket.scope["session"]["logged_in"] = True
socket.scope["session"]["username"] = content["username"]
socket.scope["session"].save()
except Exception as e:
await socket.sendError("Error create account", 9005, e)
socket.sendError("Error create account", 9005, e)
def generateToken():
list = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 22:53:14 by edbernar #+# #+# #
# Updated: 2024/08/22 19:13:09 by tomoron ### ########.fr #
# Updated: 2024/08/23 23:56:06 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -56,7 +56,7 @@ def generate_random_string():
string += char[random.randint(0, len(char) - 1)]
return string
async def getPrivateListMessage(socket, content):
def getPrivateListMessage(socket, content):
# |TOM| Requete pour avoir la liste des messages privés grace à l'id de l'utilisateur
copyListMessage = listMessage.copy()
for message in copyListMessage["content"]:
@ -65,5 +65,5 @@ async def getPrivateListMessage(socket, content):
else:
message["from"] = content["id"]
message["content"] = generate_random_string()
await socket.send(copyListMessage)
socket.send(text_data=json.dumps(copyListMessage))

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 15:10:23 by edbernar #+# #+# #
# Updated: 2024/08/22 19:13:09 by tomoron ### ########.fr #
# Updated: 2024/08/23 23:55:50 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -52,9 +52,9 @@ data = [
}
]
async def getPrivateListUser(socket, content=None):
def getPrivateListUser(socket, content=None):
# |TOM| Faire une requête à la base de données pour récupérer la liste des
# utilisateurs qui doivent apparaitre dans la liste du chat privé
# (ceux qui ont eu conversation avec l'utilisateur)
# Si user existe pas, faire ça : await socket.sendError("User not found", 9008)
await socket.send({"type": "private_list_user", "content": data})
# Si user existe pas, faire ça : socket.sendError("User not found", 9008)
socket.send(text_data=json.dumps({"type": "private_list_user", "content": data}))

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 08:10:38 by edbernar #+# #+# #
# Updated: 2024/08/22 19:12:23 by tomoron ### ########.fr #
# Updated: 2024/08/24 01:11:15 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -56,55 +56,44 @@ userList = [
}
]
async def loginByToken(socket, content):
# |TOM| Requete pour savoir si le token est valide
for user in userList:
if (user["token"] == content["token"]):
jsonVar = {"type": "login", "content": {"username": user["username"], "token": user["token"], "id": user["id"]}}
socket.username = jsonVar["content"]["username"]
socket.token = jsonVar["content"]["token"]
socket.id = jsonVar["content"]["id"]
await socket.send(jsonVar)
return
jsonVar = {"type": "error", "content": "Invalid token", "code": 9001}
await socket.send(json.dumps(jsonVar))
async def loginByPass(socket, content):
def loginByPass(socket, content):
# |TOM| Requete pour savoir si le mail et le mot de passe sont valides
# et créer un token si celui-ci n'existe pas
for user in userList:
if (user["mail"] == content["mail"] and user["password"] == content["password"]):
jsonVar = {"type": "login", "content": {"username": user["username"], "token": user["token"], "id": user["id"]}}
socket.username = jsonVar["content"]["username"]
socket.token = jsonVar["content"]["token"]
socket.id = jsonVar["content"]["id"]
await socket.send(jsonVar)
jsonVar = {"type": "login", "content": {"username": user["username"]}}
socket.scope["session"]["logged_in"] = True
socket.scope["session"]["username"] = jsonVar["content"]["username"]
socket.scope["session"].save()
socket.send(text_data=json.dumps(jsonVar))
return
await socket.send({"type": "error", "content": "Invalid username or password", "code": 9007})
socket.send(text_data=json.dumps({"type": "error", "content": "Invalid username or password", "code": 9007}))
async def loginBy42(socket, content):
def loginBy42(socket, content):
# |TOM| Requete pour récuperer les informations de l'utilisateur selon l'intra de la personne
# et créer un token si celui-ci n'existe pas
try:
await main42login(socket, content, userList)
main42login(socket, content, userList)
except Exception as e:
await socket.sendError("Invalid 42 token", 9010, e)
socket.sendError("Invalid 42 token", 9010, e)
async def login(socket, content):
def login(socket, content):
# |TOM| Faire 3 types de requêtes:
# - byToken: Récupérer les informations de l'utilisateur en fonction de son token
# - nope
# - byPass: Récupérer les informations de l'utilisateur en fonction de mail et de son mot de passe
# - by42: Récupérer les informations de l'utilisateur en fonction de son token42 (qui sera different du token)
print(json.dumps(content))
try:
if (content["type"] == "byToken"):
await loginByToken(socket, content)
elif (content["type"] == "byPass"):
await loginByPass(socket, content)
# if (content["type"] == "byToken"):
# loginByToken(socket, content)
if (content["type"] == "byPass"):
loginByPass(socket, content)
elif (content["type"] == "by42"):
await loginBy42(socket, content)
loginBy42(socket, content)
else:
await socket.sendError("Invalid login type", 9006)
socket.sendError("Invalid login type", 9006)
except Exception as e:
await socket.sendError("Invalid request", 9005, e)
socket.sendError("Invalid request", 9005, e)

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/09 09:32:17 by edbernar #+# #+# #
# Updated: 2024/08/22 19:13:31 by tomoron ### ########.fr #
# Updated: 2024/08/24 01:12:08 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -27,7 +27,7 @@ if (UID42 == None or SECRET42 == None):
print("Please set the environment variables uid and secret")
exit()
async def main42login(socket, content, userList):
def main42login(socket, content, userList):
global access_token
print(content['token'])
@ -56,17 +56,13 @@ async def main42login(socket, content, userList):
break
i += 1
if (i == len(userList)):
await socket.sendError("Not user registered with this 42 account", 9011)
socket.sendError("Not user registered with this 42 account", 9011)
return
else:
await socket.send({
socket.scope["session"]["logged_in"] = True
socket.scope["session"]["username"] = userList[i]['username']
socket.scope["session"].save()
socket.send(text_data=json.dumps({
"type": "login",
"content": {
"username": userList[i]['username'],
"token": userList[i]['token'],
"id": userList[i]['id']
}
})
"content": {"username": userList[i]['username']}
}))

View File

@ -6,15 +6,15 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/04 13:44:11 by edbernar #+# #+# #
# Updated: 2024/08/22 19:13:31 by tomoron ### ########.fr #
# Updated: 2024/08/23 23:54:32 by tomoron ### ########.fr #
# #
# **************************************************************************** #
from datetime import datetime
async def sendPrivateMessage(socket, content):
def sendPrivateMessage(socket, content):
# |Tom| Requete pour vérifier si l'user existe
# Si user existe pas, faire ça : await socket.sendError("User not found", 9008)
# Si user existe pas, faire ça : socket.sendError("User not found", 9008)
# Sinon l'ajouter à la base de données
# |Eddy| Si user existe, envoyer le message privé aux deux personnes concernées
# sachant que le receveur doit être connecté. Dans le cas contraire, uniquement
@ -30,6 +30,6 @@ async def sendPrivateMessage(socket, content):
"content": content["content"],
"date": time
}}
await socket.send(jsonVar)
socket.send(text_data=json.dumps(jsonVar))
except Exception as e:
await socket.sendError("Invalid message sent", 9009, e)
socket.sendError("Invalid message sent", 9009, e)

View File

@ -1,9 +1,6 @@
from django.http import HttpResponse
from django.shortcuts import render
from .models import User
def index(request):
if(request.session.get("visited", False)):
print("already visited")
request.session["visited"] = True
return HttpResponse("AAAAAAAAAAAAAAAAAAAAAAA")
return render(request, "index.html", {})

View File

@ -17,25 +17,21 @@ from random import randint
class WebsocketHandler(WebsocketConsumer):
debugMode = True
session = None
def connect(self):
print("new client")
self.accept()
print(self.scope["session"].get("number"))
if(self.scope["session"].get("number") == None):
self.scope["session"]["number"] = randint(0,2147483647)
self.scope["session"].save()
print("new number : ", self.scope["session"].get("number"))
else:
print("remembered number : ", self.scope["session"].get("number"))
self.send(text_data=json.dumps({"type":"is_logged_in", "content":self.scope["session"].get("logged_in",False)}))
print("new client")
def disconnect(self, close_code):
print("you can go, we never wanted you anyway")
print("you can go, i am not mad, we never wanted you anyway")
def receive(self, text_data):
print(self.scope["session"].get("number"))
print("someone is talking")
print("username is ", self.scope["session"].get("username"))
if(self.scope["session"].get("logged_in", False)):
print("user is logged in")
else:
print("user is not logged in")
try:
jsonRequest = json.loads(text_data)
except json.JSONDecodeError:
@ -47,13 +43,14 @@ class WebsocketHandler(WebsocketConsumer):
if (jsonRequest["type"] == "login" or jsonRequest["type"] == "create_account"):
functionRequest[typeRequest.index(jsonRequest["type"])](self, jsonRequest["content"])
else:
if (self.verifyToken(jsonRequest["token"]) == False):
return
if (not self.scope["session"].get("logged_in", False)):
return;
functionRequest[typeRequest.index(jsonRequest["type"])](self, jsonRequest["content"])
else:
self.sendError("Invalid type", 9004)
except Exception as e:
self.sendError("Invalid request", 9005, e)
print(e)
def sendError(self, message, code, error=None):
try:

View File

@ -1,6 +1,7 @@
until pg_isready -h "$DB_HOST"; do sleep 0.5 ;echo "waiting for database";done
cd /var/www/djangoserver/server
python3 manage.py makemigrations server
python3 manage.py migrate
python3.12 manage.py makemigrations server
python3.12 manage.py migrate
python3.12 manage.py collectstatic
#python3 manage.py runserver 0.0.0.0:8000
daphne -p 8000 -b 0.0.0.0 server.asgi:application

View File

@ -7,6 +7,7 @@ RUN apt install openssl nginx -y
RUN mkdir -p /etc/nginx/ssl
RUN openssl req -x509 -nodes -out /etc/nginx/ssl/inception.crt -keyout /etc/nginx/ssl/inception.key -subj "/C=FR/ST=IDF/L=Paris/O=42/OU=42/CN=ptme.com/UID=ptme"
COPY conf/nginx.conf /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx/nginx.conf
COPY static /var/www/static
ENTRYPOINT ["nginx", "-g", "daemon off;"]

View File

@ -13,6 +13,8 @@ http {
client_max_body_size 2G;
server {
access_log /dev/stdout;
error_log /dev/stdout;
server_name ptme.com;
listen 443 ssl;
@ -20,10 +22,11 @@ http {
ssl_certificate /etc/nginx/ssl/inception.crt;
ssl_certificate_key /etc/nginx/ssl/inception.key;
root /var/www/djangoserver/;
root /var/www/;
include /etc/nginx/mime.types;
location /static/ {
alias /var/www/djangoserver/static/;
alias /var/www/static/;
}
location / {

View File

@ -0,0 +1,143 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Screen.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: marvin <marvin@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/22 23:13:53 by edbernar #+# #+# */
/* Updated: 2024/08/24 11:39:09 by marvin ### ########.fr */
/* */
/* ************************************************************************** */
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import * as THREE from 'three'
const loader = new GLTFLoader();
class Screen
{
screen = null;
tv = null;
pointLightIntensity = 1;
screenMaterial = null;
constructor(scene)
{
this.screen = this.#createScreen(scene);
loader.load( './modeles/tv.glb', (gltf) => {
const tv = gltf.scene.children[0];
const boundingBox = new THREE.Box3().setFromObject(tv);
const center = boundingBox.getCenter(new THREE.Vector3());
tv.geometry.center();
this.tv = tv;
tv.position.set(0, 0.99, 2);
tv.material = new THREE.MeshPhysicalMaterial({color: 0xaaaaaa});
tv.material.roughness = 10;
tv.material.metalness = 1;
tv.scale.set(0.05, 0.05, 0.05);
tv.castShadow = true;
tv.receiveShadow = true;
scene.add(tv);
}, undefined, function ( error ) {
console.error( error );
throw Error("Can't open file 'tv.glb'");
} );
this.#showVideo('/modeles/pong.mp4')
}
#createScreen(scene)
{
const geometry = new THREE.PlaneGeometry(4.1, 3, 50, 50);
const positionAttribute = geometry.attributes.position;
const vertices = positionAttribute.array;
const material = new THREE.MeshStandardMaterial({color: 0xbbbbbb});
const mesh = new THREE.Mesh(geometry, material);
const pointLight = new THREE.PointLight( 0xffffff, 10 * this.pointLightIntensity, 0, 2);
for (let i = 0; i < vertices.length; i += 3)
{
const x = vertices[i];
const y = vertices[i + 1];
const distance = (Math.sqrt(x * x + y * y));
const height = Math.pow(distance, 2) * -0.02;
vertices[i + 2] = height;
}
positionAttribute.needsUpdate = true;
mesh.scale.set(0.41, 0.42);
mesh.position.set(-0.155, 1.2, 1.15);
mesh.rotation.x = Math.PI + 0.05;
mesh.rotation.z = Math.PI;
scene.add(mesh);
pointLight.position.set(-0.05, 1.2, 0.95);
pointLight.castShadow = true;
pointLight.shadow.mapSize.width = 2048;
pointLight.shadow.mapSize.height = 2048;
console.log(pointLight.shadow)
scene.add(pointLight);
setInterval(() => {
const intensity = Math.random() * 2 + 10;
pointLight.intensity = intensity * this.pointLightIntensity > 13 * this.pointLightIntensity ? 13 * this.pointLightIntensity : intensity * this.pointLightIntensity;
}, 100);
return (mesh);
}
#showVideo(path)
{
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d', { willReadFrequently: true });
const video = document.createElement('video');
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.MeshBasicMaterial({ map: texture,color: 0xffffff, transparent: true, opacity: 1 });
canvas.width = 534;
canvas.height = 360;
video.src = path + '?t=' + new Date().getTime();
video.loop = true;
video.muted = true;
video.crossOrigin = 'anonymous';
video.addEventListener('loadedmetadata', () => {
const texture = this.screen.material.map;
texture.needsUpdate = true;
video.play().then(() => {
updateCanvas();
}).catch(err => console.error("Error playing video: ", err));
});
function addNoiseOnImage(context)
{
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4)
{
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const brightness = (3 * r + 4 * g + b) >>> 3;
const noise = Math.random() * 128 - 32;
data[i] = data[i + 1] = data[i + 2] = brightness + noise;
}
context.putImageData(imageData, 0, 0);
}
function updateCanvas()
{
if (!video.paused && !video.ended)
{
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(video, 0, 0, canvas.width, canvas.height);
addNoiseOnImage(context);
texture.needsUpdate = true;
}
requestAnimationFrame(updateCanvas);
}
texture.offset.set(0.02, 0);
this.screen.material = material;
video.load();
}
};
export { Screen };

View File

@ -0,0 +1,162 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* home3D.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: marvin <marvin@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/22 17:19:17 by edbernar #+# #+# */
/* Updated: 2024/08/24 11:41:18 by marvin ### ########.fr */
/* */
/* ************************************************************************** */
import * as THREE from 'three'
import { Screen } from './Screen.js'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { BokehPass } from 'three/examples/jsm/postprocessing/BokehPass.js';
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({antialias: true});
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight);
const ambiantLight = new THREE.AmbientLight(0xffffff, 35);
const screen = new Screen(scene);
const cube = createCube();
renderer.toneMapping = THREE.LinearToneMapping;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.getElementsByClassName('homeSection')[0].appendChild(renderer.domElement);
scene.background = new THREE.Color(0x020202)
camera.position.set(6, 1, -5.5);
camera.rotation.set(Math.PI + 0.2, 0, Math.PI);
scene.add(ambiantLight);
let globalSpeed = 0.75;
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
const dofPass = new BokehPass(scene, camera, {
focus: 10.0,
aperture: 0.020,
maxblur: 0.01,
});
composer.addPass(dofPass);
setTimeout(() => {
let interval = setInterval(() => {
camera.position.x -= (0.01 * globalSpeed);
camera.lookAt(screen.tv.position);
if (camera.position.x < 3.3)
fadeInOut();
if (dofPass.materialBokeh.uniforms.aperture.value > 0)
dofPass.materialBokeh.uniforms.aperture.value -= 0.0001;
if (camera.position.x < 3)
{
clearInterval(interval);
camera.position.set(-2, 4, -6);
interval = setInterval(() => {
camera.lookAt(screen.tv.position);
camera.position.x += (0.01 * globalSpeed);
camera.position.y -= (0.005 * globalSpeed);
if (camera.position.x > 1.7)
fadeInOut();
if (camera.position.x > 2)
{
camera.position.set(0, 1.2, 0);
clearInterval(interval);
interval = setInterval(() => {
camera.lookAt(screen.tv.position);
camera.position.y += (0.005 * globalSpeed);
camera.position.z -= (0.01 * globalSpeed);
if (camera.position.x < -2.3)
fadeInOut();
if (camera.position.z < -2)
{
globalSpeed -= 0.001;
if (globalSpeed < 0)
clearInterval(interval);
}
}, 10);
}
}, 10);
}
}, 10);
}, 500)
document.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
let isInFade = false;
function fadeInOut()
{
if (isInFade)
return;
let interval = null;
isInFade = true;
interval = setInterval(() => {
screen.pointLightIntensity -= 0.2;
screen.screen.material.opacity -= 0.05;
if (screen.screen.material.opacity <= 0)
{
clearInterval(interval);
setTimeout(() => {
interval = setInterval(() => {
screen.pointLightIntensity += 0.2;
screen.screen.material.opacity += 0.05;
if (screen.screen.material.opacity >= 1)
{
clearInterval(interval);
isInFade = false;
}
}, 20);
}, 500);
}
}, 20);
}
function createCube()
{
const geometry = new THREE.BoxGeometry(5, 5, 0.1);
const material = new THREE.MeshStandardMaterial({color: 0x020202});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(8, 1, -5);
scene.add(mesh);
}
function home3D()
{
createPlane();
renderer.setAnimationLoop(loop)
}
function createPlane()
{
const geometry = new THREE.PlaneGeometry(500, 500);
const material = new THREE.MeshPhysicalMaterial({side: THREE.DoubleSide, color: 0x020202});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 0, 0);
mesh.rotateX(-(Math.PI / 2));
mesh.receiveShadow = true;
scene.add(mesh);
}
function loop()
{
composer.render();
// renderer.render(scene, camera);
}
export { home3D };

View File

@ -0,0 +1,81 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* main.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/04 19:19:10 by edbernar #+# #+# */
/* Updated: 2024/08/04 23:10:18 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { infoPanel } from "../typeResponse/typePrivateListMessage.js";
import { showActualGameMessage } from "./showActualGameMessage.js";
import { showListUser } from "./showUserList.js";
/*
Todo (Eddy) :
- add a function to "New conversation +"
- game message when game will be implemented
*/
function addDefaultButton()
{
const newDiv = document.createElement("div");
const newPrivateButton = document.createElement("h2");
const newGameButton = document.createElement("h2");
const divMessageListChatHome = document.createElement("div");
newDiv.setAttribute("id", "buttonTypeChatHome");
newPrivateButton.textContent = "Private";
newGameButton.textContent = "Game";
newPrivateButton.setAttribute("id", "selected");
newDiv.appendChild(newPrivateButton);
newDiv.appendChild(newGameButton);
document.getElementById("chatDiv").appendChild(newDiv);
divMessageListChatHome.setAttribute("id", "messageListChatHome");
document.getElementById("chatDiv").appendChild(divMessageListChatHome);
newPrivateButton.addEventListener("click", async () => {
newGameButton.removeAttribute("id");
newPrivateButton.setAttribute("id", "selected");
await showListUser();
});
newGameButton.addEventListener("click", () => {
newPrivateButton.removeAttribute("id");
newGameButton.setAttribute("id", "selected");
showActualGameMessage();
});
}
function removeButtonIfExist()
{
const divButtonTypeChatHome = document.getElementById("buttonTypeChatHome");
if (divButtonTypeChatHome)
{
divButtonTypeChatHome.remove();
document.getElementById("messageListChatHome").remove();
}
}
function liveChat()
{
const chatButton = document.getElementById("chatButton");
const chatDiv = document.getElementById("chatDiv");
const topChatHomeCross = document.getElementById("topChatCross");
chatButton.addEventListener("click", async () => {
chatDiv.style.display = "flex";
removeButtonIfExist();
addDefaultButton();
await showListUser();
});
topChatHomeCross.addEventListener("click", () => {
chatDiv.style.display = "none";
infoPanel.isOpen = false;
});
}
export { liveChat };

View File

@ -0,0 +1,96 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* showActualGameMessage.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/04 19:21:55 by edbernar #+# #+# */
/* Updated: 2024/08/06 23:19:51 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { sendRequest } from "../websocket.js";
function showActualGameMessage()
{
const divMessageListChatHome = document.getElementById("messageListChatHome");
let newDiv = null;
let contentNode = null;
let dateNode = null;
let tmp = null;
let me = "Kumita";
let request = {
isInGame: true,
opponent: {
name: "Astropower",
id: "301547"
},
listMessage: [
{
from: "Astropower",
content: "Hello !",
date: "19:21 30/07/2024"
},
{
from: "Kumita",
content: "Hey",
date: "19:21 30/07/2024"
},
{
from: "Astropower",
content: "Do you want play ?",
date: "19:22 30/07/2024"
},
{
from: "Kumita",
content: "Yes, i'm ready !",
date: "19:22 30/07/2024"
},
{
from: "Kumita",
content: "The game was too hard but well played",
date: "19:27 30/07/2024"
},
{
from: "Astropower",
content: "Yeah but you still won. See you soon",
date: "19:27 30/07/2024"
},
]
}; //Remplace temporairement la requete qui devra être de la meme forme
divMessageListChatHome.style.height = "230px";
divMessageListChatHome.style.paddingBottom = "20px";
divMessageListChatHome.innerHTML = '';
if (request.isInGame === false)
{
divMessageListChatHome.innerHTML = "<p style='text-align: center; margin-top: 20px;'>You are currently not in a game.</p>";
return ;
}
request.listMessage.forEach(element => {
newDiv = document.createElement("div");
contentNode = document.createTextNode(element.content);
dateNode = document.createTextNode(element.date);
newDiv.classList.add(element.from == me ? "meMessage" : "opponentMessage");
tmp = document.createElement("p");
tmp.classList.add("content");
tmp.appendChild(contentNode);
newDiv.appendChild(tmp);
tmp = document.createElement("p");
tmp.classList.add("time");
tmp.appendChild(dateNode);
newDiv.appendChild(tmp);
divMessageListChatHome.appendChild(newDiv);
});
divMessageListChatHome.scrollTop = divMessageListChatHome.scrollHeight;
divMessageListChatHome.innerHTML += `
<div id="inputMessageDiv">
<textarea type="text" id="inputMessage" placeholder="Enter your message here"></textarea>
<p id="sendButton">\></p>
</div>
`;
}
export { showActualGameMessage };

View File

@ -0,0 +1,153 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* showPrivateChat.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/04 19:17:54 by edbernar #+# #+# */
/* Updated: 2024/08/06 23:32:35 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { messageList, infoPanel, waitForMessageList } from "../typeResponse/typePrivateListMessage.js";
import { userMeInfo } from "../typeResponse/typeLogin.js";
import { showListUser } from "./showUserList.js";
import { sendRequest } from "../websocket.js";
let savedButtons = [];
async function showPrivateChat(user)
{
const divMessageListChatHome = document.getElementById("messageListChatHome");
sendRequest("get_private_list_message", {id: user.id});
await waitForMessageList();
infoPanel.id = user.id;
infoPanel.isOpen = true;
infoPanel.divMessage = divMessageListChatHome;
await changeButton(user);
await displayAllMessage(divMessageListChatHome);
await displayInputBar(divMessageListChatHome, user);
}
async function restoreButton()
{
const divButtonTypeChatHome = document.getElementById("buttonTypeChatHome");
divButtonTypeChatHome.innerHTML = '';
savedButtons.forEach(element => {
divButtonTypeChatHome.appendChild(element);
});
}
async function changeButton(user)
{
const divButtonTypeChatHome = document.getElementById("buttonTypeChatHome");
const h2Username = document.createElement("h2");
const h2UsernameNode = document.createTextNode(user.name);
let returnButton = null;
let h2Button = null;
let lenh2Button = 0;
h2Button = divButtonTypeChatHome.getElementsByTagName("h2");
lenh2Button = h2Button.length;
savedButtons.splice(0, savedButtons.length);
for (let i = 0; i < lenh2Button; i++) {
savedButtons.push(h2Button[0]);
h2Button[0].remove();
}
h2Username.appendChild(h2UsernameNode);
divButtonTypeChatHome.appendChild(h2Username);
divButtonTypeChatHome .innerHTML += `
<p id="returnButton" style="margin: 8px 10px 0 0; text-align: right;">Return</p>
`;
h2Button[0].style.cursor = "default";
returnButton = document.getElementById("returnButton");
returnButton.style.cursor = "pointer";
returnButton.addEventListener("click", () => {
restoreButton();
infoPanel.isOpen = false;
showListUser();
});
}
async function displayAllMessage(divMessageListChatHome)
{
let newDiv = null;
let contentNode = null;
let dateNode = null;
let tmp = null;
divMessageListChatHome.style.height = "230px";
divMessageListChatHome.style.paddingBottom = "20px";
divMessageListChatHome.innerHTML = '';
messageList.forEach(element => {
newDiv = document.createElement("div");
contentNode = document.createTextNode(element.content);
dateNode = document.createTextNode(element.date);
console.log(element.from, userMeInfo.id);
newDiv.classList.add(element.from === userMeInfo.id ? "meMessage" : "opponentMessage");
tmp = document.createElement("p");
tmp.classList.add("content");
tmp.appendChild(contentNode);
newDiv.appendChild(tmp);
tmp = document.createElement("p");
tmp.classList.add("time");
tmp.appendChild(dateNode);
newDiv.appendChild(tmp);
divMessageListChatHome.appendChild(newDiv);
});
divMessageListChatHome.scrollTop = divMessageListChatHome.scrollHeight;
}
async function displayInputBar(divMessageListChatHome, user)
{
let sendButton;
let inputMessage;
divMessageListChatHome.innerHTML += `
<div id="inputMessageDiv">
<textarea type="text" id="inputMessage" placeholder="Enter your message here"></textarea>
<p id="sendButton"">\></p>
</div>
`;
sendButton = document.getElementById("sendButton");
sendButton.style.cursor = "pointer";
sendButton.addEventListener("click", () => {
sendMessage(user);
inputMessage.value = "";
inputMessage.focus();
});
inputMessage = document.getElementById("inputMessage");
inputMessage.addEventListener("keyup", (event) => {
if (event.key === "Enter" && !event.shiftKey && inputMessage.value.trim() !== "")
{
event.preventDefault();
sendMessage(user);
inputMessage.value = "";
inputMessage.focus();
}
});
inputMessage.addEventListener("keydown", (event) => {
if (event.key === "Enter")
event.preventDefault();
});
inputMessage.focus();
}
function sendMessage(user)
{
const inputMessage = document.getElementById("inputMessage");
let message;
message = {
from: userMeInfo.id,
to: user.id,
content: inputMessage.value,
time: new Date()
};
sendRequest("send_private_message", message);
}
export { showPrivateChat };

View File

@ -0,0 +1,53 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* showUserList.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/04 19:21:10 by edbernar #+# #+# */
/* Updated: 2024/08/05 14:28:31 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { waitForUserList } from "../typeResponse/typePrivateListUser.js";
import { userList } from "../typeResponse/typePrivateListUser.js";
import { showPrivateChat } from "./showPrivateChat.js";
import { sendRequest } from "../websocket.js";
async function showListUser() {
const divMessageListChatHome = document.getElementById("messageListChatHome");
let divUser;
sendRequest("get_private_list_user", {});
await waitForUserList();
divMessageListChatHome.style.height = "100%";
divMessageListChatHome.style.paddingBottom = "10px";
divMessageListChatHome.innerHTML = '';
divMessageListChatHome.scrollTop = 0;
if (JSON.stringify(userList) !== "{}")
{
userList.forEach(element => {
let user = document.createElement("div");
user.classList.add("user");
user.innerHTML = `
<div class="status ${element.status}">
<img>
</div>
<h3></h3>
`
user.querySelector("img").src = element.pfp;
user.querySelector("h3").innerText = element.name;
divMessageListChatHome.appendChild(user);
});
}
divMessageListChatHome.innerHTML += "<p style='text-align: center; margin-top: 20px;'>New conversation +</p>";
divUser = document.getElementsByClassName("user");
for (let i = 0; i < divUser.length; i++) {
divUser[i].addEventListener("click", async () => {
await showPrivateChat(userList[i]);
});
}
}
export { showListUser };

View File

@ -0,0 +1,28 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* connectedWith42.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/09 09:15:24 by edbernar #+# #+# */
/* Updated: 2024/08/10 15:02:33 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { typeLogin } from "../typeResponse/typeLogin.js";
import { sendRequest } from "../websocket.js";
function connectedWith42Func()
{
const token42 = window.location.search.split('code=')[1];
if (!token42)
{
typeLogin(null);
return ;
}
sendRequest("login", {type: "by42", token: token42});
}
export { connectedWith42Func };

View File

@ -0,0 +1,87 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* main.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: madegryc <madegryc@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/07 17:40:15 by edbernar #+# #+# */
/* Updated: 2024/08/23 18:35:44 by madegryc ### ########.fr */
/* */
/* ************************************************************************** */
import { createNotification as CN } from "../notification/main.js";
import { userMeInfo, waitForLogin } from "../typeResponse/typeLogin.js";
function login()
{
const loginButton = document.getElementById('loginButton');
const pLoginButton = loginButton.getElementsByTagName('p')[0];
let nodeText = null;
// waitForLogin().then((token) => {
// nodeText = document.createTextNode(userMeInfo.username);
// if (userMeInfo.id !== -1)
// {
// loginButton.replaceChild(nodeText, pLoginButton);
// loginButton.addEventListener('click', showMenu);
// }
// else
loginButton.addEventListener('click', showLoginDiv);
// });
}
function showLoginDiv()
{
const popout = document.getElementById('loginPopup');
if (popout.style.display === 'flex')
popout.style.display = 'none';
else
popout.style.display = 'flex';
}
function showMenu()
{
const loginButton = document.getElementById('loginButton');
const divMenu = document.createElement("div");
const ul = document.createElement("ul");
const li1 = document.createElement("li");
const li2 = document.createElement("li");
let already_activated = false;
divMenu.setAttribute("id", "menuDiv");
li1.innerHTML = "Profile";
li2.innerHTML = "Logout";
li1.addEventListener('click', (e) => {
console.log("profile");
});
li2.addEventListener('click', (e) => {
document.cookie = "token=; path=/; Secure; SameSite=Strict; max-age=0";
window.location.href = "/";
location.reload();
});
ul.appendChild(li1);
ul.appendChild(li2);
divMenu.appendChild(ul);
divMenu.style.position = "absolute";
divMenu.style.width = loginButton.offsetWidth + "px";
divMenu.style.top = loginButton.offsetTop + loginButton.offsetHeight + "px";
divMenu.style.left = loginButton.offsetLeft + "px";
document.body.appendChild(divMenu);
loginButton.removeEventListener('click', showMenu);
loginButton.addEventListener('click', () => {
if (!already_activated)
{
setTimeout(() => {
document.getElementById("menuDiv").remove();
loginButton.addEventListener('click', showMenu);
already_activated = true;
}, 199);
document.getElementById("menuDiv").style.animation = "animHideMenuDiv 0.21s";
}
});
}
export { login, showLoginDiv, showMenu };

View File

@ -0,0 +1,36 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* main.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: marvin <marvin@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/07/30 13:50:35 by edbernar #+# #+# */
/* Updated: 2024/08/24 11:57:47 by marvin ### ########.fr */
/* */
/* ************************************************************************** */
import { liveChat } from "./liveChat/main.js";
import { login } from "./login/main.js";
import { home3D } from "./home3D/home3D.js"
window.addEventListener('scroll', () => {
const scrollPosition = window.scrollY;
const rotationAngle = scrollPosition * 0.1;
const parallaxElement = document.querySelector('#firstBall');
const parallaxElement2 = document.querySelector('#secondBall');
const parallaxSpeed = scrollPosition * -0.17;
parallaxElement.style.transform = `translateX(-50%) translateY(${-parallaxSpeed}px) rotate(${rotationAngle}deg)`;
parallaxElement2.style.transform = `translateX(50%) translateY(${-parallaxSpeed}px) rotate(${rotationAngle}deg)`;
});
// document.getElementById('closePopupBtn').addEventListener('click', function() {
// document.getElementById('loginPopup').style.display = 'none';
// });
document.addEventListener('DOMContentLoaded', () => {
liveChat();
login();
home3D();
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,170 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* main.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/04 23:32:52 by edbernar #+# #+# */
/* Updated: 2024/08/06 23:34:39 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
function createHeader(title, img)
{
const divHeader = document.createElement("div");
const icon = document.createElement("img");
const h1Title = document.createElement("h1");
const cross = document.createElement("p");
const titleTextNode = document.createTextNode(title);
divHeader.classList.add("header");
if (img)
{
icon.style.width = "20px";
icon.style.height = "20px";
icon.style.position = 'absolute';
icon.src = img;
}
h1Title.appendChild(titleTextNode);
h1Title.style.textAlign = "center";
h1Title.style.width = "100%";
h1Title.style.marginTop = "5px";
cross.innerHTML = "X";
cross.style.position = 'absolute';
cross.style.cursor = 'pointer';
cross.style.margin = '0';
cross.style.right = '10px';
cross.style.marginTop = '5px';
cross.style.fontSize = '20px';
cross.style.fontWeight = 'bold';
cross.addEventListener("click", () => {
divHeader.parentNode.style.animation = "slideOut 0.21s";
setTimeout(() => {
divHeader.parentNode.remove();
}, 199);
});
if (img)
divHeader.appendChild(icon);
divHeader.appendChild(h1Title);
divHeader.appendChild(cross);
return (divHeader);
}
function createContent(message)
{
const divContent = document.createElement("div");
const pMessage = document.createElement("p");
const pMessageNode = document.createTextNode(message);
const limit = 100;
divContent.classList.add("content");
pMessage.style.textAlign = "center";
if (message.length > limit)
message = message.substring(0, limit) + "...";
pMessage.appendChild(pMessageNode);
divContent.appendChild(pMessage);
return (divContent);
}
function createLoadBar(newNotification, timer)
{
const divLoadBar = document.createElement("div");
const progress = document.createElement("div");
let interval = null;
const intervalTimer = timer / 100;
let i = 1;
progress.classList.add("progress");
divLoadBar.classList.add("loadBar");
divLoadBar.appendChild(progress);
progress.style.height = '5px';
progress.style.width = '0px';
progress.style.backgroundColor = 'black';
newNotification.addEventListener("mouseover", () => {
clearInterval(interval);
progress.style.width = "100%";
});
interval = setInterval(() => {
progress.style.width = (intervalTimer * i) * 100 / timer + "%";
i++;
}, intervalTimer);
setTimeout(() => {
clearInterval(interval);
}, timer);
newNotification.appendChild(divLoadBar);
return (interval);
}
function createFooter(action, actionText)
{
const newButton = document.createElement("div");
const textNode = document.createTextNode(actionText);
if (action == null)
return (null);
newButton.style.cursor = "pointer";
if (actionText.length > 20)
actionText = actionText.substring(0, 20) + "...";
newButton.appendChild(textNode);
newButton.setAttribute("onclick", action);
newButton.classList.add("footer");
if (typeof(action) !== "function")
throw new Error("Action must be a function");
newButton.addEventListener("click", action);
return (newButton);
}
function newNotification(title, message, img, action, timer, actionText)
{
const divNotification = document.getElementById("divNotification");
const newNotification = document.createElement("div");
const header = createHeader(title, img);
const content = createContent(message);
const footer = createFooter(action, actionText);
let intervalLoadBar = null;
let timeoutInTimout = null;
console.log("New notification: " + message);
newNotification.classList.add("notification");
newNotification.style.width = "100%";
newNotification.appendChild(header);
divNotification.appendChild(newNotification);
newNotification.appendChild(content);
if (footer)
newNotification.appendChild(footer);
intervalLoadBar = createLoadBar(newNotification, timer);
const timeout = setTimeout(() => {
timeoutInTimout = setTimeout(() => {
divNotification.removeChild(newNotification);
}, 199);
newNotification.style.animation = "slideOut 0.21s";
}, timer);
newNotification.addEventListener("mouseover", () => {
clearTimeout(timeout);
clearTimeout(timeoutInTimout);
clearInterval(intervalLoadBar);
});
}
class notification
{
timer = 5000;
defaultIcon = {
"warning": "/site/notification/ico/warning.png",
"error": "/site/notification/ico/error.png",
"success": "/site/notification/ico/success.png",
"info": "/site/notification/ico/info.png"
};
constructor() {}
new(title, message, img=null, action=null, actionText="Confirm")
{
newNotification(title, message, img, action, this.timer, actionText);
}
}
const createNotification = new notification();
export { createNotification };

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 MiB

View File

@ -0,0 +1,409 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* home.css :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: marvin <marvin@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/07 12:00:55 by edbernar #+# #+# */
/* Updated: 2024/08/24 11:26:27 by marvin ### ########.fr */
/* */
/* ************************************************************************** */
@keyframes animShowMenuDiv {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes animHideMenuDiv {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-thumb {
background: white;
}
* {
margin: 0;
padding: 0;
}
body {
border: 0;
padding: 0;
width: 100%;
height: 100%;
background-color: #020202;
user-select: none;
font-family: "Poppins", sans-serif;
font-weight: 500;
font-style: normal;
}
#topBar {
margin-block: 25px;
padding: 0;
padding-inline: 50px;
display: flex;
gap: 2rem;
align-items: center;
position: absolute;
inset-inline: 0;
top: 0;
z-index: 999;
}
#topButton{
padding: 0;
color: white;
display: flex;
font-size: 25px;
padding-left: 60px;
gap: 6rem;
}
#topButton p {
position: relative;
}
#topButton p:after {
content: "";
position: absolute;
background-color: white;
height: 3px;
width: 0%;
left: 0;
bottom: 1px;
transition: 0.3s;
}
#topButton p:hover:after {
/* color: blue; */
width: 100%;
}
#topBar h1 {
padding: 0;
padding-top: 4px;
font-size: 35px;
color: white;
font-family: 'Poppins';
font-style: italic;
font-weight: bold;
}
#topBar #loginButton {
font-size: 20px;
background-color: white;
height: 40px;
width: 130px;
color: black;
text-align: center;
line-height: 40px;
margin-left: auto;
transition: background-color 0.3s ease;
}
#topBar #loginButton:hover {
background-color: #020202;
color: white;
cursor: pointer;
}
.popup {
display: none; /* La popup est masquée par défaut */
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(5px);
justify-content: center;
align-items: center;
z-index: 1000;
}
.container {
display: flex;
width: 70%;
height: 80%;
background-color: #020202;
}
.left-side {
background-color: #D3D3D3;
flex: 1;
}
.right-side {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
padding: 0;
padding-inline: 180px;
color: white;
}
.right-side h1 {
font-size: 2rem;
margin-bottom: 30px;
align-items: center;
justify-content: center;
}
form {
display: flex;
flex-direction: column;
}
label {
margin-bottom: 5px;
font-size: 1rem;
}
input {
border: none;
padding: 20px;
margin-bottom: 20px;
font-size: 1rem;
font-family: "Poppins", sans-serif;
font-weight: 500;
font-style: normal;
}
button {
padding: 15px;
font-size: 1rem;
cursor: pointer;
border: none;
font-family: "Poppins", sans-serif;
font-weight: 500;
font-style: normal;
}
.login-btn {
background-color: #fff;
margin-bottom: 20px;
transition: background-color 0.3s ease;
}
.login-btn:hover {
background-color: #f0f0f0e1;
}
.new-player {
text-align: center;
margin-bottom: 20px;
}
.new-player a {
color: white;
text-decoration: underline;
transition: color 0.3s ease;
}
.new-player a:hover {
color: #f0f0f0e1;
}
.divider {
display: flex;
align-items: center;
text-align: center;
margin-bottom: 20px;
}
.divider span {
flex: 1;
height: 1px;
background-color: #fff;
}
.divider p {
margin: 0 10px;
font-size: 1rem;
}
.login-42-btn {
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
transition: background-color 0.3s ease;
}
.login-42-btn span {
font-size: 1.5rem;
font-weight: bold;
}
.login-42-btn:hover {
background-color: #f0f0f0e1;
}
.close {
position: absolute;
top: 10px;
right: 10px;
font-size: 20px;
cursor: pointer;
}
.homeSection{
min-height: 100svh;
overflow: hidden;
}
.homeSection p{
color: white;
}
#firstText{
font-size: 45px;
padding-inline: 50px;
padding-top: 70px;
}
#secondText{
font-size: 45px;
padding-inline: 50px;
padding-top: 140px;
text-align: right;
}
#firstBall{
position: absolute;
width: 340px;
transform-origin: center;
transform: translateX(-50%);
left: 0;
}
#secondBall{
position: absolute;
width: 340px;
transform-origin: center;
transform: translateX(50%);
top: 250px;
right: 0;
}
.relative{
position: relative;
}
#menuDiv {
display: flex;
flex-direction: column;
align-items: right;
font-family: "Poppins", sans-serif;
background-color: #ffffff;
animation: animShowMenuDiv 0.5s;
}
#menuDiv li {
list-style-type: none;
text-align: center;
font-size: 16px;
padding: 10px;
cursor: pointer;
}
#menuDiv li:hover {
background-color: #f0f0f0;
}
.team {
display: flex;
gap: 40px;
padding-inline: 200px;
padding-block: 200px;
justify-content: center;
}
.team h2 {
color: white;
font-size: 30px;
}
.team-member {
max-width: 350px;
transition: transform 0.3s ease;
}
.team-member:hover {
transform: scale(1.2);
}
.team-member:not(:hover) {
transform: scale(0.8);
}
.team-photo {
width: 100%;
height: auto;
}
.info {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%) translateY(10px);
background-color: #020202;
padding: 10px;
width: 100%;
opacity: 0;
transition: transform 0.3s ease, opacity 0.3s ease;
}
.team-member:hover .info {
transform: translateX(-50%) translateY(25%);
opacity: 1;
}
footer {
padding: 25px;
overflow: hidden;
height: 150px;
background-color: white;
color: #020202;
}
.footer-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.footer-left h1 {
font-size: 1.5em;
font-style: italic;
font-weight: bold;
margin: 0;
}
.footer-left p {
color: #afafaf;
}
.footer-right p {
font-weight: bold;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 MiB

View File

@ -0,0 +1,235 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* liveChat.css :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: marvin <marvin@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/07/30 13:53:39 by edbernar #+# #+# */
/* Updated: 2024/08/10 16:47:10 by marvin ### ########.fr */
/* */
/* ************************************************************************** */
#chatButton {
position: absolute;
bottom: 10px;
left: 30px;
background-color: white;
width: 100px;
height: 40px;
text-align: center;
cursor : pointer;
z-index: 10;
}
#chatButton p {
margin: 0;
margin-top: 10px;
}
#chatButton:hover {
background-color: rgb(204, 204, 204);
}
#chatDiv {
width: 350px;
height: 400px;
background-color: #131313;
position: absolute;
left: 20px;
bottom: 0px;
z-index: 999;
display: none;
flex-direction: column;
color: white;
font-family: 'Poppins';
padding: 20px;
padding-bottom: 0;
}
#chatDiv h1 {
margin: 0;
font-size: 25px;
}
/* Delete this, is just for cross style */
#chatDiv h2 {
cursor : pointer;
margin: 0;
font-size: 25px;
}
#chatDiv #topChatHome {
display: flex;
flex-direction: row;
justify-content: space-between;
padding-bottom: 10px;
}
#buttonTypeChatHome {
display: grid;
grid-template-columns: 50% 50%;
width: 100%;
}
#buttonTypeChatHome h2 {
text-align: center;
font-size: 20px;
color: #dfdfdf;
padding-top: 5px;
padding-bottom: 5px;
}
#selected {
background-color: black;
}
#messageListChatHome {
display: flex;
flex-direction: column;
overflow: auto;
height: 230px;
padding-bottom: 20px;
padding-top: 5px;
}
#messageListChatHome .user {
display: flex;
flex-direction: row;
height: 75px;
margin: 0;
padding: 10px 0 5px 5px;
}
#messageListChatHome .user:hover {
background-color: #484848;
cursor : pointer;
}
#messageListChatHome .user .status {
border-radius: 1000px;
width: 60px;
height: 60px;
margin-right: 10px;
}
#messageListChatHome .online {
background-color: rgb(17, 165, 29);
}
#messageListChatHome .offline {
background-color: rgb(148, 39, 39);
}
#messageListChatHome .user img {
height: 52px;
width: 52px;
margin-left: 4px;
margin-top: 4px;
border-radius: 100%;
}
#messageListChatHome .opponentMessage {
max-width: 80%;
padding: 10px;
margin-top: 20px;
background-color: #484848;
margin-right: auto;
}
#messageListChatHome .meMessage {
max-width: 80%;
padding: 10px;
margin-top: 20px;
background-color: #222222;
margin-right: 0;
margin-left: auto;
}
#messageListChatHome .meMessage p {
text-align: right;
}
#messageListChatHome .content {
user-select: text;
}
#messageListChatHome .time {
margin-top: 10px;
font-size: 12px;
}
#messageListChatHome p {
margin: 0;
word-break: break-word;
}
#inputMessageDiv {
position: absolute;
width: 348px;
height: 50px;
background-color: #0B0B0B;
bottom: 10px;
color: white;
display: flex;
flex-direction: row;
}
#inputMessageDiv p {
margin: 0;
margin-left: 10px;
margin-right: 10px;
font-family: "Poppins";
font-weight: bolder;
font-size: 35px;
margin-top: -2px;
}
#inputMessage{
user-select: text;
background-color: #0f0f0f;
width: 100%;
overflow: hidden;
resize: none;
border: 0;
color: white;
padding: 15px 5% 15px 5%;
}
#inputMessage:focus {
outline: none;
border: 0;
}
#messageListChatHome {
--sb-thumb-color: #080808;
--sb-size: 5px;
}
#messageListChatHome::-webkit-scrollbar {
width: var(--sb-size)
}
#messageListChatHome::-webkit-scrollbar-track {
border-radius: 1px;
}
#messageListChatHome::-webkit-scrollbar-thumb {
background: var(--sb-thumb-color);
border-radius: 1px;
}
@supports not selector(::-webkit-scrollbar) {
#messageListChatHome {
scrollbar-color: var(--sb-thumb-color)
var(--sb-track-color);
}
}

View File

@ -0,0 +1,199 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* loginPage.css :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: marvin <marvin@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/07 17:15:28 by edbernar #+# #+# */
/* Updated: 2024/08/13 13:30:43 by marvin ### ########.fr */
/* */
/* ************************************************************************** */
@keyframes anim1 {
0% {
transform: translate(0, -150%);
}
100% {
transform: translateY(0, 0);
}
}
@keyframes anim2 {
0% {
backdrop-filter: blur(0px);
background-color: rgba(0, 0, 0, 0);
}
100% {
backdrop-filter: blur(5px);
background-color: rgba(0, 0, 0, 0.8);
}
}
#mainText{
color: white;
font-size: 50px;
font-family: "Poppins", sans-serif;
font-weight: 500;
font-style: normal;
margin-top: 125px;
margin-bottom: 50px;
align-content: center;
text-align: center;
}
#inputLogin{
margin-top: 2px;
margin-bottom: 15px;
padding-left: 3%;
padding-right: 3%;
font-family: "Poppins", sans-serif;
font-weight: 500;
font-style: normal;
border: none;
text-decoration: none;
height: 45px;
width: 94%;
}
#inputPassword{
margin-top: 2px;
margin-bottom: 25px;
padding-left: 3%;
padding-right: 3%;
font-family: "Poppins", sans-serif;
font-weight: 500;
font-style: normal;
border: none;
text-decoration: none;
height: 45px;
width: 94%;
}
#styleButton{
font-family: "Poppins", sans-serif;
font-weight: 600;
font-style: normal;
height: 45px;
width: 100%;
border: none;
text-decoration: none;
transition: background-color 0.3s ease;
}
#styleButton:hover{
background-color: #b4b4b4;
}
#styleButton42{
font-family: "Poppins", sans-serif;
font-weight: 600;
font-style: normal;
height: 45px;
width: 100%;
border: none;
text-decoration: none;
transition: background-color 0.3s ease;
}
#styleButton42:hover{
background-color: #b4b4b4;
}
#createAccText{
margin-left: 10px;
cursor: pointer;
border-bottom: white 1px solid;
transition: color 0.3s ease;
}
#createAccText:hover{
color: rgb(165, 165, 165);
}
#orText{
align-content: center;
text-align: center;
margin-top: 15px;
margin-bottom: 15px;
}
#newAccDiv{
display: flex;
flex-direction: row;
margin-top: 15px;
margin-bottom: 15px;
justify-content: center;
}
#loginDiv {
inset: 0;
padding-block: 7rem;
display: flex;
position: absolute;
z-index: 500;
animation: anim1 0.4s;
font-family: "Poppins", sans-serif;
font-weight: 500;
font-style: normal;
justify-content: center;
}
#globalBg {
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
position: absolute;
z-index: 499;
top: 0;
left: 0;
backdrop-filter: blur(5px);
animation: anim2 0.5s;
}
#threeDiv {
width: 20%;
height: 100%;
background-color: white;
}
#connectDiv {
width: 45%;
height: 100%;
background-color: #020202;
display: flex;
flex-direction: column;
}
#connectDiv #divCenter {
width: 45%;
height: 50%;
margin-left: 27.5%;
}
#connectDiv form {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
#connectDiv form p{
color: white;
}
#connectDiv #button {
width: 20%;
height: 20px;
margin: 10px;
cursor: pointer;
background-color: white;
text-align: center;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 MiB

View File

@ -0,0 +1,104 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* notification.css :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/04 23:44:17 by edbernar #+# #+# */
/* Updated: 2024/08/07 18:04:17 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
@keyframes slideIn {
0% {
transform: translateX(100%);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOut {
0% {
transform: translateX(0);
opacity: 1;
}
100% {
transform: translateX(100%);
opacity: 0;
}
}
#divNotification {
position: fixed;
overflow: hidden;
font-family: 'Poppins';
top: 0px;
right: 10px;
display: flex;
flex-direction: column;
z-index: 1000;
}
#divNotification .notification {
background-color: #222222;
display: flex;
flex-direction: column;
color: white;
margin-top: 10px;
min-height: 100px;
min-width: 350px;
max-width: 350px;
animation: slideIn 0.1s;
}
#divNotification .header {
display: flex;
flex-direction: row;
}
#divNotification .header h1 {
font-size: 1.2em;
margin: 0;
}
#divNotification .header img {
color: white;
border: none;
margin-left: 9px;
margin-top: 9px;
object-fit: cover;
object-position: 50% 0;
}
#divNotification .content {
margin: 0;
width: 95%;
padding: 2.5%;
padding-bottom: 0;
}
#divNotification .content p {
word-wrap: break-word;
}
#divNotification .footer {
text-align: center;
background-color: #333333;
margin: 10px;
}
#divNotification .loadBar {
margin-top: auto;
margin-bottom: 0;
padding: 0;
/* position: fixed; */
}
.progress {
transition: width 0.1s;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 MiB

View File

@ -0,0 +1,20 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* typeErrorInvalidPassword.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/07 21:16:09 by edbernar #+# #+# */
/* Updated: 2024/08/07 21:18:22 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { createNotification as NC } from "../notification/main.js";
function typeErrorInvalidPassword()
{
NC.new("Connection error", "Invalid mail or password", NC.defaultIcon.error);
}
export { typeErrorInvalidPassword };

View File

@ -0,0 +1,23 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* typeErrorInvalidToken42.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/10 14:29:34 by edbernar #+# #+# */
/* Updated: 2024/08/10 14:40:10 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { createNotification as NC } from "../notification/main.js";
function typeErrorInvalidToken42()
{
// |Eddy| Changer le path pour mettre le bon path quand il y aura un vrai serveur
window.history.replaceState({}, document.title, "/site/");
NC.new("Error 42", "Invalid token", NC.defaultIcon.error);
}
export { typeErrorInvalidToken42 };

View File

@ -0,0 +1,23 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* typeErrorUnknown42Account.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/10 16:01:51 by edbernar #+# #+# */
/* Updated: 2024/08/10 18:01:08 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { createNotification as CN } from "../notification/main.js";
import { typeLogin } from "../typeResponse/typeLogin.js";
function typeErrorUnknown42Account()
{
window.history.replaceState({}, document.title, "/site/");
CN.new("Unknown 42 account", "Your 42 account is not linked to any account.");
typeLogin(null);
}
export { typeErrorUnknown42Account };

View File

@ -0,0 +1,51 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* typeLogin.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/02 00:39:53 by edbernar #+# #+# */
/* Updated: 2024/08/07 22:14:49 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
let userMeInfo = {
username: "",
id: -1
};
let loginAvailable = false;
let loginResolve = null;
function waitForLogin() {
return new Promise((resolve) => {
if (loginAvailable)
resolve();
else
loginResolve = resolve;
});
}
function typeLogin(content)
{
if (content != null)
{
console.log("Welcome " + content.username + "\nYou're id is " + content.id);
userMeInfo.username = content.username;
userMeInfo.id = content.id;
}
loginAvailable = true;
if (loginResolve)
{
if (content != null)
loginResolve(content.token);
else
loginResolve();
loginResolve = null;
loginAvailable = false;
}
}
export { userMeInfo, typeLogin, waitForLogin };

View File

@ -0,0 +1,32 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* typeNewPrivateMessage.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/04 15:15:49 by edbernar #+# #+# */
/* Updated: 2024/08/04 18:26:40 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { sendRequest } from "../websocket.js";
import { messageList, infoPanel } from "./typePrivateListMessage.js";
import { userMeInfo } from "./typeLogin.js";
function typeNewPrivateMessage(content)
{
messageList.push(content);
if (infoPanel.isOpen && infoPanel.id === content.channel)
{
infoPanel.divMessage.insertAdjacentHTML('beforeend', `
<div class="${content.from === userMeInfo.id ? "meMessage" : "opponentMessage"}">
<p class="content">${content.content}</p>
<p class="time">${content.date}</p>
</div>
`);
infoPanel.divMessage.scrollTop = infoPanel.divMessage.scrollHeight;
}
}
export { typeNewPrivateMessage };

View File

@ -0,0 +1,43 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* typePrivateListMessage.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/03 22:20:35 by edbernar #+# #+# */
/* Updated: 2024/08/04 18:58:45 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
let infoPanel = {
isOpen: false,
id: -1,
divMessage: null
}
let messageList = [];
let messageListAvailable = false;
let messageListResolve = null;
function waitForMessageList() {
return new Promise((resolve) => {
if (messageListAvailable)
resolve();
else
messageListResolve = resolve;
});
}
function typePrivateListMessage(list) {
messageList = list;
messageListAvailable = true;
if (messageListResolve)
{
messageListResolve();
messageListResolve = null;
messageListAvailable = false;
}
}
export { messageList, infoPanel, typePrivateListMessage, waitForMessageList };

View File

@ -0,0 +1,36 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* typePrivateListUser.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/02 01:56:15 by edbernar #+# #+# */
/* Updated: 2024/08/03 14:36:20 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
let userList = [];
let userListAvailable = false;
let userListResolve = null;
function waitForUserList() {
return new Promise((resolve) => {
if (userListAvailable)
resolve();
else
userListResolve = resolve;
});
}
function typePrivateListUser(list) {
userList = list;
userListAvailable = true;
if (userListResolve)
{
userListResolve();
userListResolve = null;
}
}
export { userList, typePrivateListUser, waitForUserList };

View File

@ -0,0 +1,124 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* websocket.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/07/31 22:17:24 by edbernar #+# #+# */
/* Updated: 2024/08/13 00:12:26 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { typeErrorUnknown42Account } from "./typeErrorResponse/typeErrorUnknown42Account.js";
import { typeErrorInvalidPassword } from "./typeErrorResponse/typeErrorInvalidPassword.js";
import { typeErrorInvalidToken42 } from "./typeErrorResponse/typeErrorInvalidToken42.js";
import { typePrivateListMessage } from "./typeResponse/typePrivateListMessage.js";
import { typeNewPrivateMessage } from "./typeResponse/typeNewPrivateMessage.js";
import { typePrivateListUser } from "./typeResponse/typePrivateListUser.js";
import { connectedWith42Func } from "./login/connectedWith42.js";
import { typeLogin } from "./typeResponse/typeLogin.js";
/*
Todo (Eddy) :
- Request to connect by email and password. Waiting for the front to do it (already functional on the back side)
sendRequest("login", {type: "byPass", mail: "aa@aa.fr", password: "ABC123"});
- Information: the 'token' variable is only used until the connection is fully implemented
*/
const socket = new WebSocket('ws://localhost:8000/');
const typeResponse = ["login", "private_list_user", "private_list_message", "new_private_message"];
const functionResponse = [typeLogin, typePrivateListUser, typePrivateListMessage, typeNewPrivateMessage];
const errorCode = [9007, 9010, 9011];
const errorFunction = [typeErrorInvalidPassword, typeErrorInvalidToken42, typeErrorUnknown42Account];
let status = 0;
function getCookie(name)
{
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
let token = null;
if (parts.length === 2)
{
token = parts.pop().split(';').shift();
token = token.substring(1, token.length - 1);
}
return (token);
}
socket.onopen = () => {
let token = getCookie("token");
status = 1;
console.log('Connected');
if (token)
sendRequest("login", {type: "byToken", token: token});
else
connectedWith42Func();
};
socket.onmessage = (event) => {
let response;
try {
response = JSON.parse(event.data);
} catch {
return ;
}
if (response.code >= 9000 && response.code <= 9999)
{
try {
errorFunction[errorCode.indexOf(response.code)]();
} catch {
console.warn(response);
}
}
else
{
try {
functionResponse[typeResponse.indexOf(response.type)](response.content);
} catch {
console.warn(response);
}
}
};
socket.onclose = () => {
status = 0;
console.log('Disconnected');
};
function sendRequest(type, content) {
let coc = null;
if (status === 0)
{
console.warn('Not connected');
return ;
}
if (content instanceof Object)
coc = JSON.stringify(content);
else
coc = content;
if (getCookie("token"))
{
socket.send(JSON.stringify({
type: type,
token: getCookie("token"),
content: content
}));
}
else
{
socket.send(JSON.stringify({
type: type,
content: content
}));
}
}
export { socket, sendRequest };

View File

@ -3,10 +3,10 @@
/* ::: :::::::: */
/* Screen.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: marvin <marvin@student.42.fr> +#+ +:+ +#+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/22 23:13:53 by edbernar #+# #+# */
/* Updated: 2024/08/24 11:39:09 by marvin ### ########.fr */
/* Updated: 2024/08/24 16:56:57 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
@ -15,12 +15,18 @@ import * as THREE from 'three'
const loader = new GLTFLoader();
let light = {
point: 1,
};
class Screen
{
screen = null;
tv = null;
pointLightIntensity = 1;
screenMaterial = null;
canvasVideo = null;
interval = null;
constructor(scene)
{
@ -34,17 +40,17 @@ class Screen
this.tv = tv;
tv.position.set(0, 0.99, 2);
tv.material = new THREE.MeshPhysicalMaterial({color: 0xaaaaaa});
tv.material.roughness = 10;
tv.material.metalness = 1;
tv.material.roughness = 1;
tv.material.metalness = 1.05;
tv.scale.set(0.05, 0.05, 0.05);
tv.castShadow = true;
tv.receiveShadow = true;
scene.add(tv);
this.showVideo('/modeles/pong.mp4');
}, undefined, function ( error ) {
console.error( error );
throw Error("Can't open file 'tv.glb'");
} );
this.#showVideo('/modeles/pong.mp4')
}
#createScreen(scene)
@ -54,7 +60,8 @@ class Screen
const vertices = positionAttribute.array;
const material = new THREE.MeshStandardMaterial({color: 0xbbbbbb});
const mesh = new THREE.Mesh(geometry, material);
const pointLight = new THREE.PointLight( 0xffffff, 10 * this.pointLightIntensity, 0, 2);
// const pointLight = new THREE.PointLight( 0xffffff, 10 * light.point, 0, 2);
const pointLight = new THREE.SpotLight(0xffffff, 10 * light.point, 0, Math.PI / 1.6);
for (let i = 0; i < vertices.length; i += 3)
{
@ -74,17 +81,27 @@ class Screen
pointLight.castShadow = true;
pointLight.shadow.mapSize.width = 2048;
pointLight.shadow.mapSize.height = 2048;
console.log(pointLight.shadow)
const targetObject = new THREE.Object3D();
targetObject.position.set(0, 1.2, 0);
pointLight.target = targetObject;
pointLight.target.updateMatrixWorld();
scene.add(pointLight);
setInterval(() => {
const intensity = Math.random() * 2 + 10;
pointLight.intensity = intensity * this.pointLightIntensity > 13 * this.pointLightIntensity ? 13 * this.pointLightIntensity : intensity * this.pointLightIntensity;
pointLight.intensity = intensity * light.point > 13 * light.point ? 13 * light.point : intensity * light.point;
}, 100);
return (mesh);
}
#showVideo(path)
changeVideo(path)
{
this.#disposeVideo();
this.showVideo(path);
}
showVideo(path)
{
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d', { willReadFrequently: true });
@ -92,9 +109,12 @@ class Screen
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.MeshBasicMaterial({ map: texture,color: 0xffffff, transparent: true, opacity: 1 });
canvas.video = video;
canvas.context = context;
canvas.width = 534;
canvas.height = 360;
video.src = path + '?t=' + new Date().getTime();
this.canvasVideo = canvas;
video.src = path;
video.loop = true;
video.muted = true;
video.crossOrigin = 'anonymous';
@ -107,37 +127,70 @@ class Screen
}).catch(err => console.error("Error playing video: ", err));
});
function addNoiseOnImage(context)
{
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4)
{
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const brightness = (3 * r + 4 * g + b) >>> 3;
const noise = Math.random() * 128 - 32;
data[i] = data[i + 1] = data[i + 2] = brightness + noise;
}
context.putImageData(imageData, 0, 0);
}
// function addNoiseOnImage(context)
// {
// const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
// const data = imageData.data;
// for (let i = 0; i < data.length; i += 4)
// {
// const r = data[i];
// const g = data[i + 1];
// const b = data[i + 2];
// const brightness = (3 * r + 4 * g + b) >>> 3;
// const noise = Math.random() * 128 - 32;
// data[i] = data[i + 1] = data[i + 2] = brightness + noise;
// }
// context.putImageData(imageData, 0, 0);
// }
function updateCanvas()
{
if (!video.paused && !video.ended)
if (canvas.video != null || canvas.video == undefined)
{
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(video, 0, 0, canvas.width, canvas.height);
addNoiseOnImage(context);
texture.needsUpdate = true;
if (canvas.video && !canvas.video.paused && !canvas.video.ended)
{
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(canvas.video, 0, 0, canvas.width, canvas.height);
// addNoiseOnImage(context);
texture.needsUpdate = true;
}
requestAnimationFrame(updateCanvas);
}
requestAnimationFrame(updateCanvas);
}
texture.offset.set(0.02, 0);
texture.offset.set(0.05, 0);
this.screen.material = material;
video.load();
canvas.video.load();
}
#disposeVideo()
{
if (this.canvasVideo)
{
const canvas = this.canvasVideo;
const video = canvas.video;
const texture = this.screen.material.map;
if (video)
{
video.pause();
video.src = '';
video.removeAttribute('src');
video.load();
}
if (texture)
texture.dispose();
canvas.video = null;
canvas.context = null;
if (this.screen)
{
this.screen.material.map = null;
this.screen.material.dispose();
}
this.canvasVideo = null;
}
}
};
export { Screen };
export { Screen, light };

View File

@ -3,19 +3,20 @@
/* ::: :::::::: */
/* home3D.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: marvin <marvin@student.42.fr> +#+ +:+ +#+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/22 17:19:17 by edbernar #+# #+# */
/* Updated: 2024/08/24 11:41:18 by marvin ### ########.fr */
/* Updated: 2024/08/24 16:47:41 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import * as THREE from 'three'
import { Screen } from './Screen.js'
import { Screen, light } from './Screen.js'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { BokehPass } from 'three/examples/jsm/postprocessing/BokehPass.js';
import Stats from 'stats.js';
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({antialias: true});
@ -24,6 +25,10 @@ const ambiantLight = new THREE.AmbientLight(0xffffff, 35);
const screen = new Screen(scene);
const cube = createCube();
const stats = new Stats();
stats.showPanel(0); // 0: fps, 1: ms, 2: mémoire
document.body.appendChild(stats.dom);
renderer.toneMapping = THREE.LinearToneMapping;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
@ -41,7 +46,7 @@ composer.addPass(new RenderPass(scene, camera));
const dofPass = new BokehPass(scene, camera, {
focus: 10.0,
aperture: 0.020,
aperture: 0.02,
maxblur: 0.01,
});
composer.addPass(dofPass);
@ -102,18 +107,23 @@ function fadeInOut()
let interval = null;
isInFade = true;
interval = setInterval(() => {
screen.pointLightIntensity -= 0.2;
light.point -= 0.2;
screen.screen.material.opacity -= 0.05;
if (screen.screen.material.opacity <= 0)
{
clearInterval(interval);
setTimeout(() => {
interval = setInterval(() => {
screen.pointLightIntensity += 0.2;
light.point += 0.2;
screen.screen.material.opacity += 0.05;
if (screen.screen.material.opacity >= 1)
{
clearInterval(interval);
interval = setInterval(() => {
light.point += 0.2;
if (light.point >= 1)
clearInterval(interval);
}, 10);
isInFade = false;
}
}, 20);
@ -132,6 +142,15 @@ function createCube()
scene.add(mesh);
}
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
document.addEventListener( 'mousemove', (event) => {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
});
function home3D()
{
@ -151,11 +170,57 @@ function createPlane()
scene.add(mesh);
}
const video = {
pong: '/modeles/pong.mp4',
login: '/modeles/notLogin.webm'
}
let actualVideo = -1;
if (Math.random() % 100 > 0.97)
video.pong = './modeles/easteregg.webm'
setTimeout(() => {
screen.changeVideo(video.pong);
actualVideo = 0;
}, 100);
function loop()
{
stats.begin()
raycaster.setFromCamera( mouse, camera );
const intersects = raycaster.intersectObjects( scene.children, false );
if (!screen.canvasVideo)
{
composer.render();
stats.end();
return ;
}
if (intersects.length === 0)
{
if (actualVideo != 0)
{
console.log("change 1");
screen.changeVideo(video.pong);
actualVideo = 0;
}
}
else if (intersects[0].object == screen.screen)
{
if (actualVideo != 1)
{
console.log("change 2");
screen.changeVideo(video.login);
actualVideo = 1;
}
}
else if (actualVideo != 0)
{
console.log("change 3");
screen.changeVideo(video.pong);
actualVideo = 0;
}
composer.render();
// renderer.render(scene, camera);
stats.end();
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -33,6 +33,12 @@
"file": "three_examples_jsm_postprocessing_RenderPass__js.js",
"fileHash": "5b030582",
"needsInterop": false
},
"stats.js": {
"src": "../../stats.js/build/stats.min.js",
"file": "stats__js.js",
"fileHash": "243d1a1e",
"needsInterop": true
}
},
"chunks": {
@ -41,6 +47,9 @@
},
"chunk-IS2ZBFBB": {
"file": "chunk-IS2ZBFBB.js"
},
"chunk-BUSYA2B4": {
"file": "chunk-BUSYA2B4.js"
}
}
}

View File

@ -0,0 +1,9 @@
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
export {
__commonJS
};
//# sourceMappingURL=chunk-BUSYA2B4.js.map

View File

@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}

View File

@ -0,0 +1,80 @@
import {
__commonJS
} from "./chunk-BUSYA2B4.js";
// node_modules/stats.js/build/stats.min.js
var require_stats_min = __commonJS({
"node_modules/stats.js/build/stats.min.js"(exports, module) {
(function(f, e) {
"object" === typeof exports && "undefined" !== typeof module ? module.exports = e() : "function" === typeof define && define.amd ? define(e) : f.Stats = e();
})(exports, function() {
var f = function() {
function e(a2) {
c.appendChild(a2.dom);
return a2;
}
function u(a2) {
for (var d = 0; d < c.children.length; d++) c.children[d].style.display = d === a2 ? "block" : "none";
l = a2;
}
var l = 0, c = document.createElement("div");
c.style.cssText = "position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";
c.addEventListener("click", function(a2) {
a2.preventDefault();
u(++l % c.children.length);
}, false);
var k = (performance || Date).now(), g = k, a = 0, r = e(new f.Panel("FPS", "#0ff", "#002")), h = e(new f.Panel("MS", "#0f0", "#020"));
if (self.performance && self.performance.memory) var t = e(new f.Panel("MB", "#f08", "#201"));
u(0);
return { REVISION: 16, dom: c, addPanel: e, showPanel: u, begin: function() {
k = (performance || Date).now();
}, end: function() {
a++;
var c2 = (performance || Date).now();
h.update(c2 - k, 200);
if (c2 > g + 1e3 && (r.update(1e3 * a / (c2 - g), 100), g = c2, a = 0, t)) {
var d = performance.memory;
t.update(d.usedJSHeapSize / 1048576, d.jsHeapSizeLimit / 1048576);
}
return c2;
}, update: function() {
k = this.end();
}, domElement: c, setMode: u };
};
f.Panel = function(e, f2, l) {
var c = Infinity, k = 0, g = Math.round, a = g(window.devicePixelRatio || 1), r = 80 * a, h = 48 * a, t = 3 * a, v = 2 * a, d = 3 * a, m = 15 * a, n = 74 * a, p = 30 * a, q = document.createElement("canvas");
q.width = r;
q.height = h;
q.style.cssText = "width:80px;height:48px";
var b = q.getContext("2d");
b.font = "bold " + 9 * a + "px Helvetica,Arial,sans-serif";
b.textBaseline = "top";
b.fillStyle = l;
b.fillRect(0, 0, r, h);
b.fillStyle = f2;
b.fillText(e, t, v);
b.fillRect(d, m, n, p);
b.fillStyle = l;
b.globalAlpha = 0.9;
b.fillRect(d, m, n, p);
return { dom: q, update: function(h2, w) {
c = Math.min(c, h2);
k = Math.max(k, h2);
b.fillStyle = l;
b.globalAlpha = 1;
b.fillRect(0, 0, r, m);
b.fillStyle = f2;
b.fillText(g(h2) + " " + e + " (" + g(c) + "-" + g(k) + ")", t, v);
b.drawImage(q, d + a, m, n - a, p, d, m, n - a, p);
b.fillRect(d + n - a, m, a, p);
b.fillStyle = l;
b.globalAlpha = 0.9;
b.fillRect(d + n - a, m, a, g((1 - h2 / w) * p));
} };
};
return f;
});
}
});
export default require_stats_min();
//# sourceMappingURL=stats__js.js.map

View File

@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../stats.js/build/stats.min.js"],
"sourcesContent": ["// stats.js - http://github.com/mrdoob/stats.js\n(function(f,e){\"object\"===typeof exports&&\"undefined\"!==typeof module?module.exports=e():\"function\"===typeof define&&define.amd?define(e):f.Stats=e()})(this,function(){var f=function(){function e(a){c.appendChild(a.dom);return a}function u(a){for(var d=0;d<c.children.length;d++)c.children[d].style.display=d===a?\"block\":\"none\";l=a}var l=0,c=document.createElement(\"div\");c.style.cssText=\"position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000\";c.addEventListener(\"click\",function(a){a.preventDefault();\nu(++l%c.children.length)},!1);var k=(performance||Date).now(),g=k,a=0,r=e(new f.Panel(\"FPS\",\"#0ff\",\"#002\")),h=e(new f.Panel(\"MS\",\"#0f0\",\"#020\"));if(self.performance&&self.performance.memory)var t=e(new f.Panel(\"MB\",\"#f08\",\"#201\"));u(0);return{REVISION:16,dom:c,addPanel:e,showPanel:u,begin:function(){k=(performance||Date).now()},end:function(){a++;var c=(performance||Date).now();h.update(c-k,200);if(c>g+1E3&&(r.update(1E3*a/(c-g),100),g=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/\n1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){k=this.end()},domElement:c,setMode:u}};f.Panel=function(e,f,l){var c=Infinity,k=0,g=Math.round,a=g(window.devicePixelRatio||1),r=80*a,h=48*a,t=3*a,v=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement(\"canvas\");q.width=r;q.height=h;q.style.cssText=\"width:80px;height:48px\";var b=q.getContext(\"2d\");b.font=\"bold \"+9*a+\"px Helvetica,Arial,sans-serif\";b.textBaseline=\"top\";b.fillStyle=l;b.fillRect(0,0,r,h);b.fillStyle=f;b.fillText(e,t,v);\nb.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(h,w){c=Math.min(c,h);k=Math.max(k,h);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=f;b.fillText(g(h)+\" \"+e+\" (\"+g(c)+\"-\"+g(k)+\")\",t,v);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,g((1-h/w)*p))}}};return f});\n"],
"mappings": ";;;;;AAAA;AAAA;AACA,KAAC,SAAS,GAAE,GAAE;AAAC,mBAAW,OAAO,WAAS,gBAAc,OAAO,SAAO,OAAO,UAAQ,EAAE,IAAE,eAAa,OAAO,UAAQ,OAAO,MAAI,OAAO,CAAC,IAAE,EAAE,QAAM,EAAE;AAAA,IAAC,GAAG,SAAK,WAAU;AAAC,UAAI,IAAE,WAAU;AAAC,iBAAS,EAAEA,IAAE;AAAC,YAAE,YAAYA,GAAE,GAAG;AAAE,iBAAOA;AAAA,QAAC;AAAC,iBAAS,EAAEA,IAAE;AAAC,mBAAQ,IAAE,GAAE,IAAE,EAAE,SAAS,QAAO,IAAI,GAAE,SAAS,CAAC,EAAE,MAAM,UAAQ,MAAIA,KAAE,UAAQ;AAAO,cAAEA;AAAA,QAAC;AAAC,YAAI,IAAE,GAAE,IAAE,SAAS,cAAc,KAAK;AAAE,UAAE,MAAM,UAAQ;AAAuE,UAAE,iBAAiB,SAAQ,SAASA,IAAE;AAAC,UAAAA,GAAE,eAAe;AACngB,YAAE,EAAE,IAAE,EAAE,SAAS,MAAM;AAAA,QAAC,GAAE,KAAE;AAAE,YAAI,KAAG,eAAa,MAAM,IAAI,GAAE,IAAE,GAAE,IAAE,GAAE,IAAE,EAAE,IAAI,EAAE,MAAM,OAAM,QAAO,MAAM,CAAC,GAAE,IAAE,EAAE,IAAI,EAAE,MAAM,MAAK,QAAO,MAAM,CAAC;AAAE,YAAG,KAAK,eAAa,KAAK,YAAY,OAAO,KAAI,IAAE,EAAE,IAAI,EAAE,MAAM,MAAK,QAAO,MAAM,CAAC;AAAE,UAAE,CAAC;AAAE,eAAM,EAAC,UAAS,IAAG,KAAI,GAAE,UAAS,GAAE,WAAU,GAAE,OAAM,WAAU;AAAC,eAAG,eAAa,MAAM,IAAI;AAAA,QAAC,GAAE,KAAI,WAAU;AAAC;AAAI,cAAIC,MAAG,eAAa,MAAM,IAAI;AAAE,YAAE,OAAOA,KAAE,GAAE,GAAG;AAAE,cAAGA,KAAE,IAAE,QAAM,EAAE,OAAO,MAAI,KAAGA,KAAE,IAAG,GAAG,GAAE,IAAEA,IAAE,IAAE,GAAE,IAAG;AAAC,gBAAI,IAAE,YAAY;AAAO,cAAE,OAAO,EAAE,iBACte,SAAQ,EAAE,kBAAgB,OAAO;AAAA,UAAC;AAAC,iBAAOA;AAAA,QAAC,GAAE,QAAO,WAAU;AAAC,cAAE,KAAK,IAAI;AAAA,QAAC,GAAE,YAAW,GAAE,SAAQ,EAAC;AAAA,MAAC;AAAE,QAAE,QAAM,SAAS,GAAEC,IAAE,GAAE;AAAC,YAAI,IAAE,UAAS,IAAE,GAAE,IAAE,KAAK,OAAM,IAAE,EAAE,OAAO,oBAAkB,CAAC,GAAE,IAAE,KAAG,GAAE,IAAE,KAAG,GAAE,IAAE,IAAE,GAAE,IAAE,IAAE,GAAE,IAAE,IAAE,GAAE,IAAE,KAAG,GAAE,IAAE,KAAG,GAAE,IAAE,KAAG,GAAE,IAAE,SAAS,cAAc,QAAQ;AAAE,UAAE,QAAM;AAAE,UAAE,SAAO;AAAE,UAAE,MAAM,UAAQ;AAAyB,YAAI,IAAE,EAAE,WAAW,IAAI;AAAE,UAAE,OAAK,UAAQ,IAAE,IAAE;AAAgC,UAAE,eAAa;AAAM,UAAE,YAAU;AAAE,UAAE,SAAS,GAAE,GAAE,GAAE,CAAC;AAAE,UAAE,YAAUA;AAAE,UAAE,SAAS,GAAE,GAAE,CAAC;AACrf,UAAE,SAAS,GAAE,GAAE,GAAE,CAAC;AAAE,UAAE,YAAU;AAAE,UAAE,cAAY;AAAG,UAAE,SAAS,GAAE,GAAE,GAAE,CAAC;AAAE,eAAM,EAAC,KAAI,GAAE,QAAO,SAASC,IAAE,GAAE;AAAC,cAAE,KAAK,IAAI,GAAEA,EAAC;AAAE,cAAE,KAAK,IAAI,GAAEA,EAAC;AAAE,YAAE,YAAU;AAAE,YAAE,cAAY;AAAE,YAAE,SAAS,GAAE,GAAE,GAAE,CAAC;AAAE,YAAE,YAAUD;AAAE,YAAE,SAAS,EAAEC,EAAC,IAAE,MAAI,IAAE,OAAK,EAAE,CAAC,IAAE,MAAI,EAAE,CAAC,IAAE,KAAI,GAAE,CAAC;AAAE,YAAE,UAAU,GAAE,IAAE,GAAE,GAAE,IAAE,GAAE,GAAE,GAAE,GAAE,IAAE,GAAE,CAAC;AAAE,YAAE,SAAS,IAAE,IAAE,GAAE,GAAE,GAAE,CAAC;AAAE,YAAE,YAAU;AAAE,YAAE,cAAY;AAAG,YAAE,SAAS,IAAE,IAAE,GAAE,GAAE,GAAE,GAAG,IAAEA,KAAE,KAAG,CAAC,CAAC;AAAA,QAAC,EAAC;AAAA,MAAC;AAAE,aAAO;AAAA,IAAC,CAAC;AAAA;AAAA;",
"names": ["a", "c", "f", "h"]
}

View File

@ -418,6 +418,7 @@ import {
ZeroStencilOp,
createCanvasElement
} from "./chunk-IS2ZBFBB.js";
import "./chunk-BUSYA2B4.js";
export {
ACESFilmicToneMapping,
AddEquation,

View File

@ -66,6 +66,7 @@ import {
Vector3,
VectorKeyframeTrack
} from "./chunk-IS2ZBFBB.js";
import "./chunk-BUSYA2B4.js";
// node_modules/three/examples/jsm/utils/BufferGeometryUtils.js
function toTrianglesDrawMode(geometry, drawMode) {

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,7 @@ import {
UniformsUtils,
WebGLRenderTarget
} from "./chunk-IS2ZBFBB.js";
import "./chunk-BUSYA2B4.js";
// node_modules/three/examples/jsm/shaders/BokehShader.js
var BokehShader = {

File diff suppressed because one or more lines are too long

View File

@ -11,6 +11,7 @@ import {
Vector2,
WebGLRenderTarget
} from "./chunk-IS2ZBFBB.js";
import "./chunk-BUSYA2B4.js";
// node_modules/three/examples/jsm/shaders/CopyShader.js
var CopyShader = {

File diff suppressed because one or more lines are too long

View File

@ -4,6 +4,7 @@ import {
import {
Color
} from "./chunk-IS2ZBFBB.js";
import "./chunk-BUSYA2B4.js";
// node_modules/three/examples/jsm/postprocessing/RenderPass.js
var RenderPass = class extends Pass {

View File

@ -2,6 +2,6 @@
"version": 3,
"sources": ["../../three/examples/jsm/postprocessing/RenderPass.js"],
"sourcesContent": ["import {\n\tColor\n} from 'three';\nimport { Pass } from './Pass.js';\n\nclass RenderPass extends Pass {\n\n\tconstructor( scene, camera, overrideMaterial = null, clearColor = null, clearAlpha = null ) {\n\n\t\tsuper();\n\n\t\tthis.scene = scene;\n\t\tthis.camera = camera;\n\n\t\tthis.overrideMaterial = overrideMaterial;\n\n\t\tthis.clearColor = clearColor;\n\t\tthis.clearAlpha = clearAlpha;\n\n\t\tthis.clear = true;\n\t\tthis.clearDepth = false;\n\t\tthis.needsSwap = false;\n\t\tthis._oldClearColor = new Color();\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {\n\n\t\tconst oldAutoClear = renderer.autoClear;\n\t\trenderer.autoClear = false;\n\n\t\tlet oldClearAlpha, oldOverrideMaterial;\n\n\t\tif ( this.overrideMaterial !== null ) {\n\n\t\t\toldOverrideMaterial = this.scene.overrideMaterial;\n\n\t\t\tthis.scene.overrideMaterial = this.overrideMaterial;\n\n\t\t}\n\n\t\tif ( this.clearColor !== null ) {\n\n\t\t\trenderer.getClearColor( this._oldClearColor );\n\t\t\trenderer.setClearColor( this.clearColor, renderer.getClearAlpha() );\n\n\t\t}\n\n\t\tif ( this.clearAlpha !== null ) {\n\n\t\t\toldClearAlpha = renderer.getClearAlpha();\n\t\t\trenderer.setClearAlpha( this.clearAlpha );\n\n\t\t}\n\n\t\tif ( this.clearDepth == true ) {\n\n\t\t\trenderer.clearDepth();\n\n\t\t}\n\n\t\trenderer.setRenderTarget( this.renderToScreen ? null : readBuffer );\n\n\t\tif ( this.clear === true ) {\n\n\t\t\t// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600\n\t\t\trenderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );\n\n\t\t}\n\n\t\trenderer.render( this.scene, this.camera );\n\n\t\t// restore\n\n\t\tif ( this.clearColor !== null ) {\n\n\t\t\trenderer.setClearColor( this._oldClearColor );\n\n\t\t}\n\n\t\tif ( this.clearAlpha !== null ) {\n\n\t\t\trenderer.setClearAlpha( oldClearAlpha );\n\n\t\t}\n\n\t\tif ( this.overrideMaterial !== null ) {\n\n\t\t\tthis.scene.overrideMaterial = oldOverrideMaterial;\n\n\t\t}\n\n\t\trenderer.autoClear = oldAutoClear;\n\n\t}\n\n}\n\nexport { RenderPass };\n"],
"mappings": ";;;;;;;;AAKA,IAAM,aAAN,cAAyB,KAAK;AAAA,EAE7B,YAAa,OAAO,QAAQ,mBAAmB,MAAM,aAAa,MAAM,aAAa,MAAO;AAE3F,UAAM;AAEN,SAAK,QAAQ;AACb,SAAK,SAAS;AAEd,SAAK,mBAAmB;AAExB,SAAK,aAAa;AAClB,SAAK,aAAa;AAElB,SAAK,QAAQ;AACb,SAAK,aAAa;AAClB,SAAK,YAAY;AACjB,SAAK,iBAAiB,IAAI,MAAM;AAAA,EAEjC;AAAA,EAEA,OAAQ,UAAU,aAAa,YAA0C;AAExE,UAAM,eAAe,SAAS;AAC9B,aAAS,YAAY;AAErB,QAAI,eAAe;AAEnB,QAAK,KAAK,qBAAqB,MAAO;AAErC,4BAAsB,KAAK,MAAM;AAEjC,WAAK,MAAM,mBAAmB,KAAK;AAAA,IAEpC;AAEA,QAAK,KAAK,eAAe,MAAO;AAE/B,eAAS,cAAe,KAAK,cAAe;AAC5C,eAAS,cAAe,KAAK,YAAY,SAAS,cAAc,CAAE;AAAA,IAEnE;AAEA,QAAK,KAAK,eAAe,MAAO;AAE/B,sBAAgB,SAAS,cAAc;AACvC,eAAS,cAAe,KAAK,UAAW;AAAA,IAEzC;AAEA,QAAK,KAAK,cAAc,MAAO;AAE9B,eAAS,WAAW;AAAA,IAErB;AAEA,aAAS,gBAAiB,KAAK,iBAAiB,OAAO,UAAW;AAElE,QAAK,KAAK,UAAU,MAAO;AAG1B,eAAS,MAAO,SAAS,gBAAgB,SAAS,gBAAgB,SAAS,gBAAiB;AAAA,IAE7F;AAEA,aAAS,OAAQ,KAAK,OAAO,KAAK,MAAO;AAIzC,QAAK,KAAK,eAAe,MAAO;AAE/B,eAAS,cAAe,KAAK,cAAe;AAAA,IAE7C;AAEA,QAAK,KAAK,eAAe,MAAO;AAE/B,eAAS,cAAe,aAAc;AAAA,IAEvC;AAEA,QAAK,KAAK,qBAAqB,MAAO;AAErC,WAAK,MAAM,mBAAmB;AAAA,IAE/B;AAEA,aAAS,YAAY;AAAA,EAEtB;AAED;",
"mappings": ";;;;;;;;;AAKA,IAAM,aAAN,cAAyB,KAAK;AAAA,EAE7B,YAAa,OAAO,QAAQ,mBAAmB,MAAM,aAAa,MAAM,aAAa,MAAO;AAE3F,UAAM;AAEN,SAAK,QAAQ;AACb,SAAK,SAAS;AAEd,SAAK,mBAAmB;AAExB,SAAK,aAAa;AAClB,SAAK,aAAa;AAElB,SAAK,QAAQ;AACb,SAAK,aAAa;AAClB,SAAK,YAAY;AACjB,SAAK,iBAAiB,IAAI,MAAM;AAAA,EAEjC;AAAA,EAEA,OAAQ,UAAU,aAAa,YAA0C;AAExE,UAAM,eAAe,SAAS;AAC9B,aAAS,YAAY;AAErB,QAAI,eAAe;AAEnB,QAAK,KAAK,qBAAqB,MAAO;AAErC,4BAAsB,KAAK,MAAM;AAEjC,WAAK,MAAM,mBAAmB,KAAK;AAAA,IAEpC;AAEA,QAAK,KAAK,eAAe,MAAO;AAE/B,eAAS,cAAe,KAAK,cAAe;AAC5C,eAAS,cAAe,KAAK,YAAY,SAAS,cAAc,CAAE;AAAA,IAEnE;AAEA,QAAK,KAAK,eAAe,MAAO;AAE/B,sBAAgB,SAAS,cAAc;AACvC,eAAS,cAAe,KAAK,UAAW;AAAA,IAEzC;AAEA,QAAK,KAAK,cAAc,MAAO;AAE9B,eAAS,WAAW;AAAA,IAErB;AAEA,aAAS,gBAAiB,KAAK,iBAAiB,OAAO,UAAW;AAElE,QAAK,KAAK,UAAU,MAAO;AAG1B,eAAS,MAAO,SAAS,gBAAgB,SAAS,gBAAgB,SAAS,gBAAiB;AAAA,IAE7F;AAEA,aAAS,OAAQ,KAAK,OAAO,KAAK,MAAO;AAIzC,QAAK,KAAK,eAAe,MAAO;AAE/B,eAAS,cAAe,KAAK,cAAe;AAAA,IAE7C;AAEA,QAAK,KAAK,eAAe,MAAO;AAE/B,eAAS,cAAe,aAAc;AAAA,IAEvC;AAEA,QAAK,KAAK,qBAAqB,MAAO;AAErC,WAAK,MAAM,mBAAmB;AAAA,IAE/B;AAEA,aAAS,YAAY;AAAA,EAEtB;AAED;",
"names": []
}