Table of Contents
Background
Dango, dango, dango, dango
Dango, dango, daikazoku
For many people familiar with anime and manga, these song lyrics are bound to induce strong and bittersweet emotions. Those not familiar may be wondering, “What in the world is a ‘dango’?” - to which the answer will be, depending on whom is asked, either a Japanese rice flour dumpling or a colored squishy ball with a face on the front. Dangos are so well-known and cherished, they even have their own emoji! But why?
Spoiled, perhaps, by the image above, dangos also originate from one of the most beloved animated series of all time (and also my favorite of all time), Clannad and Clannad: After Story - together, as with most anime, these two story arcs offer a myriad of lessons about life, such as becoming triumphant in the face of tragedy and the ultimate paradoxical realization that life is happiness and sadness rolled into one. No other series or story has ever been so soul-touching - I can honestly say that my outlook on life and even segments of my personality changed upon completing them for myself. I will shamelessly admit that I even named my cat after the main character, Nagisa.
Aside from the apex that is Clannad, countless other anime have impacted me too. While I could spend the time listing them all out, doing so would defeat the purpose of including this project page in my portfolio. This is because for those anime that I cherish the most, I created custom dynamic webpages in tribute to specific scenes from the series. The implementation of each of these is “enshrined” below.
Implementation
Clannad, “Cherry Blossoms”
This page uses an external library and jQuery to handle the cherry blossoms and a simple JavaScript audio playlist to cycle through each .mp3
in the project’s ./audio/
directory.
var audio = new Audio();
var playlist = new Array(
'https://andrewburch.me/assets/web/projects/anime_webpages/clannad-cherry_blossoms/audio/to_the_same_heights.mp3',
'https://andrewburch.me/assets/web/projects/anime_webpages/clannad-cherry_blossoms/audio/ana.mp3',
'https://andrewburch.me/assets/web/projects/anime_webpages/clannad-cherry_blossoms/audio/nagisa.mp3',
'https://andrewburch.me/assets/web/projects/anime_webpages/clannad-cherry_blossoms/audio/shining_in_the_sky.mp3'
);
var i = 0;
audio.addEventListener('ended', function() {
i++;
if(i == playlist.length) {
audio.pause();
} else {
audio.src = playlist[i];
audio.play();
}
}, true);
audio.volume = 0.2;
audio.loop = false;
audio.src = playlist[0];
var promise = audio.play();
if(promise) {
promise.catch(function(error) {
console.error(error);
});
}
Clannad, “Confession”
The sun rays were produced by slowly rotating a transparent rays.png
with CSS. I may edit this one further in the future - perhaps with a light orb effect as demonstrated in the “Illusionary” page listed below. For now, the rays and music do it justice.
#rays {
-webkit-animation: rays_spin 175s infinite linear;
animation: rays_spin 175s infinite linear;
background-image: url('https://andrewburch.me/assets/web/projects/anime_webpages/clannad-confession/img/rays.png');
background-position: center;
background-repeat: no-repeat;
background-size: cover;
-webkit-filter: opacity(8%);
filter: opacity(8%);
height: 0;
margin: -90% 0 0 -50%;
padding-bottom: 200%;
position: fixed;
width: 200%;
}
Clannad, “Illusionary”
This page implements a sine wave to generate a movement path for 100 particles over a 2D canvas
context. I lost the original source .js
for this effect, but I was able to find, deobfuscate, and manually refactor a version I had obfuscated at some point in the past.
window['onload'] = function() {
var audio = document.getElementById('audio');
audio.volume = 0.15;
var canvas = document['getElementById']('canvas');
var context = canvas['getContext']('2d');
var width = window['innerWidth'];
var height = window['innerHeight'];
canvas['width'] = width;
canvas['height'] = height;
var particles = 100;
var arr = [];
for(var i = 0; i < particles; i++) {
arr['push']({
x: Math['random']() * width,
y: Math['random']() * height,
r: Math['random']() * 5 + 1,
d: Math['random']() * particles
});
};
function draw() {
context['clearRect'](0, 0, width, height);
context['fillStyle'] = 'rgba(255, 255, 255, 0.8)';
context['shadowBlur'] = 30;
context['shadowColor'] = 'yellow';
context['beginPath']();
for(var i = 0; i < particles; i++) {
var p = arr[i];
context['moveTo'](p['x'], p['y']);
context['arc'](p['x'], p['y'], p['r'], 0, Math['PI'] * 2, true);
};
context['fill']();
move();
}
var offset = 0;
function move() {
offset += 0.01;
for(var i = 0; i < particles; i++) {
var p = arr[i];
p['y'] -= Math['cos'](offset + p['d']) + 1 + p['r'] / 2;
p['x'] -= Math['sin'](offset) * 2;
if(p['x'] > width + 2 || p['x'] < -2 || p['y'] < 0) {
if(i % 3 > 0) {
arr[i] = {
x: Math['random']() * width,
y: height,
r: p['r'],
d: p['d']
};
} else {
if(Math['sin'](offset) > 0) {
arr[i] = {
x: -5,
y: Math['random']() * height,
r: p['r'],
d: p['d']
};
} else {
arr[i] = {
x: width + 5,
y: Math['random']() * height,
r: p['r'],
d: p['d']
};
}
}
}
}
}
setInterval(draw, 33);
}
Clannad, “Meadow”
The sun rays were produced the same exact way as seen in the “Confession” page.
Clannad, “Nagisa and Ushio”
The particles were produced the same exact way as seen in the “Illusionary” page.
Clannad, “Night Dangos”
The particles were produced the same exact way as seen in other pages, except the shadowColor
context setting was changed from yellow
to blue
to give the orbs a blue glow, making them look more suitable for night.
Clannad, “Snowfield”
Similar to the “Night Dangos” page, I edited the shadowColor
to white
to appear as snow rather than glowing orbs of light. I also reversed their y-axis direction so that they fall towards the bottom of the screen, giving the illusion of snowfall.
if(p['x'] > width + 2 || p['x'] < -2 || p['y'] > height) {
if(i % 3 > 0) {
arr[i] = {
x: Math['random']() * width,
y: 0,
r: p['r'],
d: p['d']
};
} else {
if(Math['sin'](offset) > 0) {
arr[i] = {
x: -5,
y: Math['random']() * height,
r: p['r'],
d: p['d']
};
} else {
arr[i] = {
x: width + 5,
y: Math['random']() * height,
r: p['r'],
d: p['d']
};
}
}
}
Death Note, “Kira”
After finishing Death Note, I felt compelled to tribute Light Yagami (a.k.a. “Kira” or “キラ”) in some way. Perhaps the most intelligent anime character of all time, whose 2006-2007 utopian-seeking global murder campaign remains controversial in the anime community to this day, I gave Light an ominously slow “fade in” effect from darkness with CSS.
@-webkit-keyframes fadeIn {
from { opacity: 0; }
to { opacity: .3301; }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: .3301; }
}
Kimi no Na wa, “Nandemonaiya”
To create the randomized stars and twinkle effect, I implemented a 2D canvas
context and Math.random()
to assign locations to each star. I used Math.floor()
to avoid placing stars towards the lower-middle section of the screen, maintaining the twilight effect seen in the film. The sun rays were produced the same exact way as seen in the other pages.
window.onload = function() {
var audio = document.getElementById('audio');
audio.volume = 0.2;
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var w = window.innerWidth;
var h = window.innerHeight;
canvas.width = w;
canvas.height = h;
var max_particles = 100;
var particles = [];
function createStars() {
var first_third = Math.floor(w / 3);
var second_third = w - first_third;
var middle = Math.floor(h / 2);
for(var i = 0; i < max_particles; i++) {
var push_x = Math.random() * w;
var push_y = Math.random() * h;
if((push_x > first_third && push_x < second_third) && (push_y > middle)) {
i--;
continue;
}
particles.push({
x: push_x,
y: push_y,
r: Math.random() * 2 + 1,
d: Math.random() * max_particles
});
}
}
function draw() {
context.clearRect(0, 0, w, h);
context.fillStyle = "rgba(255, 255, 255, 0.8)";
context.shadowBlur = 30;
context.shadowColor = 'white';
context.beginPath();
for(var i = 0; i < max_particles; i++) {
var p = particles[i];
context.moveTo(p.x, p.y);
context.arc(p.x, p.y, p.r, 0, Math.PI * 2, true);
}
context.fill();
}
function update() {
for(var i = 0; i < max_particles; i++) {
if(Math.random() < 0.1) {
particles[i].r = Math.random() * 2 + 1;
}
}
}
function twinkle() {
update();
draw();
}
createStars();
draw();
twinkle();
setInterval(twinkle, 1900);
setInterval(twinkle, 2300);
}
Steins;Gate, “Christina”
Upon completion of Steins;Gate, where I found my favorite anime character of all time, I knew that I needed to create a new page in her honor. There is no other character like Makise Kurisu (a.k.a. “Christina” by Okabe Rintarou), and to understand why this is, one must first become a mad scientist and watch the anime along with Steins;Gate 0.
Aldnoah.Zero, “World Peace”
For those that have finished Aldnoah.Zero, the title “World Peace” will be ironic given what is actually happening in this scene. The stars were created the same way as in the “Nandemonaiya” page with three separate loops for additional twinkles. It uses a similar JavaScript playlist to iterate through the audio. Fiat justitia ruat caelum!
Results
While the examples outlined in this project are technically “complete” (save for minor adjustments), I do intend to create more of these in my spare time as I watch more anime series in the future or if I think of new page ideas for older shows. It is my hope that those taking the time to read this page may also take the time to watch a few of the shows I have mentioned above - they are well worth the investment.
I may also look into combining .gif
(or .webm
) animations with JavaScript in future pages for double the animation. Until then, please feel free to browse and enjoy!