ECMAPortal Integration

This commit is contained in:
Andrew Illarionov 2023-11-04 22:17:44 +03:00
parent 38a022e8a2
commit ca43c9441f
9 changed files with 423 additions and 40 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 373 KiB

BIN
images/portal/portal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
images/portal/sky.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Enderman</title>
<meta property="og:type" content="website">
@ -15,12 +15,13 @@
<meta property="og:image:width" content="256">
<meta property="og:image:height" content="256">
<meta property="og:image:alt" content="Endermanch">
<link rel="icon" type="image/png" href="/favicon.png" />
<link href="https://cdn.jsdelivr.net/npm/fontawesome5-fullcss@1.1.0/css/all.min.css" rel="stylesheet" />
<link href="/styles/styles.css" rel="stylesheet" />
</head>
<body>
<canvas class="portal" id="ecmaportal">Your browser does not seem to support HTML canvas.</canvas>
<div class="body-wrapper">
<div class="container">
<main>
@ -32,7 +33,7 @@
For now, this website shall remain a crude landing page, but the actual version is
already in the works!<br>
</p>
<h2>Stay in touch</h2>
<ul>
<li>
@ -63,7 +64,7 @@
<div class="link-button">
<div class="link-icon">
<i class="fab fa-tiktok"></i>
</div>
</div>
<a href="https://go.enderman.ch/tiktok" target="_blank">TikTok</a>
</div>
</li>
@ -105,66 +106,66 @@
<i class="fab fa-steam"></i>
</div>
<a href="https://go.enderman.ch/steam" target="_blank">Steam</a>
</div>
</div>
</li>
</ul>
<h2>Websites</h2>
<ul>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/malware" target="_blank">MalwareWatch</a>
</div>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/idiot" target="_blank">You Are An Idiot! (dot cc)</a>
</div>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/hurr-durr" target="_blank">HURR-DURR (dot cc)</a>
</div>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/malware-generator" target="_blank">Malware Generator</a>
</div>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/dont-click" target="_blank">ḑ̶̛̻̬̙̯̭̲͔͈̟̯͎̭̼̳͚̮̱̥̠͆͊͜͠ͅͅơ̶̢̭̫͔̝͖̫̲̓̉͆͛̏́̀͊̕͝͝ņ̴͍̗̰̝͈͚͖͕̻̟̮̯̼͙͎̦̻̍͒͋̐̓̈́͑͌̅̍̏̀̾̊̈̆͊͌͘͝ͅ'̷̢̛̛̼̟̭̳̀͛̂͌̽̄͆̔̄̏͝͝ẗ̵̛̛̤̞̰̗́̅̐͒́̇̚͜</a>
</div>
</div>
</li>
</ul>
<h2>Projects</h2>
<ul>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/xpkeygen" target="_blank">Windows XP Keygen</a> (sister - <a href="https://go.enderman.ch/umskt" target="_blank">UMSKT</a>)
</div>
</div>
</li>
</ul>
<h2>Contact</h2>
<ul>
<li><p>Fanmail: <a href="mailto:contact@enderman.ch">contact@enderman.ch</a></p></li>
@ -184,5 +185,7 @@
<div class="bottom-right">
<img src="/images/enderman.gif" alt="Hello!">
</div>
<script src="/scripts/portal.js"></script>
</body>
</html>
</html>

1
scripts/portal-min.js vendored Normal file

File diff suppressed because one or more lines are too long

370
scripts/portal.js Normal file
View File

