Last active
June 27, 2016 02:44
-
-
Save bathos/7db63d5434725a4c7dacfe72ddf4888a to your computer and use it in GitHub Desktop.
sketchy thing I had in an about:blank tab so I could keep track of where I am in sailor moon -- paste in console
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// STATE /////////////////////////////////////////////////////////////////////// | |
const state = { | |
down: false, | |
index: 0 | |
}; | |
// DATA //////////////////////////////////////////////////////////////////////// | |
const scouts = [ | |
{ | |
index: 186, | |
name: 'Sailor Chibi Chibi', | |
symbol: '♥︎', | |
color: 'palevioletred' | |
}, | |
{ | |
index: 9, | |
name: 'Sailor Mars', | |
symbol: '♂', | |
color: 'tomato' | |
}, | |
{ | |
index: 32, | |
name: 'Sailor Venus', | |
symbol: '♀', | |
color: 'coral' | |
}, | |
{ | |
index: 91, | |
name: 'Sailor Uranus', | |
symbol: '♅', | |
color: 'gold' | |
}, | |
{ | |
index: 24, | |
name: 'Sailor Jupiter', | |
symbol: '♃', | |
color: 'forestgreen' | |
}, | |
{ | |
index: 0, | |
name: 'Sailor Moon', | |
symbol: '☾', | |
color: 'oldlace' | |
}, | |
{ | |
index: 102, | |
name: 'Sailor Chibi Moon', | |
symbol: '☾', | |
color: 'pink' | |
}, | |
{ | |
index: 91, | |
name: 'Sailor Neptune', | |
symbol: '♆', | |
color: 'cadetblue' | |
}, | |
{ | |
index: 7, | |
name: 'Sailor Mercury', | |
symbol: '☿', | |
color: 'royalblue' | |
}, | |
{ | |
index: 124, | |
name: 'Sailor Saturn', | |
symbol: '♄', | |
color: 'darkblue' | |
}, | |
{ | |
index: 74, | |
name: 'Sailor Pluto', | |
symbol: '♇', | |
color: 'indigo' | |
}, | |
{ | |
index: 172, | |
name: 'Sailor Starlights', | |
symbol: '★', | |
color: 'black' | |
}, | |
]; | |
const seasons = [ | |
{ | |
color: 'pink', | |
name: 'Sailor Moon', | |
episodes: [ | |
'The Crybaby: Usagi’s Beautiful Transformation', | |
'Punishment Awaits: The House of Fortune Is the Monster Mansion', | |
'The Mysterious Sleeping Sickness: Protect the Girls in Love', | |
'Learn How to Be Skinny from Usagi', | |
'Scent of a Monster: Chanela Will Steal Your Love', | |
'Protect the Melody of Love: Usagi Plays Cupid', | |
'Usagi Learns Her Lesson: Becoming a Star Is Hard Work', | |
'The Girl Genius Is a Monster: The Brainwashing Cram School of Horror', | |
'Usagi’s Disaster: Beware of the Clock of Confusion', | |
'The Cursed Bus: Enter Mars, the Guardian of Fire', | |
'Usagi vs. Rei: Nightmare in Dream Land', | |
'I Want a Boyfriend: The Luxury Cruise Ship Is a Trap', | |
'Girls Unite: The End of Jadeite', | |
'A New Enemy Appears: Nephrite’s Evil Crest', | |
'Usagi’s Panic: Rei’s First Date', | |
'A Girl’s Dream: Usagi Becomes a Bride', | |
'Usagi’s a Model: The Flash of the Monster Camera', | |
'Shingo’s Love: The Grieving Doll', | |
'Usagi’s Joy: A Love Letter from Tuxedo Mask', | |
'The Summer, the Beach, Youth and Ghosts', | |
'Protect the Children’s Dreams: Friendship Through Anime', | |
'Romance Under the Moon: Usagi’s First Kiss', | |
'Wish Upon a Star: Naru’s First Love', | |
'Naru’s Tears: Nephrite Dies for Love', | |
'Jupiter, the Powerful Girl in Love', | |
'Restore Naru’s Smile: Usagi’s Friendship', | |
'Crushing on Ami: The Boy Who Can See the Future', | |
'The Painting of Love: Usagi and Mamoru Get Closer', | |
'Total Chaos: The Messy Love Rectangle', | |
'Grandpa Loses Control: Rei in Danger', | |
'Love and Chased: Luna’s Worst Day Ever', | |
'Umino’s Resolve: I’ll Protect Naru', | |
'Enter Venus, the Last Sailor Guardian', | |
'The Shining Silver Crystal: The Moon Princess Appears', | |
'Returning Memories: Usagi and Mamoru’s Past', | |
'Usagi’s Confusion: Is Tuxedo Mask Evil?', | |
'Let’s Become a Princess: Usagi’s Bizarre Training', | |
'The Snow, the Mountains, Friendship and Monsters', | |
'Paired with a Monster: Mako, the Ice Skating Queen', | |
'The Legendary Lake Yokai: The Bond of Usagi’s Family', | |
'I Won’t Run Away from Love Anymore: Ami vs. Mamoru', | |
'Sailor Venus’s Past: Minako’s Tragic Love', | |
'Usagi Abandoned: The Falling-Out of the Sailor Guardians', | |
'Usagi’s Awakening: A Message from the Distant Past', | |
'Death of the Sailor Guardians: The Tragic Final Battle', | |
'Usagi’s Eternal Wish: A Brand New Life' | |
] | |
}, | |
{ | |
color: 'thistle', | |
name: 'Sailor Moon R', | |
episodes: [ | |
'Moon Returns: The Mysterious Aliens Appear', | |
'For Love and for Justice: Sailor Guardians Once Again', | |
'For Whom Is the White Rose? The Moonlight Knight Appears', | |
'Usagi’s Crisis: The Tiara Stops Working', | |
'A New Transformation: Usagi’s Power-Up', | |
'The Targeted Kindergarteners: Venus to the Rescue', | |
'Mamoru and Usagi’s Babysitting Mayhem', | |
'The School Festival Is for Me?! Queen Rei’s Song', | |
'Is Seijuro the Moonlight Knight? Mako on Fire', | |
'Steal a Kiss from Mamoru! An’s Project Snow White', | |
'After School Trouble: Usagi Is a Target', | |
'Disconnecting Love: The Raging Makai Tree', | |
'True Love Awakens: The Makai Tree’s Secret', | |
'Angel or Devil? The Mysterious Girl from the Sky', | |
'Usagi Devastated: Mamoru Declares a Break-Up', | |
'A Guardian’s Friendship: Goodbye, Ami', | |
'Women Must Be Strong and Beautiful: Rei’s New Special Technique', | |
'In Search of the Silver Crystal: Chibi-Usa’s Secret', | |
'Dispute Over Love: Minako and Makoto’s Conflict', | |
'Usagi’s Parental Love: The Curry Romance Triangle', | |
'The Beach, the Island and a Vacation: The Guardians’ Break', | |
'Protect Chibi-Usa: Clash of the Ten Warriors', | |
'Awaken the Sleeping Beauty: Mamoru’s Distress', | |
'Battle of the Flames of Love! Mars vs. Koan', | |
'For Friendship! Ami vs. Berthier', | |
'Rubeus the Heartless: The Tragic Sisters', | |
'A UFO Appears: The Sailor Guardians Abducted', | |
'Defeat Rubeus: The Battle in Space', | |
'The Mysterious New Guardian: Sailor Pluto Appears', | |
'Magic of Darkness: Esmeraude’s Invasion', | |
'Shared Feelings: Usagi and Mamoru in Love Once Again', | |
'Venus: Minako’s Nurse Mayhem', | |
'Artemis’s Adventure: The Monster Animal Kingdom', | |
'The Terrifying Illusion: Ami All Alone', | |
'The Dark Gate Is Completed? The Targeted Elementary School', | |
'Journey to the Future: Battle in the Space-Time Corridor', | |
'The Shocking Future: Demande’s Dark Ambition', | |
'Wiseman’s Evil Hand: Chibiusa Disappears', | |
'The Dark Queen: Birth of Black Lady', | |
'Saphir Dies: Wiseman’s Trap', | |
'Believing in Love and the Future: Usagi’s Decision', | |
'The Final Battle Between Light and Dark: Pledge of Love to the Future', | |
'Usagi and the Girls’ Resolve: Prelude to a New Battle' | |
] | |
}, | |
{ | |
color: 'paleturquoise', | |
name: 'Sailor Moon S', | |
episodes: [ | |
'Premonition of the Apocalypse: The Mysterious New Guardians Appear', | |
'The Rod of Love Is Born: Usagi’s New Transformation', | |
'A Handsome Boy? Haruka Tenoh’s Secret', | |
'Usagi’s Idol: The Graceful Genius Michiru', | |
'Protect the Pure Heart: The Three-Way Battle', | |
'Let Moon Help With Your Love Problems', | |
'Coldhearted Uranus: Makoto in Danger', | |
'The Labyrinth of Water: Ami Targeted', | |
'To Save Our Friends: Moon and Uranus Join Forces', | |
'A Man’s Kindness: Yuichiro Heartbroken by Rei', | |
'I Want to Quit Being a Sailor Guardian: Minako’s Dilemma', | |
'Usagi in Tears: a Glass Slipper for My Birthday', | |
'The Stolen Pure Heart: Usagi’s Crisis', | |
'The Arrival of a Tiny Pretty Guardian', | |
'Making New Friends: Chibi Moon’s Adventure', | |
'I Want Power: Mako Lost in Doubt', | |
'The Bond of Destiny: Uranus’s Distant Past', | |
'Art Is an Explosion of Love: Chibi-Usa’s First Love', | |
'Usagi Dancing to the Waltz', | |
'The Shocking Moment: Everyone’s Identities Revealed', | |
'The Death of Uranus and Neptune: The Talisman Appear', | |
'The Holy Grail’s Mystical Power: Moon’s Double Transformation', | |
'Who is the True Messiah? Chaos of Light and Darkness', | |
'A House Filled With Evil Presence: The Beautiful Hotaru’s Secret', | |
'I Love Idols: Mimete’s Dilemma', | |
'Shadow of Silence: The Pale Glimmer of a Firefly', | |
'Sunny Skies After a Storm: A Friendship Dedicated to Hotaru', | |
'Higher and Stronger: A Cheer from Usagi', | |
'The Battle Inside the Demonic Space: The Sailor Guardians’ Gamble', | |
'The Messiah of Silence Awakens? Stars of Destiny', | |
'An Invasion from an Another Dimension: Mystery of Mugen Academy', | |
'A Bewitching Flower That Steals Hearts: Tellu, the Third Witch', | |
'Believe in Love: Ami, the Kindhearted Guardian', | |
'Shadows of Destruction: the Messiah of Silence Awakens', | |
'The Coming Terror of Darkness: Struggle of the Eight Guardians', | |
'The Shining Shooting Star: Saturn and the Messiah', | |
'A New Life: Parting of the Stars of Destiny', | |
'A Guardian’s Realization: Strength Lies Within a Pure Heart' | |
] | |
}, | |
{ | |
color: 'navajowhite', | |
name: 'Sailor Moon Super S', | |
episodes: [ | |
'Meeting of Destiny: The Night Pegasus Dances', | |
'Super Transformation Once Again: Pegasus’s Power', | |
'Protect Mom’s Dream: Double Moon’s New Attack', | |
'Catch Pegasus: The Amazon’s Trap', | |
'The Perfect Couple: Usagi and Mamoru’s Love', | |
'Artemis Is Cheating? Enter the Mysterious Kitten', | |
'Makoto’s Friendship: A Girl Who Admired Pegasus', | |
'Connecting Hearts: Chibi-Usa and Pegasus', | |
'Protect Mamoru: Ninja Usagi’s Jealousy', | |
'Forest of Illusion: A Beautiful Fairy’s Invitation', | |
'Drive to the Heavens: The Dream Car Fueled with Love', | |
'Aiming for the Top: the Pretty Swordswoman’s Dilemma', | |
'We Love Fashion: The Stylish Guardians', | |
'Storm of Love: Minako’s Grand Two-Timing Plan', | |
'The Secret Mansion: A Menu of Love for You', | |
'Believe in Pegasus: The Four Guardians’ Super Transformation', | |
'Shining Summer Days: Ami Under the Sea-Breeze', | |
'Become a Prima: Usagi’s Ballet', | |
'Juban Holiday: The Carefree Princess', | |
'Destined Partners? Makoto’s Innocence', | |
'Shadow of Evil: The Trio’s Last Chance', | |
'Mirrors of Dreams: The Amazon’s Last Stage', | |
'The Amazoness: Nightmare From Behind the Mirrors', | |
'True Power Explodes: Ami’s Melody of the Heart', | |
'Flames of Passion: Mars’s Raging Super Attack', | |
'Dentist of Horrors? Palla-Palla’s House', | |
'Clash of Dreams: Minako and Makoto’s Broken Friendship', | |
'Overcome Your Fear: the Jump to Freedom', | |
'Don’t Lose Sight of Your Dreams: The Mirror of Truth', | |
'Pegasus Disappears: Wavering Friendship', | |
'Pegasus’s Secret: The Boy Who Protects the Dream World', | |
'Chibi-Usa’s Little Rhapsody of Love', | |
'Dream to be an Adult: The Amazoness’s Confusion', | |
'Terror in Motion: The Dark Queen’s Evil Hand', | |
'The Source of Darkness: Dead Moon Circus', | |
'Labyrinth of Mirrors: Chibi Moon Captured', | |
'The Golden Crystal Appears: Nehellenia’s Magic', | |
'When the Crystal Shines: The Beautiful Power of Dreams', | |
'Dreams Forever: Fill the Heavens with Light' | |
] | |
}, | |
{ | |
color: 'khaki', | |
name: 'Sailor Moon Sailor Stars', | |
episodes: [ | |
'The Flower of Nightmares Scatters: The Queen of Darkness Returns', | |
'Saturn Awakens: The Ten Sailor Guardians Unite', | |
'The Cursed Mirror: Mamoru Caught in a Nightmare', | |
'Night of Destiny: Ordeals of a Guardian', | |
'For Love: the Endless Battle in the Dark World', | |
'Moon Power of Love: End of the Nightmare', | |
'Farewells and Encounters: the Transitioning Stars of Destiny', | |
'A School Storm: The Transfer Students Are Idols', | |
'Becoming an Idol: Minako’s Ambition', | |
'A Fighter’s True Spirit: Shocking Super Transformation', | |
'A Maker’s True Spirit: Shocking Super Transformation', | |
'Luna’s Discovery: The Real Face of Yaten', | |
'Friend or Foe? Star Lights and the Sailor Guardians', | |
'Calling of the Shining Stars: Enter Haruka and Michiru', | |
'Seiya and Usagi’s Heart-Pounding Date', | |
'Invaders from Outer Space: The Coming of Siren', | |
'The Screaming Dead: Terror of the Camp Monster', | |
'A Night Alone Together: Usagi in Danger', | |
'Taiki’s Song Filled With Passion and Faith', | |
'Chibi-Chibi’s Mystery: The Big Noisy Chase', | |
'The Shining Power of a Star: Chibi-Chibi’s Transformation', | |
'Invitation to Terror: Usagi’s Night Flight', | |
'Duty or Friendship: Conflict Between the Sailor Guardians', | |
'Truth Revealed: The Star Lights’ Past', | |
'Butterflies of Light: A New Chapter On the Horizon', | |
'Go for Your Dream: Minako Becomes an Idol', | |
'The Stolen Silver Crystal: Princess Kakyu Appears', | |
'Crusade for the Galaxy: Legend of the Sailor Wars', | |
'Princess Kakyu Perishes: Advent of Galaxia', | |
'Countdown to Destruction: The Sailor Guardians’ Final Battle', | |
'Ruler of the Galaxy: The Menace of Galaxia', | |
'Dying Stars: Uranus and Neptune’s Last Stand', | |
'The Light of Hope: The Final Battle for the Galaxy', | |
'Usagi’s Love: The Moonlight Illuminates the Galaxy' | |
] | |
} | |
]; | |
const allEpisodes = seasons | |
.reduce((acc, { episodes, name: season }) => [ | |
...acc, | |
...episodes.map((name, seasonIndex) => | |
({ name, season, seasonIndex, seasonCount: episodes.length }) | |
) | |
], []); | |
allEpisodes.forEach((episode, episodeIndex) => { | |
episode.scouts = scouts.filter(({ index }) => index <= episodeIndex); | |
}); | |
// INITIAL RENDER ////////////////////////////////////////////////////////////// | |
const seasonGradient = `linear-gradient(to right, ${ seasons | |
.reduce((acc, { color, episodes }) => { | |
const [ { fraction: start=0 }={} ] = acc.slice(-1); | |
const end = start + (episodes.length / allEpisodes.length) | |
return [ ...acc, { color, fraction: start }, { color, fraction: end } ]; | |
}, []) | |
.map(({ color, fraction }) => `${ color } ${ fraction * 100 }%`) | |
.join(', ') | |
})`; | |
const backgroundURL = | |
`http://66.media.tumblr.com/10f21440351723698c77c2d3e5a0b2a6/` + | |
`tumblr_n2r8fglrVu1s1odqho1_1280.png`; | |
const bodyStyle = ` | |
align-items : center; flex-direction:column; | |
background-blend-mode : lighten; | |
background-image : linear-gradient(to bottom, azure, lightblue), | |
url('${ backgroundURL }'); | |
background-position : bottom center; | |
background-size : cover, cover; | |
display : flex; | |
justify-content : center; | |
margin : 0; | |
padding : 2rem; | |
`; | |
const buttonRowStyle = ` | |
display : flex; | |
justify-content : space-around; | |
margin-bottom : -4.5rem; | |
width : 100%; | |
`; | |
const buttonStyle = ` | |
-webkit-appearance : none; | |
background : azure; | |
border-radius : 0.2rem; | |
border : none; | |
box-shadow : 0 1px 6px -3px slategray; | |
color : dimgrey; | |
cursor : pointer; | |
font-style : italic; | |
height : 2rem; | |
transition : all 80ms linear; | |
width : 4rem; | |
`; | |
const episodeCountStyle = ` | |
font-size : 1.5rem; | |
margin : 0; | |
`; | |
const episodeStyle = ` | |
color : darkgray; | |
font-size : 2rem; | |
`; | |
const progressBGStyle = ` | |
background-image : ${ seasonGradient }; | |
border : 4px solid aliceblue; | |
box-shadow : 0 0px 20px -5px powderblue; | |
overflow : hidden; | |
`; | |
const progressFGStyle = ` | |
background : linear-gradient(lightpink -200%, lightcoral 50%); | |
box-shadow : 0 0 15px 4px slateblue inset; | |
mix-blend-mode : color-burn; | |
transition : width 80ms ease-out; | |
`; | |
const progressNavStyle = ` | |
cursor : pointer; | |
`; | |
const progressStyle = ` | |
border-radius : 2rem; | |
height : 2rem; | |
width : 100%; | |
`; | |
const scoutStyle = ` | |
align-items : center; | |
border : 2px solid white; | |
border-radius : 2.5rem; | |
color : white; | |
display : inline-flex; | |
font-family : STIXGeneral, monospace; | |
font-size : 1.5rem; | |
height : 2.5rem; | |
justify-content : center; | |
margin : 1.5rem 0.5rem; | |
width : 2.5rem; | |
`; | |
const seasonStyle = ` | |
font-family : cursive; | |
font-size : 3rem; | |
`; | |
const textStyle = ` | |
color : mintcream; | |
font-family : monospace; | |
margin : 1rem; | |
text-shadow : 1px 1px #d2dde9; | |
`; | |
document.documentElement.innerHTML = ` | |
<head> | |
<title id="TITLE"></title> | |
</head> | |
<body style="${ bodyStyle }"> | |
<div style="${ buttonRowStyle }"> | |
<button id="PREV">PREV</button> | |
<button id="NEXT">NEXT</button> | |
</div> | |
<div id="SEASON" style="${ textStyle }${ seasonStyle }"></div> | |
<div style="${ textStyle }${ episodeCountStyle }"> | |
Episode | |
<span id="OVERALLEPISODENUMBER"></span> | |
of ${ allEpisodes.length } | |
(<span id="SEASONEPISODENUMBER"></span> of | |
<span id="SEASONEPISODECOUNT"></span> in season) | |
</div> | |
<div id="EPISODENAME" style="${ textStyle }${ episodeStyle }"></div> | |
<div style="${ progressStyle }${ progressBGStyle }"> | |
<div id="PROGRESSBAR" style="${ progressNavStyle }"> | |
<div id="PROGRESS" style="${ progressStyle }${ progressFGStyle }"></div> | |
</div> | |
</div> | |
<div id="SCOUTS"></div> | |
</body> | |
`; | |
// RENDER ////////////////////////////////////////////////////////////////////// | |
const render = () => { | |
const episode = allEpisodes[state.index]; | |
const textMapping = { | |
EPISODENAME: episode.name, | |
OVERALLEPISODENUMBER: state.index + 1, | |
SEASON: episode.season, | |
SEASONEPISODECOUNT: episode.seasonCount, | |
SEASONEPISODENUMBER: episode.seasonIndex + 1, | |
TITLE: `${ episode.season } ${ episode.seasonIndex + 1 }: ${ episode.name }` | |
}; | |
for (const [ id, text ] of Object.entries(textMapping)) | |
document.getElementById(id).innerHTML = text; | |
document.getElementById('PROGRESS').style.width = | |
`${ (state.index + 1) / allEpisodes.length * 100 }%`; | |
document.getElementById('SCOUTS').innerHTML = episode.scouts.map(scout => ` | |
<div | |
title="${ scout.name }" | |
style=" | |
${ scoutStyle } | |
background-image: linear-gradient( | |
to bottom right, | |
transparent 15%, | |
${ scout.color } 150%); | |
"> | |
${ scout.symbol } | |
</div> | |
`).join(''); | |
}; | |
render(); | |
// EVENTS: NAV BUTTONS ///////////////////////////////////////////////////////// | |
const increment = inc => () => { | |
const newIndex = Math.min( | |
allEpisodes.length - 1, | |
Math.max(0, state.index + inc) | |
); | |
if (newIndex !== state.index) { | |
state.index = newIndex; | |
render(); | |
} | |
}; | |
document.getElementById('PREV').addEventListener('click', increment(-1)); | |
document.getElementById('NEXT').addEventListener('click', increment(+1)); | |
// EVENTS: BAR ///////////////////////////////////////////////////////////////// | |
const bar = document.getElementById('PROGRESSBAR'); | |
const goto = event => { | |
if (state.down) { | |
const position = event.pageX - bar.offsetLeft; | |
const divisor = bar.clientWidth / allEpisodes.length; | |
const newIndex = Math.min( | |
allEpisodes.length - 1, | |
Math.max(0, Math.round(position / divisor)) | |
); | |
if (newIndex !== state.index) { | |
state.index = newIndex; | |
render(); | |
} | |
} | |
}; | |
const mousedown = () => { | |
state.down = true; | |
document.body.style.cursor = bar.style.cursor = 'col-resize'; | |
goto(event); | |
}; | |
const mouseup = () => { | |
state.down = false; | |
document.body.style.cursor = ''; | |
bar.style.cursor = 'pointer'; | |
}; | |
document.addEventListener('blur', mouseup); | |
document.addEventListener('mouseup', mouseup); | |
document.addEventListener('mousemove', goto); | |
bar.addEventListener('mousedown', mousedown); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment