This commit is contained in:
Nicky Case 2018-09-18 13:17:42 -04:00
commit 4670ff8e93
29 changed files with 3442 additions and 0 deletions

508
ch2.html Normal file
View File

@ -0,0 +1,508 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>An Interactive Comic</title>
<link rel="stylesheet" type="text/css" href="css/comic.css"/>
</head>
<body>
<div id="comic">
<!-- - - - - - - - - - - - -->
<!-- THE ART of SRS - - - - -->
<!-- - - - - - - - - - - - -->
<!-- Part 1.1: Leitner Calendar -->
<panel w=500 h=450>
<pic></pic> <!-- hey susan, TRAINERS -->
<words x=10 y=10 w=430 h=60>
You don't <i>have</i> to use a shoebox for Spaced Repetition,
but it's funnier if you do.
</words>
<words x=30 y=350 w=430 h=60>
(Later, we'll look at some Spaced Repetition <i>apps</i>,
like Anki &amp; Tinycards)
</words>
</panel>
<panel w=500 h=400>
<pic></pic> <!-- poker: me vs brain -->
<words x=10 y=10 w=430 h=60>
This method is called The Leitner System.
It's like a card game you play against yourself!
</words>
<words x=30 y=300 w=430 h=60>
First, divide your box up into seven "Levels".
Each Level will store some flashcards.
</words>
</panel>
<panel w=400 h=200 bg="#bada55">
"wait, what's a flashcard?"
<!-- This is, ya goof -->
<!--<sim x=0 y=0 w=600 h=400 src="sims/multicard/?cards=sci_a,sci_b,sci_c"></sim>-->
</panel>
<panel w=400 h=200 bg="#bada55">
"what kind of stuff can I learn with flashcards?"
<!-- This is, ya goof -->
<!--<sim x=0 y=0 w=600 h=400 src="sims/multicard/?cards=sci_a,sci_b,sci_c"></sim>-->
</panel>
<panel w=600 h=80>
<words w=600 x=-15 no-bg>
We need to space out our recalls with <i>increasing gaps of time</i>.
So, here's a calendar of when to review which Level's cards:
</words>
</panel>
<panel w=600 h=300 bg="#bada55">
<!-- Note: Level 4 THEN 2 THEN 1... -->
</panel>
<!-- Part 1.2: Leitner Rules -->
<panel w=600 h=80>
<words w=600 x=-15 no-bg>
But how do cards move <i>between</i> Levels?
How do you play this game of Spaced Repetition Solitaire?
</words>
</panel>
<panel w=500 h=400>
<pic></pic> <!-- joyful baby card... and grisly card -->
<words x=10 y=10 w=430 h=60>
The rules are simple.
First, all new cards start at Level 1.
</words>
<words x=30 y=300 w=430 h=60>
(If you're new to Spaced Repetition, I recommend starting with 5 new cards a day.)
</words>
</panel>
<panel w=500 h=430>
<pic></pic> <!-- valhalla -->
<words x=10 y=10 w=430 h=90>
When you review the cards in a Level, first, shuffle them.
Then, try to recall them.
Each card you get right goes up one Level.
</words>
<words x=30 y=330 w=430 h=60>
(If you're already at the final Level, congrats!
Your card gets to retire in Valhalla)
</words>
</panel>
<panel w=500 h=400>
<pic></pic> <!-- HIGH STAKES -->
<words x=10 y=10 w=430 h=60>
But each card you get wrong... goes
<i>all the way back down to Level 1.</i>
</words>
<words x=30 y=300 w=430 h=60>
(You can change the rules it's <i>your</i> shoebox
but I recommend playing it this way)
</words>
</panel>
<panel w=500 h=400>
<pic></pic> <!-- baby + REMEMBER ME?! -->
<words x=10 y=10 w=430 h=60>
Each day, you review Level 1 at the end.
You'll see your new cards + the cards you forgot.
</words>
<words x=30 y=300 w=430 h=60>
Keep trying to recall them, until you can get <i>every one</i> right!
Move them all to Level 2.
</words>
</panel>
<panel w=600 h=80>
<words w=600 x=-15 no-bg>
And that's it!
Here's how the game plays out over several days:
(Later, we'll see a sim for several <i>months</i>)
</words>
</panel>
<panel w=600 h=300 bg="#bada55">
</panel>
<!-- Part 1.3: Leitner Full Sim -->
<panel w=600 h=110>
<words w=600 x=-15 no-bg>
Each daily session takes 20-30 minutes.
Instead of watching a TV episode, you could play a card game
and remember anything you want <i>for life</i>.
</words>
</panel>
<panel w=500 h=400>
<pic></pic> <!-- snowball -->
<words x=10 y=10 w=430 h=60>
However, habits are hard. If you start big, you won't get the ball rolling...
</words>
<words x=30 y=300 w=430 h=60>
But if you start <i>small</i>, you can gain momentum,
and roll your snowball bigger and bigger.
</words>
</panel>
<panel w=500 h=690>
<pic></pic> <!-- katamari damacy -->
<words x=10 y=10 w=430 h=60>
That's why I recommend <i>starting</i> with 5 new cards a day.
</words>
<words x=30 y=300 w=430 h=60>
Once you're comfortable with that, you can do 10 new cards/day.
Then 15. Then 20, 25, 30.
</words>
<words x=10 y=590 w=430 h=60>
And at 30 new cards a day, you can learn <i>10,000+</i> new facts/words/etc a <i>year.</i>
</words>
</panel>
<panel w=600 h=50>
<words w=600 x=-15 no-bg>
Here's what that looks like, over several months:
</words>
</panel>
<panel w=600 h=300 bg="#bada55">
</panel>
<!-- Part 1.3: Leitner Outro -->
<panel w=600 h=110>
<words w=600 x=-15 no-bg>
That's it. That's how you can make long-term memory a <i>choice</i>.
</words>
<words w=600 x=-15 y=50 no-bg>
Let's let that sink in. Take a break, and recall what we just learnt:
</words>
</panel>
<panel w=600 h=400 bg="#bada55">
<!--<sim x=0 y=0 w=600 h=400 src="sims/multicard/?cards=sci_a,sci_b,sci_c"></sim>-->
</panel>
<!-- Part 2.1: Pitfalls -->
<panel w=600 h=80>
<words w=600 x=-15 no-bg>
Spaced Repetition almost seems too good to be true.
<br>
And it is... <i>IF</i> you fall for 3 very common pitfalls.
</words>
</panel>
<panel w=500 h=450>
<pic></pic> <!-- Library, humor -->
<words x=10 y=10 w=430 h=60>
Spaced Repetition will fail if your cards feel
bloated, disconnected, or meaningless.
</words>
<words x=30 y=350 w=430 h=60>
Memory isn't a private library,
where you hoard a bunch of random books to impress others.
</words>
</panel>
<panel w=500 h=450>
<pic></pic> <!-- ANGRY FACE -->
<words x=10 y=10 w=430 h=90>
Memory is more like a jigsaw puzzle, full of tiny pieces joined together.
(This is also how neurons work: lots of tiny, connected things)
</words>
<words x=30 y=380 w=430 h=30>
It's not about <i>collection</i>, it's about <i>connection</i>.
</words>
</panel>
<panel w=500 h=400>
<pic></pic>
<words x=10 y=10 w=410 h=60>
So, to get the most out of Spaced Repetition,
you must make your cards...
</words>
<!--SMALL, CONNECTED, and MEANINGFUL.-->
</panel>
<!-- Part 2.2: Small -->
<panel w=600 h=100 bg="#000">
<words x=10 y=10 w=400>
<b>SMALL</b>
</words>
</panel>
<panel w=450 h=50>
<words w=450 x=-15 no-bg>
This card sucks:
</words>
</panel>
<panel w=400 h=200 bg="#bada55">
<!-- Mitochrondria? -->
<!--<sim x=0 y=0 w=600 h=400 src="sims/multicard/?cards=sci_a,sci_b,sci_c"></sim>-->
</panel>
<panel w=450 h=350>
<pic></pic>
<words x=10 y=10 w=400 h=30>
It's too big. Too much information.
</words>
<words x=10 y=250 w=400 h=60>
Instead, let's cut in up into a bunch of smaller, connected pieces,
like so:
</words>
</panel>
<panel w=400 h=600 bg="#bada55">
<!--<sim x=0 y=0 w=600 h=400 src="sims/multicard/?cards=sci_a,sci_b,sci_c"></sim>-->
</panel>
<panel w=450 h=90>
<words w=450 x=-15 no-bg>
Facts connect to facts.
But there's other, more playful ways for cards to be...
</words>
</panel>
<!-- Part 2.3: Connected -->
<panel w=600 h=100 bg="#000">
<words x=10 y=10 w=400>
<b>CONNECTED</b>
</words>
</panel>
<panel w=450 h=110>
<words w=450 x=-15 no-bg>
This card is... alright.
It's an English word on the front, French word on the back.
It's the standard for most flashcards:
</words>
</panel>
<panel w=400 h=200 bg="#bada55">
<!--<sim x=0 y=0 w=600 h=400 src="sims/multicard/?cards=sci_a,sci_b,sci_c"></sim>-->
</panel>
<panel w=450 h=400>
<pic></pic>
<words x=10 y=10 w=400 h=60>
But you know what would make it stick in memory better?
</words>
<words x=10 y=300 w=400 h=60>
If you connected it to
<i>images, sounds, context, and/or personal details!</i>
Like so:
</words>
</panel>
<panel w=400 h=200 bg="#bada55">
<!-- comically FAT cat -->
<!--<sim x=0 y=0 w=600 h=400 src="sims/multicard/?cards=sci_a,sci_b,sci_c"></sim>-->
</panel>
<panel w=600 h=300>
<pic></pic>
<words x=10 y=10 w=200>
The front now has a drawing of a cat (image)
with a fill-in-the-blank French sentence (context: grammar)
about my childhood cat, Stripes. (personal)
</words>
</panel>
<panel w=600 h=300>
<pic></pic>
<words x=10 y=10 w=200>
The back now has a symbol of the noun's gender (image),
its pronunciation (sound*),
and a warning not to use the female version. (context: slang)
</words>
<words w=330 x=240 y=230 no-bg fontsize=20>
* Obviously, paper cards can't play sounds.
But apps like Anki/Tinycards can!
</words>
</panel>
<panel w=450 h=90>
<words w=450 x=-15 no-bg>
But the <i>most</i> important connection of all,
is to connect your learning to something that is...
</words>
</panel>
<!-- Part 2.4: Meaningful -->
<panel w=600 h=100 bg="#000">
<words x=10 y=10 w=400>
<b>MEANINGFUL</b>
</words>
</panel>
<panel w=500 h=350>
<pic></pic> <!-- examples: programming, ukulele, french -->
<words x=10 y=10 w=450 h=60>
Personally, here's how I've learnt best:
First, I try to <b>do</b> something.
</words>
</panel>
<panel w=500 h=350>
<pic></pic> <!-- examples: programming, ukulele, french -->
<words x=10 y=10 w=450 h=60>
Inevitably, I'll get stuck.
In that moment, I'll look up what I need,
and <b>learn</b> something.
</words>
</panel>
<panel w=400 h=200 bg="#bada55">
<!--
..and then back to doing.
-->
<!--
...and then back to learning.
-->
</panel>
<panel w=450 h=30>
<words w=450 x=-15 y=-15 no-bg>
And so on. <!-- FADE PANEL -->
</words>
</panel>
<panel w=450 h=30>
<words w=450 x=-15 y=-15 no-bg>
And so on. <!-- FADE PANEL -->
</words>
</panel>
<panel w=450 h=30>
<words w=450 x=-15 y=-15 no-bg>
And so on. <!-- FADE PANEL -->
</words>
</panel>
<panel w=450 h=400>
<pic></pic> <!-- connected to HEART -->
<words x=10 y=10 w=400 h=60>
That, I believe, is the best way to keep yourself motivated while learning:
</words>
<words x=10 y=300 w=400 h=60>
By making sure your learning is in service of <i>something you actually care about.</i>
</words>
</panel>
<panel w=600 h=90>
<words w=600 x=-15 no-bg>
Speaking of learning, let's practice recalling what we've learnt:
(this is the second-last time!)
</words>
</panel>
<panel w=600 h=400 bg="#bada55">
<!--<sim x=0 y=0 w=600 h=400 src="sims/multicard/?cards=sci_a,sci_b,sci_c"></sim>-->
</panel>
<!-- Part 2.5: Outro -->
<panel w=500 h=450>
<pic></pic> <!-- show three rules -->
<words x=10 y=10 w=370 h=30>
These three rules for making cards...
</words>
<!-- SMALL, CONNECTED, MEANINGFUL -->
<words x=30 y=320 w=430 h=90>
...are why it's consensus among the Spaced Repetition community that,
for the most part,
<b>you should make your own cards.</b>
</words>
</panel>
<panel w=400 h=400>
<pic></pic> <!-- me, talking -->
<words x=10 y=10 w=300 no-bg>
This way, you can connect facts to things <i>you</i> know,
to images and sounds <i>you</i> like,
in service of something <i>you</i> love.
</words>
</panel>
<panel w=400 h=400>
<pic></pic>
<words x=10 y=10 w=300 no-bg>
That's why, in the <i>final</i> part of this interactive comic,
you're going to make your own cards!
</words>
<words x=30 y=160 w=170 no-bg>
And these cards will be about...
</words>
</panel>
<panel w=400 h=400>
<pic></pic> <!-- goofy pic -->
<words x=130 y=10 w=230 fontsize=150 no-bg>
YOU
</words>
</panel>
</div>
<!-- - - - - - - - - - -->
<!-- SIMULATION LABELS -->
<!-- - - - - - - - - - -->
<div id="labels">
<div id="default_labels">
<span id="leitner_day">
Day [N]
</span>
<span id="leitner_step_to_review">
to review: Level
</span>
<span id="leitner_step_reviewing">
review Level [N]
</span>
<span id="leitner_step_new">
add [N] new cards
</span>
<span id="leitner_step_stats">
total: [N] cards!
</span>
<span id="leitner_step_stats_2">
([N] in very-long-term memory)
</span>
</div>
</div>
</body>
</html>
<script src="js/minpubsub.src.js"></script>
<script src="js/comic.js"></script>

BIN
css/PatrickHand-Regular.ttf Executable file

Binary file not shown.

95
css/comic.css Normal file
View File

@ -0,0 +1,95 @@
/* FONT FACE */
@font-face {
font-family: "PatrickHand";
font-style: normal;
font-weight: 400;
src: url(PatrickHand-Regular.ttf) format('truetype');
}
/* HTML & BODY */
html, body{
width:100%;
height:100%;
}
body{
background: #eeeeee;
margin:0;
font-family: "PatrickHand", Helvetica, Arial;
font-size: 25px;
line-height: 1.2em;
}
/* fake bold */
b, strong{
font-weight: normal;
text-shadow:1px 0 0 currentColor;
letter-spacing: 1px;
}
/*********/
/* COMIC */
/*********/
#comic{
overflow:hidden;
width:610px;
margin: 50px auto;
text-align: center;
}
#comic panel{
display: inline-block;
width: 250px;
height: 250px;
/*border: 2px solid #ccc;*/
margin: 5px;
position: relative;
overflow: hidden;
transition: opacity 0.5s ease-in-out;
}
#comic panel[fadeInOn]{
opacity: 0;
}
#comic panel pic{
display: block;
position: absolute;
top:0;
left:0;
width: 100%;
height: 100%;
/*background: #bada55;*/
background: #ccc;
}
#comic panel words{
display: block;
position: absolute;
top:0;
left:0;
background: #fff;
/*text-align: left;*/
padding: 15px;
}
#comic panel words[no-bg]{
background: none;
}
#comic panel sim{
display: block;
position: absolute;
}
#comic panel sim > iframe{
border: none;
width: 100%;
height: 100%;
position: absolute;
top:0; left:0;
}
#comic panel sim > label{
display:none;
}
/**********/
/* LABELS */
/**********/
#labels{
display: none;
}

460
index.html Normal file
View File

@ -0,0 +1,460 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>An Interactive Comic</title>
<link rel="stylesheet" type="text/css" href="css/comic.css"/>
</head>
<body>
<div id="comic">
<!-- - - - - - - - - - - - -->
<!-- THE SCIENCE of SRS - - -->
<!-- - - - - - - - - - - - -->
<panel w=600 h=90>
<words w=600 x=-15 no-bg>
(<b>This is a work-in-progress!</b>
Please don't share yet.
<br>
Let me know your honest feedback, thanks!)
</words>
</panel>
<!-- Part I: Decay -->
<panel w=500 h=450>
<pic src="pics/sci0.png" sx=0 sy=0></pic>
<words x=10 y=10 w=400 h=60>
In 1885, Hermann Ebbinghaus performed an act of scientific masochism.
</words>
<words x=30 y=320 w=430 h=90>
The German psychologist memorized <i>thousands</i> of nonsense words,
recorded how much he forgot over time, and discovered...
</words>
</panel>
<panel w=400 h=500>
<pic src="pics/sci0.png" sx=500 sy=0></pic>
<words x=60 y=10 w=250>
<b>THE FORGETTING CURVE</b>
</words>
<words x=10 y=310 w=350>
He found that you forget most of what you learn in the first 24 hours,
then if you dont practice recall your remaining memories decay exponentially.
</words>
</panel>
<panel w=500 h=450>
<pic src="pics/sci0.png" sx=900 sy=0></pic>
<words x=10 y=10 w=400 h=60>
Since then, Ebbinghauss findings have been replicated again and again
</words>
<words x=60 y=350 w=400 h=60>
and grew into a whole new scientific field of memory!
</words>
</panel>
<panel w=600 h=80>
<words w=600 x=-15 no-bg>
Heres a playable simulation of the Forgetting Curve.
<br>
<b>Change the rate of “memory decay”. What happens?</b>
</words>
</panel>
<panel w=600 h=370>
<sim x=0 y=0 w=600 h=370 src="sims/ebbinghaus?mode=0"></sim>
</panel>
<!-- Part II: Reminder -->
<panel w=600 h=90>
<words w=600 x=-15 no-bg>
As you can see, the less the decay, the flatter the curve
that is, the longer the memory lasts.
</words>
</panel>
<panel w=400 h=400>
<pic src="pics/sci0.png" sx=0 sy=500></pic>
<words x=10 y=10 w=300>
How fast a persons memory decays depends on the person and the memory...
</words>
</panel>
<panel w=400 h=400>
<pic src="pics/sci0.png" sx=400 sy=500></pic>
<words x=10 y=10 w=300>
But, in general, a memorys “rate of decay” slows down each time you <b>actively recall</b> it.
</words>
</panel>
<panel w=400 h=400>
<pic src="pics/sci0.png" sx=800 sy=500></pic>
<words x=10 y=10 w=300>
(although, when you stop practicing, it still decays.)
</words>
</panel>
<panel w=600 h=120>
<words w=600 x=-15 no-bg>
Heres the simulation again, with a single active recall session.
<br>
(grey line: what memory would've been <i>without</i> the recall)
<br>
<b>Change the timing of the recall. What happens?</b>
</words>
</panel>
<panel w=600 h=400>
<sim x=0 y=0 w=600 h=400 src="sims/ebbinghaus?mode=1"></sim>
</panel>
<!-- Part III: Desirable Difficulty -->
<panel w=600 h=90>
<words w=600 x=-15 no-bg>
A single recall boosts memory for a bit... but in the long run,
due to exponential decay of memory, a single recall changes nothing.
</words>
</panel>
<panel w=450 h=400>
<pic src="pics/sci1.png" sx=0 sy=0></pic>
<words x=10 y=10 w=390>
Is there a better way to learn?
There is! The trick to remembering...
</words>
<words x=210 y=330 w=200>
...<i>is to forget.</i>
</words>
</panel>
<panel w=500 h=300>
<pic src="pics/sci1.png" sx=450 sy=0></pic>
<words x=250 y=20 w=200>
To understand this, think about training your muscles.
Youll gain nothing with a weight thats too easy...
</words>
</panel>
<panel w=500 h=300>
<pic src="pics/sci1.png" sx=450 sy=300></pic>
<words x=250 y=20 w=200>
...nor one thats too hard.
</words>
</panel>
<panel w=350 h=350>
<pic src="pics/sci1.png" sx=950 sy=0></pic>
<words x=10 y=10 w=300>
The sames true of training your brain.
You need <b>desirable difficulty</b>: the sweet spot of just-hard-enough.
</words>
</panel>
<panel w=450 h=400>
<pic src="pics/sci1.png" sx=0 sy=400></pic>
<words x=10 y=10 w=360>
Therefore: to best learn something, you need to recall it...
</words>
<words x=60 y=330 w=350>
...<i>just as youre about to forget it.</i>
</words>
</panel>
<panel w=600 h=120>
<words w=600 x=-15 no-bg>
Same simulation as before, but now it shows the <span style="background:#ffe866">sweet spot</span>
where youve forgotten <i>just a little bit.</i>
<br>
<b>Change the timing of the recall. What happens now?</b>
</words>
</panel>
<panel w=600 h=400>
<sim x=0 y=0 w=600 h=400 src="sims/ebbinghaus?mode=2"></sim>
</panel>
<!-- Part IV: Bigger and Bigger spaces -->
<panel w=600 h=90>
<words w=600 x=-15 no-bg>
See? If you time a <i>single</i> recall so that it's in the sweet spot,
you can slow down the decay!
Now, what about <i>multiple</i> recalls?
</words>
</panel>
<panel w=500 h=450>
<pic src="pics/sci2.png" sx=0 sy=0></pic>
<words x=10 y=10 w=430>
Lets say youre
<span style="text-decoration:line-through;">lazy</span>
time-efficient, so youre only doing 4 recall sessions.
</words>
<words x=30 y=350 w=430>
Question:
<i>whats the best way to spread out your recalls?</i>
</words>
</panel>
<panel w=500 h=350>
<pic src="pics/sci2.png" sx=500 sy=0></pic>
<words x=10 y=10 w=190>
Should you have evenly spaced gaps?
Gaps of increasing length?
Gaps of decreasing length?
Or make it unpredictable, to keep you on your toes?
</words>
</panel>
<panel w=400 h=90>
<words h=90>
<b>Give it your best guess</b>,
then when youre ready, <b>flip the card over &darr;</b>
</words>
</panel>
<panel w=600 h=300 bg="#e0e0e0">
<sim x=80 y=0 w=440 h=300 src="sims/singlecard?card=guessgap"></sim>
</panel>
<panel fadeInOn="flip_guessgap" w=600 h=120>
<words w=600 x=-15 y=0 no-bg>
Which is very counter-intuitive!
You can prove to yourself this is true, by playing with the sim below.
<b>
Get all recalls into the <span style="background:#ffe866">sweet spot</span>.
What spacing do you get?
</b>
</words>
</panel>
<panel w=600 h=470>
<sim x=0 y=0 w=600 h=470 src="sims/ebbinghaus?mode=3"></sim>
</panel>
<!-- Part V: Sandbox -->
<panel w=600 h=120>
<words w=600 x=-15 no-bg>
(To prove this isn't a fluke,
heres a sim where you can change
the initial memory decay &amp; sweet spot.
Note how, in all but the extreme cases,
the best schedule is still “increasing gaps”!)
</words>
</panel>
<panel w=600 h=520>
<sim x=0 y=0 w=600 h=520 src="sims/ebbinghaus?mode=4"></sim>
</panel>
<!-- Part VI: And now, in practice... -->
<panel w=350 h=500>
<pic src="pics/sci2.png" sx=0 sy=450></pic>
<words x=10 y=10 w=300>
Why <i>must</i> the gaps increase?
Because: each time you do a recall at the sweet spot of forgetting,
the memorys decay slows down...
</words>
<words x=10 y=400 w=300>
...meaning itll take <i>longer</i>
to hit the sweet spot next time!
</words>
</panel>
<panel w=500 h=500>
<pic src="pics/sci2.png" sx=350 sy=450></pic>
<words x=10 y=10 w=400>
But you know whats sweeter?
This also means if you time your recalls just right...
</words>
<words x=60 y=400 w=400>
...you can easily keep <i>any number</i> of things in your long-term memory,
<i>FOREVER.</i>
</words>
</panel>
<panel w=250 h=250>
<pic src="pics/sci2.png" sx=850 sy=450></pic>
</panel>
<panel w=600 h=90>
<words w=600 x=-15 no-bg>
And speaking of doing active recall in order to learn,
let's do some active recall on what we just learnt:
</words>
</panel>
<panel w=600 h=400 bg="#e0e0e0">
<sim x=0 y=0 w=600 h=400 src="sims/multicard/?cards=sci_a,sci_b,sci_c"></sim>
</panel>
<panel w=400 h=400>
<pic src="pics/sci2.png" sx=0 sy=950></pic>
<words x=50 y=20 w=300 bg=none>
Anyway, this all sounds great,
but finding the optimal schedule must be impossible, right?
</words>
</panel>
<panel w=400 h=400>
<pic src="pics/sci2.png" sx=400 sy=950></pic>
<words x=50 y=30 w=300 bg=none>
<i>Au contraire!</i>
Its so simple, you can even create your own automatic scheduler...
</words>
</panel>
<panel w=400 h=400>
<pic src="pics/sci2.png" sx=800 sy=950></pic>
<words x=30 y=30 w=200 bg=none>
...using a <i>shoebox.</i>
</words>
</panel>
<panel w=600 h=500>
<words w=600 x=-15 no-bg>
<b>[END OF PROTOTYPE]</b>
<br><br>
Sorry for the cliffhanger!
The rest of this comic would show you how to make a <b>Leitner Box</b>,
tell you about other digital <b>spaced repetition systems</b> like <b>Anki</b>,
and finally, help you get started using spaced repetition <i>today!</i>
<br><br>
(And every once in a while, it'll use flashcards to get you
to actively recall what you just learnt. I'll use spaced repetition
to teach you <i>about</i> spaced repetition!)
<br><br>
Anyway, please let me know your <i>honest</i> feedback so far!
Early feedback helps me a lot. Many thanks in advance!
<br><br>
&lt;3,
<br>~ Nicky
</words>
</panel>
</div>
<!-- SIMULATION LABELS -->
<div id="labels">
<!-- Ebbinghaus -->
<span id="ebbinghaus_y_axis">
memory &rarr;
</span>
<span id="ebbinghaus_x_axis">
time &rarr;
</span>
<span id="ebbinghaus_decay">
decay:
</span>
<span id="ebbinghaus_forgetting">
sweet spot:
</span>
<span id="ebbinghaus_recalls">
timing of recall(s):
</span>
<span id="ebbinghaus_auto">
auto-optimize!
</span>
<!-- Flashcards -->
<span id="flashcard_guessgap_front">
<div class="fcard_center" style="height:2.5em">
the best way to space out your recalls is...
</div>
</span>
<span id="flashcard_guessgap_back">
<div class="fcard_bg" src="pics/fcards0.png" sx=0 sy=0></div>
<div class="fcard_center" style="height:2.5em">
...with <i>increasing</i> gaps!
</div>
</span>
<!-- Flashcards -->
<span id="flashcard_sci_a_front">
<div class="fcard_center" style="height:2.5em">
The discoverer of the Forgetting Curve was...
</div>
</span>
<span id="flashcard_sci_a_back">
<div class="fcard_bg" src="pics/fcards0.png" sx=400 sy=0></div>
<div style="position: absolute; width: 250px; top: 60px; right: 0; line-height: 1.1em;">
Hermann Ebbinghaus
</div>
</span>
<span id="flashcard_sci_b_front">
<div class="fcard_center" style="height:3.4em">
The Forgetting Curve (<i>without</i> any recalls) looks like...
</div>
</span>
<span id="flashcard_sci_b_back">
<div class="fcard_bg" src="pics/fcards0.png" sx=0 sy=240></div>
<div style="position: absolute; width: 280px; top: 70px; right: 20px; font-size:20px; line-height: 1.1em;">
(note: it decays quickly, then slowly "exponential decay")
</div>
</span>
<span id="flashcard_sci_c_front">
<div class="fcard_center" style="height:3.4em">
The Forgetting Curve (<i>with</i> optimally-spaced recalls) looks like...
</div>
</span>
<span id="flashcard_sci_c_back">
<div class="fcard_bg" src="pics/fcards0.png" sx=400 sy=240></div>
<div style="position: absolute; width: 360px; top: 120px; left: 20px; font-size:20px; line-height: 1.1em;">
(note: the gaps between recalls <i>increase</i> in length)
</div>
</span>
<!-- Multi Card Labels -->
<span id="multicard_q">
try to recall &uarr;
then flip ↻
</span>
<span id="multicard_cards_left">
(cards left: [N])
</span>
<span id="multicard_a">
did you remember this?
</span>
<span id="multicard_no">
nah, try again
</span>
<span id="multicard_yes">
yup, onwards!
</span>
<span id="multicard_done">
done for now! keep scrolling
<br>
&darr;
</span>
</div>
</body>
</html>
<script src="js/minpubsub.src.js"></script>
<script src="js/comic.js"></script>

92
js/comic.js Normal file
View File

@ -0,0 +1,92 @@
// The poor man's jQuery
function $(query){
return document.querySelector(query);
}
function $all(query){
return [].slice.call(document.querySelectorAll(query));
}
window.onload = function(){
var panels = $all("panel");
var pics = $all("pic");
var sims = $all("sim");
var words = $all("words");
// Adjust positions & dimensions of all the things
var boxes = panels.concat(pics).concat(words).concat(sims);
boxes.forEach(function(b){
var s = b.style;
var val;
if(val = b.getAttribute("x")) s.left = val+"px";
if(val = b.getAttribute("y")) s.top = val+"px";
if(val = b.getAttribute("w")) s.width = val+"px";
if(val = b.getAttribute("h")) s.height = val+"px";
});
// Pics have image (and maybe crop it?)
pics.forEach(function(p){
var s = p.style;
var val;
if(val = p.getAttribute("src")){
s.backgroundImage = "url("+val+")";
var x = p.getAttribute("sx") || 0;
var y = p.getAttribute("sy") || 0;
s.backgroundPosition = (-x)+"px "+(-y)+"px";
var w = p.getBoundingClientRect().width;
s.backgroundSize = Math.round((3000/w)*50)+"%";
}
});
// Sims have iframes in them. (Pass in the labels!)
sims.forEach(function(sim){
// Create & append iframe
var iframe = document.createElement("iframe");
iframe.src = sim.getAttribute("src");
iframe.scrolling = "no";
sim.appendChild(iframe);
});
// Words... no bg? And, fontsize?
words.forEach(function(word){
var s = word.style;
var val;
if(val = word.getAttribute("bg")) s.background = val;
if(val = word.getAttribute("fontsize")) s.fontSize = s.lineHeight = val+"px";
});
// Panels... Any MESSAGES?
panels.forEach(function(panel){
var msg;
// Fade in!
if(msg = panel.getAttribute("fadeInOn")){
subscribe(msg, function(){
panel.style.opacity = 1;
});
}
// BG?
var s = panel.style;
var val;
if(val = panel.getAttribute("bg")) s.background = val;
});
};
window.getLabel = function(name){
return $("#"+name).innerHTML;
}
window.broadcastMessage = function(message){
publish(message);
};

96
js/minpubsub.src.js Normal file
View File

@ -0,0 +1,96 @@
/*!
* MinPubSub
* Copyright(c) 2011 Daniel Lamb <daniellmb.com>
* MIT Licensed
*/
window.c_ = {}; // NICKY - UNIT TESTING
(function (context) {
var MinPubSub = {};
// the topic/subscription hash
var cache = context.c_ || {}; //check for 'c_' cache for unit testing
MinPubSub.publish = function ( /* String */ topic, /* Array? */ args) {
// summary:
// Publish some data on a named topic.
// topic: String
// The channel to publish on
// args: Array?
// The data to publish. Each array item is converted into an ordered
// arguments on the subscribed functions.
//
// example:
// Publish stuff on '/some/topic'. Anything subscribed will be called
// with a function signature like: function(a,b,c){ ... }
//
// publish('/some/topic', ['a','b','c']);
var subs = cache[topic],
len = subs ? subs.length : 0;
//can change loop or reverse array if the order matters
while (len--) {
subs[len].apply(context, args || []);
}
};
MinPubSub.subscribe = function ( /* String */ topic, /* Function */ callback) {
// summary:
// Register a callback on a named topic.
// topic: String
// The channel to subscribe to
// callback: Function
// The handler event. Anytime something is publish'ed on a
// subscribed channel, the callback will be called with the
// published array as ordered arguments.
//
// returns: Array
// A handle which can be used to unsubscribe this particular subscription.
//
// example:
// subscribe('/some/topic', function(a, b, c){ /* handle data */ });
if (!cache[topic]) {
cache[topic] = [];
}
cache[topic].push(callback);
return [topic, callback]; // Array
};
MinPubSub.unsubscribe = function ( /* Array */ handle, /* Function? */ callback) {
// summary:
// Disconnect a subscribed function for a topic.
// handle: Array
// The return value from a subscribe call.
// example:
// var handle = subscribe('/some/topic', function(){});
// unsubscribe(handle);
var subs = cache[callback ? handle : handle[0]],
callback = callback || handle[1],
len = subs ? subs.length : 0;
while (len--) {
if (subs[len] === callback) {
subs.splice(len, 1);
}
}
};
// UMD definition to allow for CommonJS, AMD and legacy window
if (typeof module === 'object' && module.exports) {
// CommonJS, just export
module.exports = exports = MinPubSub;
} else if (typeof define === 'function' && define.amd) {
// AMD support
define(function () {
return MinPubSub;
});
} else if (typeof context === 'object') {
// If no AMD and we are in the browser, attach to window
context.publish = MinPubSub.publish;
context.subscribe = MinPubSub.subscribe;
context.unsubscribe = MinPubSub.unsubscribe;
}
})(this.window);

BIN
pics/cardboard.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
pics/fcards0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
pics/sci0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 KiB

BIN
pics/sci1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

BIN
pics/sci2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

View File

@ -0,0 +1,67 @@
/* FONT FACE */
@font-face {
font-family: "PatrickHand";
font-style: normal;
font-weight: 400;
src: url(../../css/PatrickHand-Regular.ttf) format('truetype');
}
body{
margin: 0;
font-family: "PatrickHand", Helvetica, Arial;
color: #000;
padding: 0 10px;
background: #fff;
letter-spacing: 1px;
}
#content{
background: #fff;
width: 600px;
overflow: hidden;
position: absolute;
top: 0;
left: 0;
}
#container{
width: 500px;
margin: 30px auto;
}
#graph{
border-left: 2px solid black;
border-bottom: 2px solid black;
}
#y_axis, #x_axis{
font-size: 18px;
position: absolute;
color: #000;
}
#y_axis{
position: absolute;
transform: rotate(-90deg);
left: -67px;
top: 114px;
text-align: right;
width: 200px;
}
#x_axis{
width: 200px;
left: 358px;
top: 282px;
text-align: right;
}
#ui{
margin-top: 25px;
font-size: 25px;
line-height: 1em;
}
input[fullw]{
width:100%;
}
#default_labels{
display:none;
}

View File

@ -0,0 +1,398 @@
window.MODE = -1;
window.onload = function(){
// Get Mode
window.MODE = parseInt( _getQueryVariable("mode") );
// Init labels
$("#y_axis").innerHTML = _getLabel("ebbinghaus_y_axis");
$("#x_axis").innerHTML = _getLabel("ebbinghaus_x_axis");
// Initialize all the things!
switch(MODE){
// Just decay
case 0:
sim_params.push(_sliders.d);
break;
// ONE retrieval
case 1:
recall_params.push(_sliders.r1);
break;
// ONE retrieval, with optimal learning
case 2:
PARAMS.optimal = 0.75;
recall_params.push(_sliders.r1);
break;
// MULTI retrievals, with optimal learning
case 3:
PARAMS.optimal = 0.75;
recall_params.push(_sliders.r1);
recall_params.push(_sliders.r2);
recall_params.push(_sliders.r3);
recall_params.push(_sliders.r4);
break;
// FULL SANDBOX
case 4:
sim_params.push(_sliders.d);
sim_params.push(_sliders.o);
recall_params.push(_sliders.r1);
recall_params.push(_sliders.r2);
recall_params.push(_sliders.r3);
recall_params.push(_sliders.r4);
break;
}
sim_params.concat(recall_params).forEach(_createParamSlider);
// Add UI
switch(MODE){
// Just decay
case 0:
_appendSpan("ebbinghaus_decay");
_appendSlider("init_decay");
break;
// ONE retrieval
case 1:
_appendSpan("ebbinghaus_recalls");
_appendSlider("recall_1");
break;
// ONE retrieval, with optimal learning
case 2:
_appendSpan("ebbinghaus_recalls");
_appendSlider("recall_1");
break;
// MULTI retrievals, with optimal learning
case 3:
_appendSpan("ebbinghaus_recalls");
_appendSlider("recall_1");
_appendSlider("recall_2");
_appendSlider("recall_3");
_appendSlider("recall_4");
break;
// FULL SANDBOX
case 4:
_appendSpan("ebbinghaus_decay");
_appendSlider("init_decay");
_appendSpan("ebbinghaus_forgetting");
_appendSlider("optimal");
_appendBr();
_appendBr();
_appendSpan("ebbinghaus_recalls");
_appendButton("ebbinghaus_auto",_AUTO_OPTIMIZE);
_appendSlider("recall_1");
_appendSlider("recall_2");
_appendSlider("recall_3");
_appendSlider("recall_4");
break;
}
// Update
window.PARAMS_CHANGED = true;
update();
};
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
// The most fudge-y function in existence
var _AUTO_OPTIMIZE = function(){
// When t hits the sweet spot (k)...
// k = A*e^(-Bt)
// Therefore:
// t = (ln(A) - ln(k))/B
// Dunno what A & B are. Fudge it.
var A = 1; // coz, at 0, it's 1. Duh.
var k = PARAMS.optimal;
var B = 102 * PARAMS.init_decay * MAGIC_CONSTANT; // FUDGE IT.
var timing = (Math.log(A) - Math.log(k))/B;
// Set first one!
_sliderUI.recall_1.value = timing;
_sliderUI.recall_1.oninput();
// Multiply by fudged values for the rest.
timing *= 2.92;
_sliderUI.recall_2.value = timing;
_sliderUI.recall_2.oninput();
timing *= 2.23;
_sliderUI.recall_3.value = timing;
_sliderUI.recall_3.oninput();
timing *= 2.01;
_sliderUI.recall_4.value = timing;
_sliderUI.recall_4.oninput();
};
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
var canvas = document.getElementById("graph");
var ctx = canvas.getContext('2d');
// Params & their sliders
var PARAMS = {};
var sim_params = [];
var recall_params = [];
var _sliders = {
d: {name:"init_decay", min:0, max:1, step:0.01, value:0.5},
o: {name:"optimal", min:0, max:1, step:0.01, value:0.75},
r1: {name:"recall_1", min:0, max:10, step:0.01, value:2.0, fullw:true},
r2: {name:"recall_2", min:0, max:10, step:0.01, value:4.0, fullw:true},
r3: {name:"recall_3", min:0, max:10, step:0.01, value:6.0, fullw:true},
r4: {name:"recall_4", min:0, max:10, step:0.01, value:8.0, fullw:true},
//r5: {name:"recall_5", min:0, max:10, step:0.01, value:2.5, fullw:true}
};
var _sliderUI = {};
var _appendBr = function(){
$("#ui").appendChild(document.createElement("br"));
};
var _appendSpan = function(name){
var label = _getLabel(name);
var span = document.createElement("span");
span.innerHTML = label;
$("#ui").appendChild(span);
};
var _appendSlider = function(name){
$("#ui").appendChild(_sliderUI[name]);
}
var _appendButton = function(name, onclick){
var label = _getLabel(name);
var button = document.createElement("button");
button.innerHTML = label;
button.onclick = onclick;
$("#ui").appendChild(button);
};
window.PARAMS_CHANGED = false;
var _createParamSlider = function(config){
// Make DOM
var slider = document.createElement("input");
slider.type = "range";
slider.min = config.min;
slider.max = config.max;
slider.step = config.step;
slider.value = config.value;
if(config.fullw) slider.setAttribute("fullw","yes");
// Gimme DOM
_sliderUI[config.name] = slider;
// Sync it
var _onSliderUpdate = function(){
PARAMS[config.name] = parseFloat(slider.value);
PARAMS_CHANGED = true;
};
slider.oninput = _onSliderUpdate;
_onSliderUpdate();
};
// Update
var MAGIC_CONSTANT = 0.013815; // Through pure brute force, don't care.
var ERROR = 0.00001;
var OPTIMAL_RANGE = 0.10; //0.05;
function update(){
// Don't re-draw unnecessarily!
if(window.PARAMS_CHANGED){
window.PARAMS_CHANGED = false;
// Clear & Retina
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.save();
ctx.scale(2,2);
// Memory strength over 1000 iterations...
var memory = 1; // full strength at first!
var decay = PARAMS.init_decay!==undefined ? PARAMS.init_decay : 0.5; // init decay...
var optimal = PARAMS.optimal!==undefined ? PARAMS.optimal : 999;
var curves = [
{ start:0, memory:1, decay:decay, line:[], cut:-1 } // original line
];
//debugger;
var ALREADY_USED_THESE_CUTS = {};
// For each timestep, and all curves...
for(var t=0; t<=10; t+=0.01){
for(var c=0; c<curves.length; c++){
var curve = curves[c];
// Record!
curve.line.push({
t: t,
m: curve.memory
});
// Decay a bit...
curve.memory -= curve.memory * curve.decay * MAGIC_CONSTANT;
// If not already cut...
if(curve.cut<0){
// If this is in a recall session, create ONE NEW CURVE
// Find THE FIRST AND ONLY ONE cut.
for(var cutIndex=0; cutIndex<recall_params.length; cutIndex++){
var config = recall_params[cutIndex];
if(ALREADY_USED_THESE_CUTS[config.name]) continue; // DON'T RE-USE CUT
var recall_t = PARAMS[config.name];
if(Math.abs(t-recall_t)<ERROR){ // floating point
// If memory is near optimal range, HALVE decay.
if(Math.abs(curve.memory-optimal)<OPTIMAL_RANGE){
//decay *= 0.5;
// Continuous?
var distanceFromOptimal = Math.abs(curve.memory-optimal)/OPTIMAL_RANGE;
var decayMultiplier = (0.5+distanceFromOptimal*0.5); // (0,1) => (0.5,1.0)
decay *= decayMultiplier;
}else{
if(MODE===1){
decay *= 0.9; // helps a little bit ANYWAY?
}
}
// Cut THIS curve.
curve.cut = t;
// Create new curve!
curves.push({
start: t,
memory: 1, // boost memory to top!
decay: decay,
line: [],
cut: -1
});
// WE USED THIS CUT
ALREADY_USED_THESE_CUTS[config.name] = true;
// And, use NO MORE CUTS
break;
}
};
}
}
}
// DRAW.
// Days
/*ctx.strokeStyle = "#ddd";
ctx.lineWidth = 1;
ctx.beginPath();
for(var t=0; t<10; t++){
var from = _project(t,0);
var to = _project(t,1);
ctx.moveTo(from.x,from.y);
ctx.lineTo(to.x,to.y);
}
ctx.stroke();*/
// Ideal Forgetting
//ctx.fillStyle = "#FFD700";
var tl = _project(0,optimal+OPTIMAL_RANGE);
var br = _project(10,optimal-OPTIMAL_RANGE);
var gradient = ctx.createLinearGradient(0, tl.y, 0, br.y);
gradient.addColorStop(0.0, "hsl(51, 100%, 50%, 0)");
gradient.addColorStop(0.5, "hsl(51, 100%, 50%, 0.5)");
gradient.addColorStop(1.0, "hsl(51, 100%, 50%, 0)");
ctx.fillStyle = gradient;
ctx.fillRect(tl.x, tl.y, br.x-tl.x, br.y-tl.y);
// DRAW THE POTENTIAL CURVES
ctx.lineJoin = ctx.lineCap = "round";
ctx.lineWidth = 1;
ctx.strokeStyle = "rgba(0,0,0,0.2)";
for(var c=0; c<curves.length; c++){
var curve = curves[c];
if(curve.cut>=0){ // only draw if line HAS been cut
var imCut = false;
for(var i=0; i<curve.line.length; i++){
var point = curve.line[i];
p = _project(point.t, point.m);
if(point.t>=curve.cut && !imCut){ // CUT. Start drawing!
ctx.beginPath();
ctx.moveTo(p.x,p.y);
imCut = true;
}else{
ctx.lineTo(p.x,p.y);
}
}
ctx.stroke();
}
}
// DRAW THE MAIN THICK CURVES
ctx.lineWidth = 5;
// For each curve, draw until cut.
for(var c=0; c<curves.length; c++){
var curve = curves[c];
// Redness for decay
var d = Math.sqrt(Math.sqrt(curve.decay));
var saturation = Math.round(d*100); // (0,1) => (0,100)
var lightness = Math.round(d*70); // (0,1) => (0,60)
ctx.strokeStyle = "hsl(0,"+saturation+"%,"+lightness+"%)";
var imCut = false;
for(var i=0; i<curve.line.length; i++){
var point = curve.line[i];
if(curve.cut<0 || point.t<=curve.cut){ // CUT
p = _project(point.t, point.m);
if(i==0){
ctx.beginPath();
ctx.moveTo(p.x,p.y);
}else{
ctx.lineTo(p.x,p.y);
}
}else if(!imCut){
p = _project(point.t, 1);
ctx.lineTo(p.x,p.y);
imCut = true;
}
}
ctx.stroke();
}
// And, again...
ctx.restore();
}
requestAnimationFrame(update);
}
var _project = function(x,y){
return {
x: (x/10.05) * (canvas.width/2), // retina (with lil' buffer)
y: (1-(y*0.98)) * (canvas.height/2) // retina (with lil' buffer)
};
};

View File

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>The Forgetting Curve</title>
<link rel="stylesheet" type="text/css" href="ebbinghaus.css"/>
</head>
<body>
<div id="content">
<div id="container">
<canvas id="graph" width="1000" height="500" style="width:500px; height:250px;"></canvas>
<div id="y_axis"></div>
<div id="x_axis"></div>
<div id="ui"></div>
</div>
</div>
<div id="default_labels">
<span id="ebbinghaus_y_axis">
*memory &rarr;
</span>
<span id="ebbinghaus_x_axis">
*time &rarr;
</span>
<span id="ebbinghaus_decay">
*decay:
</span>
<span id="ebbinghaus_forgetting">
*optimal:
</span>
<span id="ebbinghaus_recalls">
*recalls:
</span>
<span id="ebbinghaus_auto">
*auto
</span>
</div>
</body>
</html>
<script src="../helpers.js"></script>
<script src="ebbinghaus.js"></script>

16
sims/fcard.css Normal file
View File

@ -0,0 +1,16 @@
.fcard_center{
max-width: 370px;
position: absolute;
margin: auto;
top: 0;
right: 0;
left: 0;
bottom: 0;
line-height: 1.1em;
}
.fcard_bg{
position:absolute;
width:100%;
height:100%;
background:#ff4040;
}

