commit 4670ff8e93efe359975cf7d2e63b9d696a24af25 Author: Nicky Case Date: Tue Sep 18 13:17:42 2018 -0400 beta diff --git a/ch2.html b/ch2.html new file mode 100644 index 0000000..ca60315 --- /dev/null +++ b/ch2.html @@ -0,0 +1,508 @@ + + + + + An Interactive Comic + + + + + + + +
+ + + + + + + + + + + + You don't have to use a shoebox for Spaced Repetition, + but it's funnier if you do. + + + (Later, we'll look at some Spaced Repetition apps, + like Anki & Tinycards) + + + + + + + This method is called The Leitner System. + It's like a card game you play against yourself! + + + First, divide your box up into seven "Levels". + Each Level will store some flashcards. + + + + +"wait, what's a flashcard?" + + + + + +"what kind of stuff can I learn with flashcards?" + + + + + + + We need to space out our recalls with increasing gaps of time. + So, here's a calendar of when to review which Level's cards: + + + + + + + + + + + + + But how do cards move between Levels? + How do you play this game of Spaced Repetition Solitaire? + + + + + + + The rules are simple. + First, all new cards start at Level 1. + + + (If you're new to Spaced Repetition, I recommend starting with 5 new cards a day.) + + + + + + + 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. + + + (If you're already at the final Level, congrats! + Your card gets to retire in Valhalla) + + + + + + + But each card you get wrong... goes + all the way back down to Level 1. + + + (You can change the rules – it's your shoebox – + but I recommend playing it this way) + + + + + + + Each day, you review Level 1 at the end. + You'll see your new cards + the cards you forgot. + + + Keep trying to recall them, until you can get every one right! + Move them all to Level 2. + + + + + + And that's it! + Here's how the game plays out over several days: + (Later, we'll see a sim for several months) + + + + + + + + + + + + + Each daily session takes 20-30 minutes. + Instead of watching a TV episode, you could play a card game – + and remember anything you want for life. + + + + + + + However, habits are hard. If you start big, you won't get the ball rolling... + + + But if you start small, you can gain momentum, + and roll your snowball bigger and bigger. + + + + + + + That's why I recommend starting with 5 new cards a day. + + + Once you're comfortable with that, you can do 10 new cards/day. + Then 15. Then 20, 25, 30. + + + And at 30 new cards a day, you can learn 10,000+ new facts/words/etc a year. + + + + + + Here's what that looks like, over several months: + + + + + + + + + + + + + That's it. That's how you can make long-term memory a choice. + + + Let's let that sink in. Take a break, and recall what we just learnt: + + + + + + + + + + + + + + Spaced Repetition almost seems too good to be true. +
+ And it is... IF you fall for 3 very common pitfalls. +
+
+ + + + + Spaced Repetition will fail if your cards feel + bloated, disconnected, or meaningless. + + + Memory isn't a private library, + where you hoard a bunch of random books to impress others. + + + + + + + Memory is more like a jigsaw puzzle, full of tiny pieces joined together. + (This is also how neurons work: lots of tiny, connected things) + + + It's not about collection, it's about connection. + + + + + + So, to get the most out of Spaced Repetition, + you must make your cards... + + + + + + + + + SMALL + + + + + + This card sucks: + + + + + + + + + + + + It's too big. Too much information. + + + Instead, let's cut in up into a bunch of smaller, connected pieces, + like so: + + + + + + + + + + Facts connect to facts. + But there's other, more playful ways for cards to be... + + + + + + + + + CONNECTED + + + + + + This card is... alright. + It's an English word on the front, French word on the back. + It's the standard for most flashcards: + + + + + + + + + + + + But you know what would make it stick in memory better? + + + If you connected it to + images, sounds, context, and/or personal details! + Like so: + + + + + + + + + + + + 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) + + + + + + + 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) + + + * Obviously, paper cards can't play sounds. + But apps like Anki/Tinycards can! + + + + + + But the most important connection of all, + is to connect your learning to something that is... + + + + + + + + + MEANINGFUL + + + + + + + Personally, here's how I've learnt best: + First, I try to do something. + + + + + + + Inevitably, I'll get stuck. + In that moment, I'll look up what I need, + and learn something. + + + + + + + + + + + And so on. + + + + + And so on. + + + + + And so on. + + + + + + + That, I believe, is the best way to keep yourself motivated while learning: + + + By making sure your learning is in service of something you actually care about. + + + + + + + + Speaking of learning, let's practice recalling what we've learnt: + (this is the second-last time!) + + + + + + + + + + + + + + + These three rules for making cards... + + + + ...are why it's consensus among the Spaced Repetition community that, + for the most part, + you should make your own cards. + + + + + + + This way, you can connect facts to things you know, + to images and sounds you like, + in service of something you love. + + + + + + + That's why, in the final part of this interactive comic, + you're going to make your own cards! + + + And these cards will be about... + + + + + + + YOU + + + + +
+ + + + + +
+ +
+ + Day [N] + + + to review: Level + + + review Level [N] + + + add [N] new cards + + + total: [N] cards! + + + ([N] in very-long-term memory) + +
+ +
+ + + + + + + diff --git a/css/PatrickHand-Regular.ttf b/css/PatrickHand-Regular.ttf new file mode 100755 index 0000000..fb45ccd Binary files /dev/null and b/css/PatrickHand-Regular.ttf differ diff --git a/css/comic.css b/css/comic.css new file mode 100644 index 0000000..2da22c5 --- /dev/null +++ b/css/comic.css @@ -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; +} + diff --git a/index.html b/index.html new file mode 100644 index 0000000..819665c --- /dev/null +++ b/index.html @@ -0,0 +1,460 @@ + + + + + An Interactive Comic + + + + + + + +
+ + + + + + + + +(This is a work-in-progress! +Please don't share yet. +
+Let me know your honest feedback, thanks!) + +
+
+ + + + + + + In 1885, Hermann Ebbinghaus performed an act of scientific masochism. + + + The German psychologist memorized thousands of nonsense words, + recorded how much he forgot over time, and discovered... + + + + + + + THE FORGETTING CURVE + + + 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. + + + + + + + Since then, Ebbinghaus’s findings have been replicated again and again– + + + –and grew into a whole new scientific field of memory! + + + + + + Here’s a playable simulation of the Forgetting Curve. +
+ Change the rate of “memory decay”. What happens? +
+
+ + + + + + + + + + As you can see, the less the decay, the flatter the curve – + that is, the longer the memory lasts. + + + + + + +How fast a person’s memory decays depends on the person and the memory... + + + + + + +But, in general, a memory’s “rate of decay” slows down each time you actively recall it. + + + + + + +(although, when you stop practicing, it still decays.) + + + + + + Here’s the simulation again, with a single active recall session. +
+ (grey line: what memory would've been without the recall) +
+ Change the timing of the recall. What happens? +
+
+ + + + + + + + + + A single recall boosts memory for a bit... but in the long run, + due to exponential decay of memory, a single recall changes nothing. + + + + + + + Is there a better way to learn? + There is! The trick to remembering... + + + ...is to forget. + + + + + + +To understand this, think about training your muscles. +You’ll gain nothing with a weight that’s too easy... + + + + + + +...nor one that’s too hard. + + + + + + +The same’s true of training your brain. +You need desirable difficulty: the sweet spot of just-hard-enough. + + + + + + + Therefore: to best learn something, you need to recall it... + + + ...just as you’re about to forget it. + + + + + + Same simulation as before, but now it shows the sweet spot – + where you’ve forgotten just a little bit. +
+ Change the timing of the recall. What happens now? +
+
+ + + + + + + + + + See? If you time a single recall so that it's in the sweet spot, + you can slow down the decay! + Now, what about multiple recalls? + + + + + + +Let’s say you’re +lazy +time-efficient, so you’re only doing 4 recall sessions. + + +Question: +what’s the best way to spread out your recalls? + + + + + + +Should you have evenly spaced gaps? +Gaps of increasing length? +Gaps of decreasing length? +Or make it unpredictable, to keep you on your toes? + + + + + +Give it your best guess, +then when you’re ready, flip the card over ↓ + + + + + + + + + + Which is very counter-intuitive! + You can prove to yourself this is true, by playing with the sim below. + + Get all recalls into the sweet spot. + What spacing do you get? + + + + + + + + + + + + + (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”!) + + + + + + + + + + + + + Why must the gaps increase? + Because: each time you do a recall at the sweet spot of forgetting, + the memory’s decay slows down... + + + ...meaning it’ll take longer + to hit the sweet spot next time! + + + + + + +But you know what’s sweeter? +This also means if you time your recalls just right... + + +...you can easily keep any number of things in your long-term memory, +FOREVER. + + + + + + + + + +And speaking of doing active recall in order to learn, +let's do some active recall on what we just learnt: + + + + + + + + + + +Anyway, this all sounds great, +but finding the optimal schedule must be impossible, right? + + + + + + +Au contraire! +It’s so simple, you can even create your own automatic scheduler... + + + + + + +...using a shoebox. + + + + + + +[END OF PROTOTYPE] + +

+ +Sorry for the cliffhanger! +The rest of this comic would show you how to make a Leitner Box, +tell you about other digital spaced repetition systems like Anki, +and finally, help you get started using spaced repetition today! + +

+ +(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 about spaced repetition!) + +

+ +Anyway, please let me know your honest feedback so far! +Early feedback helps me a lot. Many thanks in advance! + +

+ +<3, +
~ Nicky + +
+
+ +
+ + +
+ + + + memory → + + + time → + + + decay: + + + sweet spot: + + + timing of recall(s): + + + auto-optimize! + + + + +
+ the best way to space out your recalls is... +
+
+ +
+
+ ...with increasing gaps! +
+
+ + + +
+ The discoverer of the Forgetting Curve was... +
+
+ +
+
+ Hermann Ebbinghaus +
+
+ +
+ The Forgetting Curve (without any recalls) looks like... +
+
+ +
+
+ (note: it decays quickly, then slowly – "exponential decay") +
+
+ +
+ The Forgetting Curve (with optimally-spaced recalls) looks like... +
+
+ +
+
+ (note: the gaps between recalls increase in length) +
+
+ + + + try to recall ↑ + then flip ↻ + + + (cards left: [N]) + + + did you remember this? + + + nah, try again + + + yup, onwards! + + + done for now! keep scrolling +
+ ↓ +
+ +
+ + + + + + + diff --git a/js/comic.js b/js/comic.js new file mode 100644 index 0000000..794a955 --- /dev/null +++ b/js/comic.js @@ -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); +}; diff --git a/js/minpubsub.src.js b/js/minpubsub.src.js new file mode 100644 index 0000000..7c33257 --- /dev/null +++ b/js/minpubsub.src.js @@ -0,0 +1,96 @@ +/*! + * MinPubSub + * Copyright(c) 2011 Daniel Lamb + * 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); \ No newline at end of file diff --git a/pics/cardboard.jpg b/pics/cardboard.jpg new file mode 100644 index 0000000..41e27a0 Binary files /dev/null and b/pics/cardboard.jpg differ diff --git a/pics/fcards0.png b/pics/fcards0.png new file mode 100644 index 0000000..60b1b05 Binary files /dev/null and b/pics/fcards0.png differ diff --git a/pics/sci0.png b/pics/sci0.png new file mode 100644 index 0000000..c7a4e18 Binary files /dev/null and b/pics/sci0.png differ diff --git a/pics/sci1.png b/pics/sci1.png new file mode 100644 index 0000000..59ab781 Binary files /dev/null and b/pics/sci1.png differ diff --git a/pics/sci2.png b/pics/sci2.png new file mode 100644 index 0000000..0856442 Binary files /dev/null and b/pics/sci2.png differ diff --git a/sims/ebbinghaus/ebbinghaus.css b/sims/ebbinghaus/ebbinghaus.css new file mode 100644 index 0000000..e9af98d --- /dev/null +++ b/sims/ebbinghaus/ebbinghaus.css @@ -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; +} \ No newline at end of file diff --git a/sims/ebbinghaus/ebbinghaus.js b/sims/ebbinghaus/ebbinghaus.js new file mode 100644 index 0000000..1e621e5 --- /dev/null +++ b/sims/ebbinghaus/ebbinghaus.js @@ -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 (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=0){ // only draw if line HAS been cut + var imCut = false; + for(var i=0; i=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 (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 + + + + The Forgetting Curve + + + + +
+
+ +
+
+
+
+
+ +
+ + *memory → + + + *time → + + + *decay: + + + *optimal: + + + *recalls: + + + *auto + +
+ + + + + + + \ No newline at end of file diff --git a/sims/fcard.css b/sims/fcard.css new file mode 100644 index 0000000..247b9fd --- /dev/null +++ b/sims/fcard.css @@ -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; +} \ No newline at end of file diff --git a/sims/helpers.js b/sims/helpers.js new file mode 100644 index 0000000..8e6a3b5 --- /dev/null +++ b/sims/helpers.js @@ -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 + + + + The Leitner Box + + + + +
+
+ + + + + +
+ +
+ +
+ +
+
+ +
+ + Day [N] + + + to review: Level + + + review Level [N] + + + add [N] new cards + + + total: [N] cards! + + + ([N] in very-long-term memory) + +
+ + + + + + + \ No newline at end of file diff --git a/sims/leitner/leitner.css b/sims/leitner/leitner.css new file mode 100644 index 0000000..9df409a --- /dev/null +++ b/sims/leitner/leitner.css @@ -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; +} \ No newline at end of file diff --git a/sims/leitner/leitner.js b/sims/leitner/leitner.js new file mode 100644 index 0000000..3ec6fe4 --- /dev/null +++ b/sims/leitner/leitner.js @@ -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;i0) 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=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); + +} diff --git a/sims/multicard/index.html b/sims/multicard/index.html new file mode 100644 index 0000000..5a9645d --- /dev/null +++ b/sims/multicard/index.html @@ -0,0 +1,104 @@ + + + + + The Flashcard + + + + + + +
+ + +
+ + +
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+
+ + +
+ +
+ + +
+ + + try to recall ↑ + then flip ↻ + + + (cards left: [N]) + + + did you remember this? + + + nah, try again + + + yup, onwards! + + + done for now! keep scrolling +
+ ↓ +
+ + + + A? + + + Apple + + + B? + + + Banana + + + C? + + + COOL BEANS + + +
+ + + + + + + \ No newline at end of file diff --git a/sims/multicard/multicard.css b/sims/multicard/multicard.css new file mode 100644 index 0000000..badd974 --- /dev/null +++ b/sims/multicard/multicard.css @@ -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; +} \ No newline at end of file diff --git a/sims/multicard/multicard.js b/sims/multicard/multicard.js new file mode 100644 index 0000000..6746e2a --- /dev/null +++ b/sims/multicard/multicard.js @@ -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 += "
"; + html += ""; + html += _getLabel("multicard_cards_left").replace("[N]",CARDS.length); + html += ""; + $("#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); +} +*/ \ No newline at end of file diff --git a/sims/singlecard/index.html b/sims/singlecard/index.html new file mode 100644 index 0000000..2ae50f0 --- /dev/null +++ b/sims/singlecard/index.html @@ -0,0 +1,26 @@ + + + + + The Flashcard + + + + + + +
+
+
+
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/sims/singlecard/singlecard.css b/sims/singlecard/singlecard.css new file mode 100644 index 0000000..6aed3a5 --- /dev/null +++ b/sims/singlecard/singlecard.css @@ -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; +} \ No newline at end of file diff --git a/sims/singlecard/singlecard.js b/sims/singlecard/singlecard.js new file mode 100644 index 0000000..666ec40 --- /dev/null +++ b/sims/singlecard/singlecard.js @@ -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")); \ No newline at end of file diff --git a/words/Draft 1.md b/words/Draft 1.md new file mode 100644 index 0000000..4b93598 --- /dev/null +++ b/words/Draft 1.md @@ -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.* \ No newline at end of file diff --git a/words/Draft 2.md b/words/Draft 2.md new file mode 100644 index 0000000..4b93598 --- /dev/null +++ b/words/Draft 2.md @@ -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.* \ No newline at end of file diff --git a/words/Outline.md b/words/Outline.md new file mode 100644 index 0000000..09b0b3d --- /dev/null +++ b/words/Outline.md @@ -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 ) \ No newline at end of file diff --git a/words/SRS.JPG b/words/SRS.JPG new file mode 100644 index 0000000..da372c5 Binary files /dev/null and b/words/SRS.JPG differ