beta
This commit is contained in:
commit
4670ff8e93
|
@ -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 & 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>
|
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 don’t 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, Ebbinghaus’s 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>
|
||||
Here’s 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 person’s 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 memory’s “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>
|
||||
Here’s 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.
|
||||
You’ll gain nothing with a weight that’s 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 that’s 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 same’s 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 you’re 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 you’ve 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>
|
||||
Let’s say you’re
|
||||
<span style="text-decoration:line-through;">lazy</span>
|
||||
time-efficient, so you’re only doing 4 recall sessions.
|
||||
</words>
|
||||
<words x=30 y=350 w=430>
|
||||
Question:
|
||||
<i>what’s 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 you’re ready, <b>flip the card over ↓</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,
|
||||
here’s a sim where you can change
|
||||
the initial memory decay & 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 memory’s decay slows down...
|
||||
</words>
|
||||
<words x=10 y=400 w=300>
|
||||
...meaning it’ll 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 what’s 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>
|
||||
It’s 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>
|
||||
|
||||
<3,
|
||||
<br>~ Nicky
|
||||
|
||||
</words>
|
||||
</panel>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- SIMULATION LABELS -->
|
||||
<div id="labels">
|
||||
|
||||
<!-- Ebbinghaus -->
|
||||
<span id="ebbinghaus_y_axis">
|
||||
memory →
|
||||
</span>
|
||||
<span id="ebbinghaus_x_axis">
|
||||
time →
|
||||
</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 ↑
|
||||
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>
|
||||
↓
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
<script src="js/minpubsub.src.js"></script>
|
||||
<script src="js/comic.js"></script>
|
|
@ -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);
|
||||
};
|
|
@ -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);
|
Binary file not shown.
After Width: | Height: | Size: 1.9 MiB |
Binary file not shown.
After Width: | Height: | Size: 141 KiB |
Binary file not shown.
After Width: | Height: | Size: 362 KiB |
Binary file not shown.
After Width: | Height: | Size: 196 KiB |
Binary file not shown.
After Width: | Height: | Size: 309 KiB |
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
};
|
||||
};
|
|
@ -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 →
|
||||
</span>
|
||||
<span id="ebbinghaus_x_axis">
|
||||
*time →
|
||||
</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>
|
|
@ -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;
|
||||
}
|
|
@ -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)+"%";
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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 ↑
|
||||
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>
|
||||
↓
|
||||
</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>
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
*/
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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"));
|
|
@ -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.*
|
|
@ -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.*
|
|
@ -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 )
|
Binary file not shown.
After Width: | Height: | Size: 1.0 MiB |
Loading…
Reference in New Issue