40
sims/helpers.js Normal file
View File

@ -0,0 +1,40 @@
// The poor man's jQuery
function $(query){
return document.querySelector(query);
}
function $all(query){
return [].slice.call(document.querySelectorAll(query));
}
function _getQueryVariable(name){
var query = window.location.search.substring(1);
var vars = query.split("&");
for(var i=0;i<vars.length;i++){
var pair = vars[i].split("=");
if(pair[0]==name) return pair[1];
}
return(false);
}
function _getLabel(name){
if(window!=window.top){
return window.top.getLabel(name);
}else{
return $("#"+name).innerHTML;
}
}
function _modifyFlashCard(fcard){
var bg = fcard.querySelector(".fcard_bg");
if(bg){
var src = bg.getAttribute("src");
bg.style.backgroundImage = "url(../../"+src+")";
var x = bg.getAttribute("sx") || 0;
var y = bg.getAttribute("sy") || 0;
bg.style.backgroundPosition = (-x)+"px "+(-y)+"px";
var w = 400;//p.getBoundingClientRect().width;
bg.style.backgroundSize = Math.round((1600/w)*50)+"%";
}
}

52
sims/leitner/index.html Normal file
View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>The Leitner Box</title>
<link rel="stylesheet" type="text/css" href="leitner.css"/>
</head>
<body>
<div id="content">
<div id="container">
<canvas id="sim" width="1000" height="800" style="width:500px; height:400px;"></canvas>
<button id="next_step">next STEP</button>
<button id="next_day">next DAY</button>
<button id="next_week">next WEEK</button>
<button id="next_month">next MONTH</button>
<hr>
<span id="label_day"></span>
<br>
<span id="label_step"></span>
<br>
<span id="label_stats"></span>
</div>
</div>
<div id="default_labels">
<span id="leitner_day">
Day [N]
</span>
<span id="leitner_step_to_review">
to review: Level
</span>
<span id="leitner_step_reviewing">
review Level [N]
</span>
<span id="leitner_step_new">
add [N] new cards
</span>
<span id="leitner_step_stats">
total: [N] cards!
</span>
<span id="leitner_step_stats_2">
([N] in very-long-term memory)
</span>
</div>
</body>
</html>
<script src="../helpers.js"></script>
<script src="leitner.js"></script>

33
sims/leitner/leitner.css Normal file
View File

@ -0,0 +1,33 @@
/* FONT FACE */
@font-face {
font-family: "PatrickHand";
font-style: normal;
font-weight: 400;
src: url(../../css/PatrickHand-Regular.ttf) format('truetype');
}
body{
margin: 0;
font-family: "PatrickHand", Helvetica, Arial;
color: #000;
padding: 0 10px;
background: #eee;
letter-spacing: 1px;
}
#content{
background: #fff;
width: 600px;
overflow: hidden;
position: absolute;
top: 0;
left: 0;
}
#container{
width: 500px;
margin: 0px auto;
}
#default_labels{
display:none;
}

435
sims/leitner/leitner.js Normal file
View File

@ -0,0 +1,435 @@
/*******************************
// Step 1: a bunch of numbered, colored boxes (array) @done
// Step 2: a calendar @done
// Step 3: "cards" go up/down on STEP/day @done
// Step 4: ...with 5% failing @done
Next steps:
- Per DAY, now. @done
- labels for steps @done
- labels for day @done
Animation
- cards number @done
- box bounce @done
- multiple times... @done
- arrows for movement of cards
- + for adding cards
// Arrowheads @done
// TOTAL CARDS say...
CALCULATOR... nah.
********************************/
window.onload = function(){
BOXES[0] += NEW_CARDS;
_newStep();
update();
};
//////////////////////////////////////////
//////////////////////////////////////////
/***************
Each day...
a. Review levels from top to bottom
(if succeed, next level)
(if fail, back to Level 1)
b. All cards in Level 1 go to Level 2
c. Add new cards to Level 1
****************/
var NEW_CARDS = 10;
var _STAGE = 0;
// 0 - new day
// 1 - reviewing
// 2 - adding
function _updateLabels(){
// Step
var html;
switch(_STAGE){
case 2:
html = _getLabel("leitner_step_new").replace("[N]",NEW_CARDS);
break;
case 0:
html = _getLabel("leitner_step_to_review") + QUEUE.toString();
break;
case 1:
html = _getLabel("leitner_step_reviewing").replace("[N]",CURRENTLY_REVIEWED+1);
break;
}
$("#label_step").innerHTML = html;
// Day
$("#label_day").innerHTML = _getLabel("leitner_day").replace("[N]",DAY);
// Stats
var sum = 0;
var vlt = 0;
BOXES.forEach(function(n, i){
sum += n;
if(i>=7) vlt += n; // Level 6 and up
});
html = _getLabel("leitner_step_stats").replace("[N]", sum);
if(vlt>0){
html += _getLabel("leitner_step_stats_2").replace("[N]", vlt);
}
$("#label_stats").innerHTML = html;
}
$("#next_step").onclick = function(){
_newStep();
};
function _newStep(skipLabels){
// If queue's empty, start a new day!
if(QUEUE.length==0){
if(_STAGE==1){
_STAGE = 2; // add new cards
BOXES[0] += NEW_CARDS;
// Annotate
_clearAnnotations();
_annotateAdd(NEW_CARDS);
}else{
_newDay();
_STAGE = 0; // new day!
_clearAnnotations();
}
CURRENTLY_REVIEWED = -1;
}else{
// review
_STAGE = 1;
// But if not, pop off the queue.
var reviewedLevel = QUEUE.shift();
var rIndex = reviewedLevel-1;
CURRENTLY_REVIEWED = rIndex;
// Is this Level 1?
var total, passed, failed;
total = BOXES[rIndex];
if(reviewedLevel==1){
// ALL goes to Level 2
passed = total;
failed = 0;
}else{
// 95% goes to next level
// the rest goes to ONE
passed = Math.round(total*0.95);
failed = total-passed;
}
BOXES[rIndex+1] += passed;
BOXES[0] += failed;
BOXES[rIndex] = 0;
// Annotations
_clearAnnotations();
_annotatePass(rIndex, passed);
_annotateFail(rIndex, failed);
}
// Label
if(!skipLabels) _updateLabels();
window.REDRAW = 60;
};
$("#next_day").onclick = function(){
_newDay();
_updateLabels();
};
function _newDay(skipLabels){
// Any previous stuff in queue? Finish it!
if(QUEUE.length>0){
while(QUEUE.length>0 || _STAGE==1){
_newStep(true); // until queue's done AND past "adding new cards"
}
}
// Increase day, add stuff to queue
DAY++;
var d = (DAY-1)%CALENDAR.length; // -1 for offset, also loop around.
QUEUE = QUEUE.concat(CALENDAR[d]); // to clone it.
// Redraw
window.REDRAW = 60;
// Label
_STAGE = 0; // new day!
_clearAnnotations();
if(!skipLabels) _updateLabels();
};
function _reviewMultipleDays(days){
for(var i=0;i<days;i++) _newDay();
_updateLabels()
}
$("#next_week").onclick = function(){
_reviewMultipleDays(7);
};
$("#next_month").onclick = function(){
_reviewMultipleDays(30);
};
//////////////////////////////////////////
//////////////////////////////////////////
var canvas = document.getElementById("sim");
var ctx = canvas.getContext('2d');
var COLORS = [
"#ee4035", // red
"#f37736", // orange
"#ffdb13", // yellow
"#7bc043", // green
"#0392cf", // blue
"#673888", // indigo-ish
"#ef4f91", // violet-ish
"#eeeeee" // white. VALHALLA.
];
var BOXES = [
0,0,0,0,
0,0,0,0,
];
var ANIM_CARDS = BOXES.concat(); // clone
var ANIM_BOXES = BOXES.concat(); // clone
var CURRENTLY_REVIEWED = -1;
var ANIM_EASE = 0.8;
var DAY = 0;
var QUEUE = [];
var CALENDAR = [
[2,1], [3,1], [2,1], [4,1], [2,1], [3,1], [2,1], [1],
[2,1], [3,1], [2,1], [5,1], [4,2,1], [3,1], [2,1], [1],
[2,1], [3,1], [2,1], [4,1], [2,1], [3,1], [2,1], [6,1],
[2,1], [3,1], [2,1], [5,1], [4,2,1], [3,1], [2,1], [1],
[2,1], [3,1], [2,1], [4,1], [2,1], [3,1], [2,1], [1],
[2,1], [3,1], [2,1], [5,1], [4,2,1], [3,1], [2,1], [1],
[2,1], [3,1], [2,1], [4,1], [2,1], [3,1], [2,1], [7,1],
[2,1], [3,1], [6,2,1],[5,1], [4,2,1], [3,1], [2,1], [1],
];
function _calculateCardLabelPosition(boxN){
var x = 0;
var y = 0;
x += boxN*62.5;
y += canvas.height/2 - 60;
y += -ANIM_BOXES[boxN];
y += -ANIM_CARDS[boxN]/3;
x += 60/2;
y -= 13;
if(y<50) y=50;
return {
x:x,
y:y
};
}
var annPass = null;
var annFail = null;
var annAdd = null;
function _clearAnnotations(){
annPass = null;
annFail = null;
annAdd = null;
};
function _annotatePass(from, N){
if(N>0) annPass = {from:from, N:N};
}
function _annotateFail(from, N){
if(N>0) annFail = {from:from, N:N};
}
function _annotateAdd(N){
annAdd = {N:N};
}
window.REDRAW = 0;
function update(){
// Don't re-draw unnecessarily!
if(window.REDRAW>0){
window.REDRAW -= 1;
// Clear & Retina
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.save();
ctx.scale(2,2);
// Draw boxes, 1 to 7
for(var i=0;i<BOXES.length;i++){
var w = 60;
var h = 60;
// ANIMATED!
ANIM_CARDS[i] = ANIM_CARDS[i]*ANIM_EASE + BOXES[i]*(1-ANIM_EASE);
// Card labels...
ctx.fillStyle = "#bbb";
ctx.font = "20px PatrickHand";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
var pos = _calculateCardLabelPosition(i);
ctx.fillText(Math.round(ANIM_CARDS[i]), pos.x, pos.y);
// Transform...
ctx.save();
ctx.translate(i*62.5, canvas.height/2-h);
// Bounce! ANIMATED!
var elevation = (CURRENTLY_REVIEWED==i) ? 10 : 0;
ANIM_BOXES[i] = ANIM_BOXES[i]*ANIM_EASE + elevation*(1-ANIM_EASE);
ctx.translate(0, -ANIM_BOXES[i]);
// The cards inside me
var cardsHeight = ANIM_CARDS[i]/3;
ctx.save();
ctx.translate(0, -cardsHeight);
ctx.fillStyle = "rgba(0,0,0,0.2)";
ctx.fillRect(5, 0, w-10, cardsHeight);
ctx.restore();
// Am I active today?
var activeToday = (QUEUE.indexOf(i+1)>=0); // +1 coz offset
if(CURRENTLY_REVIEWED==i) activeToday=true; // also if CURRENTLY reviewed...
var color = COLORS[i];
// Fill
ctx.fillStyle = activeToday ? color : "#fff";
ctx.fillRect(0, 0, 60, 60);
// Stroke
if(!activeToday){
ctx.strokeStyle = color;
var lw = 2;
ctx.lineWidth = lw;
ctx.beginPath();
ctx.rect(lw/2, lw/2, w-lw, h-lw);
ctx.stroke();
}
// Number
ctx.font = "50px PatrickHand";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = activeToday ? "#fff": color;
ctx.fillText((i+1), w/2, h/2);
ctx.restore();
}
// Draw Annotations!
if(annFail){
_drawArrow(true);
}
if(annPass){
_drawArrow();
}
if(annAdd){
// The number...
ctx.fillStyle = "#000";
ctx.font = "18px PatrickHand";
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
var label = "+" + annAdd.N;
var pos = _calculateCardLabelPosition(0);
ctx.fillText(label, pos.x, pos.y-15);
}
// And, again...
ctx.restore();
}
requestAnimationFrame(update);
}
function _drawArrow(fail){
var ann = fail ? annFail : annPass;
// Points
var pos1 = _calculateCardLabelPosition(ann.from);
var pos2 = _calculateCardLabelPosition(fail ? 0 : ann.from+1);
var xOffset = fail ? -5 : 5;
pos1.x += xOffset;
pos1.y -= 15;
pos2.x -= xOffset;
pos2.y -= 15;
var cp = {
x: (pos1.x+pos2.x)/2,
y: Math.min(pos1.y,pos2.y)-30
};
// Color!
var color = fail ? COLORS[0] : COLORS[3]; // red/green
// Arrow
ctx.beginPath();
ctx.moveTo(pos1.x, pos1.y);
ctx.quadraticCurveTo(cp.x, cp.y, pos2.x, pos2.y);
ctx.strokeStyle = color;
var w = ann.N/10;
if(w<1) w=1;
if(w>7) w=7;
ctx.lineWidth = w;
ctx.stroke();
// ArrowHEAD
ctx.save();
ctx.translate(pos2.x, pos2.y);
var dy = pos2.y - cp.y;
var dx = pos2.x - cp.x;
var rotation = Math.atan2(dy,dx);
ctx.rotate(rotation-Math.PI/2);
ctx.beginPath();
var arrSize = w*1.5;
if(arrSize<5) arrSize=5;
ctx.moveTo(-arrSize,-arrSize);
ctx.lineTo(0,0);
ctx.lineTo(arrSize,-arrSize);
ctx.stroke();
ctx.restore();
// The number...
ctx.fillStyle = color;
ctx.font = "18px PatrickHand";
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
var label = (fail ? "-" : "+") + ann.N;
ctx.fillText(label, cp.x, cp.y+15);
}

