From 758bfb77f29bde33b8ca43a3c07171b8637a4547 Mon Sep 17 00:00:00 2001
From: Lars <github@lar5.com>
Date: Sat, 9 Aug 2014 15:05:07 -0700
Subject: [PATCH] v1.2

---
 roofpig_and_three.min.js  | 78 ++++++++++++++++++++++++---------------
 source/document.js.coffee |  2 +-
 2 files changed, 50 insertions(+), 30 deletions(-)

diff --git a/roofpig_and_three.min.js b/roofpig_and_three.min.js
index c6c2b1c..730e4eb 100644
--- a/roofpig_and_three.min.js
+++ b/roofpig_and_three.min.js
@@ -790,7 +790,7 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
         return TimedChanger.prototype.update = function (now) {
             return this._finished ? void 0 : now > this.start_time + this.duration ? this.finish() : this._make_change(now)
         }, TimedChanger.prototype.finish = function () {
-            return this.finished() ? void 0 : (this._make_change(this.start_time + this.duration), this._finished = !0)
+            return this.finished() ? void 0 : (this._make_change(this.start_time + this.duration), this._finished = !0, this._realign())
         }, TimedChanger.prototype.finished = function () {
             return this._finished
         }, TimedChanger.prototype._make_change = function (to_time) {
@@ -816,6 +816,8 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
 
         return __extends(CameraMovement, _super), CameraMovement.prototype.do_change = function (completion_diff) {
             return this.camera.rotate(this.axis, completion_diff * this.angle_to_turn)
+        }, CameraMovement.prototype._realign = function () {
+            return this.camera.to_position()
         }, CameraMovement
     }(TimedChanger)
 }.call(this), function () {
@@ -839,6 +841,10 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
         }, MoveExecution.prototype._rotateAroundWorldAxis = function (object, radians) {
             var rotWorldMatrix;
             return rotWorldMatrix = new THREE.Matrix4, rotWorldMatrix.makeRotationAxis(this.axis, radians), rotWorldMatrix.multiply(object.matrix), object.matrix = rotWorldMatrix, object.rotation.setFromRotationMatrix(object.matrix)
+        }, MoveExecution.prototype._realign = function () {
+            var p2, piece, r, _i, _len, _ref, _ref1, _results;
+            for (p2 = Math.PI / 2, _ref = this.pieces, _results = [], _i = 0, _len = _ref.length; _len > _i; _i++)piece = _ref[_i], r = piece.rotation, _results.push((_ref1 = [Math.round(r.x / p2) * p2, Math.round(r.y / p2) * p2, Math.round(r.z / p2) * p2], r.x = _ref1[0], r.y = _ref1[1], r.z = _ref1[2], _ref1));
+            return _results
         }, MoveExecution
     }(TimedChanger)
 }.call(this), function () {
@@ -1002,8 +1008,7 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
     this.Alg = function () {
         function Alg(move_codes, world3d, algdisplay, speed, dom) {
             var code, _i, _len, _ref;
-            if (this.move_codes = move_codes, this.world3d = world3d, this.algdisplay = algdisplay, this.speed = speed, this.dom = dom, !this.move_codes || "" === this.move_codes)throw new Error("Invalid alg: '" + this.move_codes + "'");
-            for (this.moves = [], _ref = this.move_codes.split(" "), _i = 0, _len = _ref.length; _len > _i; _i++)code = _ref[_i], code.length > 0 && this.moves.push(this._make_move(code));
+            for (this.move_codes = move_codes, this.world3d = world3d, this.algdisplay = algdisplay, this.speed = speed, this.dom = dom, this.moves = [], _ref = this.move_codes.split(" "), _i = 0, _len = _ref.length; _len > _i; _i++)code = _ref[_i], code.length > 0 && this.moves.push(this._make_move(code));
             this.next = 0, this.playing = !1, this._update_dom("first time")
         }
 
@@ -1067,12 +1072,14 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
                         return"B" + t1 + "+S" + t2
                 }
             }(), new CompositeMove(moves, this.world3d, this.speed, code))
-        }, Alg.prototype.side_drift = function () {
-            var result;
-            for (result = {U: "U", D: "D", L: "L", R: "R", F: "F", B: "B"}, this.next = this.moves.length; !this.at_start();)this.prev_move().track_drift(result);
-            return result
+        }, Alg.side_drift = function (moves) {
+            return new Alg(moves, null, "")._side_drift()
+        }, Alg.prototype._side_drift = function () {
+            var drift;
+            for (drift = {U: "U", D: "D", L: "L", R: "R", F: "F", B: "B"}, this.next = this.moves.length; !this.at_start();)this.prev_move().track_drift(drift);
+            return drift
         }, Alg.prototype._update_dom = function (time) {
-            return null == time && (time = "later"), this.dom ? ("first time" === time && this.dom.init_alg_text(this.display_text().future), this.dom.alg_changed(this.playing, this.at_start(), this.at_end(), this._count_text(), this.display_text())) : void 0
+            return null == time && (time = "later"), this.dom && this.moves.length > 0 ? ("first time" === time && this.dom.init_alg_text(this.display_text().future), this.dom.alg_changed(this.playing, this.at_start(), this.at_end(), this._count_text(), this.display_text())) : void 0
         }, Alg.prototype._count_text = function () {
             var count, current, i, move, total, _i, _len, _ref;
             for (total = current = 0, _ref = this.moves, i = _i = 0, _len = _ref.length; _len > _i; i = ++_i)move = _ref[i], count = move.count(this.algdisplay.rotations), this.next > i && (current += count), total += count;
@@ -1091,6 +1098,10 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
             var v, _i, _len, _ref;
             for (_ref = [this.cam.position, this.cam.up, this.user_dir.dl, this.user_dir.dr, this.user_dir.up], _i = 0, _len = _ref.length; _len > _i; _i++)v = _ref[_i], v.applyAxisAngle(axis, angle);
             return this._cam_moved()
+        }, Camera.prototype.to_position = function () {
+            var v, _i, _len, _ref, _ref1, _results;
+            for (_ref = [this.cam.position, this.cam.up, this.user_dir.dl, this.user_dir.dr, this.user_dir.up], _results = [], _i = 0, _len = _ref.length; _len > _i; _i++)v = _ref[_i], _results.push((_ref1 = [Math.round(v.x), Math.round(v.y), Math.round(v.z)], v.x = _ref1[0], v.y = _ref1[1], v.z = _ref1[2], _ref1));
+            return _results
         }, Camera.prototype.bend = function (dx, dy) {
             var axis, v, v1, v2, _i, _len, _ref;
             for (v1 = v3_x(this.user_dir.up, dx), v2 = v3_sub(this.user_dir.dr, this.user_dir.dl).normalize().multiplyScalar(dy), axis = v3_add(v1, v2).normalize(), this.cam.position = this.unbent_position.clone(), this.cam.up = this.unbent_up.clone(), _ref = [this.cam.position, this.cam.up], _i = 0, _len = _ref.length; _len > _i; _i++)v = _ref[_i], v.applyAxisAngle(axis, Math.sqrt(dx * dx + dy * dy));
@@ -1188,9 +1199,10 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
         }, Tweaks
     }()
 }.call(this), function () {
+    var __hasProp = {}.hasOwnProperty;
     this.Colors = function () {
-        function Colors(colored, solved, tweaks, colors) {
-            null == colors && (colors = ""), this.colored = new Cubexp(colored || "*"), this.solved = new Cubexp(solved), this.tweaks = new Tweaks(tweaks), this.side_colors = Colors._set_colors(colors)
+        function Colors(side_drift, colored, solved, tweaks, colors) {
+            null == colors && (colors = ""), this.colored = new Cubexp(this._undrift(colored, side_drift) || "*"), this.solved = new Cubexp(this._undrift(solved, side_drift)), this.tweaks = new Tweaks(this._undrift(tweaks, side_drift)), this.side_colors = Colors._set_colors(colors, side_drift)
         }
 
         var DEFAULT_COLORS;
@@ -1209,19 +1221,27 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
             var type;
             if (type = sticker_type.name || sticker_type, !this.side_colors[type])throw new Error("Unknown sticker type '" + sticker_type + "'");
             return this.side_colors[type]
-        }, Colors.prototype.adjust_for = function (drift) {
-            var sc, _ref;
-            return sc = this.side_colors, _ref = [sc[drift.U], sc[drift.D], sc[drift.R], sc[drift.L], sc[drift.F], sc[drift.B]], sc.U = _ref[0], sc.D = _ref[1], sc.R = _ref[2], sc.L = _ref[3], sc.F = _ref[4], sc.B = _ref[5], _ref
-        }, DEFAULT_COLORS = {g: "#0d0", b: "#07f", r: "red", o: "orange", y: "yellow", w: "#eee"}, Colors._set_colors = function (overrides) {
-            var color, dc, override, result, type, _i, _len, _ref, _ref1;
+        }, Colors.prototype._undrift = function (code, side_drift) {
+            var char, key, reverse_drift, value;
+            if (!code)return code;
+            reverse_drift = {};
+            for (key in side_drift)__hasProp.call(side_drift, key) && (value = side_drift[key], reverse_drift[value] = key, reverse_drift[value.toLowerCase()] = key.toLowerCase());
+            return function () {
+                var _i, _len, _ref, _results;
+                for (_ref = code.split(""), _results = [], _i = 0, _len = _ref.length; _len > _i; _i++)char = _ref[_i], _results.push(reverse_drift[char] || char);
+                return _results
+            }().join("")
+        }, DEFAULT_COLORS = {g: "#0d0", b: "#07f", r: "red", o: "orange", y: "yellow", w: "#eee"}, Colors._set_colors = function (overrides, side_drift) {
+            var color, d, dc, override, r, result, type, _i, _len, _ref, _ref1, _ref2, _ref3;
             for (dc = DEFAULT_COLORS, result = {R: dc.g, L: dc.b, F: dc.r, B: dc.o, U: dc.y, D: dc.w, solved: "#444", ignored: "#888", cube: "black"}, _ref = overrides.split(" "), _i = 0, _len = _ref.length; _len > _i; _i++)override = _ref[_i], _ref1 = override.split(":"), type = _ref1[0], color = _ref1[1], type = {s: "solved", i: "ignored", c: "cube"}[type] || type, result[type] = DEFAULT_COLORS[color] || color;
-            return result
+            return _ref2 = [result, side_drift], r = _ref2[0], d = _ref2[1], _ref3 = [r[d.U], r[d.D], r[d.R], r[d.L], r[d.F], r[d.B]], r.U = _ref3[0], r.D = _ref3[1], r.R = _ref3[2], r.L = _ref3[3], r.F = _ref3[4], r.B = _ref3[5], result
         }, Colors
     }()
 }.call(this), function () {
+    var ALG, ALGDISPLAY, BASE, COLORED, COLORS, FLAGS, HOVER, POV, PROPERTIES, SETUPMOVES, SOLVED, SPEED, TWEAKS;
     this.Config = function () {
         function Config(config_string) {
-            this.raw_input = Config._parse(config_string), this.base = this.base_config(this.raw_input.base, config_string), this.alg = this.raw("alg"), this.algdisplay = this._alg_display(), this.colors = new Colors(this.raw("colored"), this.raw("solved"), this.raw("tweaks"), this.raw("colors")), this.flags = this.raw("flags"), this.hover = this._hover(), this.pov = this.raw("pov", "Ufr"), this.setup = this.raw("setupmoves"), this.speed = this.raw("speed", 400)
+            this.raw_input = Config._parse(config_string), this.base = this.base_config(this.raw_input[BASE], config_string), this.alg = this.raw(ALG), this.algdisplay = this._alg_display(), this.colors = new Colors(Alg.side_drift(this.alg), this.raw(COLORED), this.raw(SOLVED), this.raw(TWEAKS), this.raw(COLORS)), this.flags = this.raw(FLAGS), this.hover = this._hover(), this.pov = this.raw(POV, "Ufr"), this.setup = this.raw(SETUPMOVES), this.speed = this.raw(SPEED, 400)
         }
 
         return Config.prototype.flag = function (name) {
@@ -1234,7 +1254,7 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
             }}
         }, Config.prototype._hover = function () {
             var raw_hover;
-            switch (raw_hover = this.raw("hover", "near")) {
+            switch (raw_hover = this.raw(HOVER, "near")) {
                 case"none":
                     return 1;
                 case"near":
@@ -1246,14 +1266,14 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
             }
         }, Config.prototype._alg_display = function () {
             var ad, result;
-            return ad = this.raw("algdisplay"), result = {}, result.fancy2s = ad.indexOf("fancy2s") > -1, result.rotations = ad.indexOf("rotations") > -1, result.Zcode = "2", ad.indexOf("2p") > -1 && (result.Zcode = "2'"), ad.indexOf("Z") > -1 && (result.Zcode = "Z"), result
+            return ad = this.raw(ALGDISPLAY), result = {}, result.fancy2s = ad.indexOf("fancy2s") > -1, result.rotations = ad.indexOf("rotations") > -1, result.Zcode = "2", ad.indexOf("2p") > -1 && (result.Zcode = "2'"), ad.indexOf("Z") > -1 && (result.Zcode = "Z"), result
         }, Config._parse = function (config_string) {
             var conf, eq_pos, key, result, value, _i, _len, _ref;
             if (!config_string)return{};
-            for (result = {}, _ref = config_string.split("|"), _i = 0, _len = _ref.length; _len > _i; _i++)conf = _ref[_i], eq_pos = conf.indexOf("="), key = conf.substring(0, eq_pos).trim(), value = conf.substring(eq_pos + 1).trim(), result[key] = value;
+            for (result = {}, _ref = config_string.split("|"), _i = 0, _len = _ref.length; _len > _i; _i++)conf = _ref[_i], eq_pos = conf.indexOf("="), key = conf.substring(0, eq_pos).trim(), value = conf.substring(eq_pos + 1).trim(), result[key] = value, -1 === PROPERTIES.indexOf(key) && log_error("Unknown config parameter '" + key + "' ignored");
             return result
         }, Config
-    }()
+    }(), PROPERTIES = [ALG = "alg", BASE = "base", ALGDISPLAY = "algdisplay", COLORED = "colored", COLORS = "colors", FLAGS = "flags", HOVER = "hover", POV = "pov", SETUPMOVES = "setupmoves", SOLVED = "solved", SPEED = "speed", TWEAKS = "tweaks"]
 }.call(this), function () {
     this.Css = function () {
         function Css() {
@@ -1264,8 +1284,8 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
     }()
 }.call(this), function () {
     this.Dom = function () {
-        function Dom(cube_id, div, renderer) {
-            this.cube_id = cube_id, this.div = div, this.div.css({position: "relative", "font-family": '"Lucida Sans Unicode", "Lucida Grande", sans-serif'}), this.has_focus(!1), this.div.data("cube_id", this.cube_id), renderer.setSize(this.div.width(), this.div.width()), this.div.append(renderer.domElement), this.scale = this.div.width() / 400, this.hscale = Math.max(this.scale, .375)
+        function Dom(cube_id, div, renderer, make_alg_area, showalg) {
+            this.cube_id = cube_id, this.div = div, this.div.css({position: "relative", "font-family": '"Lucida Sans Unicode", "Lucida Grande", sans-serif'}), this.has_focus(!1), this.div.data("cube_id", this.cube_id), renderer.setSize(this.div.width(), this.div.width()), this.div.append(renderer.domElement), this.scale = this.div.width() / 400, this.hscale = Math.max(this.scale, .375), make_alg_area && this.add_alg_area(showalg)
         }
 
         var LUCIDA_WIDTHS;
@@ -1334,7 +1354,7 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
 
         var button_keys, key_A, key_C, key_D, key_J, key_K, key_L, key_S, key_X, key_Z, key_down_arrow, key_end, key_home, key_left_arrow, key_question, key_right_arrow, key_space, key_tab, key_up_arrow, rotate_keys, side_for, turn_keys;
         return EventHandlers.set_focus = function (new_focus) {
-            return this.focus !== new_focus ? (this.focus && this.dom.has_focus(!1), this.focus = new_focus, this.camera = this.focus.camera, this.dom = this.focus.dom, this.dom.has_focus(!0)) : void 0
+            return this.focus !== new_focus ? (this.focus && this.dom.has_focus(!1), this.focus = new_focus, this.camera = this.focus.world3d.camera, this.dom = this.focus.dom, this.dom.has_focus(!0)) : void 0
         }, EventHandlers.initialize = function () {
             return $("body").keydown(function (e) {
                 return EventHandlers.key_down(e)
@@ -1430,8 +1450,8 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
     }()
 }.call(this), function () {
     this.Pieces3D = function () {
-        function Pieces3D(scene, config, use_canvas) {
-            this.use_canvas = use_canvas, this.at = {}, this.cube_surfaces = this.use_canvas ? [!0] : [!0, !1], this.sticker_size = this.use_canvas ? .84 : .9, this.hover_size = this.use_canvas ? .91 : .97, this.make_stickers(scene, config.hover, config.colors)
+        function Pieces3D(scene, hover, colors, use_canvas) {
+            this.use_canvas = use_canvas, this.at = {}, this.cube_surfaces = this.use_canvas ? [!0] : [!0, !1], this.sticker_size = this.use_canvas ? .84 : .9, this.hover_size = this.use_canvas ? .91 : .97, this.make_stickers(scene, hover, colors)
         }
 
         var TINY;
@@ -1509,7 +1529,7 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
     this.CubeAnimation = function () {
         function CubeAnimation(roofpig_div, webgl_works, canvas_works) {
             var use_canvas;
-            return canvas_works ? (this.id = CubeAnimation.last_id += 1, CubeAnimation.by_id[this.id] = this, this.config = new Config(roofpig_div.data("config")), use_canvas = this.config.flag("canvas") || !webgl_works || CubeAnimation.webgl_cubes >= 16, use_canvas ? this.renderer = new THREE.CanvasRenderer({alpha: !0}) : (CubeAnimation.webgl_cubes += 1, this.renderer = new THREE.WebGLRenderer({antialias: !0, alpha: !0})), this.dom = new Dom(this.id, roofpig_div, this.renderer), this.scene = new THREE.Scene, this.camera = new Camera(this.config.hover, this.config.pov), "" === this.config.alg ? (this.world3d = {camera: this.camera, pieces: new Pieces3D(this.scene, this.config, use_canvas)}, this.config.setup && new Alg(this.config.setup, this.world3d).to_end()) : (this.world3d = {camera: this.camera}, this.dom.add_alg_area(this.config.flag("showalg")), this.alg = new Alg(this.config.alg, this.world3d, this.config.algdisplay, this.config.speed, this.dom), this.config.colors.adjust_for(this.alg.side_drift()), this.world3d.pieces = new Pieces3D(this.scene, this.config, use_canvas), this.config.setup && new Alg(this.config.setup, this.world3d).to_end(), this.alg.mix()), 1 === this.id && EventHandlers.set_focus(this), this.changers = {}, void this.animate(!0)) : (roofpig_div.html("Your browser does not support <a href='http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation'>WebGL</a>.<p/> Find out how to get it <a href='http://get.webgl.org/'>here</a>."), void roofpig_div.css({background: "#f66"}))
+            return canvas_works ? (this.id = CubeAnimation.last_id += 1, CubeAnimation.by_id[this.id] = this, this.config = new Config(roofpig_div.data("config")), use_canvas = this.config.flag("canvas") || !webgl_works || CubeAnimation.webgl_cubes >= 16, use_canvas ? this.renderer = new THREE.CanvasRenderer({alpha: !0}) : (CubeAnimation.webgl_cubes += 1, this.renderer = new THREE.WebGLRenderer({antialias: !0, alpha: !0})), this.dom = new Dom(this.id, roofpig_div, this.renderer, "" !== this.config.alg, this.config.flag("showalg")), this.scene = new THREE.Scene, this.world3d = {camera: new Camera(this.config.hover, this.config.pov), pieces: new Pieces3D(this.scene, this.config.hover, this.config.colors, use_canvas)}, this.alg = new Alg(this.config.alg, this.world3d, this.config.algdisplay, this.config.speed, this.dom), this.config.setup && new Alg(this.config.setup, this.world3d).to_end(), this.alg.mix(), 1 === this.id && EventHandlers.set_focus(this), this.changers = {}, void this.animate(!0)) : (roofpig_div.html("Your browser does not support <a href='http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation'>WebGL</a>.<p/> Find out how to get it <a href='http://get.webgl.org/'>here</a>."), void roofpig_div.css({background: "#f66"}))
         }
 
         return CubeAnimation.last_id = 0, CubeAnimation.by_id = [], CubeAnimation.webgl_cubes = 0, CubeAnimation.prototype.next_cube = function () {
@@ -1522,7 +1542,7 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
             var any_change, category, changer, now, _ref;
             null == first_time && (first_time = !1), now = (new Date).getTime(), _ref = this.changers;
             for (category in _ref)__hasProp.call(_ref, category) && (changer = _ref[category], changer && (changer.update(now), changer.finished() && (this.changers[category] = null), any_change = !0));
-            return(any_change || first_time) && this.renderer.render(this.scene, this.camera.cam), requestAnimationFrame(function (_this) {
+            return(any_change || first_time) && this.renderer.render(this.scene, this.world3d.camera.cam), requestAnimationFrame(function (_this) {
                 return function () {
                     return _this.animate()
                 }
@@ -1561,7 +1581,7 @@ fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform
 }.call(this), function () {
     $(document).ready(function () {
         var canvas_browser, roofpig_div, webgl_browser, _i, _len, _ref;
-        for (console.log("Roofpig version 1.1 (2014-07-11 14:59). Expecting jQuery 1.11.1 and Three.js 67."), console.log("jQuery version", $.fn.jquery), $("head").append(Css.CODE), webgl_browser = function () {
+        for (console.log("Roofpig version 1.2 (2014-08-09 12:52). Expecting jQuery 1.11.1 and Three.js 67."), console.log("jQuery version", $.fn.jquery), $("head").append(Css.CODE), webgl_browser = function () {
             var e;
             try {
                 return!!window.WebGLRenderingContext && !!document.createElement("canvas").getContext("experimental-webgl")
diff --git a/source/document.js.coffee b/source/document.js.coffee
index 3aa4603..f4f1800 100644
--- a/source/document.js.coffee
+++ b/source/document.js.coffee
@@ -1,7 +1,7 @@
 #= require roofpig/Css
 
 $(document).ready ->
-  console.log("Roofpig version 1.1 (@@BUILT_WHEN@@). Expecting jQuery 1.11.1 and Three.js 67.")
+  console.log("Roofpig version 1.2 (@@BUILT_WHEN@@). Expecting jQuery 1.11.1 and Three.js 67.")
   console.log("jQuery version", $.fn.jquery)
 
   $('head').append(Css.CODE)