330 lines
7.7 KiB
JavaScript
330 lines
7.7 KiB
JavaScript
var firstInit = true;
|
|
|
|
function mobileConditions() {
|
|
return !($(window).width() > 900 && $(window).height() < $(window).width());
|
|
}
|
|
|
|
function bgInit(useCSSbg) {
|
|
$('.works-card').each(function() {
|
|
var $el = $(this);
|
|
|
|
if(firstInit) {
|
|
var bg = $el.css('background-image');
|
|
if(bg == 'none') bg = $el.css('background-color');
|
|
$el.attr('data-bg', bg);
|
|
var el = $('<div class="bg"></div>');
|
|
el.css('background', bg);
|
|
$('.bg-scroller').append(el);
|
|
}
|
|
|
|
|
|
if(useCSSbg) {
|
|
$el.css('background', $el.attr('data-bg'));
|
|
$el.find('.text-container').css('opacity', '1');
|
|
}
|
|
else {
|
|
$el.css('background', '');
|
|
}
|
|
});
|
|
|
|
firstInit = false;
|
|
}
|
|
|
|
bgInit(false);
|
|
|
|
function calculateBg() {
|
|
if(!mobileConditions()) {
|
|
bgInit(false);
|
|
let backgrounds = $('.bg-scroller').find('.bg');
|
|
let bgOps = new Array(backgrounds.length).fill(0);
|
|
let textOps = new Array(backgrounds.length).fill(0);
|
|
let scrolledWindows = ($(window).scrollTop() - $(window).height()) / $(window).height();
|
|
if(scrolledWindows < 0) scrolledWindows = 0;
|
|
let minBg = Math.floor(scrolledWindows);
|
|
let maxBg = minBg + 1;
|
|
let delta = scrolledWindows - minBg;
|
|
if(delta < 0.3) {
|
|
delta = 0;
|
|
}
|
|
else if(delta < 0.7) {
|
|
delta = 2.5*(delta-0.3);
|
|
}
|
|
else {
|
|
delta = 1;
|
|
}
|
|
|
|
//delta = -1 * Math.cos(delta/1 * (Math.PI/2)) + 1;
|
|
|
|
bgOps[minBg] = 1;
|
|
bgOps[maxBg] = delta;
|
|
backgrounds.each(function(i) {
|
|
$(this).css('opacity', bgOps[i]);
|
|
});
|
|
|
|
textOps[minBg] = 1-delta;
|
|
textOps[maxBg] = delta;
|
|
$('.works-card .text-container').each(function(i) {
|
|
$(this).css('opacity', textOps[i]);
|
|
});
|
|
}
|
|
|
|
else {
|
|
bgInit(true);
|
|
}
|
|
}
|
|
|
|
calculateBg();
|
|
|
|
var timer;
|
|
|
|
setInterval(function() {
|
|
clearTimeout(timer);
|
|
|
|
timer = setTimeout(function() {
|
|
var sections = $('section');
|
|
|
|
var hash = '';
|
|
|
|
sections.each(function() {
|
|
var $el = $(this);
|
|
var viewportPos = ($(window).scrollTop() - $el.offset().top) / $(window).height();
|
|
|
|
if(viewportPos < 0.4 && viewportPos > -0.6) {
|
|
hash = $el.attr('id');
|
|
}
|
|
});
|
|
|
|
if(hash && '#' + hash != location.hash) {
|
|
history.replaceState({
|
|
page: hash
|
|
}, $('title').html(), '#' + hash);
|
|
}
|
|
}, 200);
|
|
}, 500);
|
|
|
|
function scrollAnimations() {
|
|
calculateBg();
|
|
|
|
if(!mobileConditions()) {
|
|
$('.main h1, .main h3').each(function() {
|
|
var scrolledFrac = $(window).scrollTop() / $(window).height();
|
|
$(this).css({
|
|
opacity: Math.min(1, 1.2 - 1.5*scrolledFrac),
|
|
position: 'relative',
|
|
// fun fact: using transforms here causes weird rendering bugs in Chrome
|
|
top: (scrolledFrac * $(window).height() / 2) + 'px'
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
//window.addEventListener('scroll', scrollAnimations);
|
|
function scrollLoop() {
|
|
scrollAnimations();
|
|
requestAnimationFrame(scrollLoop);
|
|
}
|
|
scrollLoop();
|
|
|
|
var canvas = $('canvas#bg')[0];
|
|
|
|
canvas.width = $(window).width();
|
|
canvas.height = $(window).height();
|
|
|
|
var ctx = canvas.getContext('2d');
|
|
|
|
$(window).on('resize', function() {
|
|
canvas.width = $(window).width();
|
|
canvas.height = $(window).height();
|
|
})
|
|
|
|
function Point() {
|
|
var p = this;
|
|
|
|
var r = 8;
|
|
|
|
// progress below 0 is neglected, negative initial
|
|
// progress serves to introduce random delays -
|
|
// at 0.05 progress points per second, for example
|
|
// a dot with initial progress -0.15 will run 2 frames
|
|
// after a dot with initial progress -0.05
|
|
var initialProgress = -4 * Math.random();
|
|
|
|
// moves point to a random location and
|
|
// resets its progress
|
|
this.init = function() {
|
|
p.x = Math.random() * canvas.width;
|
|
p.y = Math.random() * canvas.height;
|
|
p.progress = initialProgress;
|
|
}
|
|
|
|
this.draw = function() {
|
|
if(p.progress >= 0) {
|
|
// opacity of of dot changes with progress
|
|
const isDarkMode = document.body.classList.contains('dark-mode');
|
|
let color = isDarkMode ? 255 : 0;
|
|
let multiplier = isDarkMode ? 0.05 : 0.005;
|
|
ctx.fillStyle = `rgba(${color}, ${color}, ${color}, ${Math.sqrt(p.progress*multiplier)})`;
|
|
ctx.beginPath();
|
|
// radius calculation: maps progress from [0, 1] to [0, pi],
|
|
// then takes sine of that to get an increase, then decrease
|
|
// in radius. absolute value to prevent floating point errors
|
|
// accidentally causing negative sine values which cause ctx.arc
|
|
// to throw errors
|
|
ctx.arc(p.x, p.y, Math.abs(Math.sin(Math.PI*p.progress)*r), 0, 2*Math.PI);
|
|
ctx.fill();
|
|
}
|
|
};
|
|
this.render = function() {
|
|
// stars come faster than they go
|
|
// so user can look at them longer
|
|
// i guess? idk this just looked pretty
|
|
if(p.progress > 0.5)
|
|
p.progress += 0.005;
|
|
else
|
|
p.progress += 0.05;
|
|
p.draw();
|
|
if(p.progress >= 1) p.init();
|
|
}
|
|
}
|
|
var dots = [];
|
|
|
|
var n = 20;
|
|
|
|
for(var i = 0; i < n; i++) {
|
|
dots[i] = new Point();
|
|
dots[i].init();
|
|
}
|
|
|
|
function loop() {
|
|
if($(window).scrollTop() <= $(window).height()) {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
for(var i = 0; i < n; i++) {
|
|
dots[i].render();
|
|
}
|
|
}
|
|
|
|
requestAnimationFrame(loop);
|
|
}
|
|
|
|
loop();
|
|
|
|
var sentences = [
|
|
'Semicolons optional.',
|
|
'Best viewed in Visual Studio Code.',
|
|
'sh -c "$(curl -sL https://nsood.in/randomscript.sh)"',
|
|
'This text is subject to change.',
|
|
'Alliteration alert!',
|
|
'Boolean logic jokes are funny, whether you laugh xor not.',
|
|
];
|
|
|
|
var counter = 1;
|
|
|
|
var ticker = $("footer .ticker");
|
|
|
|
function changeText() {
|
|
var el = ticker,
|
|
text = sentences[counter],
|
|
oldText = el.text();
|
|
|
|
var x = setInterval(function() {
|
|
if(oldText.length != 0) {
|
|
oldText = oldText.slice(0, -1);
|
|
el.text(oldText);
|
|
}
|
|
else {
|
|
setTimeout(function() {
|
|
var y = setInterval(function() {
|
|
if(el.text().length != text.length) {
|
|
el.text(text.slice(0, el.text().length+1));
|
|
}
|
|
else {
|
|
setTimeout(function() {
|
|
if(counter >= sentences.length - 1)
|
|
counter = 0;
|
|
else
|
|
counter++;
|
|
|
|
changeText();
|
|
}, 5000);
|
|
clearInterval(y);
|
|
}
|
|
}, 60);
|
|
}, 60);
|
|
clearInterval(x);
|
|
}
|
|
}, 60);
|
|
}
|
|
|
|
ticker.html(sentences[0]);
|
|
|
|
setTimeout(changeText, 5000);
|
|
|
|
$('a[href^="#"]').on('click', function(e) {
|
|
e.preventDefault();
|
|
|
|
var el = $($(this).attr('href'));
|
|
|
|
var distance = Math.abs($(window).scrollTop() - $(el).offset().top);
|
|
|
|
var time = Math.floor( Math.sqrt(distance / $(document).height()) * 1500 );
|
|
|
|
$('html, body').animate({
|
|
scrollTop: el.offset().top
|
|
}, time);
|
|
});
|
|
|
|
// slight convenience: fix the header section with my correct age automatically
|
|
|
|
const birthday = {
|
|
date: 19,
|
|
month: 1,
|
|
year: 2001,
|
|
}
|
|
let today = new Date();
|
|
let age = today.getFullYear() - birthday.year;
|
|
if(today.getMonth() <= birthday.month && today.getDate() < birthday.date) {
|
|
--age;
|
|
}
|
|
const tens = ['', ' ten plus', ' twenty', ' thirty', ' forty', ' fifty', ' sixty', ' seventy', 'n eighty', ' ninety'];
|
|
const ones = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];
|
|
$('.age').html(`${tens[Math.floor(age / 10)]} ${ones[age % 10]}`);
|
|
|
|
// easter egg
|
|
|
|
var sequences = [
|
|
[ 99, 108, 97, 112, 111, 102, 102 ],
|
|
[ 99, 108, 97, 112, 111, 110 ],
|
|
];
|
|
|
|
var mode = 0;
|
|
|
|
var eei = 0;
|
|
|
|
$(window).on('keypress', function(e) {
|
|
const clapper = document.querySelector('.clapper');
|
|
var sequence = sequences[mode];
|
|
if(e.keyCode == sequence[eei]) {
|
|
eei++;
|
|
}
|
|
else {
|
|
eei = 0;
|
|
console.log(`expected ${sequence[eei]}, got ${e.keyCode}`);
|
|
}
|
|
|
|
if(eei == sequence.length) {
|
|
clapper.classList.toggle('clapping');
|
|
setTimeout(() => {
|
|
if(mode === 1) {
|
|
$('body').removeClass('dark-mode');
|
|
mode = 0;
|
|
}
|
|
else {
|
|
$('body').addClass('dark-mode');
|
|
mode = 1;
|
|
}
|
|
eei = 0;
|
|
setTimeout(() => clapper.classList.toggle('clapping'), 500);
|
|
}, 500);
|
|
}
|
|
})
|