@ -0,0 +1,370 @@
class Portal {
constructor(canvas, resourceDir) {
// Vertex shader.
const vglsl = `#version 300 es
layout (location = 0) in vec3 Position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
vec4 projection_from_position(vec4 position) {
vec4 projection = position * 0.5;
projection.xy = vec2(projection.x + projection.w, projection.y + projection.w);
projection.zw = position.zw;
return projection;
}
out vec4 texProj0;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(Position, 1.0);
texProj0 = projection_from_position(gl_Position);
}`
// Fragment shader.
const fglsl = `#version 300 es
precision highp float;
uniform sampler2D sky;
uniform sampler2D particles;
uniform float dt;
in vec4 texProj0;
const int LAYERS = 15;
const vec3 COLORS[] = vec3[](
vec3(0.022087, 0.098399, 0.110818),
vec3(0.011892, 0.095924, 0.089485),
vec3(0.027636, 0.101689, 0.100326),
vec3(0.046564, 0.109883, 0.114838),
vec3(0.064901, 0.117696, 0.097189),
vec3(0.063761, 0.086895, 0.123646),
vec3(0.084817, 0.111994, 0.166380),
vec3(0.097489, 0.154120, 0.091064),
vec3(0.106152, 0.131144, 0.195191),
vec3(0.097721, 0.110188, 0.187229),
vec3(0.133516, 0.138278, 0.148582),
vec3(0.070006, 0.243332, 0.235792),
vec3(0.196766, 0.142899, 0.214696),
vec3(0.047281, 0.315338, 0.321970),
vec3(0.204675, 0.390010, 0.302066),
vec3(0.080955, 0.314821, 0.661491)
);
const mat4 SCALE_TRANSLATE = mat4(
0.5, 0.0, 0.0, 0.25,
0.0, 0.5, 0.0, 0.25,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);
mat2 mat2_rotate_z(float radians) {
return mat2(
cos(radians), -sin(radians),
sin(radians), cos(radians)
);
}
mat4 portal_layer(float layer) {
mat4 translate = mat4(
1.0, 0.0, 0.0, 17.0 / layer,
0.0, 1.0, 0.0, (2.0 + layer / 1.5) * (dt * 1.5),
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);
mat2 rotate = mat2_rotate_z(radians((layer * layer * 4321.0 + layer * 9.0) * 2.0));
mat2 scale = mat2((4.5 - layer / 4.0) * 2.0);
return mat4(scale * rotate) * translate * SCALE_TRANSLATE;
}
out vec4 fragColor;
void main() {
vec3 color = textureProj(sky, texProj0).rgb * COLORS[0];
for (int i = 0; i < LAYERS; i++) {
color += textureProj(particles, texProj0 * portal_layer(float(i + 1))).rgb * COLORS[i];
}
fragColor = vec4(color, 1.0);
}`
const images = [
`${resourceDir !== '/' ? resourceDir : ''}/sky.png`,
`${resourceDir !== '/' ? resourceDir : ''}/portal.png`,
];
// Version & notice.
this.version = '1.0';
this.notice();
this.canvas = canvas;
this.gl = this.canvas.getContext('webgl2');
// If WebGL isn't part of available features, fail.
if (!this.gl) {
alert("Unable to initialize WebGL 2. Your browser or machine may not support it.");
return;
}
// Size the canvas to window initially.
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
// Get current tick and slightly randomize it.
this.time = Date.now() - this.randomRange(60 * 1000, 180 * 1000);
// Build shaders.
this.prog = this.build(vglsl, fglsl);
if (!this.prog) {
alert("Failed to compile WebGL 2 shaders.\nOpen the developer console for debug output.");
return;
}
// Bind class context to the resize handler, pass it to the event bus.
window.addEventListener('resize', this.resize.bind(this));
// Create image loading promises.
this.promises = images.map(image => this.loadImage(image));
// Initialize the scene.
this.initialize();
// Once all promises have been fulfilled, build the scene.
Promise.all(this.promises).then(resources => {
// Load resources.
resources.forEach((image, index) => this.loadResource(image, index));
// Bind program
this.gl.useProgram(this.prog);
// Begin render.
this.render();
});
}
notice() {
console.log(
`%c \u2587%c\u2587%c\u2587 %c\u2587%c\u2587%c\u2587 %c // ECMAPortal v${this.version} by Endermanch & WiPet\n\n\thttps://enderman.ch\n\thttps://go.enderman.ch/wipet`,
'color: #E58EFF',
'color: #D52DFF',
'color: #E58EFF',
'color: #E58EFF',
'color: #D52DFF',
'color: #E58EFF',
'color: #008000',
);
console.log(
'If any errors occur below, please send a screenshot of them my way!\n\t%ccontact@enderman.ch',
'color: #87CEFA'
);
}
randomRange(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
build(vshSource, fshSource) {
let vsh = this.gl.createShader(this.gl.VERTEX_SHADER);
this.gl.shaderSource(vsh, vshSource);
this.gl.compileShader(vsh);
if (!this.gl.getShaderParameter(vsh, this.gl.COMPILE_STATUS)) {
console.error(this.gl.getShaderInfoLog(vsh));
return false;
}
let fsh = this.gl.createShader(this.gl.FRAGMENT_SHADER);
this.gl.shaderSource(fsh, fshSource);
this.gl.compileShader(fsh);
if (!this.gl.getShaderParameter(fsh, this.gl.COMPILE_STATUS)) {
console.error(this.gl.getShaderInfoLog(fsh));
return false;
}
let program = this.gl.createProgram();
this.gl.attachShader(program, vsh);
this.gl.attachShader(program, fsh);
this.gl.linkProgram(program);
if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
console.error(this.gl.getProgramInfoLog(program));
return false;
}
return program;
}
loadImage(url) {
return new Promise((resolve, reject) => {
let img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = url;
});
}
loadResource(image, index) {
const samplerParameters = [
this.gl.CLAMP_TO_EDGE,
this.gl.MIRRORED_REPEAT,
];
let sampler = this.gl.createSampler();
this.gl.samplerParameteri(sampler, this.gl.TEXTURE_WRAP_S, samplerParameters[index]);
this.gl.samplerParameteri(sampler, this.gl.TEXTURE_WRAP_T, samplerParameters[index]);
this.gl.samplerParameteri(sampler, this.gl.TEXTURE_WRAP_R, samplerParameters[index]);
this.gl.samplerParameteri(sampler, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST_MIPMAP_LINEAR);
this.gl.samplerParameteri(sampler, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
this.gl.bindSampler(index, sampler);
let texture = this.gl.createTexture();
this.gl.activeTexture(this.gl.TEXTURE0 + index);
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
this.gl.texImage2D(
this.gl.TEXTURE_2D,
0,
this.gl.RGBA,
this.gl.RGBA,
this.gl.UNSIGNED_BYTE,
image
);
this.gl.generateMipmap(this.gl.TEXTURE_2D);
}
initialize() {
this.uniforms = {
modelViewMatrix: this.gl.getUniformLocation(this.prog, "modelViewMatrix"),
projectionMatrix: this.gl.getUniformLocation(this.prog, "projectionMatrix"),
dt: this.gl.getUniformLocation(this.prog, "dt"),
sky: this.gl.getUniformLocation(this.prog, "sky"),
particles: this.gl.getUniformLocation(this.prog, "particles"),
}
let vertexPosBuffer = this.gl.createBuffer();
let positions = new Float32Array([
-1.0, -1.0,
1.0, -1.0,
1.0, 1.0,
1.0, 1.0,
-1.0, 1.0,
-1.0, -1.0
]);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexPosBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, positions, this.gl.STATIC_DRAW);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
let vertexTexBuffer = this.gl.createBuffer();
let texcoords = new Float32Array([
0.0, 1.0,
1.0, 1.0,
1.0, 0.0,
1.0, 0.0,
0.0, 0.0,
0.0, 1.0
]);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexTexBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, texcoords, this.gl.STATIC_DRAW);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
let vertexPosLocation = 0;
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexPosBuffer);
this.gl.vertexAttribPointer(vertexPosLocation, 2, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vertexPosLocation);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
let vertexTexLocation = 4;
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexTexBuffer);
this.gl.vertexAttribPointer(vertexTexLocation, 2, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vertexTexLocation);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
}
scene() {
let identityMatrix = new Float32Array([
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
]);
let dt = (Date.now() - this.time) / (1000 * 1000);
this.gl.uniformMatrix4fv(this.uniforms.modelViewMatrix, false, identityMatrix);
this.gl.uniformMatrix4fv(this.uniforms.projectionMatrix, false, identityMatrix);
this.gl.uniform1f(this.uniforms.dt, dt);
this.gl.uniform1i(this.uniforms.sky, 0);
this.gl.uniform1i(this.uniforms.particles, 1);
this.gl.drawArraysInstanced(this.gl.TRIANGLES, 0, 6, 1);
}
render() {
// Make sure the viewport matches the size of the canvas' drawingBuffer.
this.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);
// Run the scene.
this.scene();
// Request the next animation frame.
requestAnimationFrame(this.render.bind(this));
}
resize() {
let width = window.innerWidth;
let height = window.innerHeight;
if (
this.canvas.width !== width ||
this.canvas.height !== height
) {
this.canvas.width = width;
this.canvas.height = height;
}
}
destruct() {
// Doesn't need to be called usually, the garbage collector should do its job.
// The method isn't implemented, but the pseudocode is as follows:
this.gl.deleteBuffer(vertexPosBuffer);
this.gl.deleteBuffer(vertexTexBuffer);
this.gl.deleteSampler(sampler);
this.gl.deleteTexture(texture);
this.gl.deleteProgram(this.prog);
}
}
const canvas = document.querySelector('#ecmaportal');
const portal = new Portal(canvas, '/images/portal');

View File

@ -4,8 +4,6 @@
body {
background-color: black;
background-image: url("/images/background.jpg");
background-attachment: fixed;
background-size: cover;
@ -16,6 +14,16 @@ body {
font-size: 18px;
}
canvas.portal {
display: block;
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
a {
color: lightskyblue;
@ -34,18 +42,17 @@ a:active {
div.body-wrapper {
display: flex;
flex-direction: column;
align-items: center;
}
div.container {
display: flex;
flex-direction: column;
max-width: 80%;
background-color: rgba(0, 0, 0, 0.5);
background-color: rgba(0, 0, 0, 0.35);
border-bottom-left-radius: 7px;
border-bottom-right-radius: 7px;
}
@ -74,7 +81,7 @@ div.text p {
div.text ul {
list-style-type: none;
padding: 0;
margin-bottom: 10px;
}
@ -86,13 +93,13 @@ div.text i.fa-youtube:before {
div.text i.fa-twitch:before {
color: rgb(169, 112, 255);
background: radial-gradient(
ellipse 70% 55%,
white 60%,
transparent 50%
);
background: -webkit-radial-gradient(
ellipse 70% 55%,
white 60%,
@ -106,21 +113,21 @@ div.text i.fa-twitter:before {
div.text i.fa-telegram:before {
color: rgb(88, 169, 243);
background: radial-gradient(at center, white 50%, transparent 10%);
background: -webkit-radial-gradient(at center, white 50%, transparent 10%);
}
div.text i.fa-discord:before {
color: rgb(86, 98, 246);
background: radial-gradient(at center, white 50%, transparent 10%);
background: -webkit-radial-gradient(at center, white 50%, transparent 10%);
}
div.text i.fa-github:before {
color: white;
background: radial-gradient(
ellipse 50% 65%,
rgb(1, 4, 9) 70%,
@ -136,7 +143,7 @@ div.text i.fa-steam:before {
white 67%,
transparent 60%
);
background: -webkit-radial-gradient(
ellipse 70% 60%,
white 70%,
@ -147,7 +154,7 @@ div.text i.fa-steam:before {
div.link-button {
display: flex;
flex-direction: row;
align-items: center;
gap: 10px;
}
@ -159,19 +166,21 @@ div.link-icon > * {
div.footer {
display: flex;
flex-direction: row;
justify-content: center;
padding: 10px;
}
div.bottom-right {
position: fixed;
right: 5%;
bottom: 0;
opacity: 30%;
}
div.bottom-right img {
height: 30vmin;
}
}