Last active
December 10, 2015 23:28
-
-
Save arlimus/4509918 to your computer and use it in GitHub Desktop.
Small coffeescript to make text animate in a way similar to the one seen on 29c3.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# usage: | |
# eg have this in your html: | |
# <pre class="29c3"> | |
# N.O-T/M | |
# Y-D/E.P | |
# A/R.T-M | |
# E-N/T | |
# 2.9-C/3 | |
# </pre> | |
# then run this in javascript: | |
# ccc29c3ify($(".29c3")); | |
# take some string and scramble it in 29c3-style | |
# strength is a factor to control this from 0.0 = no scramble to 1.0 max strength | |
# lower strength will have less letter-swapping | |
scramble = (txt, strength) -> | |
strength = 0 if strength < 0 | |
# variables we need: | |
spacers = ".,:;-/\\()[]{}~+'\"" | |
text_re = /[a-z0-9 ]/i | |
# manipulators for strength | |
# use a function plotting tool to look at the curves ... | |
spacer_strength = strength * 3.0 + 0.2 | |
line_flipper_strength = 0 - Math.log(1-Math.pow(strength,3))/Math.log(1.3) | |
block_flipper_strength = 0.3 | |
# depending on spacer_strength, change char into | |
# one of the available spacers | |
scramble_spacer = (char) -> | |
# break method: don't change the char if we are | |
return char if( Math.random() > spacer_strength ) | |
spacers[ Math.floor( Math.random() * spacers.length ) ] | |
# take a line (string) and for all spacers (i.e. not part of the text) | |
# attemt to scramble it | |
scramble_line_spacer = (line) -> | |
(for c in line | |
if not text_re.exec(c) | |
scramble_spacer c | |
else c | |
).join("") | |
# take a string org and switch characters at idx_old with idx_new | |
flip = (org, idx_old, idx_new) -> | |
o = org.split "" | |
tmp = o[idx_new] | |
o[idx_new] = o[idx_old] | |
o[idx_old] = tmp | |
o.join "" | |
# for a position org element in min..max, try to move it a certain distance forwards or backwards | |
# e.g. position = 3 | |
# distance = 1 | |
# direction = true => move to 4 | |
# direction = false => move to 2 | |
# if a boundary is crossed, try to move into the opposite direction instead | |
flip_position = (org, min, max, distance, direction) -> | |
mod = if(direction) then distance else 0-distance | |
nu = org + mod | |
if(nu>max) then nu = org - mod | |
if(nu<min) then nu = org + mod | |
if(nu>max or nu <min) then nu = org | |
return nu | |
# go through the line and for each letter at chance lfp flip its position with an adjacent letter | |
# once flipped the chance lfp decreases | |
scramble_line_flipper = (line) -> | |
lfp = line_flipper_strength | |
for c in [1..line.length] | |
if Math.random() < lfp and text_re.exec(c) | |
lfp = lfp/2 # reduce the chance of this happening again | |
cn = flip_position( c-1, 0, line.length-1, 1, (Math.random() > 0.5) ) | |
line = flip(line, c-1, cn ) | |
line | |
# for a line try to scramble spacers and then letters | |
scramble_line = (line) -> | |
scramble_line_flipper scramble_line_spacer line | |
# split input string into lines and try to scramble lines separately | |
(scramble_line l for l in txt.split("\n")).join("\n") | |
scramble_timer = ( el, txt, cur_time, total_time ) -> | |
# failsafe, anything below this speed cannot be handled by browsers correctly | |
min_speed = 10 | |
# failsafe, anything above for total time will screw the animation unintentionally | |
max_total_time = 20000 | |
max_timeout = 5000 | |
f = (str = strength) -> | |
el.textContent = scramble(txt, str ) | |
rel_total_time = if(total_time > max_total_time) then max_total_time else total_time | |
x = cur_time/rel_total_time | |
# failsafe | |
x = 1.0 if x > 1.0 | |
# strength = 1-x | |
strength = 1 - (Math.atan(4*(x+0.01))/(Math.PI/2)) - 0.15 | |
irratic_curve = 1 - (Math.atan(2*(x+0.01))/(Math.PI/2)) + 0.5 | |
# only proceed if we haven't hit the maximum animation time | |
if cur_time < total_time | |
# cur_timeout = Math.floor( 10 * ( Math.exp(x*5) - Math.pow(4.5, 5*(x-0.4)) )) + min_speed | |
cur_timeout = Math.floor( max_timeout * Math.atan(0.5*x)) + min_speed | |
# failsafe | |
cur_timeout = min_speed if cur_timeout < min_speed | |
$("#debug_29c3").html([ | |
"timeout: #{cur_timeout}", | |
"strength: #{Math.round(strength*100)/100}", | |
"time: #{cur_time}/#{total_time}" | |
].join(" -- ")) | |
# add some irratic changes | |
if( cur_timeout > 200 and Math.random() > irratic_curve ) | |
# irratic changes are run via scrambling at this point in time with higher strenght | |
# and adding a short timeout for another scrambler at normal strength | |
ir_timeout = Math.random()*70 + 100 + min_speed | |
f(strength+0.25) | |
setTimeout( f, ir_timeout ) | |
else | |
f() | |
setTimeout( -> | |
scramble_timer(el, txt, cur_time + cur_timeout, total_time) | |
, cur_timeout) | |
else | |
# at the end, reset the elements content to their clear/unscrambled state | |
el.textContent = txt | |
window.ccc29c3ify = (els, duration = 60000) -> | |
for el in els | |
scramble_timer( el, el.textContent, 0, duration ) | |
#el.textContent = scramble(txt, .5) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment