├── js ├── .gitignore ├── system-ticker.js ├── jquery.ellipsis.js ├── api.js ├── jquery.cookie.js ├── lsys-intro.js ├── intro.min.js ├── live.js ├── underscore.js └── jquery.kinetic.js ├── favicon.ico ├── img ├── logo.png ├── logo2.png ├── logo3.png ├── 100x100.gif ├── logo_tr.png ├── glyphicons-halflings.png ├── systems │ ├── lsys_amoeba.png │ ├── lsys_birds.png │ ├── lsys_clover.png │ ├── lsys_coral.png │ ├── lsys_fire!.png │ ├── lsys_gears.png │ ├── lsys_gemini.png │ ├── lsys_politic.png │ ├── lsys_re-coil.png │ ├── lsys_samurai.png │ ├── lsys_start.png │ ├── lsys_tornado.png │ ├── lsys_tree!.png │ ├── lsys_trigon.png │ ├── lsys_trippy.png │ ├── lsys_wormly.png │ ├── lsys_clockwork.png │ ├── lsys_dandelion.png │ ├── lsys_flagella.png │ ├── lsys_flyweight.png │ ├── lsys_kinetica.png │ ├── lsys_leviathon.png │ ├── lsys_manta_ray.png │ ├── lsys_number_8.png │ ├── lsys_octosquid.png │ ├── lsys_pollenate.png │ ├── lsys_slamurai.png │ ├── lsys_stardust.png │ ├── lsys_stargaze.png │ ├── lsys_the_bomb.png │ ├── lsys_the_slug.png │ ├── lsys_trifecta.png │ ├── lsys_try_force.png │ ├── lsys_wormhole.png │ ├── lsys_3d_pyramids.png │ ├── lsys_3d_rollers_2.png │ ├── lsys_angel_flight.png │ ├── lsys_brainchild.png │ ├── lsys_coalescence.png │ ├── lsys_conswarmity.png │ ├── lsys_dance_for_me.png │ ├── lsys_death_spiral.png │ ├── lsys_dragonfish.png │ ├── lsys_freaky_face.png │ ├── lsys_heisenberg.png │ ├── lsys_holy_shit!.png │ ├── lsys_house_rules.png │ ├── lsys_jelly-crab.png │ ├── lsys_johnny_lee.png │ ├── lsys_mandelbutt.png │ ├── lsys_mortal_coil.png │ ├── lsys_ornate_clock.png │ ├── lsys_platterstar.png │ ├── lsys_pulse_engine.png │ ├── lsys_seriously_3d.png │ ├── lsys_shaman_face.png │ ├── lsys_snapdragon.png │ ├── lsys_spin_engine.png │ ├── lsys_spirocopter.png │ ├── lsys_the_triffids.png │ ├── lsys_tree_horse.png │ ├── lsys_wigglesaur.png │ ├── lsys_bubble_trouble.png │ ├── lsys_clockwork_coil.png │ ├── lsys_crystal_orchid.png │ ├── lsys_dream_catcher.png │ ├── lsys_metamorphosis.png │ ├── lsys_ordered_chaos.png │ ├── lsys_rorschach_test.png │ ├── lsys_snake_charmer.png │ ├── lsys_spindlethrift.png │ ├── lsys_the_DNA_dance.png │ ├── lsys_twistmas_tree.png │ ├── lsys_twizzlestache.png │ ├── lsys_I_will_crush_you.png │ ├── lsys_biohazard_angel.png │ ├── lsys_close_encounters.png │ ├── lsys_cthulu's_daughter.png │ ├── lsys_dragon_spirograph.png │ ├── lsys_single_3d_blade.png │ ├── lsys_the_park_at_night.png │ ├── lsys_3d_tusk___gearspin.png │ ├── lsys_choose_your_tunnel.png │ ├── lsys_king_of_the_jungle.png │ ├── lsys_seahorse_moustache.png │ ├── lsys_battling_dragon_tails.png │ ├── lsys_needle_in_a_haystack.png │ ├── lsys_jamiroquai_-_rippletwist.png │ ├── lsys_I_mustache_you_a_question.png │ ├── lsys_the_indomitable_moustachio.png │ ├── lsys_beating_heart_(wiggle_mouse).png │ ├── lsys_helicopter_plant_(drag_left).png │ └── lsys_the_grinch_in_a_christmas_hat.png └── glyphicons-halflings-white.png ├── font ├── fontello.eot ├── fontello.ttf ├── fontello.woff └── fontello.svg ├── .gitignore ├── bin ├── mkimg └── build ├── benchmark ├── run_data ├── run ├── benchmark.coffee ├── foo.coffee └── test.html ├── package.json ├── README.md ├── run ├── LICENSE.md ├── coffee ├── util.coffee ├── compilation.coffee ├── lsystem.coffee ├── controls.coffee ├── rendering.coffee └── manager.coffee ├── css ├── animation.css ├── fontello.css ├── forkme.css ├── introjs.min.css ├── lsys.css └── normalize.css ├── sass └── test.scss ├── examples.html ├── ticker_min.json └── index.html /js/.gitignore: -------------------------------------------------------------------------------- 1 | generated 2 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/favicon.ico -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/logo.png -------------------------------------------------------------------------------- /img/logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/logo2.png -------------------------------------------------------------------------------- /img/logo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/logo3.png -------------------------------------------------------------------------------- /img/100x100.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/100x100.gif -------------------------------------------------------------------------------- /img/logo_tr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/logo_tr.png -------------------------------------------------------------------------------- /font/fontello.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/font/fontello.eot -------------------------------------------------------------------------------- /font/fontello.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/font/fontello.ttf -------------------------------------------------------------------------------- /font/fontello.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/font/fontello.woff -------------------------------------------------------------------------------- /img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /img/systems/lsys_amoeba.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_amoeba.png -------------------------------------------------------------------------------- /img/systems/lsys_birds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_birds.png -------------------------------------------------------------------------------- /img/systems/lsys_clover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_clover.png -------------------------------------------------------------------------------- /img/systems/lsys_coral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_coral.png -------------------------------------------------------------------------------- /img/systems/lsys_fire!.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_fire!.png -------------------------------------------------------------------------------- /img/systems/lsys_gears.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_gears.png -------------------------------------------------------------------------------- /img/systems/lsys_gemini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_gemini.png -------------------------------------------------------------------------------- /img/systems/lsys_politic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_politic.png -------------------------------------------------------------------------------- /img/systems/lsys_re-coil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_re-coil.png -------------------------------------------------------------------------------- /img/systems/lsys_samurai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_samurai.png -------------------------------------------------------------------------------- /img/systems/lsys_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_start.png -------------------------------------------------------------------------------- /img/systems/lsys_tornado.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_tornado.png -------------------------------------------------------------------------------- /img/systems/lsys_tree!.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_tree!.png -------------------------------------------------------------------------------- /img/systems/lsys_trigon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_trigon.png -------------------------------------------------------------------------------- /img/systems/lsys_trippy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_trippy.png -------------------------------------------------------------------------------- /img/systems/lsys_wormly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_wormly.png -------------------------------------------------------------------------------- /img/systems/lsys_clockwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_clockwork.png -------------------------------------------------------------------------------- /img/systems/lsys_dandelion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_dandelion.png -------------------------------------------------------------------------------- /img/systems/lsys_flagella.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_flagella.png -------------------------------------------------------------------------------- /img/systems/lsys_flyweight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_flyweight.png -------------------------------------------------------------------------------- /img/systems/lsys_kinetica.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_kinetica.png -------------------------------------------------------------------------------- /img/systems/lsys_leviathon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_leviathon.png -------------------------------------------------------------------------------- /img/systems/lsys_manta_ray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_manta_ray.png -------------------------------------------------------------------------------- /img/systems/lsys_number_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_number_8.png -------------------------------------------------------------------------------- /img/systems/lsys_octosquid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_octosquid.png -------------------------------------------------------------------------------- /img/systems/lsys_pollenate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_pollenate.png -------------------------------------------------------------------------------- /img/systems/lsys_slamurai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_slamurai.png -------------------------------------------------------------------------------- /img/systems/lsys_stardust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_stardust.png -------------------------------------------------------------------------------- /img/systems/lsys_stargaze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_stargaze.png -------------------------------------------------------------------------------- /img/systems/lsys_the_bomb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_the_bomb.png -------------------------------------------------------------------------------- /img/systems/lsys_the_slug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_the_slug.png -------------------------------------------------------------------------------- /img/systems/lsys_trifecta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_trifecta.png -------------------------------------------------------------------------------- /img/systems/lsys_try_force.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_try_force.png -------------------------------------------------------------------------------- /img/systems/lsys_wormhole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_wormhole.png -------------------------------------------------------------------------------- /img/systems/lsys_3d_pyramids.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_3d_pyramids.png -------------------------------------------------------------------------------- /img/systems/lsys_3d_rollers_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_3d_rollers_2.png -------------------------------------------------------------------------------- /img/systems/lsys_angel_flight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_angel_flight.png -------------------------------------------------------------------------------- /img/systems/lsys_brainchild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_brainchild.png -------------------------------------------------------------------------------- /img/systems/lsys_coalescence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_coalescence.png -------------------------------------------------------------------------------- /img/systems/lsys_conswarmity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_conswarmity.png -------------------------------------------------------------------------------- /img/systems/lsys_dance_for_me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_dance_for_me.png -------------------------------------------------------------------------------- /img/systems/lsys_death_spiral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_death_spiral.png -------------------------------------------------------------------------------- /img/systems/lsys_dragonfish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_dragonfish.png -------------------------------------------------------------------------------- /img/systems/lsys_freaky_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_freaky_face.png -------------------------------------------------------------------------------- /img/systems/lsys_heisenberg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_heisenberg.png -------------------------------------------------------------------------------- /img/systems/lsys_holy_shit!.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_holy_shit!.png -------------------------------------------------------------------------------- /img/systems/lsys_house_rules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_house_rules.png -------------------------------------------------------------------------------- /img/systems/lsys_jelly-crab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_jelly-crab.png -------------------------------------------------------------------------------- /img/systems/lsys_johnny_lee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_johnny_lee.png -------------------------------------------------------------------------------- /img/systems/lsys_mandelbutt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_mandelbutt.png -------------------------------------------------------------------------------- /img/systems/lsys_mortal_coil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_mortal_coil.png -------------------------------------------------------------------------------- /img/systems/lsys_ornate_clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_ornate_clock.png -------------------------------------------------------------------------------- /img/systems/lsys_platterstar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_platterstar.png -------------------------------------------------------------------------------- /img/systems/lsys_pulse_engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_pulse_engine.png -------------------------------------------------------------------------------- /img/systems/lsys_seriously_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_seriously_3d.png -------------------------------------------------------------------------------- /img/systems/lsys_shaman_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_shaman_face.png -------------------------------------------------------------------------------- /img/systems/lsys_snapdragon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_snapdragon.png -------------------------------------------------------------------------------- /img/systems/lsys_spin_engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_spin_engine.png -------------------------------------------------------------------------------- /img/systems/lsys_spirocopter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_spirocopter.png -------------------------------------------------------------------------------- /img/systems/lsys_the_triffids.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_the_triffids.png -------------------------------------------------------------------------------- /img/systems/lsys_tree_horse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_tree_horse.png -------------------------------------------------------------------------------- /img/systems/lsys_wigglesaur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_wigglesaur.png -------------------------------------------------------------------------------- /img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /img/systems/lsys_bubble_trouble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_bubble_trouble.png -------------------------------------------------------------------------------- /img/systems/lsys_clockwork_coil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_clockwork_coil.png -------------------------------------------------------------------------------- /img/systems/lsys_crystal_orchid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_crystal_orchid.png -------------------------------------------------------------------------------- /img/systems/lsys_dream_catcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_dream_catcher.png -------------------------------------------------------------------------------- /img/systems/lsys_metamorphosis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_metamorphosis.png -------------------------------------------------------------------------------- /img/systems/lsys_ordered_chaos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_ordered_chaos.png -------------------------------------------------------------------------------- /img/systems/lsys_rorschach_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_rorschach_test.png -------------------------------------------------------------------------------- /img/systems/lsys_snake_charmer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_snake_charmer.png -------------------------------------------------------------------------------- /img/systems/lsys_spindlethrift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_spindlethrift.png -------------------------------------------------------------------------------- /img/systems/lsys_the_DNA_dance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_the_DNA_dance.png -------------------------------------------------------------------------------- /img/systems/lsys_twistmas_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_twistmas_tree.png -------------------------------------------------------------------------------- /img/systems/lsys_twizzlestache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_twizzlestache.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test.css 3 | .idea 4 | Lsys.iml 5 | target 6 | lsys.tar 7 | notes 8 | benchmark/run_data 9 | -------------------------------------------------------------------------------- /bin/mkimg: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | convert $1 -resize 100x100 -gravity center -background transparent -extent 100x100 $1 4 | -------------------------------------------------------------------------------- /img/systems/lsys_I_will_crush_you.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_I_will_crush_you.png -------------------------------------------------------------------------------- /img/systems/lsys_biohazard_angel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_biohazard_angel.png -------------------------------------------------------------------------------- /img/systems/lsys_close_encounters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_close_encounters.png -------------------------------------------------------------------------------- /img/systems/lsys_cthulu's_daughter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_cthulu's_daughter.png -------------------------------------------------------------------------------- /img/systems/lsys_dragon_spirograph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_dragon_spirograph.png -------------------------------------------------------------------------------- /img/systems/lsys_single_3d_blade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_single_3d_blade.png -------------------------------------------------------------------------------- /img/systems/lsys_the_park_at_night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_the_park_at_night.png -------------------------------------------------------------------------------- /benchmark/run_data: -------------------------------------------------------------------------------- 1 | 12 ms,17.2 ms,44.6 ms,128.4 ms, 2 | 12 ms,16.6 ms,42.8 ms,125.2 ms, 3 | 12 ms,16.4 ms,44.2 ms,122 ms, 4 | -------------------------------------------------------------------------------- /img/systems/lsys_3d_tusk___gearspin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_3d_tusk___gearspin.png -------------------------------------------------------------------------------- /img/systems/lsys_choose_your_tunnel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_choose_your_tunnel.png -------------------------------------------------------------------------------- /img/systems/lsys_king_of_the_jungle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_king_of_the_jungle.png -------------------------------------------------------------------------------- /img/systems/lsys_seahorse_moustache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_seahorse_moustache.png -------------------------------------------------------------------------------- /img/systems/lsys_battling_dragon_tails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_battling_dragon_tails.png -------------------------------------------------------------------------------- /img/systems/lsys_needle_in_a_haystack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_needle_in_a_haystack.png -------------------------------------------------------------------------------- /img/systems/lsys_jamiroquai_-_rippletwist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_jamiroquai_-_rippletwist.png -------------------------------------------------------------------------------- /img/systems/lsys_I_mustache_you_a_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_I_mustache_you_a_question.png -------------------------------------------------------------------------------- /img/systems/lsys_the_indomitable_moustachio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_the_indomitable_moustachio.png -------------------------------------------------------------------------------- /img/systems/lsys_beating_heart_(wiggle_mouse).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_beating_heart_(wiggle_mouse).png -------------------------------------------------------------------------------- /img/systems/lsys_helicopter_plant_(drag_left).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_helicopter_plant_(drag_left).png -------------------------------------------------------------------------------- /img/systems/lsys_the_grinch_in_a_christmas_hat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benvan/lsys/HEAD/img/systems/lsys_the_grinch_in_a_christmas_hat.png -------------------------------------------------------------------------------- /benchmark/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./benchmark.coffee 2> /dev/null | grep ms --line-buffered | tee >( tr '\n' ',' >> run_data) 4 | echo >> run_data 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lsys", 3 | "description": "interactive l-system generator", 4 | "author": "Ben van Enckevort | benvan", 5 | "version": "0.1.0", 6 | "dependencies": { 7 | "coffee-script": ">= 1.3.0", 8 | "jitter": ">= 1.1.1", 9 | "node-sass": "3.4.2", 10 | "json-minify": ">= 1.0.0", 11 | "http-server": ">= 0.5.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | interactive l-system generator written in coffeescript 2 | 3 | see it running: http://benvan.co.uk/lsys 4 | 5 | INSTALLING / RUNNING 6 | 7 | ./run - this script requires npm 8 | 9 | If you'd rather do things manually, you'll need to: 10 | - compile coffee/* into js/generated/*.js 11 | - compile sass/*.scss into sass/*.css 12 | 13 | Currently, the classes are not namespaced - so ./run uses the -b flag when invoking coffee-script / jitter. 14 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | npm install 4 | mkdir -p js/generated 5 | 6 | echo running on http://localhost:8000 7 | echo 8 | 9 | function handle_sigint() 10 | { 11 | echo Shutting down... 12 | for proc in `jobs -p` 13 | do 14 | kill $proc 15 | done 16 | } 17 | 18 | trap handle_sigint SIGINT 19 | 20 | (node_modules/http-server/bin/http-server . -p 8000 &> /dev/null) & 21 | 22 | (node_modules/node-sass/bin/node-sass sass/test.scss sass/test.css) & 23 | 24 | (node_modules/jitter/bin/jitter -b coffee js/generated) & 25 | 26 | wait 27 | 28 | -------------------------------------------------------------------------------- /benchmark/benchmark.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env phantomjs 2 | 3 | page = new WebPage() 4 | 5 | # Don't supress console output 6 | page.onConsoleMessage = (msg) -> 7 | console.log msg 8 | 9 | # Terminate when the reporter singals that testing is over. 10 | # We cannot use a callback function for this (because page.evaluate is sandboxed), 11 | # so we have to *observe* the website. 12 | if msg == "done" 13 | phantom.exit() 14 | 15 | page.open "test.html", (status) -> 16 | console.log(status) 17 | if status != "success" 18 | console.log "can't load the address!" 19 | phantom.exit 1 20 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Lsys - an interactive l-system generator 2 | Copyright (C) 2013 Ben van Enckevort 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | -------------------------------------------------------------------------------- /bin/build: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | # compile bits'n'bobs 4 | node_modules/coffee-script/bin/coffee -b -c -o js/generated coffee 5 | node_modules/node-sass/bin/node-sass sass/test.scss sass/test.css 6 | 7 | # pack up resources 8 | echo "Packing resources..." 9 | tar -cf lsys.tar font/* css/*.css sass/*.css favicon.ico img index.html js ticker.json ticker_min.json 10 | 11 | echo "Clearing workspace..." 12 | rm -rf target/lsys 13 | mkdir -p target/lsys 14 | 15 | # unpack 16 | tar -xf lsys.tar -C target/lsys 17 | 18 | # prepare for live 19 | echo "Preparing CDN links..." 20 | sed -e 's#js/jquery-1.8.1.js#http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js#' -i "" target/lsys/index.html 21 | 22 | # clear old tarball 23 | rm lsys.tar 24 | 25 | # repack with appropriate root 26 | echo "Packaging lsys.tar..." 27 | tar -cf lsys.tar -C target lsys 28 | 29 | echo DONE 30 | -------------------------------------------------------------------------------- /js/system-ticker.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | $.fn.ticker = function (location) { 3 | return this.each(function () { 4 | var el = $(this); 5 | 6 | $.getJSON(location, "", function (data) { 7 | el.html(""); 8 | $(data.systems).each(function (i, sys) { 9 | el.append( 10 | $("
  • ") 11 | .addClass("elem") 12 | .append( 13 | $('') 14 | .append( $('
    ') 15 | .append('') 16 | .append('
    ' + LSystem.fromUrl(sys.url).name + '
    ') 17 | )) 18 | ); 19 | }); 20 | }); 21 | 22 | }); 23 | }; 24 | })(jQuery); 25 | -------------------------------------------------------------------------------- /js/jquery.ellipsis.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.fn.ellipsis = function() 3 | { 4 | return this.each(function() 5 | { 6 | var el = $(this); 7 | 8 | if(el.css("overflow") == "hidden") 9 | { 10 | var text = el.html(); 11 | var multiline = el.hasClass('multiline'); 12 | var t = $(this.cloneNode(true)) 13 | .hide() 14 | .css('position', 'absolute') 15 | .css('overflow', 'visible') 16 | .width(multiline ? el.width() : 'auto') 17 | .height(multiline ? 'auto' : el.height()) 18 | ; 19 | 20 | el.after(t); 21 | 22 | function height() { return t.height() > el.height(); }; 23 | function width() { return t.width() > el.width(); }; 24 | 25 | var func = multiline ? height : width; 26 | 27 | while (text.length > 0 && func()) 28 | { 29 | text = text.substr(0, text.length - 1); 30 | t.html(text + "..."); 31 | } 32 | 33 | el.html(t.html()); 34 | t.remove(); 35 | } 36 | }); 37 | }; 38 | })(jQuery); -------------------------------------------------------------------------------- /benchmark/foo.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env phantomjs 2 | 3 | # Runs a Jasmine Suite from an html page 4 | # @page is a PhantomJs page object 5 | # @exit_func is the function to call in order to exit the script 6 | 7 | class PhantomJasmineRunner 8 | constructor: (@page, @exit_func = phantom.exit) -> 9 | @tries = 0 10 | @max_tries = 10 11 | 12 | get_status: -> @page.evaluate(-> console_reporter.status) 13 | 14 | terminate: -> 15 | switch @get_status() 16 | when "success" then @exit_func 0 17 | when "fail" then @exit_func 1 18 | else @exit_func 2 19 | 20 | # Script Begin 21 | if phantom.args.length == 0 22 | console.log "Need a url as the argument" 23 | phantom.exit 1 24 | 25 | page = new WebPage() 26 | 27 | runner = new PhantomJasmineRunner(page) 28 | 29 | # Don't supress console output 30 | page.onConsoleMessage = (msg) -> 31 | console.log msg 32 | 33 | # Terminate when the reporter singals that testing is over. 34 | # We cannot use a callback function for this (because page.evaluate is sandboxed), 35 | # so we have to *observe* the website. 36 | if msg == "ConsoleReporter finished" 37 | runner.terminate() 38 | 39 | address = phantom.args[0] 40 | 41 | page.open address, (status) -> 42 | if status != "success" 43 | console.log "can't load the address!" 44 | phantom.exit 1 45 | 46 | # Now we wait until onConsoleMessage reads the termination signal from the log. 47 | -------------------------------------------------------------------------------- /coffee/util.coffee: -------------------------------------------------------------------------------- 1 | class Util 2 | @log:(x) -> console.log(x) 3 | @control:(name) -> document.getElementById(name) 4 | @value: (name) => parseFloat(Util.stringvalue(name)) 5 | @stringvalue: (name) -> Util.control(name).value 6 | @clone:(x) -> JSON.parse(JSON.stringify(x)) 7 | @toObj:(kvPairs) -> 8 | obj = {} 9 | obj[k] = v for [k,v] in kvPairs 10 | return obj 11 | @map: (obj, fn) -> 12 | result = {} 13 | for key of obj then do -> 14 | result[key] = fn(obj[key], key) 15 | return result 16 | @merge: (a,b,c) -> $.extend(true, a,b,c) 17 | @round: (n,d) -> 18 | pow = Math.pow(10,d) 19 | Math.round(n*pow) / pow 20 | @time: (n,f) -> 21 | f = n if n instanceof Function 22 | s = new Date; f(); (new Date - s) 23 | @openDataUrl: (data, filename) -> 24 | a = document.createElement("a") 25 | a.href = data 26 | a.download=filename 27 | evt = document.createEvent("MouseEvents") 28 | evt.initMouseEvent("click", true, true,window,0,0,0,0,0,true,false,false,false,0,null) 29 | a.dispatchEvent(evt) 30 | 31 | # thanks Brian Nickel http://stackoverflow.com/questions/11163344/update-non-retina-canvas-app-to-retina-display 32 | @enhanceCanvas = (canvas, container) -> 33 | context = canvas.getContext('2d') 34 | ratio = window.devicePixelRatio || 1 35 | width = canvas.width = $(container).width() 36 | height = canvas.height = $(container).height() 37 | 38 | if (ratio > 1) 39 | canvas.width = width * ratio 40 | canvas.height = height * ratio 41 | canvas.style.width = width + "px" 42 | canvas.style.height = height + "px" 43 | context.scale(ratio,ratio) 44 | 45 | @enhanceAndStretchCanviiInContainer = (container) -> 46 | $(container).find('canvas').each(() -> 47 | Util.enhanceCanvas($(this).get(0), container); 48 | ); 49 | -------------------------------------------------------------------------------- /css/animation.css: -------------------------------------------------------------------------------- 1 | /* 2 | Animation example, for spinners 3 | */ 4 | .icon-spin4 { 5 | -moz-animation: spin 2s infinite linear; 6 | -o-animation: spin 2s infinite linear; 7 | -webkit-animation: spin 2s infinite linear; 8 | animation: spin 2s infinite linear; 9 | display: inline-block; 10 | } 11 | @-moz-keyframes spin { 12 | 0% { 13 | -moz-transform: rotate(0deg); 14 | -o-transform: rotate(0deg); 15 | -webkit-transform: rotate(0deg); 16 | transform: rotate(0deg); 17 | } 18 | 19 | 100% { 20 | -moz-transform: rotate(359deg); 21 | -o-transform: rotate(359deg); 22 | -webkit-transform: rotate(359deg); 23 | transform: rotate(359deg); 24 | } 25 | } 26 | @-webkit-keyframes spin { 27 | 0% { 28 | -moz-transform: rotate(0deg); 29 | -o-transform: rotate(0deg); 30 | -webkit-transform: rotate(0deg); 31 | transform: rotate(0deg); 32 | } 33 | 34 | 100% { 35 | -moz-transform: rotate(359deg); 36 | -o-transform: rotate(359deg); 37 | -webkit-transform: rotate(359deg); 38 | transform: rotate(359deg); 39 | } 40 | } 41 | @-o-keyframes spin { 42 | 0% { 43 | -moz-transform: rotate(0deg); 44 | -o-transform: rotate(0deg); 45 | -webkit-transform: rotate(0deg); 46 | transform: rotate(0deg); 47 | } 48 | 49 | 100% { 50 | -moz-transform: rotate(359deg); 51 | -o-transform: rotate(359deg); 52 | -webkit-transform: rotate(359deg); 53 | transform: rotate(359deg); 54 | } 55 | } 56 | @-ms-keyframes spin { 57 | 0% { 58 | -moz-transform: rotate(0deg); 59 | -o-transform: rotate(0deg); 60 | -webkit-transform: rotate(0deg); 61 | transform: rotate(0deg); 62 | } 63 | 64 | 100% { 65 | -moz-transform: rotate(359deg); 66 | -o-transform: rotate(359deg); 67 | -webkit-transform: rotate(359deg); 68 | transform: rotate(359deg); 69 | } 70 | } 71 | @keyframes spin { 72 | 0% { 73 | -moz-transform: rotate(0deg); 74 | -o-transform: rotate(0deg); 75 | -webkit-transform: rotate(0deg); 76 | transform: rotate(0deg); 77 | } 78 | 79 | 100% { 80 | -moz-transform: rotate(359deg); 81 | -o-transform: rotate(359deg); 82 | -webkit-transform: rotate(359deg); 83 | transform: rotate(359deg); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /css/fontello.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'fontello'; 3 | src: url('../font/fontello.eot'); 4 | src: url('../font/fontello.eot#iefix') format('embedded-opentype'), 5 | url('../font/fontello.ttf') format('truetype'), 6 | url('../font/fontello.svg#fontello') format('svg'); 7 | font-weight: normal; 8 | font-style: normal; 9 | } 10 | /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ 11 | /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ 12 | /* 13 | @media screen and (-webkit-min-device-pixel-ratio:0) { 14 | @font-face { 15 | font-family: 'fontello'; 16 | src: url('../font/fontello.svg?33376660#fontello') format('svg'); 17 | } 18 | } 19 | */ 20 | 21 | [class^="icon-"]:before, [class*=" icon-"]:before { 22 | font-family: "fontello"; 23 | font-style: normal; 24 | font-weight: normal; 25 | speak: none; 26 | 27 | display: inline-block; 28 | text-decoration: inherit; 29 | width: 1em; 30 | margin-right: .2em; 31 | text-align: center; 32 | /* opacity: .8; */ 33 | 34 | /* For safety - reset parent styles, that can break glyph codes*/ 35 | font-variant: normal; 36 | text-transform: none; 37 | 38 | /* fix buttons height, for twitter bootstrap */ 39 | line-height: 1em; 40 | 41 | /* Animation center compensation - margins should be symmetric */ 42 | /* remove if not needed */ 43 | margin-left: .2em; 44 | 45 | /* you can be more comfortable with increased icons size */ 46 | /* font-size: 120%; */ 47 | 48 | /* Uncomment for 3D effect */ 49 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ 50 | } 51 | 52 | .icon-help-circled:before { content: '\e800'; } /* '' */ 53 | .icon-trash:before { content: '\e803'; } /* '' */ 54 | .icon-spin4:before { content: '\e806'; } /* '' */ 55 | .icon-twitter:before { content: '\e80b'; } /* '' */ 56 | .icon-facebook:before { content: '\e805'; } /* '' */ 57 | .icon-gplus:before { content: '\e80a'; } /* '' */ 58 | .icon-comment-empty:before { content: '\e809'; } /* '' */ 59 | .icon-help:before { content: '\e802'; } /* '' */ 60 | .icon-export-alt:before { content: '\e804'; } /* '' */ 61 | .icon-download:before { content: '\e801'; } /* '' */ 62 | .icon-link:before { content: '\e808'; } /* '' */ -------------------------------------------------------------------------------- /js/api.js: -------------------------------------------------------------------------------- 1 | var toJson = function(passTo){ 2 | return function(response){ 3 | passTo(jQuery.parseJSON(response.responseText)); 4 | }; 5 | }; 6 | 7 | api = { 8 | user: { 9 | token:{}, 10 | setToken:function(token){ 11 | api.user.token = token; 12 | api.user.name = token.substring(token.indexOf("%")+1,token.length); 13 | $.cookie("token", token); 14 | }, 15 | logout: function(){ 16 | api.token = {}; 17 | $.removeCookie("token"); 18 | }, 19 | login: function (username, password, success, failure) { 20 | $.ajax({ 21 | type:"POST", 22 | url:"http://localhost:9000/login", 23 | data:{ 24 | username: username, 25 | password: password 26 | }, 27 | success:function (data) { 28 | api.user.setToken(data.token); 29 | success(); 30 | }, 31 | dataType:"json" 32 | }).fail(toJson(failure)); 33 | }, 34 | register: function (username, password, email, success, failure) { 35 | $.ajax({ 36 | type:"POST", 37 | url:"http://localhost:9000/register", 38 | data:{ 39 | username: username, 40 | password: password, 41 | email: email 42 | }, 43 | success:function (data) { 44 | api.user.setToken(data.token); 45 | success(); 46 | }, 47 | dataType:"json" 48 | }).fail(toJson(failure)); 49 | } 50 | }, 51 | system: { 52 | all: function () { 53 | $.getJSON("http://localhost:9000/system/all").done(LOG).fail(FAIL); 54 | }, 55 | add: function (name, author, system) { 56 | $.ajax({ 57 | url: "http://localhost:9000/system", 58 | type:"post", 59 | data: { 60 | name: name, 61 | author: author, 62 | system: system 63 | }, 64 | headers:{ 65 | token:api.user.token 66 | }, 67 | success:LOG 68 | }).done(LOG).fail(FAIL); 69 | } 70 | } 71 | }; -------------------------------------------------------------------------------- /js/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Cookie Plugin v1.3.1 3 | * https://github.com/carhartl/jquery-cookie 4 | * 5 | * Copyright 2013 Klaus Hartl 6 | * Released under the MIT license 7 | */ 8 | (function (factory) { 9 | if (typeof define === 'function' && define.amd) { 10 | // AMD. Register as anonymous module. 11 | define(['jquery'], factory); 12 | } else { 13 | // Browser globals. 14 | factory(jQuery); 15 | } 16 | }(function ($) { 17 | 18 | var pluses = /\+/g; 19 | 20 | function raw(s) { 21 | return s; 22 | } 23 | 24 | function decoded(s) { 25 | return decodeURIComponent(s.replace(pluses, ' ')); 26 | } 27 | 28 | function converted(s) { 29 | if (s.indexOf('"') === 0) { 30 | // This is a quoted cookie as according to RFC2068, unescape 31 | s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 32 | } 33 | try { 34 | return config.json ? JSON.parse(s) : s; 35 | } catch(er) {} 36 | } 37 | 38 | var config = $.cookie = function (key, value, options) { 39 | 40 | // write 41 | if (value !== undefined) { 42 | options = $.extend({}, config.defaults, options); 43 | 44 | if (typeof options.expires === 'number') { 45 | var days = options.expires, t = options.expires = new Date(); 46 | t.setDate(t.getDate() + days); 47 | } 48 | 49 | value = config.json ? JSON.stringify(value) : String(value); 50 | 51 | return (document.cookie = [ 52 | config.raw ? key : encodeURIComponent(key), 53 | '=', 54 | config.raw ? value : encodeURIComponent(value), 55 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 56 | options.path ? '; path=' + options.path : '', 57 | options.domain ? '; domain=' + options.domain : '', 58 | options.secure ? '; secure' : '' 59 | ].join('')); 60 | } 61 | 62 | // read 63 | var decode = config.raw ? raw : decoded; 64 | var cookies = document.cookie.split('; '); 65 | var result = key ? undefined : {}; 66 | for (var i = 0, l = cookies.length; i < l; i++) { 67 | var parts = cookies[i].split('='); 68 | var name = decode(parts.shift()); 69 | var cookie = decode(parts.join('=')); 70 | 71 | if (key && key === name) { 72 | result = converted(cookie); 73 | break; 74 | } 75 | 76 | if (!key) { 77 | result[name] = converted(cookie); 78 | } 79 | } 80 | 81 | return result; 82 | }; 83 | 84 | config.defaults = {}; 85 | 86 | $.removeCookie = function (key, options) { 87 | if ($.cookie(key) !== undefined) { 88 | // Must not alter options, thus extending a fresh object... 89 | $.cookie(key, '', $.extend({}, options, { expires: -1 })); 90 | return true; 91 | } 92 | return false; 93 | }; 94 | 95 | })); 96 | -------------------------------------------------------------------------------- /js/lsys-intro.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // This whole file / intro business is one huge hack. I'd go look somewhere else if you're looking for a good time. 4 | 5 | var intro; 6 | // gaaaah. no nice way to hook into buttons on step 1 of tour. 7 | // there's no callback which fires after the template's been rendered. 8 | window.goToStep = function(i){ 9 | intro.goToStep(i); 10 | }; 11 | function mkIntro(){ 12 | var startingLocation = location.hash; 13 | if (intro && !intro.hasQuit) intro.exit(); 14 | var killItWithFire = function(){ intro.hasQuit = true; location.hash = startingLocation; } 15 | intro = introJs() 16 | .oncomplete(killItWithFire) 17 | .onexit(killItWithFire); 18 | var examples = { 19 | "square" : "#?i=1&r=S%20%3A%20F%2BF%2BF%2BF&p.size=100,0&p.angle=90,0&s.size=0.8,1&s.angle=2,1&offsets=0,0,0", 20 | "square-recursive" : "#?i=4&r=S%20%3A%20F%2BS&p.size=100,0&p.angle=90,0&s.size=0.6,1&s.angle=2.8,1&offsets=0,0,0", 21 | "spirograph" : "#?i=50&r=A%20%3A%20%5BS%5D%2BA%0AS%20%3A%20F%2BS&p.size=100,0&p.angle=90,0&s.size=0.6,1&s.angle=2.8,1&offsets=0,0,0", 22 | "serpinski" : "#?i=8&r=A%20%3A%20BF-AF-B%0AB%20%3A%20AF%2BBF%2BA&p.size=1.0352999999999999,0.010817999999999967&p.angle=60,0&s.size=200,1000000&s.angle=200,1000000&offsets=-124,87,30" 23 | }; 24 | var steps = $('#tour li').map(function(){ 25 | var step = $(this); 26 | return { 27 | "element" : step.data('element'), 28 | "intro" : step.html(), 29 | "position" : step.data('position') || "right", 30 | "data" : step.data() 31 | } 32 | }); 33 | 34 | return intro.onbeforechange(function(){ 35 | if (intro._currentStep == undefined){ 36 | intro.goToStep(1); 37 | $('.introjs-tooltipbuttons').hide(); 38 | }else{ 39 | $('.introjs-tooltipbuttons').show(); 40 | } 41 | }).onchange(function(){ 42 | var item = intro._introItems[intro._currentStep]; 43 | var data = item.data; 44 | if (data.example) window.location.hash = examples[data.example]; 45 | if (data.overlay == 'on') $('.introjs-overlay').removeClass('hidden'); 46 | if (data.overlay == 'off') $('.introjs-overlay').addClass('hidden'); 47 | }).setOptions({ 48 | exitOnOverlayClick: true, 49 | tooltipPosition:'right', 50 | showStepNumbers: false, 51 | steps: steps 52 | }); 53 | } 54 | 55 | 56 | $('#helpTrigger').click(function(){ 57 | mkIntro().start(); 58 | return false; 59 | }); 60 | 61 | $('#syntaxTrigger').click(function(){ 62 | mkIntro().start().goToStep(13); 63 | return false; 64 | }); -------------------------------------------------------------------------------- /benchmark/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 |
    9 |
    10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /coffee/compilation.coffee: -------------------------------------------------------------------------------- 1 | NullSystem = new LSystem({},{},{},"",1,"no system") 2 | DefaultSystem = new LSystem({ 3 | size: {value:12.27} 4 | angle: {value:4187.5} 5 | },{},{ size: {value:9} } ,"L : SS\nS : F->[F-Y[S(L]]\nY : [-|F-F+)Y]\n" ,12 ,"click-and-drag-me!" ) 6 | 7 | # ========================================= 8 | class CompiledSystem 9 | constructor: (@system, @elements) -> 10 | 11 | # ========================================= 12 | class SystemCompiler 13 | _halt: false 14 | 15 | halt: -> @_halt = true; 16 | 17 | compile: (system) -> 18 | @_halt = false 19 | CHUNK_SIZE = 400000 20 | def = $.Deferred() 21 | def.notify(0) # zero progress 22 | 23 | textRules = system.rules.split("\n").map (r) -> (r.replace(/\ /g, '')).split(':') 24 | 25 | ruleMap = Util.toObj(textRules) 26 | seed = textRules[0][0] #choose first rule as system initialiser 27 | 28 | removeNonInstructions = (expr) -> expr.split('').filter((e) -> true if (Renderer.prototype.definitions[e])) 29 | 30 | 31 | 32 | # todo: this is absolutely horrifying. Sort it out. 33 | # note to any bypassers - this used to be a single reduce operation, 34 | # then I decided to make compilation interruptible (or I'll be crashing people's browsers...) 35 | # Sigh. 36 | expandChunk = (levelNum,levelExpr, acc, start, processed, count) => 37 | while( processed < count ) 38 | if (@._halt) 39 | def.reject() 40 | return 41 | else if (levelNum == 0) 42 | def.resolve(removeNonInstructions(levelExpr)) 43 | return 44 | remaining = count - processed 45 | reachesEndOfLevel = remaining >= (levelExpr.length - start) 46 | if (reachesEndOfLevel) then remaining = levelExpr.length - start 47 | i = start 48 | end = start + remaining 49 | while ( i < end) 50 | symbol = levelExpr[i] 51 | acc += ruleMap[symbol] || symbol 52 | i++ 53 | processed += remaining 54 | start += remaining 55 | if (reachesEndOfLevel) 56 | levelNum-- 57 | levelExpr = acc 58 | acc = '' 59 | start = 0 60 | 61 | def.notify((system.iterations - levelNum) / system.iterations) 62 | setTimeout(( -> expandChunk(levelNum,levelExpr,acc,start,0,count)),0) 63 | 64 | expandChunk(system.iterations, seed, '', 0,0,CHUNK_SIZE) 65 | return def.promise() 66 | 67 | # ========================================= 68 | class SystemManager 69 | compiler: new SystemCompiler 70 | stagedSystem: null # system pending compilation (replaces active when compiled) 71 | activeSystem: NullSystem 72 | compiledElements: null 73 | 74 | activate: (system) -> 75 | if (@promise and @stagedSystem?.isIsomorphicTo(system)) 76 | @activeSystem.merge(system) 77 | @promise 78 | else if (@promise?.state() == 'pending') 79 | @compiler.halt() 80 | @promise.fail( => @_recompile(system)) 81 | else @_recompile(system) 82 | 83 | 84 | _recompile: (system) -> 85 | @stagedSystem = system 86 | @promise = @compiler.compile(system) 87 | @promise.fail( => @stagedSystem = @activeSystem ) 88 | @promise.pipe( (elements) => 89 | @activeSystem = system 90 | @compiledElements = elements 91 | return elements 92 | ) 93 | 94 | getInstructions: -> @compiledElements 95 | 96 | -------------------------------------------------------------------------------- /coffee/lsystem.coffee: -------------------------------------------------------------------------------- 1 | class Param 2 | @urlPrefix: "p" 3 | constructor:(@name,@value,@growth) -> 4 | toUrlComponent: -> "#{@constructor.urlPrefix}.#{@name}=#{@value},#{@growth}" 5 | @fromUrlComponent: (x) -> 6 | if (x||"").indexOf("#{@urlPrefix}.") != 0 then return undefined 7 | parts = x.split('=') 8 | name = parts[0].substring(2) 9 | vars = parts[1].split(',').map((v) -> parseFloat(v)) 10 | return new @(name,vars[0],vars[1]) 11 | @fromJson: (json) -> new @(json.name, json.value, json.growth) 12 | toJson: -> { 13 | name: @name 14 | value: @value 15 | growth: @growth 16 | } 17 | clone: -> Param.fromJson(@.toJson()) 18 | 19 | class Sensitivity extends Param 20 | @urlPrefix: "s" 21 | constructor:(@name,@value,@growth) -> 22 | 23 | # ========================================= 24 | class Defaults 25 | @offsets: (input) -> Util.merge({ 26 | x: 0 27 | y: 0 28 | rot: 0 29 | }, input) 30 | @params: (input) -> Util.map(Util.merge(Defaults._params(), input), (p,k) -> _.extend(p, {name:k})) 31 | @_params: -> 32 | size: {value:1, growth: 0.01} 33 | angle: {value:1, growth: 0.05} 34 | @sensitivities: (input) -> Util.map(Util.merge(Util.merge(Util.map(Defaults.params(),@_constrain(0,10)), Defaults._sensitivites()), input), (p,k) -> _.extend(p, {name:k})) 35 | @_constrain: (min,max) -> (val) -> Math.max(min,Math.min(max,val)) 36 | @_sensitivites: -> 37 | size: {value: 7.7, growth:7.53} 38 | angle: {value: 7.6, growth:4} 39 | 40 | # ========================================= 41 | class LSystem 42 | constructor: (params, offsets, sensitivities, @rules, @iterations, @name) -> 43 | @params = Util.map(Defaults.params(params), (c) -> Param.fromJson(c)) 44 | @offsets = Defaults.offsets(offsets) 45 | @sensitivities = Util.map(Defaults.sensitivities(sensitivities), (s) -> Sensitivity.fromJson(s)) 46 | 47 | # this is not the most efficient of methods... 48 | clone: -> return LSystem.fromUrl(@toUrl()) 49 | 50 | toUrl: -> 51 | base = "#?i=#{@iterations}&r=#{encodeURIComponent(@rules)}" 52 | mkQueryString = (params) -> _.reduce(params, ((acc,v) -> "#{acc}&#{v.toUrlComponent()}"), "") 53 | params = mkQueryString(@params) 54 | sensitivities = mkQueryString(@sensitivities) 55 | offsets = "&offsets=#{@offsets.x},#{@offsets.y},#{@offsets.rot}" 56 | name = "&name=#{encodeURIComponent(@name)}" 57 | return base+params+sensitivities+offsets+name 58 | 59 | merge: (system) -> 60 | _.extend(@, system) if system 61 | 62 | @fromUrl: (url = location.hash) -> 63 | return null if url == "" 64 | 65 | params = {} 66 | sensitivities = {} 67 | config = {} 68 | _.each(url.substring(2).split("&").map( (x) -> x.split("=")), ([k,v]) -> 69 | param = Param.fromUrlComponent("#{k}=#{v}") 70 | sensitivity = Sensitivity.fromUrlComponent("#{k}=#{v}") 71 | if param then params[param.name] = param.toJson() 72 | else if sensitivity then sensitivities[sensitivity.name] = sensitivity.toJson() 73 | else config[k] = v 74 | config[k] = (parseInt(v) or 0) if k == 'i' 75 | ) 76 | offsets = undefined 77 | if (config.offsets) 78 | o = config.offsets.split(',') 79 | offsets = 80 | x: parseFloat(o[0]) 81 | y: parseFloat(o[1]) 82 | rot: parseFloat(o[2]) 83 | 84 | return new LSystem(params, offsets, sensitivities, decodeURIComponent(config.r), config.i, decodeURIComponent(config.name) or "unnamed") 85 | 86 | isIsomorphicTo: (system) -> if (!system) then false else @rules == system.rules and @iterations == system.iterations 87 | 88 | 89 | # ========================================= 90 | -------------------------------------------------------------------------------- /css/forkme.css: -------------------------------------------------------------------------------- 1 | /* Left will inherit from right (so we don't need to duplicate code */ 2 | .github-fork-ribbon { 3 | /* The right and left lasses determine the side we attach our banner to */ 4 | position: absolute; 5 | 6 | /* Add a bit of padding to give some substance outside the "stitching" */ 7 | padding: 2px 0; 8 | 9 | /* Set the base colour */ 10 | background-color: #a00; 11 | 12 | /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */ 13 | background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.00)), to(rgba(0, 0, 0, 0.15))); 14 | background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); 15 | background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); 16 | background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); 17 | background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); 18 | background-image: linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); 19 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#000000', EndColorStr='#000000'); 20 | 21 | /* Add a drop shadow */ 22 | -webkit-box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5); 23 | box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5); 24 | 25 | z-index: 9999; 26 | } 27 | 28 | .github-fork-ribbon a, 29 | .github-fork-ribbon a:hover { 30 | /* Set the font */ 31 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 32 | font-size: 13px; 33 | font-weight: 700; 34 | color: white; 35 | 36 | /* Set the text properties */ 37 | text-decoration: none; 38 | text-shadow: 0 -1px rgba(0,0,0,0.5); 39 | text-align: center; 40 | 41 | /* Set the geometry. If you fiddle with these you'll also need to tweak the top and right values in #github-fork-ribbon. */ 42 | width: 200px; 43 | line-height: 20px; 44 | 45 | /* Set the layout properties */ 46 | display: inline-block; 47 | padding: 2px 0; 48 | 49 | /* Add "stitching" effect */ 50 | border-width: 1px 0; 51 | border-style: dotted; 52 | border-color: rgba(255,255,255,0.7); 53 | } 54 | 55 | .github-fork-ribbon-wrapper { 56 | width: 150px; 57 | height: 150px; 58 | position: absolute; 59 | overflow: hidden; 60 | top: 0; 61 | z-index: 9999; 62 | } 63 | 64 | .github-fork-ribbon-wrapper.fixed { 65 | position: fixed; 66 | } 67 | 68 | .github-fork-ribbon-wrapper.fm-left { 69 | left: 0; 70 | } 71 | 72 | .github-fork-ribbon-wrapper.right { 73 | right: 0; 74 | } 75 | 76 | .github-fork-ribbon-wrapper.left-bottom { 77 | position: fixed; 78 | top: inherit; 79 | bottom: 0; 80 | left: 0; 81 | } 82 | 83 | .github-fork-ribbon-wrapper.right-bottom { 84 | position: fixed; 85 | top: inherit; 86 | bottom: 0; 87 | right: 0; 88 | } 89 | 90 | .github-fork-ribbon-wrapper.right .github-fork-ribbon { 91 | top: 42px; 92 | right: -43px; 93 | 94 | /* Rotate the banner 45 degrees */ 95 | -webkit-transform: rotate(45deg); 96 | -moz-transform: rotate(45deg); 97 | -o-transform: rotate(45deg); 98 | transform: rotate(45deg); 99 | } 100 | 101 | .github-fork-ribbon-wrapper.fm-left .github-fork-ribbon { 102 | top: 42px; 103 | left: -43px; 104 | 105 | /* Rotate the banner -45 degrees */ 106 | -webkit-transform: rotate(-45deg); 107 | -moz-transform: rotate(-45deg); 108 | -o-transform: rotate(-45deg); 109 | transform: rotate(-45deg); 110 | } 111 | 112 | 113 | .github-fork-ribbon-wrapper.left-bottom .github-fork-ribbon { 114 | top: 80px; 115 | left: -43px; 116 | 117 | /* Rotate the banner -45 degrees */ 118 | -webkit-transform: rotate(45deg); 119 | -moz-transform: rotate(45deg); 120 | -o-transform: rotate(45deg); 121 | transform: rotate(45deg); 122 | } 123 | 124 | .github-fork-ribbon-wrapper.right-bottom .github-fork-ribbon { 125 | top: 80px; 126 | right: -43px; 127 | 128 | /* Rotate the banner -45 degrees */ 129 | -webkit-transform: rotate(-45deg); 130 | -moz-transform: rotate(-45deg); 131 | -o-transform: rotate(-45deg); 132 | transform: rotate(-45deg); 133 | } 134 | -------------------------------------------------------------------------------- /coffee/controls.coffee: -------------------------------------------------------------------------------- 1 | class Point 2 | constructor: (@x, @y) -> 3 | 4 | # =============================== 5 | 6 | class Key 7 | @ctrl: 17 8 | @meta: 91 9 | @shift: 16 10 | @alt: 18 11 | @space: 32 12 | @enter: 13 13 | 14 | # =============================== 15 | 16 | class KeyState 17 | keys:{} 18 | codeToKey: [] #maps int -> keyname for reverse lookup 19 | constructor: -> 20 | for key of Key then do => 21 | @[key] = false 22 | @codeToKey[Key[key]] = key 23 | @createBindings() 24 | 25 | createBindings: -> 26 | setDown = (val) => (ev) => 27 | keyname = @codeToKey[ev.keyCode] 28 | @[keyname] = val if keyname 29 | 30 | document.addEventListener("keydown", setDown(true)) 31 | document.addEventListener("keyup", setDown(false)) 32 | document.addEventListener("mousedown", (evt) => 33 | for key of Key then do => 34 | pressed = evt[key+"Key"] 35 | @[key] = pressed if pressed? 36 | ) 37 | 38 | # =============================== 39 | 40 | class Joystick 41 | enabled:true 42 | active:false 43 | start: new Point(0,0) 44 | now: new Point(0,0) 45 | 46 | constructor: (@container) -> 47 | @createBindings() 48 | 49 | enable: -> @enabled = true ; 50 | disable: -> @enabled = false; 51 | 52 | onActivate: -> # noop unless overriden 53 | onRelease: -> # noop unless overriden 54 | 55 | dx: (sensitivity) -> (@now.x - @start.x) * if (sensitivity) then Math.pow(10,sensitivity-10) else 1 56 | dy: (sensitivity) -> (@now.y - @start.y) * if (sensitivity) then Math.pow(10,sensitivity-10) else 1 57 | 58 | clear: -> #noop for now 59 | draw: -> #noop for now 60 | 61 | center: -> 62 | @start.x = @now.x; @start.y = @now.y 63 | 64 | createBindings: -> 65 | @container.onmousedown = (ev) => 66 | if ev.button == 0 and @enabled 67 | @onActivate() 68 | @active = true 69 | @start = new Point(ev.pageX, ev.pageY) 70 | 71 | document.onmouseup = => 72 | if @enabled 73 | wasActive = @active 74 | @active = false 75 | @onRelease() if wasActive 76 | 77 | document.onmousemove = (ev) => 78 | if @enabled 79 | @now.x = ev.pageX 80 | @now.y = ev.pageY 81 | 82 | document.addEventListener("keydown", () => 83 | if (@enabled and @active) 84 | @center() 85 | @onActivate() 86 | ) 87 | 88 | # =============================== 89 | 90 | # ui binding for a single system variable 91 | class Control 92 | constructor: (@controlkey) -> 93 | tpl: -> "you need to override this" 94 | create: (container) -> 95 | @el = $(@tpl()) 96 | $(container).append(@el) 97 | return @el 98 | 99 | getInput: (param) -> @el.find("[data-param=#{param}]") 100 | getVal: (param) -> parseFloat(@getInput(param).val()) 101 | setVal: (param, value) -> 102 | input = @getInput(param) 103 | if (parseFloat(input.val()) != value and not isNaN(parseFloat(value))) then input.val(value) 104 | 105 | toJson: -> return @update({}) 106 | 107 | sync: (setting) -> 108 | _.chain(setting).omit("name").each( (v,k) => @setVal(k, v)) 109 | return setting 110 | 111 | update: (setting) -> 112 | _.each(@el.find("[data-param]"), (el) => 113 | key = $(el).data("param") 114 | val = @getVal(key) 115 | setting[key] = val if not isNaN(val) 116 | ) 117 | return setting 118 | 119 | class OffsetControl extends Control 120 | tpl: -> """ 121 | 126 | """ 127 | 128 | class ParamControl extends Control 129 | tpl: -> """ 130 | 135 | """ 136 | toJson: -> 137 | dummy = new Param(@controlkey, 0 , 0) 138 | return @update(dummy).toJson() 139 | 140 | class SensitivityControl extends ParamControl 141 | toJson: -> 142 | dummy = new Sensitivity(@controlkey, 0, 0) 143 | return @update(dummy).toJson() 144 | 145 | # container class for all system variables 146 | class Controls 147 | constructor: (params, ControlType) -> 148 | @controls = Util.map(params, (p,k) -> new ControlType(k)) 149 | 150 | create: (container) -> 151 | _.each(@controls, (c) -> c.create(container) ) 152 | 153 | sync: (params) -> 154 | Util.map(params, (p) => @controls[p.name].sync(p) ) 155 | 156 | toJson: -> Util.map(@controls, (c) -> c.toJson()) -------------------------------------------------------------------------------- /css/introjs.min.css: -------------------------------------------------------------------------------- 1 | .introjs-overlay{position:absolute;z-index:999999;background-color:#000;opacity:0;background:-moz-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-webkit-gradient(radial,center center,0px,center center,100%,color-stop(0%,rgba(0,0,0,0.4)),color-stop(100%,rgba(0,0,0,0.9)));background:-webkit-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-o-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-ms-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#66000000',endColorstr='#e6000000',GradientType=1);-ms-filter:"alpha(opacity=50)";filter:alpha(opacity=50);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-fixParent{z-index:auto!important}.introjs-showElement{z-index:9999999!important}.introjs-relativePosition{position:relative}.introjs-helperLayer{position:absolute;z-index:9999998;background-color:#FFF;background-color:rgba(255,255,255,.9);border:1px solid #777;border:1px solid rgba(0,0,0,.5);border-radius:4px;box-shadow:0 2px 15px rgba(0,0,0,.4);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-helperNumberLayer{position:absolute;top:-16px;left:-16px;z-index:9999999999!important;padding:2px;font-family:Arial,verdana,tahoma;font-size:13px;font-weight:bold;color:white;text-align:center;text-shadow:1px 1px 1px rgba(0,0,0,.3);background:#ff3019;background:-webkit-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#ff3019),color-stop(100%,#cf0404));background:-moz-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-ms-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-o-linear-gradient(top,#ff3019 0,#cf0404 100%);background:linear-gradient(to bottom,#ff3019 0,#cf0404 100%);width:20px;height:20px;line-height:20px;border:3px solid white;border-radius:50%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3019',endColorstr='#cf0404',GradientType=0);filter:progid:DXImageTransform.Microsoft.Shadow(direction=135,strength=2,color=ff0000);box-shadow:0 2px 5px rgba(0,0,0,.4)}.introjs-arrow{border:5px solid white;content:'';position:absolute}.introjs-arrow.top{top:-10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.right{right:-10px;top:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:transparent;border-left-color:white}.introjs-arrow.bottom{bottom:-10px;border-top-color:white;border-right-color:transparent;border-bottom-color:transparent;border-left-color:transparent}.introjs-arrow.left{left:-10px;top:10px;border-top-color:transparent;border-right-color:white;border-bottom-color:transparent;border-left-color:transparent}.introjs-tooltip{position:absolute;padding:10px;background-color:white;min-width:200px;max-width:300px;border-radius:3px;box-shadow:0 1px 10px rgba(0,0,0,.4);-webkit-transition:opacity .1s ease-out;-moz-transition:opacity .1s ease-out;-ms-transition:opacity .1s ease-out;-o-transition:opacity .1s ease-out;transition:opacity .1s ease-out}.introjs-tooltipbuttons{text-align:right}.introjs-button{position:relative;overflow:visible;display:inline-block;padding:.3em .8em;border:1px solid #d4d4d4;margin:0;text-decoration:none;text-shadow:1px 1px 0 #fff;font:11px/normal sans-serif;color:#333;white-space:nowrap;cursor:pointer;outline:0;background-color:#ececec;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f4f4f4),to(#ececec));background-image:-moz-linear-gradient(#f4f4f4,#ececec);background-image:-o-linear-gradient(#f4f4f4,#ececec);background-image:linear-gradient(#f4f4f4,#ececec);-webkit-background-clip:padding;-moz-background-clip:padding;-o-background-clip:padding-box;-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em;zoom:1;*display:inline;margin-top:10px}.introjs-button:hover{border-color:#bcbcbc;text-decoration:none;box-shadow:0 1px 1px #e3e3e3}.introjs-button:focus,.introjs-button:active{background-image:-webkit-gradient(linear,0 0,0 100%,from(#ececec),to(#f4f4f4));background-image:-moz-linear-gradient(#ececec,#f4f4f4);background-image:-o-linear-gradient(#ececec,#f4f4f4);background-image:linear-gradient(#ececec,#f4f4f4)}.introjs-button::-moz-focus-inner{padding:0;border:0}.introjs-skipbutton{margin-right:5px;color:#7a7a7a}.introjs-prevbutton{-webkit-border-radius:.2em 0 0 .2em;-moz-border-radius:.2em 0 0 .2em;border-radius:.2em 0 0 .2em;border-right:0}.introjs-nextbutton{-webkit-border-radius:0 .2em .2em 0;-moz-border-radius:0 .2em .2em 0;border-radius:0 .2em .2em 0}.introjs-disabled,.introjs-disabled:hover,.introjs-disabled:focus{color:#9a9a9a;border-color:#d4d4d4;box-shadow:none;cursor:default;background-color:#f4f4f4;background-image:none;text-decoration:none} -------------------------------------------------------------------------------- /font/fontello.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2012 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /coffee/rendering.coffee: -------------------------------------------------------------------------------- 1 | class RenderingContext 2 | initialised:false 3 | state:null 4 | bounding:null 5 | stack:[] 6 | constructor: (@container) -> 7 | 8 | reset: (system) => 9 | @initialised = true 10 | @state = 11 | x: (@container.clientWidth/2)+system.offsets.x 12 | y: (@container.clientHeight/2)+system.offsets.y 13 | orientation: -90 + system.offsets.rot 14 | stepAngle: system.params.angle.value 15 | stepSize: system.params.size.value 16 | color: 0 17 | @bounding = new Bounding 18 | @stack = [] 19 | 20 | # receive gs from renderer. These will change on system change 21 | prepare: (gs) => @gs = gs; @g = gs[0]; 22 | 23 | #================================================================ 24 | 25 | class Bounding 26 | x1: Infinity 27 | y1: Infinity 28 | x2: -Infinity 29 | y2: -Infinity 30 | width: => (@x2-@x1) 31 | height: => (@y2-@y1) 32 | constrain: (x,y) -> 33 | @x1 = Math.max(@x1, 0) 34 | @y1 = Math.max(@y1, 0) 35 | @x2 = Math.min(@x2, x) 36 | @y2 = Math.min(@y2, y) 37 | 38 | #================================================================ 39 | 40 | getG = (c) -> c.getContext('2d') 41 | getColors = (system) -> ["#ffffff","#0044DD","#00DD44","#DD4400"] 42 | 43 | class Renderer 44 | context:null 45 | g:null 46 | stack:[] 47 | isDrawing:false 48 | constructor: (@container) -> 49 | @context = new RenderingContext(container) 50 | 51 | prepare: (system) => 52 | colors = getColors(system) 53 | # ensures numColors canvases available 54 | diff = colors.length - @container.children.length 55 | while (diff-- > 0) 56 | @container.appendChild(document.createElement("canvas")) 57 | canvii = [].slice.apply(@container.children) 58 | Util.enhanceAndStretchCanviiInContainer(@container) 59 | gs = canvii.map(getG) 60 | colors.forEach (c,i) -> gs[i].strokeStyle = c 61 | @context.prepare(gs) 62 | 63 | clearCanvas: => 64 | if (@context.initialised) 65 | b = @context.bounding 66 | p = padding = 5 67 | b.constrain(@container.clientWidth, @container.clientHeight) 68 | @context.gs.forEach (g) -> g.clearRect(b.x1-p, b.y1-p, b.width()+2*p, b.height()+2*p) 69 | 70 | reset: (system) => 71 | @clearCanvas() 72 | @context.reset(system) 73 | 74 | render: (elems, system) => 75 | @isDrawing = true 76 | start = new Date 77 | 78 | this.reset(system) 79 | 80 | @context.gs.forEach (g,i) => 81 | g.lineWidth = 0.218 82 | g.beginPath() 83 | g.moveTo(@context.state.x, @context.state.y) 84 | 85 | #initialise lower-bounds 86 | [s,b] = [@context.state, @context.bounding] 87 | [b.x2,b.y2] = [s.x, s.y] 88 | 89 | #draw 90 | _.each elems, (e) => 91 | @definitions[e](@context.state, system.params, @context, e) 92 | 93 | @context.gs.forEach (g) -> g.stroke() 94 | 95 | 96 | @isDrawing = false 97 | return (new Date - start) 98 | 99 | #this really *really* doesn't belong here.. but it requires a hell of a lot more 100 | #dereferences if I put it anywhere else. Considering it's looked up on the order 101 | #of hundreds of thousands of times, I'm leaving it here for the time being... 102 | definitions: (() -> 103 | [cos,sin,pi,min,max] = [Math.cos, Math.sin, Math.PI,Math.min,Math.max] 104 | len = ang = s = c = 0 105 | # expanded (explicit) for efficiency 106 | cloneState = (c) -> { 107 | x: c.x 108 | y: c.y 109 | orientation: c.orientation 110 | stepAngle: c.stepAngle 111 | stepSize: c.stepSize 112 | color: c.color 113 | } 114 | return { 115 | "F": (state, params, context) -> 116 | 117 | ang = ((state.orientation%360) / 180) * pi #todo - stop storing degrees?! 118 | state.x += cos(ang)*state.stepSize 119 | state.y += sin(ang)*state.stepSize 120 | 121 | bounding = context.bounding 122 | 123 | if (state.x < bounding.x1) 124 | bounding.x1 = state.x 125 | else if (state.x > bounding.x2) 126 | bounding.x2 = state.x 127 | 128 | if (state.y < bounding.y1) 129 | bounding.y1 = state.y 130 | else if (state.y > bounding.y2) 131 | bounding.y2 = state.y 132 | 133 | context.g.lineTo(state.x,state.y) 134 | 135 | "+": (state) -> state.orientation += state.stepAngle 136 | "-": (state) -> state.orientation -= state.stepAngle 137 | "|": (state) -> state.orientation += 180 138 | #todo: push stack changes into RenderingContext class 139 | "[": (state, params, context) -> context.stack.push(cloneState state) 140 | "]": (state, params, context) -> context.state = state = context.stack.pop(); context.g = context.gs[state.color]; context.g.moveTo(state.x,state.y) 141 | "!": (state) -> state.stepAngle *= -1 142 | "(": (state, params) -> state.stepAngle *= (1 - params.angle.growth) 143 | ")": (state, params) -> state.stepAngle *= (1 + params.angle.growth) 144 | "<": (state, params) -> state.stepSize *= (1 + params.size.growth) 145 | ">": (state, params) -> state.stepSize *= (1 - params.size.growth) 146 | "0": (state, params, context, a) -> state.color = a; if (context.g != context.gs[0]) then ( context.g = context.gs[0]; context.g.moveTo(state.x,state.y)) 147 | "1": (state, params, context, a) -> state.color = a; if (context.g != context.gs[1]) then ( context.g = context.gs[1]; context.g.moveTo(state.x,state.y)) 148 | "2": (state, params, context, a) -> state.color = a; if (context.g != context.gs[2]) then ( context.g = context.gs[2]; context.g.moveTo(state.x,state.y)) 149 | "3": (state, params, context, a) -> state.color = a; if (context.g != context.gs[3]) then ( context.g = context.gs[3]; context.g.moveTo(state.x,state.y)) 150 | } 151 | )() 152 | -------------------------------------------------------------------------------- /coffee/manager.coffee: -------------------------------------------------------------------------------- 1 | class InputHandler 2 | snapshot: null # lsystem params as they were was when joystick activated 3 | constructor: (@keystate, @joystick) -> 4 | update: (system) => 5 | return if not @joystick.active 6 | if (@keystate.alt) 7 | system.params.size.value = Util.round(@snapshot.params.size.value + (@joystick.dy(system.sensitivities.size.value)), 2) 8 | system.params.size.growth = Util.round(@snapshot.params.size.growth + @joystick.dx(system.sensitivities.size.growth),6) 9 | else if (@keystate.meta or @keystate.ctrl) 10 | system.offsets.x = @snapshot.offsets.x + @joystick.dx() 11 | system.offsets.y = @snapshot.offsets.y + @joystick.dy() 12 | else 13 | system.params.angle.value = Util.round(system.params.angle.value + @joystick.dx(system.sensitivities.angle.value), 4) 14 | system.params.angle.growth = Util.round(system.params.angle.growth + @joystick.dy(system.sensitivities.angle.growth),9) 15 | 16 | 17 | class AppManager 18 | joystick:null 19 | keystate: null 20 | inputHandler: null 21 | renderer:null 22 | systemManager: null 23 | 24 | constructor: (@container, @controls) -> 25 | @joystick = new Joystick(container) 26 | @keystate = new KeyState 27 | @inputHandler = new InputHandler(@keystate, @joystick) 28 | 29 | @joystick.onRelease = => @syncLocationQuiet() 30 | @joystick.onActivate = => @inputHandler.snapshot = @systemManager.activeSystem.clone() 31 | 32 | @renderer = new Renderer(@container) 33 | 34 | @systemManager = new SystemManager 35 | 36 | @initControls() 37 | @joystick.disable() 38 | 39 | initControls: -> 40 | @createBindings() 41 | @createControls() 42 | 43 | syncLocation: -> location.hash = @systemManager.activeSystem.toUrl() 44 | syncLocationQuiet: -> location.quietSync = true; @syncLocation() 45 | 46 | beforeRecalculate: -> 47 | afterRecalculate: -> 48 | onRecalculateFail: -> 49 | onRecalculateProgress: -> 50 | 51 | prepareContainer: -> @renderer.prepare(@systemManager.activeSystem) 52 | 53 | isRecalculating: -> not @recalculationPromise or @recalculationPromise?.state() == 'pending' 54 | recalculate: (system = @lsystemFromControls()) -> 55 | @beforeRecalculate() 56 | @recalculationPromise = @systemManager.activate(system).progress(@onRecalculateProgress) 57 | @recalculationPromise.done( => 58 | @joystick.enable() 59 | @renderer.prepare(system) 60 | @syncAll(); 61 | @draw() 62 | @afterRecalculate() 63 | ) 64 | @recalculationPromise.fail(@onRecalculateFail) 65 | @recalculationPromise 66 | 67 | lsystemFromControls: -> 68 | return new LSystem( 69 | @paramControls.toJson(), 70 | @offsetControls.toJson(), 71 | @sensitivityControls.toJson(), 72 | $(@controls.rules).val(), 73 | parseInt($(@controls.iterations).val()), 74 | $(@controls.name).val() 75 | ) 76 | 77 | exportToPng: (system = @systemManager.activeSystem) -> 78 | [x,y] = [(@container.clientWidth / 2) + system.offsets.x, (@container.clientHeight / 2) + system.offsets.y] 79 | 80 | b = @renderer.context.bounding 81 | frameWidth = b.width()+30 82 | frameHeight = b.height()+30 83 | container = $('
    ').css({ 84 | "width" : frameWidth, 85 | "height": frameHeight 86 | })[0]; 87 | 88 | r = new Renderer(container) 89 | r.prepare(system) 90 | 91 | r.reset = (system) -> 92 | r.context.reset(system) 93 | r.context.state.x = (x-b.x1+15) 94 | r.context.state.y = (y-b.y1+15) 95 | 96 | @draw(r) 97 | filename = "lsys_"+system.name.replace(/[\ \/]/g,"_") 98 | rootCanvas = container.children[0] 99 | rootContext = rootCanvas.getContext('2d') 100 | [].slice.call(container.children, 1).forEach( (c) -> 101 | rootContext.drawImage(c,0,0,frameWidth,frameHeight) 102 | ) 103 | Util.openDataUrl( rootCanvas.toDataURL("image/png"), filename ) 104 | 105 | start: -> 106 | startingSystem = LSystem.fromUrl() or DefaultSystem 107 | @recalculate(startingSystem) 108 | .fail( => @syncAll(startingSystem) ) 109 | .pipe( => @draw()) 110 | .always(@run) 111 | 112 | run: => 113 | requestAnimationFrame(@run, @container) 114 | @inputHandler.update(@systemManager.activeSystem) 115 | if @joystick.active and not @renderer.isDrawing 116 | @draw() 117 | @joystick.draw() 118 | @syncControls() 119 | 120 | draw: (renderer = @renderer) => 121 | elems = @systemManager.getInstructions() 122 | renderer.render(elems, @systemManager.activeSystem) if elems 123 | 124 | createControls: -> 125 | @paramControls = new Controls(Defaults.params(), ParamControl) 126 | @offsetControls = new OffsetControl(Defaults.offsets()) 127 | @sensitivityControls = new Controls(Defaults.sensitivities(), SensitivityControl) 128 | 129 | @paramControls.create(@controls.params) 130 | @offsetControls.create(@controls.offsets) 131 | @sensitivityControls.create(@controls.sensitivities) 132 | 133 | syncAll: (system = @systemManager.activeSystem) -> 134 | $(@controls.name).val(system.name) 135 | @syncControls(system) 136 | @syncRulesAndIterations(system) 137 | 138 | syncRulesAndIterations: (system = @systemManager.activeSystem) -> 139 | $(@controls.iterations).val(system.iterations) 140 | $(@controls.rules).val(system.rules) 141 | 142 | syncControls: (system = @systemManager.activeSystem) -> 143 | @paramControls.sync(system.params) 144 | @offsetControls.sync(system.offsets) 145 | @sensitivityControls.sync(system.sensitivities) 146 | 147 | createBindings: -> 148 | setClassIf = (onOff, className) => 149 | method = if (onOff) then 'add' else 'remove' 150 | $(@container)["#{method}Class"](className) 151 | 152 | updateCursorType = (ev) => 153 | setClassIf(ev.ctrlKey or ev.metaKey, "moving") 154 | setClassIf(ev.altKey, "resizing") 155 | 156 | document.addEventListener("keydown", (ev) => 157 | updateCursorType(ev) 158 | if ev.keyCode == Key.enter and ev.ctrlKey 159 | @recalculate() 160 | @syncLocation() 161 | return false 162 | if ev.keyCode == Key.enter and ev.shiftKey 163 | @exportToPng() 164 | ) 165 | 166 | document.addEventListener("keyup", updateCursorType) 167 | document.addEventListener("mousedown", updateCursorType) 168 | 169 | window.onhashchange = => 170 | quiet = location.quietSync 171 | location.quietSync = false 172 | if location.hash != "" && !quiet 173 | @recalculate(LSystem.fromUrl()) 174 | 175 | 176 | #=========================================== 177 | -------------------------------------------------------------------------------- /css/lsys.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 4 | font-size: 10pt !important; 5 | line-height: 22px; 6 | background-color: #2F2F2F; 7 | color:#c6c6c6; 8 | } 9 | 10 | a{ 11 | outline: none !important; 12 | } 13 | 14 | #controls label { 15 | display: inline-block; 16 | margin-bottom: 2px; 17 | width: 59px; 18 | padding-left: 7px; 19 | font-size: 9pt; 20 | color: #C6C6C6; 21 | } 22 | 23 | input { 24 | width: 54px; 25 | height: auto !important; 26 | padding: 4px 5px !important; 27 | font-size: 10pt !important; 28 | } 29 | 30 | .row, .col { overflow: hidden; position: absolute; } 31 | .row { left: 0; right: 0; } 32 | .col { top: 0; bottom: 0; } 33 | .scroll-x { overflow-x: auto; } 34 | .scroll-y { overflow-y: auto; } 35 | 36 | .left.col { width: 250px; } 37 | .right.col { left: 250px; right: 0; } 38 | 39 | header.row { height: 55px; top: 0; } 40 | .body.row { top: 60px; bottom: 190px; } 41 | footer.row { height: 181px; bottom: 0; } 42 | 43 | .brand img{ 44 | margin-top: -3px; 45 | margin-right: 2px; 46 | } 47 | 48 | .ellipsis { 49 | white-space: nowrap; 50 | overflow: hidden; 51 | } 52 | 53 | .ellipsis.multiline { 54 | white-space: normal; 55 | } 56 | 57 | .elems{ 58 | height:143px; 59 | overflow-x: scroll; 60 | margin:6px 10px; 61 | padding:0px; 62 | display:block; 63 | white-space:nowrap; 64 | 65 | } 66 | 67 | .elems .elem{ 68 | box-shadow: #222 3px 3px inset; 69 | padding:2px; 70 | border-radius: 4px; 71 | border:1px solid #555; 72 | display: inline-block; 73 | width:110px; 74 | position:relative; 75 | font-size:8pt; 76 | margin:0 3px; 77 | background-color:#121213; 78 | } 79 | 80 | .elems .elem img{ 81 | margin:0 auto; 82 | } 83 | 84 | .elems .elem-label{ 85 | font-size: 8pt; 86 | letter-spacing: 1.8px; 87 | line-height: 15px; 88 | text-align: center; 89 | border-top: 1px solid #555; 90 | margin-top: 1px; 91 | background-color: #334; 92 | color: #ccc; 93 | text-shadow: 1px 1px #222; 94 | border-radius: 2px; 95 | 96 | } 97 | 98 | .elems .elem-author{ 99 | position: absolute; 100 | line-height: 14px; 101 | font-size: 7pt; 102 | top: 0px; 103 | right: 0px; 104 | padding: 0px 5px; 105 | border-radius: 4px; 106 | background-color: #111; 107 | color: #666; 108 | display: inline-block; 109 | border: 1px solid #333; 110 | border-right: none; 111 | border-top: none; 112 | } 113 | 114 | .elems a{ 115 | color:inherit; 116 | } 117 | 118 | .elems .elem .img-holder{ 119 | text-align: center; 120 | } 121 | 122 | #drawingContainer{ 123 | overflow: hidden; 124 | height:100%; 125 | } 126 | 127 | 128 | footer.ticker{ 129 | background-color:#181818; 130 | } 131 | 132 | .ticker-bar{ 133 | font-size:9pt; 134 | padding-left: 20px; 135 | cursor: pointer; 136 | height:25px; 137 | border-radius: 3px 3px 0; 138 | background: -webkit-gradient(linear, left bottom, left top, color-stop(10%, #222), color-stop(100%, #444)); 139 | border: 1px solid #111; 140 | border-bottom:1px solid black; 141 | } 142 | 143 | .ticker-bar:hover{ 144 | background: -webkit-gradient(linear, left bottom, left top, color-stop(10%, #333), color-stop(100%, #555)) !important; 145 | } 146 | 147 | .actions{ 148 | position: absolute; 149 | width: 42px; 150 | 151 | box-shadow: rgba(255,255,255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.4) 1px 1px 4px 0px inset; 152 | 153 | background: -webkit-gradient(linear, left bottom, left top, color-stop(60%, rgba(0,0,0,0)), color-stop(0%, rgba(0,0,0,0.5))); 154 | 155 | background-color: #555; 156 | border-radius: 0 2px 0 4px; 157 | border-bottom:1px solid black; 158 | border-left:1px solid black; 159 | padding: 5px 3px 8px 10px; 160 | top:1px; 161 | right:1px; 162 | 163 | text-shadow: 0 -1px 0 rgba(0,0,0, 0.25); 164 | } 165 | 166 | .system-info { 167 | position: absolute; 168 | width: 350px; 169 | 170 | box-shadow: rgba(255,255,255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.4) 1px 1px 4px 0px inset; 171 | 172 | background: -webkit-gradient(linear, left bottom, left top, color-stop(60%, rgba(0,0,0,0)), color-stop(0%, rgba(0,0,0,0.5))); 173 | 174 | background-color: #5d7580; 175 | border-radius: 2px 0 4px 0; 176 | border-bottom:1px solid black; 177 | border-right:1px solid black; 178 | padding: 5px 15px 8px 10px; 179 | top:1px; 180 | left:1px; 181 | 182 | text-shadow: 0 -1px 0 rgba(0,0,0, 0.25); 183 | 184 | 185 | 186 | } 187 | 188 | .navbar-inverse{ 189 | box-shadow: rgba(255,255,255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.4) 1px 1px 4px 0px inset; 190 | 191 | } 192 | 193 | .system-info.blue{ 194 | background-color: #3a6980; 195 | color: white; 196 | } 197 | 198 | .system-name { 199 | font-size:14pt; 200 | letter-spacing: 2px; 201 | float:left; 202 | 203 | } 204 | 205 | .system-author { 206 | float:right; 207 | color: inherit; 208 | } 209 | 210 | .system-author:hover { 211 | color: #dce9f5; 212 | } 213 | 214 | .modal{ 215 | background-color:#2F2F2F; 216 | border: 1px solid rgba(100, 100, 100, 0.7); 217 | } 218 | 219 | .modal-header{ 220 | color:#ddd; 221 | text-shadow: 1px 2px 2px #111; 222 | } 223 | 224 | 225 | 226 | .close{ 227 | color: #ddd; 228 | text-shadow: 0 1px 0 #000; 229 | } 230 | 231 | .close:hover{ 232 | color:#fff; 233 | } 234 | 235 | :focus{ 236 | outline: none; 237 | } 238 | 239 | .pad, textarea, input[type="text"], input[type="password"] { 240 | -ms-border-radius: 4px; 241 | border-radius: 4px; 242 | padding:5px; 243 | background: #202020; 244 | color: #ccc; 245 | border-color: #131313; 246 | box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 247 | position: relative; 248 | } 249 | 250 | textarea { 251 | width: 200px; 252 | padding:15px 16px; 253 | } 254 | 255 | .drawing-pad{ 256 | -ms-border-radius: 4px; 257 | border-radius: 4px; 258 | padding:5px; 259 | background: #202020; 260 | color: #ccc; 261 | border-color: #131313; 262 | box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 263 | margin: 0px 8px; 264 | position: absolute; 265 | top: 0px; 266 | bottom: 0; 267 | left: 0; 268 | right: 5px; 269 | } 270 | 271 | .btn-go, .btn-go:active{ 272 | box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0,0,0, 0.5) 0 -1px 0; 273 | } 274 | 275 | .btn.btn-inverse{ 276 | color:#ddd; 277 | border-color:#222222 #222222 #000000; 278 | } 279 | 280 | .navbar-text{ 281 | color:#ddd; 282 | font-weight:bold; 283 | padding: 1px 15px; 284 | } 285 | 286 | .control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline{ 287 | color:#e94a58; 288 | } 289 | 290 | 291 | .drawing-pad canvas { 292 | cursor:crosshair; 293 | } 294 | 295 | #syntaxModal table th, #syntaxModal table td{ 296 | border-color:#3a3a3a; 297 | } -------------------------------------------------------------------------------- /css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v2.0.1 | MIT License | git.io/normalize */ 2 | 3 | /* ========================================================================== 4 | HTML5 display definitions 5 | ========================================================================== */ 6 | 7 | /* 8 | * Corrects `block` display not defined in IE 8/9. 9 | */ 10 | 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | hgroup, 19 | nav, 20 | section, 21 | summary { 22 | display: block; 23 | } 24 | 25 | /* 26 | * Corrects `inline-block` display not defined in IE 8/9. 27 | */ 28 | 29 | audio, 30 | canvas, 31 | video { 32 | display: inline-block; 33 | } 34 | 35 | /* 36 | * Prevents modern browsers from displaying `audio` without controls. 37 | * Remove excess height in iOS 5 devices. 38 | */ 39 | 40 | audio:not([controls]) { 41 | display: none; 42 | height: 0; 43 | } 44 | 45 | /* 46 | * Addresses styling for `hidden` attribute not present in IE 8/9. 47 | */ 48 | 49 | [hidden] { 50 | display: none; 51 | } 52 | 53 | /* ========================================================================== 54 | Base 55 | ========================================================================== */ 56 | 57 | /* 58 | * 1. Sets default font family to sans-serif. 59 | * 2. Prevents iOS text size adjust after orientation change, without disabling 60 | * user zoom. 61 | */ 62 | 63 | html { 64 | font-family: sans-serif; /* 1 */ 65 | -webkit-text-size-adjust: 100%; /* 2 */ 66 | -ms-text-size-adjust: 100%; /* 2 */ 67 | } 68 | 69 | /* 70 | * Removes default margin. 71 | */ 72 | 73 | body { 74 | margin: 0; 75 | } 76 | 77 | /* ========================================================================== 78 | Links 79 | ========================================================================== */ 80 | 81 | /* 82 | * Addresses `outline` inconsistency between Chrome and other browsers. 83 | */ 84 | 85 | a:focus { 86 | outline: thin dotted; 87 | } 88 | 89 | /* 90 | * Improves readability when focused and also mouse hovered in all browsers. 91 | */ 92 | 93 | a:active, 94 | a:hover { 95 | outline: 0; 96 | } 97 | 98 | /* ========================================================================== 99 | Typography 100 | ========================================================================== */ 101 | 102 | /* 103 | * Addresses `h1` font sizes within `section` and `article` in Firefox 4+, 104 | * Safari 5, and Chrome. 105 | */ 106 | 107 | h1 { 108 | font-size: 2em; 109 | } 110 | 111 | /* 112 | * Addresses styling not present in IE 8/9, Safari 5, and Chrome. 113 | */ 114 | 115 | abbr[title] { 116 | border-bottom: 1px dotted; 117 | } 118 | 119 | /* 120 | * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome. 121 | */ 122 | 123 | b, 124 | strong { 125 | font-weight: bold; 126 | } 127 | 128 | /* 129 | * Addresses styling not present in Safari 5 and Chrome. 130 | */ 131 | 132 | dfn { 133 | font-style: italic; 134 | } 135 | 136 | /* 137 | * Addresses styling not present in IE 8/9. 138 | */ 139 | 140 | mark { 141 | background: #ff0; 142 | color: #000; 143 | } 144 | 145 | 146 | /* 147 | * Corrects font family set oddly in Safari 5 and Chrome. 148 | */ 149 | 150 | code, 151 | kbd, 152 | pre, 153 | samp { 154 | font-family: monospace, serif; 155 | font-size: 1em; 156 | } 157 | 158 | /* 159 | * Improves readability of pre-formatted text in all browsers. 160 | */ 161 | 162 | pre { 163 | white-space: pre; 164 | white-space: pre-wrap; 165 | word-wrap: break-word; 166 | } 167 | 168 | /* 169 | * Sets consistent quote types. 170 | */ 171 | 172 | q { 173 | quotes: "\201C" "\201D" "\2018" "\2019"; 174 | } 175 | 176 | /* 177 | * Addresses inconsistent and variable font size in all browsers. 178 | */ 179 | 180 | small { 181 | font-size: 80%; 182 | } 183 | 184 | /* 185 | * Prevents `sub` and `sup` affecting `line-height` in all browsers. 186 | */ 187 | 188 | sub, 189 | sup { 190 | font-size: 75%; 191 | line-height: 0; 192 | position: relative; 193 | vertical-align: baseline; 194 | } 195 | 196 | sup { 197 | top: -0.5em; 198 | } 199 | 200 | sub { 201 | bottom: -0.25em; 202 | } 203 | 204 | /* ========================================================================== 205 | Embedded content 206 | ========================================================================== */ 207 | 208 | /* 209 | * Removes border when inside `a` element in IE 8/9. 210 | */ 211 | 212 | img { 213 | border: 0; 214 | } 215 | 216 | /* 217 | * Corrects overflow displayed oddly in IE 9. 218 | */ 219 | 220 | svg:not(:root) { 221 | overflow: hidden; 222 | } 223 | 224 | /* ========================================================================== 225 | Figures 226 | ========================================================================== */ 227 | 228 | /* 229 | * Addresses margin not present in IE 8/9 and Safari 5. 230 | */ 231 | 232 | figure { 233 | margin: 0; 234 | } 235 | 236 | /* ========================================================================== 237 | Forms 238 | ========================================================================== */ 239 | 240 | /* 241 | * Define consistent border, margin, and padding. 242 | */ 243 | 244 | fieldset { 245 | border: 1px solid #c0c0c0; 246 | margin: 0 2px; 247 | padding: 0.35em 0.625em 0.75em; 248 | } 249 | 250 | /* 251 | * 1. Corrects color not being inherited in IE 8/9. 252 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 253 | */ 254 | 255 | legend { 256 | border: 0; /* 1 */ 257 | padding: 0; /* 2 */ 258 | } 259 | 260 | /* 261 | * 1. Corrects font family not being inherited in all browsers. 262 | * 2. Corrects font size not being inherited in all browsers. 263 | * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome 264 | */ 265 | 266 | button, 267 | input, 268 | select, 269 | textarea { 270 | font-family: inherit; /* 1 */ 271 | font-size: 100%; /* 2 */ 272 | margin: 0; /* 3 */ 273 | } 274 | 275 | /* 276 | * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in 277 | * the UA stylesheet. 278 | */ 279 | 280 | button, 281 | input { 282 | line-height: normal; 283 | } 284 | 285 | /* 286 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 287 | * and `video` controls. 288 | * 2. Corrects inability to style clickable `input` types in iOS. 289 | * 3. Improves usability and consistency of cursor style between image-type 290 | * `input` and others. 291 | */ 292 | 293 | button, 294 | html input[type="button"], /* 1 */ 295 | input[type="reset"], 296 | input[type="submit"] { 297 | -webkit-appearance: button; /* 2 */ 298 | cursor: pointer; /* 3 */ 299 | } 300 | 301 | /* 302 | * Re-set default cursor for disabled elements. 303 | */ 304 | 305 | button[disabled], 306 | input[disabled] { 307 | cursor: default; 308 | } 309 | 310 | /* 311 | * 1. Addresses box sizing set to `content-box` in IE 8/9. 312 | * 2. Removes excess padding in IE 8/9. 313 | */ 314 | 315 | input[type="checkbox"], 316 | input[type="radio"] { 317 | box-sizing: border-box; /* 1 */ 318 | padding: 0; /* 2 */ 319 | } 320 | 321 | /* 322 | * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome. 323 | * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome 324 | * (include `-moz` to future-proof). 325 | */ 326 | 327 | input[type="search"] { 328 | -webkit-appearance: textfield; /* 1 */ 329 | -moz-box-sizing: content-box; 330 | -webkit-box-sizing: content-box; /* 2 */ 331 | box-sizing: content-box; 332 | } 333 | 334 | /* 335 | * Removes inner padding and search cancel button in Safari 5 and Chrome 336 | * on OS X. 337 | */ 338 | 339 | input[type="search"]::-webkit-search-cancel-button, 340 | input[type="search"]::-webkit-search-decoration { 341 | /* -webkit-appearance: none;*/ 342 | } 343 | 344 | /* 345 | * Removes inner padding and border in Firefox 4+. 346 | */ 347 | 348 | button::-moz-focus-inner, 349 | input::-moz-focus-inner { 350 | border: 0; 351 | padding: 0; 352 | } 353 | 354 | /* 355 | * 1. Removes default vertical scrollbar in IE 8/9. 356 | * 2. Improves readability and alignment in all browsers. 357 | */ 358 | 359 | textarea { 360 | overflow: auto; /* 1 */ 361 | vertical-align: top; /* 2 */ 362 | } 363 | 364 | /* ========================================================================== 365 | Tables 366 | ========================================================================== */ 367 | 368 | /* 369 | * Remove most spacing between table cells. 370 | */ 371 | 372 | table { 373 | border-collapse: collapse; 374 | border-spacing: 0; 375 | } 376 | -------------------------------------------------------------------------------- /js/intro.min.js: -------------------------------------------------------------------------------- 1 | (function(h,f){"object"===typeof exports?f(exports):"function"===typeof define&&define.amd?define(["exports"],f):f(h)})(this,function(h){function f(a){this._targetElement=a;this._options={nextLabel:"Next →",prevLabel:"← Back",skipLabel:"Skip",doneLabel:"Done",tooltipPosition:"bottom",exitOnEsc:!0,exitOnOverlayClick:!0,showStepNumbers:!0}}function n(){"undefined"!==typeof this._introBeforeChangeCallback&&this._introBeforeChangeCallback.call(this,this._targetElement);"undefined"===typeof this._currentStep? 2 | this._currentStep=0:++this._currentStep;this._introItems.length<=this._currentStep?("function"===typeof this._introCompleteCallback&&this._introCompleteCallback.call(this),m.call(this,this._targetElement)):s.call(this,this._introItems[this._currentStep])}function t(){if(0===this._currentStep)return!1;"undefined"!==typeof this._introBeforeChangeCallback&&this._introBeforeChangeCallback.call(this,this._targetElement);s.call(this,this._introItems[--this._currentStep])}function m(a){var b=a.querySelector(".introjs-overlay"); 3 | b.style.opacity=0;setTimeout(function(){b.parentNode&&b.parentNode.removeChild(b)},500);(a=a.querySelector(".introjs-helperLayer"))&&a.parentNode.removeChild(a);if(a=document.querySelector(".introjs-showElement"))a.className=a.className.replace(/introjs-[a-zA-Z]+/g,"").replace(/^\s+|\s+$/g,"");if((a=document.querySelectorAll(".introjs-fixParent"))&&0'+a.intro+'
    ';this._options.showStepNumbers&&(b=document.createElement("span"),b.className="introjs-helperNumberLayer",b.innerHTML=a.step,e.appendChild(b));k.appendChild(d);e.appendChild(k);j=document.createElement("a"); 9 | j.onclick=function(){c._introItems.length-1!=c._currentStep&&n.call(c)};j.href="javascript:void(0);";j.innerHTML=this._options.nextLabel;b=document.createElement("a");b.onclick=function(){0!=c._currentStep&&t.call(c)};b.href="javascript:void(0);";b.innerHTML=this._options.prevLabel;e=document.createElement("a");e.className="introjs-button introjs-skipbutton";e.href="javascript:void(0);";e.innerHTML=this._options.skipLabel;e.onclick=function(){c._introItems.length-1==c._currentStep&&"function"===typeof c._introCompleteCallback&& 10 | c._introCompleteCallback.call(c);c._introItems.length-1!=c._currentStep&&"function"===typeof c._introExitCallback&&c._introExitCallback.call(c);m.call(c,c._targetElement)};var h=k.querySelector(".introjs-tooltipbuttons");h.appendChild(e);h.appendChild(b);h.appendChild(j);u.call(c,a.element,k,d)}0==this._currentStep?(b.className="introjs-button introjs-prevbutton introjs-disabled",j.className="introjs-button introjs-nextbutton",e.innerHTML=this._options.skipLabel):this._introItems.length-1==this._currentStep? 11 | (e.innerHTML=this._options.doneLabel,b.className="introjs-button introjs-prevbutton",j.className="introjs-button introjs-nextbutton introjs-disabled"):(b.className="introjs-button introjs-prevbutton",j.className="introjs-button introjs-nextbutton",e.innerHTML=this._options.skipLabel);j.focus();a.element.className+=" introjs-showElement";e=v(a.element,"position");"absolute"!==e&&"relative"!==e&&(a.element.className+=" introjs-relativePosition");for(e=a.element.parentNode;null!=e&&"body"!==e.tagName.toLowerCase();)b= 12 | v(e,"z-index"),/[0-9]+/.test(b)&&(e.className+=" introjs-fixParent"),e=e.parentNode;e=a.element.getBoundingClientRect();0<=e.top&&0<=e.left&&e.bottom+80<=window.innerHeight&&e.right<=window.innerWidth||(b=a.element.getBoundingClientRect(),e=b.bottom-(b.bottom-b.top),j=b.bottom,b=void 0!=window.innerWidth?window.innerHeight:document.documentElement.clientHeight,b=j-b,0>e?window.scrollBy(0,e-30):window.scrollBy(0,b+100))}function v(a,b){var c="";a.currentStyle?c=a.currentStyle[b]:document.defaultView&& 13 | document.defaultView.getComputedStyle&&(c=document.defaultView.getComputedStyle(a,null).getPropertyValue(b));return c.toLowerCase?c.toLowerCase():c}function x(a){var b=document.createElement("div"),c="",d=this;b.className="introjs-overlay";if("body"===a.tagName.toLowerCase())c+="top: 0;bottom: 0; left: 0;right: 0;position: fixed;",b.setAttribute("style",c);else{var g=l(a);g&&(c+="width: "+g.width+"px; height:"+g.height+"px; top:"+g.top+"px;left: "+g.left+"px;",b.setAttribute("style",c))}a.appendChild(b); 14 | b.onclick=function(){!0==d._options.exitOnOverlayClick&&m.call(d,a);void 0!=d._introExitCallback&&d._introExitCallback.call(d)};setTimeout(function(){c+="opacity: .8;";b.setAttribute("style",c)},10);return!0}function l(a){var b={};b.width=a.offsetWidth;b.height=a.offsetHeight;for(var c=0,d=0;a&&!isNaN(a.offsetLeft)&&!isNaN(a.offsetTop);)c+=a.offsetLeft,d+=a.offsetTop,a=a.offsetParent;b.top=d;b.left=c;return b}var r=function(a){if("object"===typeof a)return new f(a);if("string"===typeof a){if(a=document.querySelector(a))return new f(a); 15 | throw Error("There is no element with given selector.");}return new f(document.body)};r.version="0.4.0";r.fn=f.prototype={clone:function(){return new f(this)},setOption:function(a,b){this._options[a]=b;return this},setOptions:function(a){var b=this._options,c={},d;for(d in b)c[d]=b[d];for(d in a)c[d]=a[d];this._options=c;return this},start:function(){a:{var a=this._targetElement,b=[],c=this;if(this._options.steps)for(var d=[],g=0,d=this._options.steps.length;gd.length)break a;g=0;for(f=d.length;g= 0) { 189 | oldLink.parentNode.removeChild(oldLink); 190 | delete oldLinkElements[url]; 191 | setTimeout(function () { 192 | html.className = html.className.replace(/\s*livejs\-loading/gi, ''); 193 | }, 100); 194 | } 195 | } catch (e) { 196 | pending++; 197 | } 198 | if (pending) setTimeout(Live.removeoldLinkElements, 50); 199 | } 200 | }, 201 | 202 | // performs a HEAD request and passes the header info to the given callback 203 | getHead: function (url, callback) { 204 | pendingRequests[url] = true; 205 | var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XmlHttp"); 206 | xhr.open("HEAD", url, true); 207 | xhr.onreadystatechange = function () { 208 | delete pendingRequests[url]; 209 | if (xhr.readyState == 4 && xhr.status != 304) { 210 | xhr.getAllResponseHeaders(); 211 | var info = {}; 212 | for (var h in headers) { 213 | var value = xhr.getResponseHeader(h); 214 | // adjust the simple Etag variant to match on its significant part 215 | if (h.toLowerCase() == "etag" && value) value = value.replace(/^W\//, ''); 216 | if (h.toLowerCase() == "content-type" && value) value = value.replace(/^(.*?);.*?$/i, "$1"); 217 | info[h] = value; 218 | } 219 | callback(url, info); 220 | } 221 | } 222 | xhr.send(); 223 | } 224 | }; 225 | 226 | // start listening 227 | if (document.location.protocol != "file:") { 228 | if (!window.liveJsLoaded) 229 | Live.heartbeat(); 230 | 231 | window.liveJsLoaded = true; 232 | } 233 | else if (window.console) 234 | console.log("Live.js doesn't support the file protocol. It needs http."); 235 | })(); 236 | -------------------------------------------------------------------------------- /sass/test.scss: -------------------------------------------------------------------------------- 1 | $menu-color: #333; 2 | $top:0; 3 | $left:228px; 4 | $bottom:240px; 5 | 6 | @mixin scrollbar{ 7 | &::-webkit-scrollbar{width:4px;height:4px;} 8 | &::-webkit-scrollbar-button:start:decrement, &::-webkit-scrollbar-button:end:increment{ display:block;height:2px;background-color: #232323; } 9 | &::-webkit-scrollbar-track-piece{ background-color: #282828;-webkit-border-radius:0;-webkit-border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px; } 10 | &::-webkit-scrollbar-thumb:vertical{ height:5px;background-color: #6d6d6d;-webkit-border-radius:4px; } 11 | &::-webkit-scrollbar-thumb:horizontal{ width:5px;background-color:#999;-webkit-border-radius:4px; } 12 | } 13 | 14 | div { 15 | -webkit-touch-callout: none; 16 | -webkit-user-select: none; 17 | -khtml-user-select: none; 18 | -moz-user-select: moz-none; 19 | -ms-user-select: none; 20 | user-select: none; 21 | } 22 | 23 | #helpTrigger{ 24 | background-color: rgb(163, 7, 7); 25 | color: rgb(236, 236, 236); 26 | border-color: rgb(202, 202, 202); 27 | text-shadow: 1px 1px black; 28 | } 29 | 30 | .introjs-tooltip{ max-width: 350px; } 31 | .introjs-tooltip, .introjs-helperLayer{ 32 | color: #e8e8e8; 33 | background-color: rgb(70, 71, 77); 34 | border: 1px solid #b2b2b2; 35 | p a{ 36 | color:rgb(92, 190, 228); 37 | } 38 | } 39 | .introjs-helperLayer{ 40 | color: #e8e8e8; 41 | background-color: rgba(94, 97, 111, 0.51) 42 | } 43 | .introjs-overlay.hidden { 44 | display: none; 45 | } 46 | .introjs-overlay{ 47 | opacity: 0.3 !important; 48 | } 49 | .introjs-button.wide{ 50 | text-align: center; 51 | width:100% - 8; 52 | } 53 | 54 | .table{ 55 | //font-family:monospace; 56 | width:350px; 57 | tr{ border-top:1px solid #747474;} 58 | th{ text-align: left; } 59 | } 60 | 61 | html{ 62 | overflow:hidden; 63 | } 64 | body{ 65 | position: absolute; 66 | top: 0; 67 | bottom: 0; 68 | left: 0; 69 | right: 0; 70 | font-family:helvetica; 71 | color:#aaa; 72 | text-shadow: 0.1em 0.1em #222; 73 | letter-spacing: 1px; 74 | font-size:8pt; 75 | } 76 | 77 | input:focus, 78 | select:focus, 79 | textarea:focus, 80 | button:focus { 81 | outline: none; 82 | } 83 | 84 | ul{ 85 | list-style-type: none; 86 | padding:0; 87 | margin:0; 88 | } 89 | li{ 90 | display:inline-block; 91 | padding: 0; 92 | } 93 | 94 | .header{ 95 | height:50px; 96 | background-color: #1b1b1b; 97 | border-bottom:1px solid #545454; 98 | background-image:-webkit-linear-gradient(top, #222222, #111111); 99 | box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); 100 | -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); 101 | .actions{ 102 | padding-top:13px; 103 | padding-right:11px; 104 | a{ padding:2px 1px 1px 1px; } 105 | } 106 | a.site{ 107 | font-family:monospace; 108 | padding-left:10px; 109 | padding-top:4px; 110 | color: #dbdbdb; 111 | font-size:12pt; 112 | font-weight:bold; 113 | text-decoration: none; 114 | display:block; 115 | img{ 116 | width:40px; 117 | height:40px; 118 | float:left; 119 | } 120 | span{ 121 | margin-left:10px; 122 | line-height:42px; 123 | } 124 | } 125 | } 126 | 127 | .container-left{ 128 | bottom: 0; 129 | cursor: default; 130 | background-color:$menu-color; 131 | left: 0; 132 | padding: 0 0 0 0px; 133 | position: absolute; 134 | border-right:1px solid #555; 135 | top: $top; 136 | width: $left; 137 | } 138 | 139 | .container-right{ 140 | bottom: $bottom; 141 | left: $left+1; 142 | margin: 0; 143 | padding: 0; 144 | position: absolute; 145 | right: 0; 146 | top: $top; 147 | background-color: #1d1f20; 148 | } 149 | .container-bottom{ 150 | position:absolute; 151 | padding:0; 152 | bottom:0; 153 | left:$left+1; 154 | right:0; 155 | height:$bottom - 1; 156 | border-top:1px solid #666; 157 | background-color:#222; 158 | .fade{ 159 | position:absolute; 160 | right:0; bottom:0; left:0; 161 | height:30px; /* adjust it to your needs */ 162 | background: linear-gradient(to bottom, rgba(34, 34, 34, 0) 0%, rgb(34,34,34) 70%) 163 | } 164 | } 165 | .top{ 166 | position:absolute; 167 | top:0; 168 | right:0; 169 | left:0; 170 | height:$top - 1; 171 | background-color: #111115; 172 | border-bottom:1px solid #3f3f3f; 173 | } 174 | 175 | .controls{ 176 | @include scrollbar; 177 | font-size:9pt; 178 | position:absolute; 179 | top:51px; 180 | bottom:0; 181 | right:1px; 182 | overflow:hidden; 183 | overflow-y:auto; 184 | 185 | input[type=text], textarea{ 186 | font-family:monospace; 187 | color:#bbb; 188 | border-radius:2px; 189 | border:1px solid #1d1d1d; 190 | background-color: #42474a; 191 | font-size:9pt; 192 | padding:3px 5px; 193 | } 194 | input[type=text]{ 195 | text-align: right; 196 | } 197 | 198 | 199 | &.validation-enabled{ 200 | input:invalid{ 201 | border-color:rgb(219, 43, 43); 202 | background-color:rgb(207, 169, 176); 203 | color:black; 204 | } 205 | } 206 | 207 | li{ 208 | display:inline-block; 209 | &.section{ 210 | background-color: #27292c; 211 | width:100%; 212 | padding:4px 0px; 213 | margin-top:6px; 214 | margin-bottom:5px; 215 | border-bottom:1px solid #464646; 216 | border-top:1px solid #191919; 217 | text-align: center; 218 | i{ 219 | position:absolute; 220 | right:0; 221 | &:hover{ 222 | border-color: #aeaeae; 223 | color: #cecece; 224 | } 225 | } 226 | } 227 | &.split{ 228 | display:block; 229 | width:100%; 230 | border-bottom: 1px solid #464646; 231 | border-top: 1px solid #202626; 232 | margin-top:5px; 233 | margin-bottom:5px; 234 | } 235 | &.group{ 236 | margin-left:4px; 237 | } 238 | } 239 | ul.control-row{ 240 | padding:1px 0px 0px 0px; 241 | 242 | input{ 243 | width:60px; 244 | margin:0; 245 | } 246 | textarea{ 247 | width:132px; 248 | } 249 | &.half input{ 250 | margin-left:72px; 251 | } 252 | &.single input{ 253 | width:134px; 254 | } 255 | li.label { 256 | width:64px; 257 | padding-left:8px; 258 | } 259 | } 260 | ul.labels{ 261 | li{ 262 | border:1px solid #222222; 263 | border-bottom:none; 264 | border-radius:4px 4px 0px 0; 265 | width:65px; 266 | text-align:right; 267 | font-size:7.5pt; 268 | padding-bottom:4px; 269 | padding-top:1px; 270 | padding-right:5px; 271 | background-color: #6d6e70; 272 | color: #d7d7d7; 273 | } 274 | &.pair li:first-child{ 275 | margin-left:72px; 276 | margin-right:0px; 277 | } 278 | } 279 | .recalculate{ 280 | text-align: center; 281 | padding-top:5px; 282 | button{ 283 | border:1px solid #787878; 284 | background-color: #2f3639; 285 | color: #ececec; 286 | font-size:11pt; 287 | text-shadow: 0.1em 0.1em #222; 288 | padding:8px; 289 | width:100%; 290 | margin:6px 0px; 291 | position:relative; 292 | &:hover{ background-color: #3b4346; } 293 | &:active{ background-color: #1a2023; } 294 | 295 | .layer{ 296 | position: absolute; 297 | top:0;bottom:0;right:0;left:0; 298 | } 299 | .sheen{ box-shadow:inset 0px 15px 0 rgba(255, 255, 255, 0.1); } 300 | .progress{ display:none; background-color: rgba(102, 155, 230, 0.39); } 301 | 302 | .text-cancel { position:relative; display:none; } 303 | .text-recalculate{ position:relative; display:block; } 304 | &.recalculating { 305 | .text-cancel { display:block; } 306 | .text-recalculate{ display:none; } 307 | .progress{ display: block; } 308 | } 309 | } 310 | } 311 | } 312 | 313 | .system-info { 314 | position: absolute; 315 | top:7px; 316 | left:0; 317 | right:0; 318 | text-align: center; 319 | background-color:rgba(0,0,0,0.3); 320 | 321 | color: #d6d6d6; 322 | border:1px solid #363636; 323 | border-left:none; 324 | border-right:none; 325 | padding-top: 5px; 326 | padding-bottom:10px; 327 | 328 | .system-name{ 329 | display:inline; 330 | font-size:14pt; 331 | letter-spacing: 2px; 332 | input { 333 | background:none; 334 | text-align: center; 335 | border:none; 336 | color:#bbb; 337 | width:100%; 338 | } 339 | } 340 | .system-author { 341 | display:none; 342 | margin:0 auto; 343 | color: inherit; 344 | &:hover{ 345 | color: #dce9f5; 346 | } 347 | } 348 | } 349 | 350 | .actions{ 351 | position:absolute; 352 | right:0; 353 | top:0; 354 | padding-right:6px; 355 | padding-top:7px; 356 | height:30px; 357 | a{ 358 | font-size:8pt; 359 | padding:2px 0px 1px 1px; 360 | margin-right:5px; 361 | display:inline-block; 362 | position: relative; 363 | background-color: #1f1f20; 364 | 365 | &.facebook,&.twitter,&.gplus{ 366 | color:rgb(219, 219, 219); 367 | } 368 | &.facebook{ border-color: #3B5998;} 369 | &.twitter{ border-color: #4099FF;} 370 | &.gplus{ border-color: #d34836;} 371 | 372 | &.open input{ 373 | width:100px; 374 | } 375 | input{ 376 | background:transparent; 377 | color: #dfdfdf; 378 | border:none; 379 | width:0px; 380 | margin:0px; 381 | padding:0px; 382 | transition: width .25s ease-in-out; 383 | -moz-transition: width .25s ease-in-out; 384 | -webkit-transition: width .25s ease-in-out; 385 | } 386 | span{ 387 | margin-left:2px; 388 | margin-right:4px; 389 | } 390 | i{ 391 | font-size:12px; 392 | padding:0px 0px 0px 0px; 393 | } 394 | text-decoration: none; 395 | line-height:14px; 396 | color: #808080; 397 | border:1px solid #797979; 398 | vertical-align: middle; 399 | border-radius:2px; 400 | cursor:pointer; 401 | &:hover{ 402 | border-color: #aeaeae; 403 | color: #cecece; 404 | &.tooltip:after{ 405 | background: #333; 406 | background: rgba(0,0,0,.8); 407 | border-radius: 5px; 408 | top: 26px; 409 | color: #fff; 410 | border-color:white; 411 | content: attr(title); 412 | left: 0; 413 | padding: 5px 15px; 414 | position: absolute; 415 | z-index: 98; 416 | white-space: nowrap; 417 | } 418 | } 419 | } 420 | } 421 | 422 | 423 | .drawing-pad{ 424 | position: absolute; 425 | top: 0; 426 | bottom: 0; 427 | left: 0; 428 | right: 0; 429 | #drawingContainer{ 430 | position:relative; 431 | overflow: hidden; 432 | height:100%; 433 | } 434 | canvas { 435 | position:absolute; 436 | top:0; left:0; right:0; bottom:0; 437 | cursor:crosshair; 438 | &.moving{ cursor: move; } 439 | &.resizing{ cursor: ne-resize; } 440 | } 441 | } 442 | 443 | .ticker{ 444 | @include scrollbar; 445 | overflow-y: scroll; 446 | position:absolute; 447 | top:0; bottom:0;left:0;right:0; 448 | margin:1px; 449 | padding:0px; 450 | text-align:center; 451 | .elem{ 452 | border:1px solid #6f6f6f; 453 | padding:2px; 454 | margin:1px; 455 | border-radius:1px; 456 | position:relative; 457 | background-color: #2c2e33; 458 | 459 | width:130px; 460 | height:125px; 461 | //position:relative; 462 | font-size:8pt; 463 | 464 | &:hover{ 465 | background-color: #3f444a; 466 | } 467 | .img-holder{ 468 | text-align: center; 469 | img{ 470 | margin:0 auto; 471 | } 472 | } 473 | .elem-author{ 474 | display:none; 475 | } 476 | .elem-label{ 477 | display:block; 478 | position:absolute; 479 | left:0; 480 | right:0; 481 | bottom:5px; 482 | 483 | background-color:rgba(0,0,0,0.3); 484 | 485 | color: #d6d6d6; 486 | 487 | border:1px solid #555555; 488 | border-left:none; 489 | border-right:none; 490 | padding:2px 0; 491 | text-overflow: ellipsis; 492 | } 493 | } 494 | } 495 | 496 | 497 | 498 | -------------------------------------------------------------------------------- /examples.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | start? 11 | http://benvan.co.uk/lsys/index.html#it=100&l=2.21&a=-3423.4&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B--((ls%0AF-F%2B)FY%5D%2B%0A 12 | 13 | // color recoil 14 | http://localhost:9090/#?i=30&r=L%20%3A%20S%0AS%20%3A%20F%3E%2B%5BF-Y%5BS%5D%5DF)G%0AY%20%3A--%5B%7C1F-F3--FY%5D-%0AG%3A%20FGF%2BY&p.size=2.91,-0.105207&p.angle=-3781.7891,0.062353&s.size=8.7,7.53&s.angle=7.7,4&offsets=0,0,0&name=re-coil 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | death 118 | spiral 119 | 120 | 121 | 3d 122 | tusk 123 | / 124 | gearspin 125 | 126 | 127 | seriously 128 | 3d 129 | 130 | 131 | single 132 | 3d 133 | blade 134 | 135 | 136 | 3d 137 | rollers 138 | 139 | 140 | battling 141 | dragon 142 | tails 143 | 144 | 145 | snapdragon 146 | 147 | 148 | dragon 149 | spirograph 150 | 151 | 152 | gemini 153 | 154 | 155 | number 156 | 8 157 | 158 | 159 | wigglesaur 160 | 161 | 162 | I 163 | mustache 164 | you 165 | a 166 | question 167 | 168 | 169 | twizzlestache 170 | 171 | 172 | samurai 173 | 174 | 175 | dragonfish 176 | 177 | 178 | 3d 179 | pyramids 180 | 181 | holy 182 | shit! 183 | 184 | the 185 | bomb 186 | 187 | ornate 188 | clock 189 | 190 | manta 191 | ray 192 | 193 | biohazard 194 | angel 195 | 196 | choose 197 | your 198 | tunnel 199 | 200 | trifecta 201 | 202 | fire! 203 | 204 | birds 205 | 206 | brainchild 207 | 208 | rorschach test 209 | beating heart (wiggle mouse) 210 | needle in a haystack 211 | 212 | 213 | 214 | king of the jungle (no seriously. It's a frickin lion) 215 | 216 | amoeba 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | -------------------------------------------------------------------------------- /ticker_min.json: -------------------------------------------------------------------------------- 1 | {"systems":[{"name":"ordered chaos","url":"#it=11&l=18.67&a=-3787.3&r=L%20%3A%20SYS%0AS%20%3A%20F-%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CFF%5B-((%3E%3E%3E%3E%3E%3ES%5D%2BY%5D","img":"lsys_ordered_chaos.png"},{"name":"metamorphosis","url":"#it=40&l=4.44&a=-2361.3&r=C%20%3A%20%5BB%5DC%0AB%20%3A%20!AFB)!A-%0AA%20%3A%20-AF%2B","img":"lsys_metamorphosis.png"},{"name":"pulse engine","url":"#it=40&l=11.61&a=810&r=C%20%3A%20%5BB%5DVFC%0AB%20%3A%20A!B%0AA%20%3A%20F%2BA%7C-%0AV%20%3A%20XVY%0AX%20%3A%20%3CX%0AY%20%3A%20%3EY","img":"lsys_pulse_engine.png"},{"name":"leviathon","url":"#it=33&l=6.19&a=-4055.8&r=C%20%3A%20S!%7CVFFC%0AS%20%3A%20F!%2B%2B%5BF-YAS%5D%0AA%20%3A%20F-%7CA!%0AV%20%3A%20XVY%0AX%20%3A%20-%0AY%20%3A%20!-","img":"lsys_leviathon.png"},{"name":"the DNA dance","url":"#it=30&l=16.08&a=-660&r=C%20%3A%20B%7CVFC%0AB%20%3A%20A!B%0AA%20%3A%20F---A%7C%2B%0AV%20%3A%20XVY%0AX%20%3A%20%3CX%0AY%20%3A%20%3EY","img":"lsys_the_DNA_dance.png"},{"name":"synchronised swarming","url":"#it=33&l=6.19&sg=0.01&a=-3965.57&ag=0.03788399999999987&r=C%20%3A%20S!%7CVFFC%0AS%20%3A%20F!%2B(%2B%5BF-YAS%5D%0AA%20%3A%20F-%7CA!%0AV%20%3A%20XVY%0AX%20%3A%20-%0AY%20%3A%20!-","img":"lsys_conswarmity.png"},{"name":"snake charmer","url":"#it=30&l=6.27&a=-1442.6&r=C%20%3A%20B%7CVFC%0AB%20%3A%20A!B%0AA%20%3A%20F%2B%2B%2B%7CA%7C%2BF%0AV%20%3A%20XVY%0AX%20%3A%20%3CX%0AY%20%3A%20%3EY","img":"lsys_snake_charmer.png"},{"name":"dance for me","url":"#it=40&l=8.15&a=-1255.5&r=C%20%3A%20%5BB%5DF%7CC%0AB%20%3A%20!AB)!A-F%0AA%20%3A%20-AF%2B","img":"lsys_dance_for_me.png"},{"name":"crystal orchid","url":"#it=31&l=71.19&a=13&r=L%20%3A%20SYS%0AS%20%3A%20%3E-%7C%5BF%3E-Y%5B%3ES%5D%5D!%0AY%20%3A%20%5B%7CF%3EFF-F%2B)Y%5D","img":"lsys_crystal_orchid.png"},{"name":"platterstar","img":"lsys_platterstar.png","url":"#it=200&l=188.94&a=-3179.7&r=L%20%3A%20SSSSSS%0AS%20%3A%20%3E%7C%2B%5BF%5BS%5D%5D%7C"},{"name":"heisenberg","url":"#it=12&l=11.94&a=-3259.1&r=S%20%3A%20F-%5BF-Y%5BS%5D%5D%0AY%20%3A%20S%7C%5B%7CF-F%2B)Y%5D","img":"lsys_heisenberg.png"},{"name":"trigon","url":"#it=12&l=16.37&a=9840.1&r=L%20%3A%20SS%0AS%20%3A%20F-%5BF-Y%5BS(L%5D%5D%0AY%20%3A%20%5B-%7CF-F%2B)Y%5D","img":"lsys_trigon.png"},{"name":"spirocopter","url":"#it=40&l=5.31&a=-1972.4&r=C%20%3A%20CB%0AB%20%3A%20!A%5BFB%5D!A-%0AA%20%3A%20-AF%2B","img":"lsys_spirocopter.png"},{"name":"kinetica","url":"#it=33&l=23.82&a=-2040&r=C%20%3A%20S!%7CVFFC%0AS%20%3A%20F!%2B%2B%5BF-YS%5D%0AY%20%3A%20%5BF-FA%2BY%5D%0AA%20%3A%20F---A%7C%2B%0AV%20%3A%20XVY%0AX%20%3A%20-%0AY%20%3A%20!","img":"lsys_kinetica.png"},{"name":"johnny lee","url":"#it=30&l=6.03&a=-1705.7&r=L%20%3A%20S%0AS%20%3A%20F%7C%2B%5BF-Y%5BS%5D%5DFG%0AY%20%3A--%5B%7CF-F%2B%7C%2BFY%5D%2B%0AG%3A%20FGF%5B%2BF%5DY","img":"lsys_johnny_lee.png"},{"name":"angel flight","url":"#it=44&l=2.46&a=-3224.9&r=C%20%3A%20B%7CVFC%0AB%20%3A%20A!BF%0AA%20%3A%20F%7C-A%7C%2BF%0AV%20%3A%20%3C%3C%3C%3C%2B","img":"lsys_angel_flight.png"},{"name":"stargaze","url":"#it=44&l=2.23&a=-3275.2&r=C%20%3A%20B%7CVFC%0AB%20%3A%20ABF%0AA%20%3A%20F%7C-A%7C%2BF%0AV%20%3A%20%3C%3C%3C%3C%3C%2B","img":"lsys_stargaze.png"},{"name":"mortal coil","url":"#it=44&l=4.15&a=-1793.1&r=C%20%3A%20B%7CVFC%0AB%20%3A%20A!BF%0AA%20%3A%20F%7C-A%7C%2BF%0AV%20%3A%20%3E","img":"lsys_mortal_coil.png"},{"name":"jamiroquai | rippletwist","url":"#it=33&l=6.39&a=-2340.6&r=C%20%3A%20S!%7CVFFC%0AS%20%3A%20F!%2B%2B%5BF-YAS%5D%0AA%20%3A%20F-A%7C%2B%0AV%20%3A%20XVY%0AX%20%3A%20-%0AY%20%3A%20!-","img":"lsys_jamiroquai_-_rippletwist.png"},{"name":"coalescence","url":"#it=200&l=199.9&a=-3276.3&r=L%20%3A%20SSSSS%0AS%20%3A%20%3E%7C%2B%5BF%5BS%5D%5D","img":"lsys_coalescence.png"},{"url":"#it=21&l=18.97&a=-1525.9&r=L%20%3A%20SYS%0AS%20%3A%20F-%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CFF%2BY%5D","name":"death spiral","img":"lsys_death_spiral.png"},{"url":"#it=31&l=16.34&a=-3243.4&r=L%20%3A%20SYS%0AS%20%3A%20F-%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CF-F%2B)Y%5D","name":"3d tusk / gearspin","img":"lsys_3d_tusk___gearspin.png"},{"url":"#it=31&l=5.62&a=-2519.1&r=L%20%3A%20S%0AS%20%3A%20F%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CF-F%2B)Y%5D","name":"single 3d blade","img":"lsys_single_3d_blade.png"},{"url":"#it=20&l=91.21&a=-137.8&r=L%20%3A%20S%0AS%20%3A%20%3EF%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CF-F)%2BY%5D","name":"3d rollers 2","img":"lsys_3d_rollers_2.png"},{"url":"#it=31&l=11.61&a=-901.4&r=L%20%3A%20S)S)S)S)S%0AS%20%3A%20F%2B%5BF-Y%5B%2BS%5D%5D%0AY%20%3A%20%5B%7CF-F%2B)Y%5D","name":"battling dragon tails","img":"lsys_battling_dragon_tails.png"},{"url":"#it=31&l=11.74&a=-1251.1&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CF-F%2B)FY%5D%2B","name":"snapdragon","img":"lsys_snapdragon.png"},{"url":"#it=100&l=7.66&a=-2107.9&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B-F-F%2B)FY%5D%2B%0A","name":"dragon spirograph","img":"lsys_dragon_spirograph.png"},{"url":"#it=100&l=2.28&a=-2341.8&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B--((F-F%2B)FY%5D%2B%0A","name":"gemini","img":"lsys_gemini.png"},{"url":"#it=40&l=9.86&a=-192.8&r=C%20%3A%20%5BB%5DF%7CC%0AB%20%3A%20!AB!A-F%0AA%20%3A%20-AF%2B","name":"clockwork coil","img":"lsys_clockwork_coil.png"},{"url":"#it=31&l=20.38&a=95.4&r=L%20%3A%20SYS%0AS%20%3A%20-%7C%5BF-Y%5BS%5D%5D%2B%0AY%20%3A%20%5B%7CFFF-F%2B)Y%5D","name":"number 8","img":"lsys_number_8.png"},{"url":"#it=31&l=9.44&a=88.4&r=L%20%3A%20SYS%0AS%20%3A%20%3E-%7C%5BF%3E-Y%5B%3ES%5D%5D!%0AY%20%3A%20%5B%7CF%3E!FF-F%2B)Y%5D","name":"wigglesaur","img":"lsys_wigglesaur.png"},{"url":"#it=70&l=16.12&a=907.4&r=L%20%3A%20SYS%0AS%20%3A%20%3E-%7C%5B%2BF%3E-Y%5B%3ES%5D%5D!%0AY%20%3A%20%5B%7CF%3E!FF-F%2B)Y%5D","name":"I mustache you a question","img":"lsys_I_mustache_you_a_question.png"},{"url":"#it=50&l=9.5&a=3052.7&r=L%20%3A%20SYS%0AS%20%3A%20%3E-%7C%5B%2BF%3E-Y%3E%5B%3ES%5D%5D!%0AY%20%3A%20%5B%7CF%3E!F)F-F%2B)Y%5D","name":"twizzlestache","img":"lsys_twizzlestache.png"},{"url":"#it=41&l=3.22&a=-2399.6&r=L%20%3A%20SYSYSYS%0AS%20%3A%20F-%5BF-Y%5BS%2B%2BFFF%5B%2BF%2BF%5D%5D%0AY%20%3A%20F%5B%7CF!F%2BY%5D-F","name":"samurai","img":"lsys_samurai.png"},{"url":"#it=41&l=3.28&a=-2756.2&r=L%20%3A%20SYL%0AS%20%3A%20F-%5BF-Y%5BS%2B%2BFFF%5B%2BF%2BF%5D%5D%0AY%20%3A%20F%5B%7CF!F%2BY%5D-F","name":"dragonfish","img":"lsys_dragonfish.png"},{"url":"#it=32&l=4.17&a=-1342.1&r=L%20%3A%20SLY%0AS%20%3A%20F-%5BF!Y%5BS%2B%2BFFF%5B%2BF%2BF%5D%5D%0AY%20%3A%20F%5B%7CF!F%2BY%5D-F","name":"3d pyramids","img":"lsys_3d_pyramids.png"},{"url":"#it=100&l=10.28&a=179.3&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CF-F%2B%2BFY%5D%2B)%0A","name":"holy shit!","img":"lsys_holy_shit!.png"},{"url":"#it=80&l=13.81&a=-87.1&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CF-F%2B%2BFY%5D%2B(!%0A","name":"the bomb","img":"lsys_the_bomb.png"},{"url":"#it=80&l=5.4&a=-1563.3&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CF-F--FY%5D%2B(!%0A","name":"ornate clock","img":"lsys_ornate_clock.png"},{"url":"#it=80&l=4&a=-2279.4&r=L%20%3A%20S%0AS%20%3A%20%3EF%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CF-F--%7CFY%5D%2B!%0A","name":"manta ray","img":"lsys_manta_ray.png"},{"url":"#it=80&l=1.47&a=-2819.5&r=L%20%3A%20SSS%0AS%20%3A%20%3EF%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20F%5B-F--%7CFY%5D%2B!%0A","name":"biohazard angel","img":"lsys_biohazard_angel.png"},{"name":"twistmas tree","url":"#it=40&l=6.6&a=-480.2&r=C%20%3A%20%5BB%5DFC%0AB%20%3A%20!ABA%0AA%20%3A%20-AF-","img":"lsys_twistmas_tree.png"},{"url":"#it=80&l=7.21&a=-3185.1&r=L%20%3A%20SSS%0AS%20%3A%20%3EF%7C%2B%5BFY%5BS%5D%5D%0AY%20%3A%20F%5B-F--%7CFY%5D%2B!%0A","name":"choose your tunnel","img":"lsys_choose_your_tunnel.png"},{"name":"clover","img":"lsys_clover.png","url":"#it=80&l=9.03&a=-3686.8&r=L%20%3A%20SSSS%0AS%20%3A%20%3EF%7C%2B%5BFY%5BS%5D%5D%0AY%20%3A%20F%5B-F--%7CY%5D%2B%0A"},{"url":"#it=60&l=14.49&a=56.6&r=L%20%3A%20SSS%0AS%20%3A%20%3EF%7C)%2B%5BFY%5BS%5D%5D%0AY%20%3A%20F%5B-F--FY%5D%2B!F%0A","name":"trifecta","img":"lsys_trifecta.png"},{"url":"#it=14&l=6.96&a=-180&r=L%20%3A%20S%0AS%20%3A%20%3EF%7C%2B%5BFYS%5D%0AY%20%3A%20F%5B-F-FY%5D%2B!Y%0A","name":"fire!","img":"lsys_fire!.png"},{"url":"#it=14&l=8.51&a=1203.5&r=L%20%3A%20S%0AS%20%3A%20%3E)F%7C%2B%5BFYS%5D%0AY%20%3A%20F%5B-F-FY%5D%2B!Y%0A","name":"birds","img":"lsys_birds.png"},{"url":"#it=14&l=14.62&a=901.5&r=L%20%3A%20S%0AS%20%3A%20%3CT-F%7C%2B%5BYS%5D%0AY%20%3A%20F%5B-%7CY%5D%2B!Y%0AT%20%3A%20))))))%2B%2B%2B((((((","name":"brainchild","img":"lsys_brainchild.png"},{"url":"#it=8&l=9.31&a=-289.8&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3ES)","name":"rorschach test","img":"lsys_rorschach_test.png"},{"url":"#it=9&l=10.11&a=-652.6&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3ES)","name":"beating heart (wiggle mouse)","img":"lsys_beating_heart_(wiggle_mouse).png"},{"url":"#it=9&l=10.94&a=-1305.4&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3ES)","name":"needle in a haystack","img":"lsys_needle_in_a_haystack.png"},{"url":"#it=9&l=6.62&a=-3164.2&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3ES)s","name":"king of the jungle","img":"lsys_king_of_the_jungle.png"},{"url":"#it=9&l=9.99&a=-3241.5&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DA%0AS%20%3A%20%3ES)s","name":"amoeba","img":"lsys_amoeba.png"},{"url":"#it=10&l=9.74&a=-1194.6&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3ES))","name":"the grinch in a christmas hat...","img":"lsys_the_grinch_in_a_christmas_hat.png"},{"url":"#it=9&l=8.93&a=-1243.2&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3E%3E%3ES))))","name":"cthulu's daughter","img":"lsys_cthulu's_daughter.png"},{"name":"trippy","img":"lsys_trippy.png","url":"#it=10&l=29.68&a=-1345.1&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3E%3E%3E%3E%3E%3ES))))"},{"name":"mandelbutt","img":"lsys_mandelbutt.png","url":"#it=10&l=29.62&a=-1346.6&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3E%3E%3E%3E%3E%3ES))))"},{"name":"tree!","img":"lsys_tree!.png","url":"#it=10&l=29.24&a=-1358&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3E%3E%3E%3E%3E%3ES))))"},{"name":"freaky face","img":"lsys_freaky_face.png","url":"#it=10&l=29.3&a=-1373.3&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3E%3E%3E%3E%3E%3ES))))"},{"name":"stardust","img":"lsys_stardust.png","url":"#it=10&l=30&a=-1406.9&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3E%3E%3E%3E%3E%3ES))))"},{"name":"clockwork","img":"lsys_clockwork.png","url":"#it=8&l=1.58&a=-1817.5&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3EA))))"},{"name":"helicopter plant (drag left)","img":"lsys_helicopter_plant_(drag_left).png","url":"#it=8&l=5.56&a=-1441.2&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFAM%0AS%20%3A%20%3EA%7C%3E%0AM%3A%20)))))%2B((((("},{"name":"dandelion","img":"lsys_dandelion.png","url":"#it=10&l=7.55&a=-2923010.4&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3ES)s"},{"name":"shaman face","img":"lsys_shaman_face.png","url":"#it=10&l=5.66&a=-926.5&r=A%20%3A%20FFFS%5B%2BA%5D%5B-A%5DFA%0AS%20%3A%20%3ES)"},{"name":"wormhole","img":"lsys_wormhole.png","url":"#it=100&l=26.87&a=283.4&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y%5BS%5D%5D%0AY%20%3A%20%5B%7CF-F%2B%2BFY%5D%2B%3C"},{"name":"coral","img":"lsys_coral.png","url":"#it=18&l=2.5&a=-3082.2&r=L%20%3A%20S%0AS%20%3A%20F%7C%2B%5BF-Y%5BS%5D%5DFG%0AY%20%3A--%5B%7CF-FFF%2B%7C%2BY%5D%2B%0AG%3A%20FG%2BF%2B%7CL%2B"},{"name":"I will crush you (and various other critters)","img":"lsys_I_will_crush_you.png","url":"#it=31&l=8.26&a=2156.5&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y)%5B-S%5D%5DY-!Y%0AY%20%3A%20%5B%7CF-F%2B)Y%5D"},{"name":"the indomitable moustachio","img":"lsys_the_indomitable_moustachio.png","url":"#it=31&l=16.67&a=124.72&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y)%5B-S%5D%5DY-!Y%0AY%20%3A%20%5B%7CF-F%2B(Y%5D"},{"name":"seahorse .. moustache","img":"lsys_seahorse_moustache.png","url":"#it=31&l=11.79&a=-859.18&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y)%5B-(S%5D%5DY-!Y%0AY%20%3A%20%5B%7CF-(F%2BY%5D"},{"name":"the slug","img":"lsys_the_slug.png","url":"#it=30&l=2.5&a=-523.08&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y)%5B-(S%5D%5DY-Y%0AY%20%3A%20%5B%7CF-(F%2B!Y%5D"},{"name":"gears","img":"lsys_gears.png","url":"#it=31&l=13.79&a=-138.18&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y)%5B-S%5D%5DY-!Y%0AY%20%3A%20%5B%7CF-F%2B%2BY%5D"},{"name":"jelly-crab","img":"lsys_jelly-crab.png","url":"#it=31&l=7.01&a=-1856.68&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y)%5B-S%5D%5DY-!Y%0AY%20%3A%20%5B%7CF-F)%2B%2B(Y%5D"},{"name":"octosquid","img":"lsys_octosquid.png","url":"#it=31&l=15.2&a=-169.08&r=L%20%3A%20SYS%0AS%20%3A%20F%7C%2B%5BF-Y)%5B-S%5D%5DY-!Y%0AY%20%3A%20%5B%7CF-F)%2B%2B(Y%5D"},{"name":"dream catcher","img":"lsys_dream_catcher.png","url":"#it=30&l=4.34&a=-3769.7&r=L%20%3A%20S%0AS%20%3A%20F%2B%5BF-Y%5BS%5D%5DF)G%0AY%20%3A--%5B%7CF-F-)-FY%5D-%0AG%3A%20FGF%5B%2BF%5D%2BY"},{"name":"tornado","img":"lsys_tornado.png","url":"#it=20&l=2.79&a=-117&r=L%20%3A%20SSSL%0AS%20%3A%20F(%5BF-Y%5B(FFFFFFS%5D%5D%0AY%20%3A%20%5B%7CF-F%2B(Y%5D"},{"name":"politic","img":"lsys_politic.png","url":"#it=20&l=4.39&a=-13.6&r=L%20%3A%20SSFL%0AS%20%3A%20F%5BF-Y%5B(-FS%5D%5D%0AY%20%3A%20%5B!F-F%2B)Y%5D"},{"name":"spin engine","img":"lsys_spin_engine.png","url":"#it=20&l=5.94&a=378.5&r=L%20%3A%20SFFSFFL%0AS%20%3A%20F%5BF-Y%5B(-FS%5D%5D%0AY%20%3A%20F%2BY%7C"}]} 2 | -------------------------------------------------------------------------------- /js/underscore.js: -------------------------------------------------------------------------------- 1 | // Underscore.js 1.5.1 2 | // http://underscorejs.org 3 | // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 4 | // Underscore may be freely distributed under the MIT license. 5 | !function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,v=e.reduce,h=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,w=i.bind,j=function(n){return n instanceof j?n:this instanceof j?(this._wrapped=n,void 0):new j(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=j),exports._=j):n._=j,j.VERSION="1.5.1";var A=j.each=j.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(j.has(n,a)&&t.call(e,n[a],a,n)===r)return};j.map=j.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e.push(t.call(r,n,u,i))}),e)};var E="Reduce of empty array with no initial value";j.reduce=j.foldl=j.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduce===v)return e&&(t=j.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(E);return r},j.reduceRight=j.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduceRight===h)return e&&(t=j.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=j.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(E);return r},j.find=j.detect=function(n,t,r){var e;return O(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},j.filter=j.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&e.push(n)}),e)},j.reject=function(n,t,r){return j.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},j.every=j.all=function(n,t,e){t||(t=j.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var O=j.some=j.any=function(n,t,e){t||(t=j.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};j.contains=j.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:O(n,function(n){return n===t})},j.invoke=function(n,t){var r=o.call(arguments,2),e=j.isFunction(t);return j.map(n,function(n){return(e?t:n[t]).apply(n,r)})},j.pluck=function(n,t){return j.map(n,function(n){return n[t]})},j.where=function(n,t,r){return j.isEmpty(t)?r?void 0:[]:j[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},j.findWhere=function(n,t){return j.where(n,t,!0)},j.max=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.max.apply(Math,n);if(!t&&j.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>e.computed&&(e={value:n,computed:a})}),e.value},j.min=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.min.apply(Math,n);if(!t&&j.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;ae||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.indexi;){var o=i+a>>>1;r.call(e,n[o])=0})})},j.difference=function(n){var t=c.apply(e,o.call(arguments,1));return j.filter(n,function(n){return!j.contains(t,n)})},j.zip=function(){for(var n=j.max(j.pluck(arguments,"length").concat(0)),t=new Array(n),r=0;n>r;r++)t[r]=j.pluck(arguments,""+r);return t},j.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},j.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=j.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},j.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},j.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=new Array(e);e>u;)i[u++]=n,n+=r;return i};var M=function(){};j.bind=function(n,t){var r,e;if(w&&n.bind===w)return w.apply(n,o.call(arguments,1));if(!j.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));M.prototype=n.prototype;var u=new M;M.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},j.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},j.bindAll=function(n){var t=o.call(arguments,1);if(0===t.length)throw new Error("bindAll must be passed function names");return A(t,function(t){n[t]=j.bind(n[t],n)}),n},j.memoize=function(n,t){var r={};return t||(t=j.identity),function(){var e=t.apply(this,arguments);return j.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},j.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},j.defer=function(n){return j.delay.apply(j,[n,1].concat(o.call(arguments,1)))},j.throttle=function(n,t,r){var e,u,i,a=null,o=0;r||(r={});var c=function(){o=r.leading===!1?0:new Date,a=null,i=n.apply(e,u)};return function(){var l=new Date;o||r.leading!==!1||(o=l);var f=t-(l-o);return e=this,u=arguments,0>=f?(clearTimeout(a),a=null,o=l,i=n.apply(e,u)):a||r.trailing===!1||(a=setTimeout(c,f)),i}},j.debounce=function(n,t,r){var e,u=null;return function(){var i=this,a=arguments,o=function(){u=null,r||(e=n.apply(i,a))},c=r&&!u;return clearTimeout(u),u=setTimeout(o,t),c&&(e=n.apply(i,a)),e}},j.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},j.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},j.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},j.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},j.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)j.has(n,r)&&t.push(r);return t},j.values=function(n){var t=[];for(var r in n)j.has(n,r)&&t.push(n[r]);return t},j.pairs=function(n){var t=[];for(var r in n)j.has(n,r)&&t.push([r,n[r]]);return t},j.invert=function(n){var t={};for(var r in n)j.has(n,r)&&(t[n[r]]=r);return t},j.functions=j.methods=function(n){var t=[];for(var r in n)j.isFunction(n[r])&&t.push(r);return t.sort()},j.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},j.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},j.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)j.contains(r,u)||(t[u]=n[u]);return t},j.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]===void 0&&(n[r]=t[r])}),n},j.clone=function(n){return j.isObject(n)?j.isArray(n)?n.slice():j.extend({},n):n},j.tap=function(n,t){return t(n),n};var S=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof j&&(n=n._wrapped),t instanceof j&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==String(t);case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;var a=n.constructor,o=t.constructor;if(a!==o&&!(j.isFunction(a)&&a instanceof a&&j.isFunction(o)&&o instanceof o))return!1;r.push(n),e.push(t);var c=0,f=!0;if("[object Array]"==u){if(c=n.length,f=c==t.length)for(;c--&&(f=S(n[c],t[c],r,e)););}else{for(var s in n)if(j.has(n,s)&&(c++,!(f=j.has(t,s)&&S(n[s],t[s],r,e))))break;if(f){for(s in t)if(j.has(t,s)&&!c--)break;f=!c}}return r.pop(),e.pop(),f};j.isEqual=function(n,t){return S(n,t,[],[])},j.isEmpty=function(n){if(null==n)return!0;if(j.isArray(n)||j.isString(n))return 0===n.length;for(var t in n)if(j.has(n,t))return!1;return!0},j.isElement=function(n){return!(!n||1!==n.nodeType)},j.isArray=x||function(n){return"[object Array]"==l.call(n)},j.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){j["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),j.isArguments(arguments)||(j.isArguments=function(n){return!(!n||!j.has(n,"callee"))}),"function"!=typeof/./&&(j.isFunction=function(n){return"function"==typeof n}),j.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},j.isNaN=function(n){return j.isNumber(n)&&n!=+n},j.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},j.isNull=function(n){return null===n},j.isUndefined=function(n){return n===void 0},j.has=function(n,t){return f.call(n,t)},j.noConflict=function(){return n._=t,this},j.identity=function(n){return n},j.times=function(n,t,r){for(var e=Array(Math.max(0,n)),u=0;n>u;u++)e[u]=t.call(r,u);return e},j.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var I={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};I.unescape=j.invert(I.escape);var T={escape:new RegExp("["+j.keys(I.escape).join("")+"]","g"),unescape:new RegExp("("+j.keys(I.unescape).join("|")+")","g")};j.each(["escape","unescape"],function(n){j[n]=function(t){return null==t?"":(""+t).replace(T[n],function(t){return I[n][t]})}}),j.result=function(n,t){if(null==n)return void 0;var r=n[t];return j.isFunction(r)?r.call(n):r},j.mixin=function(n){A(j.functions(n),function(t){var r=j[t]=n[t];j.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),z.call(this,r.apply(j,n))}})};var N=0;j.uniqueId=function(n){var t=++N+"";return n?n+t:t},j.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\t|\u2028|\u2029/g;j.template=function(n,t,r){var e;r=j.defaults({},r,j.templateSettings);var u=new RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(D,function(n){return"\\"+B[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=new Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,j);var c=function(n){return e.call(this,n,j)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},j.chain=function(n){return j(n).chain()};var z=function(n){return this._chain?j(n).chain():n};j.mixin(j),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];j.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],z.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];j.prototype[n]=function(){return z.call(this,t.apply(this._wrapped,arguments))}}),j.extend(j.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}.call(this); 6 | //# sourceMappingURL=underscore-min.map -------------------------------------------------------------------------------- /js/jquery.kinetic.js: -------------------------------------------------------------------------------- 1 | /*! 2 | jQuery.kinetic v1.8.2 3 | Dave Taylor http://the-taylors.org/jquery.kinetic 4 | 5 | The MIT License (MIT) 6 | Copyright (c) <2011> 7 | */ 8 | /*global define,require */ 9 | (function($){ 10 | 'use strict'; 11 | 12 | var DEFAULT_SETTINGS = { 13 | cursor: 'move', 14 | decelerate: true, 15 | triggerHardware: false, 16 | y: true, 17 | x: true, 18 | slowdown: 0.9, 19 | maxvelocity: 40, 20 | throttleFPS: 60, 21 | movingClass: { 22 | up: 'kinetic-moving-up', 23 | down: 'kinetic-moving-down', 24 | left: 'kinetic-moving-left', 25 | right: 'kinetic-moving-right' 26 | }, 27 | deceleratingClass: { 28 | up: 'kinetic-decelerating-up', 29 | down: 'kinetic-decelerating-down', 30 | left: 'kinetic-decelerating-left', 31 | right: 'kinetic-decelerating-right' 32 | } 33 | }, 34 | SETTINGS_KEY = 'kinetic-settings', 35 | ACTIVE_CLASS = 'kinetic-active'; 36 | /** 37 | * Provides requestAnimationFrame in a cross browser way. 38 | * http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 39 | */ 40 | if ( !window.requestAnimationFrame ) { 41 | 42 | window.requestAnimationFrame = ( function() { 43 | 44 | return window.webkitRequestAnimationFrame || 45 | window.mozRequestAnimationFrame || 46 | window.oRequestAnimationFrame || 47 | window.msRequestAnimationFrame || 48 | function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) { 49 | window.setTimeout( callback, 1000 / 60 ); 50 | }; 51 | 52 | }()); 53 | 54 | } 55 | 56 | // add touch checker to jQuery.support 57 | $.support = $.support || {}; 58 | $.extend($.support, { 59 | touch: "ontouchend" in document 60 | }); 61 | var selectStart = function() { return false; }; 62 | 63 | var decelerateVelocity = function(velocity, slowdown) { 64 | return Math.floor(Math.abs(velocity)) === 0 ? 0 // is velocity less than 1? 65 | : velocity * slowdown; // reduce slowdown 66 | }; 67 | 68 | var capVelocity = function(velocity, max) { 69 | var newVelocity = velocity; 70 | if (velocity > 0) { 71 | if (velocity > max) { 72 | newVelocity = max; 73 | } 74 | } else { 75 | if (velocity < (0 - max)) { 76 | newVelocity = (0 - max); 77 | } 78 | } 79 | return newVelocity; 80 | }; 81 | 82 | var setMoveClasses = function(settings, classes) { 83 | this.removeClass(settings.movingClass.up) 84 | .removeClass(settings.movingClass.down) 85 | .removeClass(settings.movingClass.left) 86 | .removeClass(settings.movingClass.right) 87 | .removeClass(settings.deceleratingClass.up) 88 | .removeClass(settings.deceleratingClass.down) 89 | .removeClass(settings.deceleratingClass.left) 90 | .removeClass(settings.deceleratingClass.right); 91 | 92 | if (settings.velocity > 0) { 93 | this.addClass(classes.right); 94 | } 95 | if (settings.velocity < 0) { 96 | this.addClass(classes.left); 97 | } 98 | if (settings.velocityY > 0) { 99 | this.addClass(classes.down); 100 | } 101 | if (settings.velocityY < 0) { 102 | this.addClass(classes.up); 103 | } 104 | 105 | }; 106 | 107 | var stop = function($scroller, settings) { 108 | settings.velocity = 0; 109 | settings.velocityY = 0; 110 | settings.decelerate = true; 111 | if (typeof settings.stopped === 'function') { 112 | settings.stopped.call($scroller, settings); 113 | } 114 | }; 115 | 116 | /** do the actual kinetic movement */ 117 | var move = function($scroller, settings) { 118 | var scroller = $scroller[0]; 119 | // set scrollLeft 120 | if (settings.x && scroller.scrollWidth > 0){ 121 | scroller.scrollLeft = settings.scrollLeft = scroller.scrollLeft + settings.velocity; 122 | if (Math.abs(settings.velocity) > 0) { 123 | settings.velocity = settings.decelerate ? 124 | decelerateVelocity(settings.velocity, settings.slowdown) : settings.velocity; 125 | } 126 | } else { 127 | settings.velocity = 0; 128 | } 129 | 130 | // set scrollTop 131 | if (settings.y && scroller.scrollHeight > 0){ 132 | scroller.scrollTop = settings.scrollTop = scroller.scrollTop + settings.velocityY; 133 | if (Math.abs(settings.velocityY) > 0) { 134 | settings.velocityY = settings.decelerate ? 135 | decelerateVelocity(settings.velocityY, settings.slowdown) : settings.velocityY; 136 | } 137 | } else { 138 | settings.velocityY = 0; 139 | } 140 | 141 | setMoveClasses.call($scroller, settings, settings.deceleratingClass); 142 | 143 | if (typeof settings.moved === 'function') { 144 | settings.moved.call($scroller, settings); 145 | } 146 | 147 | if (Math.abs(settings.velocity) > 0 || Math.abs(settings.velocityY) > 0) { 148 | // tick for next movement 149 | window.requestAnimationFrame(function(){ move($scroller, settings); }); 150 | } else { 151 | stop($scroller, settings); 152 | } 153 | }; 154 | 155 | var callOption = function(method, options) { 156 | var methodFn = $.kinetic.callMethods[method], 157 | args = Array.prototype.slice.call(arguments) 158 | ; 159 | if (methodFn) { 160 | this.each(function(){ 161 | var opts = args.slice(1), settings = $(this).data(SETTINGS_KEY); 162 | opts.unshift(settings); 163 | methodFn.apply(this, opts); 164 | }); 165 | } 166 | }; 167 | 168 | var attachListeners = function($this, settings) { 169 | var element = $this[0]; 170 | if ($.support.touch) { 171 | $this.bind('touchstart', settings.events.touchStart) 172 | .bind('touchend', settings.events.inputEnd) 173 | .bind('touchmove', settings.events.touchMove) 174 | ; 175 | } else { 176 | $this 177 | .mousedown(settings.events.inputDown) 178 | .mouseup(settings.events.inputEnd) 179 | .mousemove(settings.events.inputMove) 180 | ; 181 | } 182 | $this 183 | .click(settings.events.inputClick) 184 | .scroll(settings.events.scroll) 185 | .bind("selectstart", selectStart) // prevent selection when dragging 186 | .bind('dragstart', settings.events.dragStart); 187 | }; 188 | var detachListeners = function($this, settings) { 189 | var element = $this[0]; 190 | if ($.support.touch) { 191 | $this.unbind('touchstart', settings.events.touchStart) 192 | .unbind('touchend', settings.events.inputEnd) 193 | .unbind('touchmove', settings.events.touchMove); 194 | } else { 195 | $this 196 | .unbind('mousedown', settings.events.inputDown) 197 | .unbind('mouseup', settings.events.inputEnd) 198 | .unbind('mousemove', settings.events.inputMove) 199 | .unbind('scroll', settings.events.scroll); 200 | } 201 | $this.unbind('click', settings.events.inputClick) 202 | .unbind("selectstart", selectStart); // prevent selection when dragging 203 | $this.unbind('dragstart', settings.events.dragStart); 204 | }; 205 | 206 | var initElements = function(options) { 207 | this 208 | .addClass(ACTIVE_CLASS) 209 | .each(function(){ 210 | 211 | var self = this, 212 | $this = $(this); 213 | 214 | if ($this.data(SETTINGS_KEY)){ 215 | return; 216 | } 217 | 218 | var settings = $.extend({}, DEFAULT_SETTINGS, options), 219 | xpos, 220 | prevXPos = false, 221 | ypos, 222 | prevYPos = false, 223 | mouseDown = false, 224 | scrollLeft, 225 | scrollTop, 226 | throttleTimeout = 1000 / settings.throttleFPS, 227 | lastMove, 228 | elementFocused 229 | ; 230 | 231 | settings.velocity = 0; 232 | settings.velocityY = 0; 233 | 234 | // make sure we reset everything when mouse up 235 | var resetMouse = function() { 236 | xpos = false; 237 | ypos = false; 238 | mouseDown = false; 239 | }; 240 | $(document).mouseup(resetMouse).click(resetMouse); 241 | 242 | var calculateVelocities = function() { 243 | settings.velocity = capVelocity(prevXPos - xpos, settings.maxvelocity); 244 | settings.velocityY = capVelocity(prevYPos - ypos, settings.maxvelocity); 245 | }; 246 | var useTarget = function(e) { 247 | if ($(e.target).height() - e.offsetY < 16) return false; 248 | if ($.isFunction(settings.filterTarget)) { 249 | return settings.filterTarget.call(self, e.target) !== false; 250 | } 251 | return true; 252 | }; 253 | var start = function(clientX, clientY) { 254 | mouseDown = true; 255 | settings.velocity = prevXPos = 0; 256 | settings.velocityY = prevYPos = 0; 257 | xpos = clientX; 258 | ypos = clientY; 259 | }; 260 | var end = function() { 261 | if (xpos && prevXPos && settings.decelerate === false) { 262 | settings.decelerate = true; 263 | calculateVelocities(); 264 | xpos = prevXPos = mouseDown = false; 265 | move($this, settings); 266 | } 267 | }; 268 | var inputmove = function(clientX, clientY) { 269 | if (!lastMove || new Date() > new Date(lastMove.getTime() + throttleTimeout)) { 270 | lastMove = new Date(); 271 | 272 | if (mouseDown && (xpos || ypos)) { 273 | if (elementFocused) { 274 | $(elementFocused).blur(); 275 | elementFocused = null; 276 | $this.focus(); 277 | } 278 | settings.decelerate = false; 279 | settings.velocity = settings.velocityY = 0; 280 | $this[0].scrollLeft = settings.scrollLeft = settings.x ? $this[0].scrollLeft - (clientX - xpos) : $this[0].scrollLeft; 281 | $this[0].scrollTop = settings.scrollTop = settings.y ? $this[0].scrollTop - (clientY - ypos) : $this[0].scrollTop; 282 | prevXPos = xpos; 283 | prevYPos = ypos; 284 | xpos = clientX; 285 | ypos = clientY; 286 | 287 | calculateVelocities(); 288 | setMoveClasses.call($this, settings, settings.movingClass); 289 | 290 | if (typeof settings.moved === 'function') { 291 | settings.moved.call($this, settings); 292 | } 293 | } 294 | } 295 | }; 296 | 297 | // Events 298 | settings.events = { 299 | touchStart: function(e){ 300 | var touch; 301 | if (useTarget(e)) { 302 | touch = e.originalEvent.touches[0]; 303 | start(touch.clientX, touch.clientY); 304 | e.stopPropagation(); 305 | } 306 | }, 307 | touchMove: function(e){ 308 | var touch; 309 | if (mouseDown) { 310 | touch = e.originalEvent.touches[0]; 311 | inputmove(touch.clientX, touch.clientY); 312 | if (e.preventDefault) {e.preventDefault();} 313 | } 314 | }, 315 | inputDown: function(e){ 316 | if (useTarget(e)) { 317 | start(e.clientX, e.clientY); 318 | elementFocused = e.target; 319 | if (e.target.nodeName === 'IMG'){ 320 | e.preventDefault(); 321 | } 322 | e.stopPropagation(); 323 | } 324 | }, 325 | inputEnd: function(e){ 326 | end(); 327 | elementFocused = null; 328 | if (e.preventDefault) {e.preventDefault();} 329 | }, 330 | inputMove: function(e) { 331 | if (mouseDown){ 332 | inputmove(e.clientX, e.clientY); 333 | if (e.preventDefault) {e.preventDefault();} 334 | } 335 | }, 336 | scroll: function(e) { 337 | if (typeof settings.moved === 'function') { 338 | settings.moved.call($this, settings); 339 | } 340 | if (e.preventDefault) {e.preventDefault();} 341 | }, 342 | inputClick: function(e){ 343 | if (Math.abs(settings.velocity) > 0) { 344 | e.preventDefault(); 345 | return false; 346 | } 347 | }, 348 | // prevent drag and drop images in ie 349 | dragStart: function(e) { 350 | if (elementFocused) { 351 | return false; 352 | } 353 | } 354 | }; 355 | 356 | attachListeners($this, settings); 357 | $this.data(SETTINGS_KEY, settings) 358 | .css("cursor", settings.cursor); 359 | 360 | if (settings.triggerHardware) { 361 | $this.css({ 362 | '-webkit-transform': 'translate3d(0,0,0)', 363 | '-webkit-perspective': '1000', 364 | '-webkit-backface-visibility': 'hidden' 365 | }); 366 | } 367 | }); 368 | }; 369 | 370 | $.kinetic = { 371 | settingsKey: SETTINGS_KEY, 372 | callMethods: { 373 | start: function(settings, options){ 374 | var $this = $(this); 375 | settings = $.extend(settings, options); 376 | if (settings) { 377 | settings.decelerate = false; 378 | move($this, settings); 379 | } 380 | }, 381 | end: function(settings, options){ 382 | var $this = $(this); 383 | if (settings) { 384 | settings.decelerate = true; 385 | } 386 | }, 387 | stop: function(settings, options){ 388 | var $this = $(this); 389 | stop($this, settings); 390 | }, 391 | detach: function(settings, options) { 392 | var $this = $(this); 393 | detachListeners($this, settings); 394 | $this 395 | .removeClass(ACTIVE_CLASS) 396 | .css("cursor", ""); 397 | }, 398 | attach: function(settings, options) { 399 | var $this = $(this); 400 | attachListeners($this, settings); 401 | $this 402 | .addClass(ACTIVE_CLASS) 403 | .css("cursor", "move"); 404 | } 405 | } 406 | }; 407 | $.fn.kinetic = function(options) { 408 | if (typeof options === 'string') { 409 | callOption.apply(this, arguments); 410 | } else { 411 | initElements.call(this, options); 412 | } 413 | return this; 414 | }; 415 | 416 | }(window.jQuery || window.Zepto)); 417 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lsys 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 28 | 29 | 30 | 31 | 143 | 144 |
    145 | 146 |
    147 | lsys 148 |
    149 | 150 | 151 | 152 |
    153 |
    154 |
    155 |
      156 |
    • offsets
    • 157 | 158 |
    • 159 |
        160 |
      • x
      • y
      • rotation
      • 161 |
      162 | 163 |
    • 164 | 165 |
    • variables
    • 166 | 167 |
    • 168 |
        169 |
      • value
      • growth
      • 171 |
      172 | 173 |
    • 174 | 175 |
    • mouse sensitivities
    • 176 | 177 |
    • 178 |
        179 |
      • value
      • growth
      • 181 |
      182 | 183 |
    • 184 | 185 |
    • 186 | system 187 | 188 |
    • 189 | 190 |
    • 191 |
        192 |
      • levels
      • 194 |
      195 |
        196 |
      • rules
      • 198 |
      199 |
      200 | 208 |
      209 |
    • 210 | 211 | 212 |
    213 |
    214 | 215 |
    216 |
    217 |
    218 |
      219 |
      220 |
      221 |
      222 |
      223 | 224 |
      225 |
      226 | 227 | 228 | 229 | 230 | 231 | 232 |
      233 |
      234 |
      235 | 236 |
      237 |
      238 | 244 | 245 | 246 |
      247 |
      248 |
      249 | 250 |
      251 |
      252 | Fork me on GitHub 253 |
      254 |
      255 | 256 |
      257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 376 | 377 | 378 | 379 | 380 | 381 | --------------------------------------------------------------------------------