104
sims/multicard/index.html Normal file
View File

@ -0,0 +1,104 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>The Flashcard</title>
<link rel="stylesheet" type="text/css" href="../fcard.css"/>
<link rel="stylesheet" type="text/css" href="multicard.css"/>
</head>
<body>
<div id="container">
<!-- Cards! -->
<div id="cards">
<!-- BG -->
<div id="card_bg" class="card">
<div id="card_bg_smiley"></div>
</div>
<!-- Next card is behind -->
<div id="next_card" class="card"></div>
<!-- Current card is on top -->
<div id="current_card">
<div class="scale_on_hover">
<div id="flip-container">
<div class="flipper">
<div id="ccard_front" class="card"></div>
<div id="ccard_back" class="card"></div>
</div>
</div>
</div>
</div>
</div>
<!-- Did you get it right? -->
<div id="info">
<div id="question"></div>
<div id="answer" style="display:none">
<div id="a_label"></div>
<div id="a_no"></div>
<div id="a_yes"></div>
</div>
<div id="done" style="display:none"></div>
</div>
</div>
<!-- Default Labels -->
<div id="default_labels">
<span id="multicard_q">
try to recall &uarr;
then flip ↻
</span>
<span id="multicard_cards_left">
(cards left: [N])
</span>
<span id="multicard_a">
did you remember this?
</span>
<span id="multicard_no">
nah, try again
</span>
<span id="multicard_yes">
yup, onwards!
</span>
<span id="multicard_done">
done for now! keep scrolling
<br>
&darr;
</span>
<!-- Flashcards -->
<span id="flashcard_test_a_front">
A?
</span>
<span id="flashcard_test_a_back">
Apple
</span>
<span id="flashcard_test_b_front">
B?
</span>
<span id="flashcard_test_b_back">
Banana
</span>
<span id="flashcard_test_c_front">
C?
</span>
<span id="flashcard_test_c_back">
COOL BEANS
</span>
</div>
</body>
</html>
<script src="../helpers.js"></script>
<script src="multicard.js"></script>

View File

@ -0,0 +1,160 @@
/* FONT FACE */
@font-face {
font-family: "PatrickHand";
font-style: normal;
font-weight: 400;
src: url(../../css/PatrickHand-Regular.ttf) format('truetype');
}
body{
margin: 0;
font-family: "PatrickHand", Helvetica, Arial;
color: #000;
}
/* Container */
#container{
/*background: #eee;*/
width: 600px;
height: 400px;
overflow: hidden;
position: relative;
}
/* Cards */
#cards{
position: absolute;
left: 100px;
top: 35px;
/* so tl centers the 400x240 cards in 600x400 container */
}
.card{
position: absolute;
width: 390px; /* 5 x 3 */
height: 230px;
border-radius: 20px;
overflow: hidden;
font-size: 40px;
background: #fff;
border: 5px inset rgba(0,0,0,0.15);
text-align: center;
}
#card_bg{
background: #888;
border-color: rgba(0,0,0,0);
}
#card_bg_smiley{
color: rgba(255,255,255,0.5);
font-size: 100px;
text-align: center;
line-height: 230px;
font-size: 200px;
display: none;
}
#next_card{
display: none;
}
#current_card{
position: absolute;
top:0;
left:0;
width: 400px;
height: 240px;
transition: left 0.3s ease-in-out;
position: relative;
left:0;
}
.scale_on_hover{
width: 100%;
height: 100%;
transition: 0.15s;
transform-origin: 200px 120px;
cursor: pointer;
}
.scale_on_hover:hover{
transform: scale(1.03);
}
/*************************/
/***** CURRENT CARD ******/
/*************************/
#flip-container {
width: 100%;
height: 100%;
perspective: 1200px;
}
#flip-container .flipper {
width: 100%;
height: 100%;
transition: 0.5s;
transform-style: preserve-3d;
transform-origin: 200px 120px;
position: absolute;
}
#flip-container[flip=yes] .flipper{
transform: rotateY(180deg);
}
#ccard_front, #ccard_back {
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
#ccard_front {
z-index: 2;
transform: rotateY(0deg);
background: #fff;
}
#ccard_back {
transform: rotateY(180deg);
background: #fff;
}
/* Q & A */
#info{
position: absolute;
width: 100%;
top: 290px;
font-size: 25px;
text-align: center;
line-height: 1.2em;
}
#question{
margin-top: 10px;
}
#question span{
color: #777;
}
#a_label{
margin-bottom: 0.25em;
}
#a_no, #a_yes{
display: inline-block;
width: 140px;
height: 40px;
border-radius: 10px;
color: rgba(0,0,0,0.7);
font-size: 20px;
line-height: 40px;
letter-spacing: 0.5px;
cursor: pointer;
transition: 0.1s;
position: relative;
top:0;
}
#a_no:hover, #a_yes:hover{
top:-2px;
}
#a_no{
background: #ff4040;
}
#a_yes{
background: #40ff40;
}
/* LABELS */
#default_labels{
display:none;
}

222
sims/multicard/multicard.js Normal file
View File

@ -0,0 +1,222 @@
window.CARDS = [];
window.onload = function(){
// Get cards, in order.
var cardnames = _getQueryVariable("cards");
cardnames = cardnames.split(",");
window.CARDS = cardnames.map(function(cardname){
return {
front: _getLabel("flashcard_"+cardname+"_front"),
back: _getLabel("flashcard_"+cardname+"_back")
};
});
// Set up info
setUpInfo();
// Logic for flippable current card
$("#current_card").onclick = function(){
// Flip!
var flipcont = $("#flip-container");
var flip = flipcont.getAttribute("flip");
flipcont.setAttribute("flip", (flip=="yes") ? "no" : "yes");
// Hide Info, then ask "did you get it?"
if(INFO_MODE == "question"){
hideInfo();
setTimeout(showInfoAnswer, 700);
}
};
// Show first card
showCurrentCard();
};
function showCurrentCard(infoTimeout){
// NO MORE CARDS? guess we're DONE.
if(CARDS.length==0){
$("#next_card").style.display = "none";
$("#current_card").style.display = "none";
showInfoDone();
}else{
// Card
var currentCard = CARDS[0];
$("#ccard_front").innerHTML = currentCard.front;
$("#ccard_back").innerHTML = currentCard.back;
_modifyFlashCard($("#ccard_front"));
_modifyFlashCard($("#ccard_back"));
// INSTANT RESET
var flipper = $("#flip-container .flipper");
flipper.style.transition = "0s"; // INSTANT
$("#flip-container").setAttribute("flip","no");
var ccardDOM = $("#current_card");
ccardDOM.style.transition = "0s"; // INSTANT
ccardDOM.style.left = "";
setTimeout(function(){
flipper.style.transition = "";
ccardDOM.style.transition = "";
},PLANCK_TIME);
// Question
infoTimeout = infoTimeout || PLANCK_TIME;
setTimeout(function(){
showInfoQuestion();
},infoTimeout);
}
}
function showNextCard(){
if(CARDS.length>0){
var nextCard = CARDS[0];
$("#next_card").style.display = "block";
$("#next_card").innerHTML = nextCard.front;
}else{
$("#card_bg_smiley").style.display = "block";
}
}
var PLANCK_TIME = 20;
var BUFFER_TIME = PLANCK_TIME*3;
function nextCard(removeCurrent){
hideInfo();
// Remove, or shuffle back?
var currCard = CARDS.shift();
if(!removeCurrent){
CARDS.push(currCard); // shuffle to back.
}
// REMOVE... CARD TO THE RIGHT!
if(removeCurrent){
showNextCard();
var currentCard = $("#current_card");
currentCard.style.left = "500px";
setTimeout(function(){
$("#next_card").style.display = "none";
showCurrentCard();
},300+BUFFER_TIME);
}else{
showNextCard();
var currentCard = $("#current_card");
currentCard.style.left = "-400px";
setTimeout(function(){
// What card is currently showing?
var cardShowing = ($("#flip-container").getAttribute("flip")=="yes") ? "#ccard_back" : "#ccard_front";
var htmlShowing = $(cardShowing).innerHTML;
// Force next card to look like past card, and teleport it out
var ncard = $("#next_card");
ncard.innerHTML = htmlShowing;
ncard.style.left = "-400px";
// Slide next card to where current card should be
setTimeout(function(){
ncard.style.transition = "left 0.3s ease-out";
setTimeout(function(){
ncard.style.left = "0px";
setTimeout(function(){
ncard.style.transition = "";
ncard.style.left = "";
ncard.style.display = "none"; // BYE.
},300+BUFFER_TIME);
},PLANCK_TIME);
},PLANCK_TIME);
// Also, show current card
showCurrentCard(300+BUFFER_TIME);
},300+BUFFER_TIME);
}
}
function setUpInfo(){
// Labels
$("#a_label").innerHTML = _getLabel("multicard_a");
$("#a_no").innerHTML = _getLabel("multicard_no");
$("#a_yes").innerHTML = _getLabel("multicard_yes");
$("#done").innerHTML = _getLabel("multicard_done");
// Clicking "yes" or "no"
$("#a_yes").onclick = function(){
nextCard(true);
};
$("#a_no").onclick = function(){
nextCard(false);
};
}
var INFO_MODE = "question";
function showInfoQuestion(){
$("#info").style.display = "block";
$("#question").style.display = "block";
$("#answer").style.display = "none";
// Show, with "(how many left)"
var html = _getLabel("multicard_q");
html += "<br>";
html += "<span>";
html += _getLabel("multicard_cards_left").replace("[N]",CARDS.length);
html += "</span>";
$("#question").innerHTML = html;
INFO_MODE = "question";
}
function showInfoAnswer(){
$("#info").style.display = "block";
$("#question").style.display = "none";
$("#answer").style.display = "block";
INFO_MODE = "answer";
}
function showInfoDone(){
$("#info").style.display = "block";
$("#question").style.display = "none";
$("#answer").style.display = "none";
$("#done").style.display = "block";
INFO_MODE = "done";
}
function hideInfo(){
$("#info").style.display = "none";
}
/*
// Also, Send message when ALL DONE
if(!FLIPPED && window.top.broadcastMessage){
FLIPPED = true;
setTimeout(function(){
window.top.broadcastMessage("flip_"+cardname);
},1000);
}
*/

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>The Flashcard</title>
<link rel="stylesheet" type="text/css" href="../fcard.css"/>
<link rel="stylesheet" type="text/css" href="singlecard.css"/>
</head>
<body>
<div id="container">
<div id="flashcard" class="flip-container">
<div class="flipper">
<div id="front" class="front"></div>
<div id="back" class="back"></div>
</div>
</div>
</div>
</body>
</html>
<script src="../helpers.js"></script>
<script src="singlecard.js"></script>

View File

@ -0,0 +1,70 @@
/* FONT FACE */
@font-face {
font-family: "PatrickHand";
font-style: normal;
font-weight: 400;
src: url(../../css/PatrickHand-Regular.ttf) format('truetype');
}
body{
margin: 0;
font-family: "PatrickHand", Helvetica, Arial;
color: #000;
letter-spacing: 1px;
font-size: 40px;
}
/* entire container, keeps perspective */
#container{
width: 440px;
height: 300px;
overflow: hidden;
}
.flip-container {
transition: 0.15s;
transform-origin: 200px 120px;
perspective: 1200px;
width: 100%;
height: 100%;
cursor: pointer;
}
.flip-container:hover {
transform: scale(1.03);
}
/* Flip it! */
.flip-container[flip=yes] .flipper{
transform: rotateY(180deg);
}
.front, .back {
width: 400px; /* 5 x 3 */
height: 240px;
border-radius: 20px;
overflow: hidden;
text-align: center;
}
.flipper {
transition: 0.5s;
transform-style: preserve-3d;
transform-origin: 200px 120px;
position: absolute;
left: 20px;
top: 30px;
}
/* Front & Back */
.front, .back {
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
.front {
z-index: 2;
transform: rotateY(0deg);
background: #fff;
}
.back {
transform: rotateY(180deg);
background: #fff;
}

View File

@ -0,0 +1,30 @@
var flashcard = $("#flashcard");
var FLIPPED = false;
flashcard.onclick = function(){
// Flip!
var flip = flashcard.getAttribute("flip");
if(flip=="yes"){
flashcard.setAttribute("flip","no");
}else{
flashcard.setAttribute("flip","yes");
}
// Also, send message (when flipped for first time)
if(!FLIPPED && window.top.broadcastMessage){
FLIPPED = true;
setTimeout(function(){
window.top.broadcastMessage("flip_"+cardname);
},1000);
}
};
window.cardname = _getQueryVariable("card");
var frontHTML = _getLabel("flashcard_"+cardname+"_front");
var backHTML = _getLabel("flashcard_"+cardname+"_back");
$("#front").innerHTML = frontHTML;
$("#back").innerHTML = backHTML;
_modifyFlashCard($("#front"));
_modifyFlashCard($("#back"));

218
words/Draft 1.md Normal file
View File

@ -0,0 +1,218 @@
#THE MEMORY THING
## Why & Science
Pffft, why bother *memorizing* anything? Nowadays, when you can use a giant techno-corp to look stuff up, what is memory good for other than party tricks like: remembering the names & lives of people you've met, knowing your favorite poems & passages by heart, and having a rich internal library you can take with you anywhere?
But seriously: memory gets a bad rap. I remember being forced to memorize countless meaningless facts in school.
But the problem isn't *memorization*, it's *meaninglessness*. If done well, memory *makes* meaning! There's a reason why, in Greek mythology, Memory was the mother of the Muses.
The Greeks were right. You may have heard that we should teach creativity & critical thinking *instead* of rote memorization but cognitive scientists have shown that creativity & critical thinking *require* memorization! (Proof: imagine composing a poem or essay if you haven't even memorized your ABCs) Before we can *connect* the dots, we must first *collect* the dots.
But people use many strategies to learn, and most of them suck. In 2013, a team of cognitive scientists did a meta-study a study of _200+ other studies_ to find out how effective 10 study techniques were. Let's see if their findings match your expectations. (they didn't match *mine!*)
**Re-reading** to remember is...
[NOT EFFECTIVE]
A lot of students re-read text to study. It's hard, it's time-consuming, but at least it's... mostly useless. Oh well. On to the next:
**Highlighting** or underlining key material is...
[NOT EFFECTIVE]
That's right despite re-reading & highlighting being the most common study techniques, they've both been proven to *NOT* work. Now, how about this:
**Spaced Practice**, spreading out your learning instead of cramming, is...
[HIGHLY EFFECTIVE!]
We're all guilty of cramming the night before the exam. And a month after the exam, you've forgotten everything. In contrast, spacing out your learning is easier _and_ helps you recall things better in the long term! Next:
**Visual Mnemonics**, making mental pictures for ideas you want to memorize, is...
[NOT EFFECTIVE]
This shocked me. Especially since I *love* visualization. But although imagery helps with learning foreign or technical vocabulary, it's not been shown to work over the long term like spaced practice does. Finally:
**Active Recall**, giving yourself quizzes, is...
[HIGHLY EFFECTIVE!]
You learn what you practice. The reason re-reading & highlighting is so ineffective is that you don't practice *recalling* answers, you practice *recognizing* answers.
There's a method that combines spaced practice and active recall. It's called **spaced repetition.** (I think "spaced recall" would be a better name, but alas) Compared to the most common study techniques, spaced repetition is easier, more effective, and *almost no schools tell you about it*.
// Note: Memory Palaces?
But I want to tell you about it. In the next 10 minutes, I'd like to help you start using spaced repetition *today*. Whether you're in school (my condolences) or learning on your own (my congratulations), I hope this little method can be the mother of your Muses.
But first... let's do a little active recall, shall we?
**TEST A:**
[3 Common But Ineffective Ways to Learn are...]
[Re-reading, Highlighting, Visual Mnemonics]
[2 Uncommon But Effective Ways to Learn are...]
[Spaced Practice, Active Recall]
[???]
[???]
## How & What
So, what, am I just recommending you use boring ol' flashcards? Well, yes. But they're flashcards... *on steroids!*
The problem with regular flashcards is that *you* decide when you see the cards. You may see cards you know as often as cards you don't. Or you may throw away cards you *think* you have in long-term memory, but really was only in short-term memory. The solution: have a shoebox tell you when to study.
**The Leitner Box** was invented by Sebastian Leitner in 1973, and was one of the first spaced repetition systems. It's a box. An actual box. (There's a digital version; we'll see that later) You can use this box to learn almost anything, but it's most popular in the language-learning community. Earlier this year, I started using this box to help me learn French and in two *months*, the box taught me more than two *years* of Canadian school French.
Not bad for a shoebox! Here's how it works.
**To make the box:**
1. Get a box.
2. Make dividers to split the box into levels. (let's say 7 levels)
**To use the box:**
You put flashcards in the box.
// how flashcards work
Here's how often you should study (active recall) the cards at each level:
[pic]
Note that for each next level, the duration *doubles*. (spaced practice) Here's a 64-day calendar you can use:
[pic]
// (Note that you should review your higher-level cards _first_.)
But how do your cards get to each level? Well, first, new flashcards go into Level 1.
[pic]
When you review the cards in a single level, all the cards you got right go up to the next level, and all the cards you got wrong go... _back to Level 1._
[pic]
// (And if you're reviewing Level 1, just keep reviewing your incorrect cards until they all go up to Level 2)
This guarantees that you'll see cards you don't know often, and cards you do know only _just as you're about to forget them_. It's a system that strengthens your weakest points!
Here's a step-by-step simulation of what this looks like over several days:
[sim]
Now, for whatever reason, you may not like the idea of scribbling index cards to shove into a shoebox. Thankfully, there are also digital spaced repetition systems, the most popular of which is the free, open-source app, **Anki.**
(Anki uses a more sophisticated spaced-practice schedule than the Leitner box, but the core idea is the same.)
(ANTI-DISCLAIMER: I am *not* affiliated with Anki, I just genuinely think it's an awesome app. Even though I personally prefer the shoebox.)
Alright, now that I've sung the high praises of a shoebox, here's the catch:
// Only for declarative knowledge (but procedural skills can be aided)
// MEMORIZATION IS NOT ENOUGH (collect THEN connect. on the side, do stuff that uses the facts together)
**No matter what fancy learning techniques you use, if what you're learning feels meaningless, it won't work.** As I said earlier: the problem isn't memorization, it's meaninglessness. It's not knowing your *whats*, it's knowing your *why*.
So now, let's turn to you. What do you want to learn, and why?
∴ TEST B (3 cards)
[What does the "Forgetting Curve" look like?] []
[Leitner Box study schedule] []
[The most popular Spaced Repetition System app (as of Sep 2018) is...] [Anki (free, open source)]
## Using it for YOU
"Meaning" may seem like a fluffy woo-word, but it all comes down to the lament of bored students everywhere:
“When am I ever going to use this?”
Before I started using the shoebox, I had tried learning French with Duolingo. It's a great app. I'm not dissing it. It's free, it's polished, and it's helped lots of people. But not me. Learning a list of words (that I didn't choose) felt too removed from what I *really* wanted to do with the language, which was read French comics and be a French film snob.
But when I tried learning French again with the shoebox, I was forced to make my *own* list of words. And I got new vocabulary from the thing I *actually* cared about: Tintin comics! And the more words I learnt from Tintin, the better I got at reading Tintin. **The thing I actually cared about was both my source & destination.**
// pic
I think *that's* the trick. Not just for memorizing French, not even just for memorizing, but for *all learning*. It needs to go into (and ideally, also come from) things you love.
// pics: (examples involving memory)
// programming
// ukulele
// kinds of birds (thing itself)
That's why the consensus among spaced repetition enthusiasts is that, in almost all cases, **you should make your own cards.** That way, you have a chance to make your cards meaningful to *you*.
Speaking of which, it's time to make your own cards:
**WHAT do you want to learn?**
If you want to start small, here's some stuff you could memorize in a few days: Morse code, Braille, the ASL alphabet, US states & their capitals, the countries in your continent, etc
**WHY do you want to learn X?**
What do you want to use your knowledge *for?* (If it's for the sake of the knowledge itself, that's great! Write that.)
Examples: "Programming -> to make games"
**WHERE will you get your cards from?**
sadasdsaasdasas
But after all this, will spaced repetition be worth it for you? The results of spaced repetition only *really* show themselves after weeks or months. That's why spaced repetition isn't as popular compared to highlighting or re-reading: although it's more effective and just as easy, it *takes longer.* It's too bad we can't get a sneak peek into the future.
Except we can. Here's a simulation-based calculator to show you how much *you* can learn with a few minutes a day over a month or so...
// sim
And finally, just one final self-test:
∴ TEST A, B, C
## Get Started Right Now
Leitner Box:
* + Arts & Craftsy!
* + You can easily modify rules
* - Can't do sound
* - Not easily portable
Anki:
* + Most popular
* + Can do sound
* + Portable: laptop and mobile web versions
* + Can customize decks and rules
* - Clunky interface
Tinycards:
* + Very well-designed and polished
* + Easy to try out: no need to download or even sign up
* - Not open source
* - Less customizeable than Anki
GET STARTED
**Leitner Box:** go to a nearby office supply store and buy flashcards, and a box for the flashcards. (you can also buy dividers, or make your own) print out your study calendar
**Anki:** Download it here. Here's a tutorial by Fluent Forever
**Tinycards.** No need for buying supplies or download or even signing up at first. Go to X and try out a few flashcards!
In 1953, Henry Molaison had a brain surgery to get rid of his epilepsy. It also got rid of his ability to make new memories. From then on, he lived in a perpetual present. He died at 82. He stopped at 27.
Memory is not should not be late nights re-reading a textbook that feels heavier than your 2AM eyelids. Memory makes us human. Memory is the mother of all our muses. It's a shame that school has left too many of us with a Pavlovian fear-response of "learning" and "memorization". I hope this interactive comic helped ease some of those fears, and given you a simple, concrete way to take back your mind, and learn better. And you'll finally recognize memory for what it is:
It's a *superpower.*

218
words/Draft 2.md Normal file
View File

@ -0,0 +1,218 @@
#THE MEMORY THING
## Why & Science
Pffft, why bother *memorizing* anything? Nowadays, when you can use a giant techno-corp to look stuff up, what is memory good for other than party tricks like: remembering the names & lives of people you've met, knowing your favorite poems & passages by heart, and having a rich internal library you can take with you anywhere?
But seriously: memory gets a bad rap. I remember being forced to memorize countless meaningless facts in school.
But the problem isn't *memorization*, it's *meaninglessness*. If done well, memory *makes* meaning! There's a reason why, in Greek mythology, Memory was the mother of the Muses.
The Greeks were right. You may have heard that we should teach creativity & critical thinking *instead* of rote memorization but cognitive scientists have shown that creativity & critical thinking *require* memorization! (Proof: imagine composing a poem or essay if you haven't even memorized your ABCs) Before we can *connect* the dots, we must first *collect* the dots.
But people use many strategies to learn, and most of them suck. In 2013, a team of cognitive scientists did a meta-study a study of _200+ other studies_ to find out how effective 10 study techniques were. Let's see if their findings match your expectations. (they didn't match *mine!*)
**Re-reading** to remember is...
[NOT EFFECTIVE]
A lot of students re-read text to study. It's hard, it's time-consuming, but at least it's... mostly useless. Oh well. On to the next:
**Highlighting** or underlining key material is...
[NOT EFFECTIVE]
That's right despite re-reading & highlighting being the most common study techniques, they've both been proven to *NOT* work. Now, how about this:
**Spaced Practice**, spreading out your learning instead of cramming, is...
[HIGHLY EFFECTIVE!]
We're all guilty of cramming the night before the exam. And a month after the exam, you've forgotten everything. In contrast, spacing out your learning is easier _and_ helps you recall things better in the long term! Next:
**Visual Mnemonics**, making mental pictures for ideas you want to memorize, is...
[NOT EFFECTIVE]
This shocked me. Especially since I *love* visualization. But although imagery helps with learning foreign or technical vocabulary, it's not been shown to work over the long term like spaced practice does. Finally:
**Active Recall**, giving yourself quizzes, is...
[HIGHLY EFFECTIVE!]
You learn what you practice. The reason re-reading & highlighting is so ineffective is that you don't practice *recalling* answers, you practice *recognizing* answers.
There's a method that combines spaced practice and active recall. It's called **spaced repetition.** (I think "spaced recall" would be a better name, but alas) Compared to the most common study techniques, spaced repetition is easier, more effective, and *almost no schools tell you about it*.
// Note: Memory Palaces?
But I want to tell you about it. In the next 10 minutes, I'd like to help you start using spaced repetition *today*. Whether you're in school (my condolences) or learning on your own (my congratulations), I hope this little method can be the mother of your Muses.
But first... let's do a little active recall, shall we?
**TEST A:**
[3 Common But Ineffective Ways to Learn are...]
[Re-reading, Highlighting, Visual Mnemonics]
[2 Uncommon But Effective Ways to Learn are...]
[Spaced Practice, Active Recall]
[???]
[???]
## How & What
So, what, am I just recommending you use boring ol' flashcards? Well, yes. But they're flashcards... *on steroids!*
The problem with regular flashcards is that *you* decide when you see the cards. You may see cards you know as often as cards you don't. Or you may throw away cards you *think* you have in long-term memory, but really was only in short-term memory. The solution: have a shoebox tell you when to study.
**The Leitner Box** was invented by Sebastian Leitner in 1973, and was one of the first spaced repetition systems. It's a box. An actual box. (There's a digital version; we'll see that later) You can use this box to learn almost anything, but it's most popular in the language-learning community. Earlier this year, I started using this box to help me learn French and in two *months*, the box taught me more than two *years* of Canadian school French.
Not bad for a shoebox! Here's how it works.
**To make the box:**
1. Get a box.
2. Make dividers to split the box into levels. (let's say 7 levels)
**To use the box:**
You put flashcards in the box.
// how flashcards work
Here's how often you should study (active recall) the cards at each level:
[pic]
Note that for each next level, the duration *doubles*. (spaced practice) Here's a 64-day calendar you can use:
[pic]
// (Note that you should review your higher-level cards _first_.)
But how do your cards get to each level? Well, first, new flashcards go into Level 1.
[pic]
When you review the cards in a single level, all the cards you got right go up to the next level, and all the cards you got wrong go... _back to Level 1._
[pic]
// (And if you're reviewing Level 1, just keep reviewing your incorrect cards until they all go up to Level 2)
This guarantees that you'll see cards you don't know often, and cards you do know only _just as you're about to forget them_. It's a system that strengthens your weakest points!
Here's a step-by-step simulation of what this looks like over several days:
[sim]
Now, for whatever reason, you may not like the idea of scribbling index cards to shove into a shoebox. Thankfully, there are also digital spaced repetition systems, the most popular of which is the free, open-source app, **Anki.**
(Anki uses a more sophisticated spaced-practice schedule than the Leitner box, but the core idea is the same.)
(ANTI-DISCLAIMER: I am *not* affiliated with Anki, I just genuinely think it's an awesome app. Even though I personally prefer the shoebox.)
Alright, now that I've sung the high praises of a shoebox, here's the catch:
// Only for declarative knowledge (but procedural skills can be aided)
// MEMORIZATION IS NOT ENOUGH (collect THEN connect. on the side, do stuff that uses the facts together)
**No matter what fancy learning techniques you use, if what you're learning feels meaningless, it won't work.** As I said earlier: the problem isn't memorization, it's meaninglessness. It's not knowing your *whats*, it's knowing your *why*.
So now, let's turn to you. What do you want to learn, and why?
∴ TEST B (3 cards)
[What does the "Forgetting Curve" look like?] []
[Leitner Box study schedule] []
[The most popular Spaced Repetition System app (as of Sep 2018) is...] [Anki (free, open source)]
## Using it for YOU
"Meaning" may seem like a fluffy woo-word, but it all comes down to the lament of bored students everywhere:
“When am I ever going to use this?”
Before I started using the shoebox, I had tried learning French with Duolingo. It's a great app. I'm not dissing it. It's free, it's polished, and it's helped lots of people. But not me. Learning a list of words (that I didn't choose) felt too removed from what I *really* wanted to do with the language, which was read French comics and be a French film snob.
But when I tried learning French again with the shoebox, I was forced to make my *own* list of words. And I got new vocabulary from the thing I *actually* cared about: Tintin comics! And the more words I learnt from Tintin, the better I got at reading Tintin. **The thing I actually cared about was both my source & destination.**
// pic
I think *that's* the trick. Not just for memorizing French, not even just for memorizing, but for *all learning*. It needs to go into (and ideally, also come from) things you love.
// pics: (examples involving memory)
// programming
// ukulele
// kinds of birds (thing itself)
That's why the consensus among spaced repetition enthusiasts is that, in almost all cases, **you should make your own cards.** That way, you have a chance to make your cards meaningful to *you*.
Speaking of which, it's time to make your own cards:
**WHAT do you want to learn?**
If you want to start small, here's some stuff you could memorize in a few days: Morse code, Braille, the ASL alphabet, US states & their capitals, the countries in your continent, etc
**WHY do you want to learn X?**
What do you want to use your knowledge *for?* (If it's for the sake of the knowledge itself, that's great! Write that.)
Examples: "Programming -> to make games"
**WHERE will you get your cards from?**
sadasdsaasdasas
But after all this, will spaced repetition be worth it for you? The results of spaced repetition only *really* show themselves after weeks or months. That's why spaced repetition isn't as popular compared to highlighting or re-reading: although it's more effective and just as easy, it *takes longer.* It's too bad we can't get a sneak peek into the future.
Except we can. Here's a simulation-based calculator to show you how much *you* can learn with a few minutes a day over a month or so...
// sim
And finally, just one final self-test:
∴ TEST A, B, C
## Get Started Right Now
Leitner Box:
* + Arts & Craftsy!
* + You can easily modify rules
* - Can't do sound
* - Not easily portable
Anki:
* + Most popular
* + Can do sound
* + Portable: laptop and mobile web versions
* + Can customize decks and rules
* - Clunky interface
Tinycards:
* + Very well-designed and polished
* + Easy to try out: no need to download or even sign up
* - Not open source
* - Less customizeable than Anki
GET STARTED
**Leitner Box:** go to a nearby office supply store and buy flashcards, and a box for the flashcards. (you can also buy dividers, or make your own) print out your study calendar
**Anki:** Download it here. Here's a tutorial by Fluent Forever
**Tinycards.** No need for buying supplies or download or even signing up at first. Go to X and try out a few flashcards!
In 1953, Henry Molaison had a brain surgery to get rid of his epilepsy. It also got rid of his ability to make new memories. From then on, he lived in a perpetual present. He died at 82. He stopped at 27.
Memory is not should not be late nights re-reading a textbook that feels heavier than your 2AM eyelids. Memory makes us human. Memory is the mother of all our muses. It's a shame that school has left too many of us with a Pavlovian fear-response of "learning" and "memorization". I hope this interactive comic helped ease some of those fears, and given you a simple, concrete way to take back your mind, and learn better. And you'll finally recognize memory for what it is:
It's a *superpower.*

57
words/Outline.md Normal file
View File

@ -0,0 +1,57 @@
// LIMIT: 1000 WORDS
### Why & Science
! Why bother memorizing?
! Actually (Memory is mother of all muses)
! Spaced experiment
! Re-read/recall experiment
∴ Spaced Recall
∴ TEST A
### How & What
∴ Leitner Box (hint at digital version later)
!! Inconvenient? Anki!
! Limitations ! Workarounds
!! But is it worth it? The calculator, testimonials. Trial
∴ TEST B
### Using it for YOU
∴ What do you want to learn
!! Why?!
∴ What declarative facts do you need?
∴ What now? Leitner Box, Anki App, Tinycards
∴ TEST A, B, C
---
**Titles?**
How to Remember Forever
How to Remember Stuff
Memory, Mother of all Muses
What If Memory Was A Choice?
Remember Everything With This One Weird Trick
**THE GOAL: GET STARTED RIGHT NOW**
* model it
* observable results ( calculator, diverse models )
* compatible with life ( 20 minutes a day, or with Anki, on phone )
* relative advantage ( better than re-reading, even bare flashcards, school )
* simple to understand ( "use it or lose it" )
* trialable ( https://tinycards.duolingo.com/users/TinyGeo )

BIN
words/SRS.JPG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB