Want to join? Log In or Join Now in seconds. English (United States)

CREATE A NEW ACCOUNT

{{registerModel.Error}}

Log In

/content/images/forum.png

Feedbacks

Get help from the knowledgeable Reddah Community and official Reddah Support!
/content/images/ambassador.png

Discuss on AD

A place for discussing the ads that reddah is currently running.
/content/images/contact_us.png

Contact Us

Get in touch with an Reddah Support technician. We are ready and willing to help you!
126

/** * EvEmitter v1.0.2 * Lil' event emitter * MIT License */ /* jshint unused: true, undef: true, strict: true */ (function(global, factory) { // universal module definition /* jshint strict: false */ /* globals define, module */ if (typeof define == 'function' && define.amd) { // AMD - RequireJS define(factory); } else if (typeof module == 'object' && module.exports) { // CommonJS - Browserify, Webpack module.exports = factory(); } else { // Browser globals global.EvEmitter = factory(); } }(this, function() { "use strict"; function EvEmitter() {} var proto = EvEmitter.prototype; proto.on = function(eventName, listener) { if (!eventName || !listener) { return; } // set events hash var events = this._events = this._events || {}; // set listeners array var listeners = events[eventName] = events[eventName] || []; // only add once if (listeners.indexOf(listener) == -1) { listeners.push(listener); } return this; }; proto.once = function(eventName, listener) { if (!eventName || !listener) { return; } // add event this.on(eventName, listener); // set once flag // set onceEvents hash var onceEvents = this._onceEvents = this._onceEvents || {}; // set onceListeners object var onceListeners = onceEvents[eventName] = onceEvents[eventName] || {}; // set flag onceListeners[listener] = true; return this; }; proto.off = function(eventName, listener) { var listeners = this._events && this._events[eventName]; if (!listeners || !listeners.length) { return; } var index = listeners.indexOf(listener); if (index != -1) { listeners.splice(index, 1); } return this; }; proto.emitEvent = function(eventName, args) { var listeners = this._events && this._events[eventName]; if (!listeners || !listeners.length) { return; } var i = 0; var listener = listeners[i]; args = args || []; // once stuff var onceListeners = this._onceEvents && this._onceEvents[eventName]; while (listener) { var isOnce = onceListeners && onceListeners[listener]; if (isOnce) { // remove listener // remove before trigger to prevent recursion this.off(eventName, listener); // unset once flag delete onceListeners[listener]; } // trigger listener listener.apply(this, args); // get next listener i += isOnce ? 0 : 1; listener = listeners[i]; } return this; }; return EvEmitter; })); /*! * Unipointer v2.1.0 * base class for doing one thing with pointer event * MIT license */ /*jshint browser: true, undef: true, unused: true, strict: true */ (function(window, factory) { // universal module definition /* jshint strict: false */ /*global define, module, require */ if (typeof define == 'function' && define.amd) { // AMD define([ 'ev-emitter/ev-emitter' ], function(EvEmitter) { return factory(window, EvEmitter); }); } else if (typeof module == 'object' && module.exports) { // CommonJS module.exports = factory( window, require('ev-emitter') ); } else { // browser global window.Unipointer = factory( window, window.EvEmitter ); } }(window, function factory(window, EvEmitter) { 'use strict'; function noop() {} function Unipointer() {} // inherit EvEmitter var proto = Unipointer.prototype = Object.create(EvEmitter.prototype); proto.bindStartEvent = function(elem) { this._bindStartEvent(elem, true); }; proto.unbindStartEvent = function(elem) { this._bindStartEvent(elem, false); }; /** * works as unbinder, as you can ._bindStart( false ) to unbind * @param {Boolean} isBind - will unbind if falsey */ proto._bindStartEvent = function(elem, isBind) { // munge isBind, default to true isBind = isBind === undefined ? true : !!isBind; var bindMethod = isBind ? 'addEventListener' : 'removeEventListener'; if (window.navigator.pointerEnabled) { // W3C Pointer Events, IE11. See https://coderwall.com/p/mfreca elem[bindMethod]('pointerdown', this); } else if (window.navigator.msPointerEnabled) { // IE10 Pointer Events elem[bindMethod]('MSPointerDown', this); } else { // listen for both, for devices like Chrome Pixel elem[bindMethod]('mousedown', this); elem[bindMethod]('touchstart', this); } }; // trigger handler methods for events proto.handleEvent = function(event) { var method = 'on' + event.type; if (this[method]) { this[method](event); } }; // returns the touch that we're keeping track of proto.getTouch = function(touches) { for (var i = 0; i < touches.length; i++) { var touch = touches[i]; if (touch.identifier == this.pointerIdentifier) { return touch; } } }; // ----- start event ----- // proto.onmousedown = function(event) { // dismiss clicks from right or middle buttons var button = event.button; if (button && (button !== 0 && button !== 1)) { return; } this._pointerDown(event, event); }; proto.ontouchstart = function(event) { this._pointerDown(event, event.changedTouches[0]); }; proto.onMSPointerDown = proto.onpointerdown = function(event) { this._pointerDown(event, event); }; /** * pointer start * @param {Event} event * @param {Event or Touch} pointer */ proto._pointerDown = function(event, pointer) { // dismiss other pointers if (this.isPointerDown) { return; } this.isPointerDown = true; // save pointer identifier to match up touch events this.pointerIdentifier = pointer.pointerId !== undefined ? // pointerId for pointer events, touch.indentifier for touch events pointer.pointerId : pointer.identifier; this.pointerDown(event, pointer); }; proto.pointerDown = function(event, pointer) { this._bindPostStartEvents(event); this.emitEvent('pointerDown', [event, pointer]); }; // hash of events to be bound after start event var postStartEvents = { mousedown: ['mousemove', 'mouseup'], touchstart: ['touchmove', 'touchend', 'touchcancel'], pointerdown: ['pointermove', 'pointerup', 'pointercancel'], MSPointerDown: ['MSPointerMove', 'MSPointerUp', 'MSPointerCancel'] }; proto._bindPostStartEvents = function(event) { if (!event) { return; } // get proper events to match start event var events = postStartEvents[event.type]; // bind events to node events.forEach(function(eventName) { window.addEventListener(eventName, this); }, this); // save these arguments this._boundPointerEvents = events; }; proto._unbindPostStartEvents = function() { // check for _boundEvents, in case dragEnd triggered twice (old IE8 bug) if (!this._boundPointerEvents) { return; } this._boundPointerEvents.forEach(function(eventName) { window.removeEventListener(eventName, this); }, this); delete this._boundPointerEvents; }; // ----- move event ----- // proto.onmousemove = function(event) { this._pointerMove(event, event); }; proto.onMSPointerMove = proto.onpointermove = function(event) { if (event.pointerId == this.pointerIdentifier) { this._pointerMove(event, event); } }; proto.ontouchmove = function(event) { var touch = this.getTouch(event.changedTouches); if (touch) { this._pointerMove(event, touch); } }; /** * pointer move * @param {Event} event * @param {Event or Touch} pointer * @private */ proto._pointerMove = function(event, pointer) { this.pointerMove(event, pointer); }; // public proto.pointerMove = function(event, pointer) { this.emitEvent('pointerMove', [event, pointer]); }; // ----- end event ----- // proto.onmouseup = function(event) { this._pointerUp(event, event); }; proto.onMSPointerUp = proto.onpointerup = function(event) { if (event.pointerId == this.pointerIdentifier) { this._pointerUp(event, event); } }; proto.ontouchend = function(event) { var touch = this.getTouch(event.changedTouches); if (touch) { this._pointerUp(event, touch); } }; /** * pointer up * @param {Event} event * @param {Event or Touch} pointer * @private */ proto._pointerUp = function(event, pointer) { this._pointerDone(); this.pointerUp(event, pointer); }; // public proto.pointerUp = function(event, pointer) { this.emitEvent('pointerUp', [event, pointer]); }; // ----- pointer done ----- // // triggered on pointer up & pointer cancel proto._pointerDone = function() { // reset properties this.isPointerDown = false; delete this.pointerIdentifier; // remove events this._unbindPostStartEvents(); this.pointerDone(); }; proto.pointerDone = noop; // ----- pointer cancel ----- // proto.onMSPointerCancel = proto.onpointercancel = function(event) { if (event.pointerId == this.pointerIdentifier) { this._pointerCancel(event, event); } }; proto.ontouchcancel = function(event) { var touch = this.getTouch(event.changedTouches); if (touch) { this._pointerCancel(event, touch); } }; /** * pointer cancel * @param {Event} event * @param {Event or Touch} pointer * @private */ proto._pointerCancel = function(event, pointer) { this._pointerDone(); this.pointerCancel(event, pointer); }; // public proto.pointerCancel = function(event, pointer) { this.emitEvent('pointerCancel', [event, pointer]); }; // ----- ----- // // utility function for getting x/y coords from event Unipointer.getPointerPoint = function(pointer) { return { x: pointer.pageX, y: pointer.pageY }; }; // ----- ----- // return Unipointer; })); function FreeSegment(a, b) { this.type = 'FreeSegment'; this.a = a; this.b = b; // orientations this.noon = { a: a, b: b }; this.three = { a: { x: -a.y, y: a.x }, b: { x: -b.y, y: b.x } }; this.six = { a: { x: -a.x, y: -a.y }, b: { x: -b.x, y: -b.y } }; this.nine = { a: { x: a.y, y: -a.x }, b: { x: b.y, y: -b.x } }; } var proto = FreeSegment.prototype; proto.connect = function(maze) { this.connectOrientation(maze, 'noon'); this.connectOrientation(maze, 'three'); this.connectOrientation(maze, 'six'); this.connectOrientation(maze, 'nine'); }; proto.connectOrientation = function(maze, orientation) { var line = this[orientation]; maze.connect(this, orientation, line.a); maze.connect(this, orientation, line.b); }; proto.render = function(ctx, center, gridSize) { var ax = this.a.x * gridSize; var ay = this.a.y * gridSize; var bx = this.b.x * gridSize; var by = this.b.y * gridSize; ctx.strokeStyle = 'hsla(200, 80%, 50%, 0.7)'; ctx.lineWidth = gridSize * 0.6; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(ax, ay); ctx.lineTo(bx, by); ctx.stroke(); ctx.closePath(); }; function FixedSegment(a, b) { this.type = 'FixedSegment'; this.a = a; this.b = b; // orientations this.noon = { a: a, b: b }; this.three = { a: a, b: b }; this.six = { a: a, b: b }; this.nine = { a: a, b: b }; } var proto = FixedSegment.prototype; proto.connect = function(maze) { maze.connect(this, 'noon', this.a); maze.connect(this, 'noon', this.b); maze.connect(this, 'three', this.a); maze.connect(this, 'three', this.b); maze.connect(this, 'six', this.a); maze.connect(this, 'six', this.b); maze.connect(this, 'nine', this.a); maze.connect(this, 'nine', this.b); }; proto.render = function(ctx, center, gridSize) { var ax = this.a.x * gridSize; var ay = this.a.y * gridSize; var bx = this.b.x * gridSize; var by = this.b.y * gridSize; ctx.strokeStyle = 'hsla(30, 100%, 40%, 0.6)'; ctx.lineWidth = gridSize * 0.8; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(ax, ay); ctx.lineTo(bx, by); ctx.stroke(); ctx.closePath(); }; function PivotSegment(a, b) { this.type = 'FreeSegment'; this.a = a; this.b = b; var dx = b.x - a.x; var dy = b.y - a.y; this.delta = { x: dx, y: dy }; // orientations this.noon = { a: a, b: b }; this.three = { a: { x: -a.y, y: a.x }, b: { x: -a.y + dx, y: a.x + dy } }; this.six = { a: { x: -a.x, y: -a.y }, b: { x: -a.x + dx, y: -a.y + dy } }; this.nine = { a: { x: a.y, y: -a.x }, b: { x: a.y + dx, y: -a.x + dy } }; } var proto = PivotSegment.prototype; proto.connect = function(maze) { this.connectOrientation(maze, 'noon'); this.connectOrientation(maze, 'three'); this.connectOrientation(maze, 'six'); this.connectOrientation(maze, 'nine'); }; proto.connectOrientation = function(maze, orientation) { var line = this[orientation]; if (maze.getIsPegOut(line.a) || maze.getIsPegOut(line.b)) { return; } maze.connect(this, orientation, line.a); maze.connect(this, orientation, line.b); }; proto.render = function(ctx, center, gridSize, mazeAngle) { var ax = this.a.x * gridSize; var ay = this.a.y * gridSize; var bx = this.delta.x * gridSize; var by = this.delta.y * gridSize; ctx.save(); ctx.translate(ax, ay); ctx.rotate(-mazeAngle); var color = 'hsla(150, 100%, 35%, 0.7)' // line ctx.strokeStyle = color; ctx.lineWidth = gridSize * 0.4; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(bx, by); ctx.stroke(); ctx.closePath(); // circle ctx.fillStyle = color; ctx.beginPath(); ctx.arc(0, 0, gridSize * 0.4, 0, Math.PI * 2); ctx.fill(); ctx.closePath(); ctx.restore(); }; // rotational physics model var TAU = Math.PI * 2; function FlyWheel(props) { this.angle = 0; this.friction = 0.95; this.velocity = 0; for (var prop in props) { this[prop] = props[prop]; } } var proto = FlyWheel.prototype; proto.integrate = function() { this.velocity *= this.friction; this.angle += this.velocity; this.normalizeAngle(); }; proto.applyForce = function(force) { this.velocity += force; }; proto.normalizeAngle = function() { this.angle = ((this.angle % TAU) + TAU) % TAU; }; proto.setAngle = function(theta) { var velo = theta - this.angle; if (velo > TAU / 2) { velo -= TAU; } else if (velo < -TAU / 2) { velo += TAU; } var force = velo - this.velocity; this.applyForce(force); }; var cub = { offset: { x: 0, y: 0 }, }; var pegOrienter = { noon: function(peg) { return peg; }, three: function(peg) { return { x: peg.y, y: -peg.x }; }, six: function(peg) { return { x: -peg.x, y: -peg.y }; }, nine: function(peg) { return { x: -peg.y, y: peg.x }; }, }; cub.setPeg = function(peg, orientation) { peg = pegOrienter[orientation](peg); this.peg = peg; this.noon = { x: peg.x, y: peg.y }; this.three = { x: -peg.y, y: peg.x }; this.six = { x: -peg.x, y: -peg.y }; this.nine = { x: peg.y, y: -peg.x }; }; var offsetOrienter = { noon: function(offset) { return offset; }, three: function(offset) { // flip y because its rendering return { x: offset.y, y: -offset.x }; }, six: function(offset) { return { x: -offset.x, y: -offset.y }; }, nine: function(offset) { // flip y because its rendering return { x: -offset.y, y: offset.x }; }, }; cub.setOffset = function(offset, orientation) { this.offset = offsetOrienter[orientation](offset); }; // ----- render ----- // cub.render = function(ctx, mazeCenter, gridSize, angle, isHovered) { function circle(x, y, radius) { ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI * 2); ctx.fill(); ctx.closePath(); } // function eye( direction ) { // ctx.beginPath(); // ctx.arc( gridSize * 0.25 * direction, gridSize * 0.05, gridSize * 0.1, Math.PI, Math.PI*2 ); // ctx.fill(); // ctx.closePath(); // } var x = this.peg.x * gridSize + this.offset.x; var y = this.peg.y * gridSize + this.offset.y; ctx.save(); ctx.translate(mazeCenter.x, mazeCenter.y); ctx.rotate(angle); ctx.translate(x, y); ctx.rotate(-angle); ctx.fillStyle = 'hsla(330, 100%, 40%, 1)'; var scale = isHovered ? 1.15 : 1; ctx.scale(scale, scale); circle(0, 0, gridSize * 0.6); circle(gridSize * -0.45, gridSize * -0.35, gridSize * 0.3); circle(gridSize * 0.45, gridSize * -0.35, gridSize * 0.3); // // eyes // ctx.fillStyle = 'hsla(0, 0%, 0%, 0.8)'; // eye( 1 ); // eye( -1 ); // // nose // ctx.beginPath(); // ctx.arc( 0, gridSize * 0.15, gridSize * 0.1, 0, Math.PI ); // ctx.fill(); // ctx.closePath(); ctx.restore(); }; /* globals FlyWheel, FreeSegment, FixedSegment, PivotSegment, cub */ function Maze() { this.freeSegments = []; this.fixedSegments = []; this.pivotSegments = []; this.flyWheel = new FlyWheel({ friction: 0.8 }); this.connections = {}; } var proto = Maze.prototype; proto.loadText = function(text) { // separate --- sections, YAML front matter first, maze source second; var sections = text.split('---\n'); // YAML front matter var frontMatter = {}; if (sections.length > 1) { var frontMatter = getFrontMatter(sections[0]); } // set instruction var instructElem = document.querySelector('.instruction'); instructElem.innerHTML = frontMatter.instruction || ''; var mazeSrc = sections[sections.length - 1]; var lines = mazeSrc.split('\n'); var gridCount = this.gridCount = lines[0].length; var gridMax = this.gridMax = (gridCount - 1) / 2; for (var i = 0; i < lines.length; i++) { var line = lines[i]; var chars = line.split(''); for (var j = 0; j < chars.length; j++) { var character = chars[j]; var pegX = j - gridMax; var pegY = i - gridMax; var parseMethod = 'parse' + character; if (this[parseMethod]) { this[parseMethod](pegX, pegY); } } } }; function getFrontMatter(text) { if (!text) { return; } var frontMatter = {}; text.split('\n').forEach(function(line) { if (!line) { return; } var parts = line.split(':'); var key = parts[0].trim(); var value = parts[1].trim(); if (value === 'true') { value = true; // boolean true } else if (value === 'false') { value = false; // boolean false } else if (value.match(/$\d+(\.\d+)?^/)) { value = parseFloat(value, 10); // number } else if (value.match(/$\d+\.\d+^/)) { value = parseFloat(value); // float } frontMatter[key] = value; }); return frontMatter; } // -------------------------- parsers -------------------------- // // horizontal free segment proto['parse-'] = proto.addFreeHorizSegment = function(pegX, pegY) { var segment = getHorizSegment(pegX, pegY, FreeSegment); segment.connect(this); this.freeSegments.push(segment); }; // vertical free segment proto['parse|'] = proto.addFreeVertSegment = function(pegX, pegY) { var segment = getVertSegment(pegX, pegY, FreeSegment); segment.connect(this); this.freeSegments.push(segment); }; // horizontal fixed segment proto['parse='] = proto.addFixedHorizSegment = function(pegX, pegY) { var segment = getHorizSegment(pegX, pegY, FixedSegment); segment.connect(this); this.fixedSegments.push(segment); }; // vertical fixed segment proto['parse!'] = proto.addFixedVertSegment = function(pegX, pegY) { var segment = getVertSegment(pegX, pegY, FixedSegment); segment.connect(this); this.fixedSegments.push(segment); }; function getHorizSegment(pegX, pegY, Segment) { var a = { x: pegX + 1, y: pegY }; var b = { x: pegX - 1, y: pegY }; return new Segment(a, b); } function getVertSegment(pegX, pegY, Segment) { var a = { x: pegX, y: pegY + 1 }; var b = { x: pegX, y: pegY - 1 }; return new Segment(a, b); } // pivot up segment proto['parse^'] = function(pegX, pegY) { var a = { x: pegX, y: pegY + 1 }; var b = { x: pegX, y: pegY - 1 }; var segment = new PivotSegment(a, b); segment.connect(this); this.pivotSegments.push(segment); }; // pivot down segment proto.parsev = proto.addPivotDownSegment = function(pegX, pegY) { var a = { x: pegX, y: pegY - 1 }; var b = { x: pegX, y: pegY + 1 }; var segment = new PivotSegment(a, b); segment.connect(this); this.pivotSegments.push(segment); }; // pivot left segment proto['parse<'] = proto.addPivotLeftSegment = function(pegX, pegY) { var a = { x: pegX + 1, y: pegY }; var b = { x: pegX - 1, y: pegY }; var segment = new PivotSegment(a, b); segment.connect(this); this.pivotSegments.push(segment); }; // pivot right segment proto['parse>'] = proto.addPivotRightSegment = function(pegX, pegY) { var a = { x: pegX - 1, y: pegY }; var b = { x: pegX + 1, y: pegY }; var segment = new PivotSegment(a, b); segment.connect(this); this.pivotSegments.push(segment); }; // free & fixed horizontal proto['parse#'] = function(pegX, pegY) { this.addFreeHorizSegment(pegX, pegY); this.addFixedHorizSegment(pegX, pegY); }; // free & fixed vertical proto.parse$ = function(pegX, pegY) { this.addFreeVertSegment(pegX, pegY); this.addFixedVertSegment(pegX, pegY); }; // pivot up + fixed vertical proto.parseI = function(pegX, pegY) { this.addPivotUpSegment(pegX, pegY); this.addFixedVertSegment(pegX, pegY); }; // pivot left + fixed horizontal proto.parseJ = function(pegX, pegY) { this.addPivotLeftSegment(pegX, pegY); this.addFixedHorizSegment(pegX, pegY); }; // pivot down + fixed vertical proto.parseK = function(pegX, pegY) { this.addPivotDownSegment(pegX, pegY); this.addFixedVertSegment(pegX, pegY); }; // pivot right + fixed horizontal proto.parseL = function(pegX, pegY) { this.addPivotRightSegment(pegX, pegY); this.addFixedHorizSegment(pegX, pegY); }; // pivot up + free vertical proto.parseW = function(pegX, pegY) { this.addPivotUpSegment(pegX, pegY); this.addFreeVertSegment(pegX, pegY); }; // pivot left + free horizontal proto.parseA = function(pegX, pegY) { this.addPivotLeftSegment(pegX, pegY); this.addFreeHorizSegment(pegX, pegY); }; // pivot down + free vertical proto.parseS = function(pegX, pegY) { this.addPivotDownSegment(pegX, pegY); this.addFreeVertSegment(pegX, pegY); }; // pivot right + free horizontal proto.parseD = function(pegX, pegY) { this.addPivotRightSegment(pegX, pegY); this.addFreeHorizSegment(pegX, pegY); }; // start position proto['parse@'] = function(pegX, pegY) { this.startPosition = { x: pegX, y: pegY }; cub.setPeg(this.startPosition, 'noon'); }; // goal position proto['parse*'] = function(pegX, pegY) { this.goalPosition = { x: pegX, y: pegY }; }; // -------------------------- -------------------------- // proto.updateItemGroups = function() { var itemGroups = {}; this.items.forEach(function(item) { if (itemGroups[item.type] === undefined) { itemGroups[item.type] = []; } itemGroups[item.type].push(item); }); this.itemGroups = itemGroups; }; proto.connect = function(segment, orientation, position) { // flatten the key var key = orientation + ':' + position.x + ',' + position.y; var connection = this.connections[key]; // create connections array if not already there if (!connection) { connection = this.connections[key] = []; } if (connection.indexOf(segment) == -1) { connection.push(segment); } }; proto.getIsPegOut = function(peg) { return Math.abs(peg.x) > this.gridMax || Math.abs(peg.y) > this.gridMax; }; // -------------------------- -------------------------- // proto.update = function() { this.flyWheel.integrate(); var angle = this.flyWheel.angle; if (angle < TAU / 8) { this.orientation = 'noon'; } else if (angle < TAU * 3 / 8) { this.orientation = 'three'; } else if (angle < TAU * 5 / 8) { this.orientation = 'six'; } else if (angle < TAU * 7 / 8) { this.orientation = 'nine'; } else { this.orientation = 'noon'; } }; proto.attractAlignFlyWheel = function() { // attract towards var angle = this.flyWheel.angle; var target; if (angle < TAU / 8) { target = 0; } else if (angle < TAU * 3 / 8) { target = TAU / 4; } else if (angle < TAU * 5 / 8) { target = TAU / 2; } else if (angle < TAU * 7 / 8) { target = TAU * 3 / 4; } else { target = TAU; } var attraction = (target - angle) * 0.03; this.flyWheel.applyForce(attraction); }; var TAU = Math.PI * 2; var orientationAngles = { noon: 0, three: TAU / 4, six: TAU / 2, nine: TAU * 3 / 4 }; proto.render = function(ctx, center, gridSize, angle) { var orientationAngle = orientationAngles[angle]; var gridMax = this.gridMax; angle = orientationAngle !== undefined ? orientationAngle : angle || 0; ctx.save(); ctx.translate(center.x, center.y); // fixed segments this.fixedSegments.forEach(function(item) { item.render(ctx, center, gridSize); }); // rotation ctx.rotate(angle); ctx.lineWidth = gridSize * 0.2; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; // axle ctx.lineWidth = gridSize * 0.2; ctx.strokeStyle = 'hsla(0, 0%, 50%, 0.2)'; // strokeCircle( ctx, 0, 0, gridSize/2 ); ctx.save(); ctx.rotate(Math.PI / 4); ctx.strokeRect(-gridSize / 5, -gridSize / 5, gridSize * 2 / 5, gridSize * 2 / 5); ctx.restore(); // start position ctx.strokeStyle = 'hsla(330, 100%, 50%, 0.3)'; ctx.lineWidth = gridSize * 0.15; var startX = this.startPosition.x * gridSize; var startY = this.startPosition.y * gridSize; strokeCircle(ctx, startX, startY, gridSize * 0.5); // pegs for (var pegY = -gridMax; pegY <= gridMax; pegY += 2) { for (var pegX = -gridMax; pegX <= gridMax; pegX += 2) { var pegXX = pegX * gridSize; var pegYY = pegY * gridSize; ctx.fillStyle = 'hsla(0, 0%, 50%, 0.6)'; fillCircle(ctx, pegXX, pegYY, gridSize * 0.15); } } // free segments this.freeSegments.forEach(function(segment) { segment.render(ctx, center, gridSize); }); // pivot segments this.pivotSegments.forEach(function(segment) { segment.render(ctx, center, gridSize, angle); }); // goal position var goalX = this.goalPosition.x * gridSize; var goalY = this.goalPosition.y * gridSize; ctx.lineWidth = gridSize * 0.3; ctx.fillStyle = 'hsla(50, 100%, 50%, 1)'; ctx.strokeStyle = 'hsla(50, 100%, 50%, 1)'; renderGoal(ctx, goalX, goalY, angle, gridSize * 0.6, gridSize * 0.3); ctx.restore(); }; function fillCircle(ctx, x, y, radius) { ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI * 2); ctx.fill(); ctx.closePath(); } function strokeCircle(ctx, x, y, radius) { ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI * 2); ctx.stroke(); ctx.closePath(); } function renderGoal(ctx, x, y, mazeAngle, radiusA, radiusB) { ctx.save(); ctx.translate(x, y); ctx.rotate(-mazeAngle); ctx.beginPath(); for (var i = 0; i < 11; i++) { var theta = Math.PI * 2 * i / 10 + Math.PI / 2; var radius = i % 2 ? radiusA : radiusB; var dx = Math.cos(theta) * radius; var dy = Math.sin(theta) * radius; ctx[i ? 'lineTo' : 'moveTo'](dx, dy); } ctx.fill(); ctx.stroke(); ctx.closePath(); ctx.restore(); } function WinAnimation(x, y) { this.x = x; this.y = y; this.startTime = new Date(); this.isPlaying = true; } // length of animation in milliseconds var duration = 1000; var proto = WinAnimation.prototype; proto.update = function() { if (!this.isPlaying) { return; } this.t = ((new Date()) - this.startTime) / duration; this.isPlaying = this.t <= 1; }; proto.render = function(ctx) { if (!this.isPlaying) { return; } ctx.save(); ctx.translate(this.x, this.y); // big burst this.renderBurst(ctx); // small burst ctx.save(); ctx.scale(0.5, -0.5); this.renderBurst(ctx); ctx.restore(); ctx.restore(); }; proto.renderBurst = function(ctx) { var t = this.t; var dt = 1 - t; var easeT = 1 - dt * dt * dt * dt * dt * dt * dt * dt; var dy = easeT * -100; // scale math var st = 2 - this.t * 2; var scale = (1 - t * t * t) * 1.5; var spin = Math.PI * 1 * t * t * t; for (var i = 0; i < 5; i++) { ctx.save(); ctx.rotate(Math.PI * 2 / 5 * i); ctx.translate(0, dy); ctx.scale(scale, scale); ctx.rotate(spin); renderStar(ctx); ctx.restore(); } }; function renderStar(ctx) { ctx.lineWidth = 8; ctx.lineJoin = 'round'; ctx.lineCap = 'round'; ctx.fillStyle = 'hsla(50, 100%, 50%, 1)'; ctx.strokeStyle = 'hsla(50, 100%, 50%, 1)'; ctx.beginPath(); for (var i = 0; i < 11; i++) { var theta = Math.PI * 2 * i / 10 + Math.PI / 2; var radius = i % 2 ? 20 : 10; var dx = Math.cos(theta) * radius; var dy = Math.sin(theta) * radius; ctx[i ? 'lineTo' : 'moveTo'](dx, dy); } ctx.fill(); ctx.stroke(); ctx.closePath(); } /* globals cub, WinAnimation, Unipointer, Maze */ var docElem = document.documentElement; var canvas = document.querySelector('canvas'); var ctx = canvas.getContext('2d'); // size canvas; var canvasSize = Math.min(window.innerWidth, window.innerHeight); var canvasWidth = canvas.width = window.innerWidth * 2; var canvasHeight = canvas.height = window.innerHeight * 2; var maze; var PI = Math.PI; var TAU = PI * 2; var dragAngle = null; var cubDragMove = null; var isCubHovered = false; var isCubDragging = false; var winAnim; var unipointer = new Unipointer(); // ----- config ----- // var gridSize = Math.min(40, canvasSize / 12); var mazeCenter = { x: canvasWidth / 4, y: Math.min(gridSize * 8, canvasHeight / 4) }; // ----- instruction ----- // var instructElem = document.querySelector('.instruction'); instructElem.style.top = (mazeCenter.y + gridSize * 5.5) + 'px'; // ----- build level select, levels array ----- // var levelList = document.querySelector('.level-list'); var levelsElem = document.querySelector('.levels'); var levels = []; (function() { var levelPres = levelsElem.querySelectorAll('pre'); var fragment = document.createDocumentFragment(); for (var i = 0; i < levelPres.length; i++) { var pre = levelPres[i]; var listItem = document.createElement('li'); listItem.className = 'level-list__item'; var id = pre.id; listItem.innerHTML = '<span class="level-list__item__number">' + (i + 1) + '</span> <span class="level-list__item__blurb">' + pre.getAttribute('data-blurb') + '</span>' + '<span class="level-list__item__check">?</span>'; listItem.setAttribute('data-id', id); fragment.appendChild(listItem); levels.push(id); } levelList.appendChild(fragment); })(); // ----- levels button ----- // var levelSelectButton = document.querySelector('.level-select-button'); var nextLevelButton = document.querySelector('.next-level-button'); levelSelectButton.addEventListener('click', function() { levelList.classList.add('is-open'); }); nextLevelButton.style.top = (mazeCenter.y + gridSize * 5.5) + 'px'; // ----- level list ----- // levelList.addEventListener('click', function(event) { var item = getParent(event.target, '.level-list__item'); if (!item) { return; } // load level from id var id = item.getAttribute('data-id'); loadLevel(id); }); function getParent(elem, selector) { var parent = elem; while (parent != document.body) { if (parent.matches(selector)) { return parent; } parent = parent.parentNode; } } // ----- load level ----- // function loadLevel(id) { var pre = levelsElem.querySelector('#' + id); maze = new Maze(); maze.id = id; // load maze level from pre text maze.loadText(pre.textContent); // close ui levelList.classList.remove('is-open'); nextLevelButton.classList.remove('is-open'); window.scrollTo(0, 0); // highlight list var previousItem = levelList.querySelector('.is-playing'); if (previousItem) { previousItem.classList.remove('is-playing'); } levelList.querySelector('[data-id="' + id + '"]').classList.add('is-playing'); localStorage.setItem('currentLevel', id); } // ----- init ----- // var initialLevel = localStorage.getItem('currentLevel') || levels[0]; loadLevel(initialLevel); unipointer.bindStartEvent(canvas); window.addEventListener('mousemove', onHoverMousemove); animate(); window["reddahApi"].loadCompleted(); // -------------------------- drag rotation -------------------------- // var canvasLeft = canvas.offsetLeft; var canvasTop = canvas.offsetTop; var pointerBehavior; // ----- pointerBehavior ----- // var cubDrag = {}; var mazeRotate = {}; // ----- ----- // unipointer.pointerDown = function(event, pointer) { event.preventDefault(); var isInsideCub = getIsInsideCub(pointer); pointerBehavior = isInsideCub ? cubDrag : mazeRotate; pointerBehavior.pointerDown(event, pointer); this._bindPostStartEvents(event); }; function getIsInsideCub(pointer) { var position = getCanvasMazePosition(pointer); var cubDeltaX = Math.abs(position.x - cub[maze.orientation].x * gridSize); var cubDeltaY = Math.abs(position.y - cub[maze.orientation].y * gridSize); var bound = gridSize * 1.5; return cubDeltaX <= bound && cubDeltaY <= bound; } function getCanvasMazePosition(pointer) { var canvasX = pointer.pageX - canvasLeft; var canvasY = pointer.pageY - canvasTop; return { x: canvasX - mazeCenter.x, y: canvasY - mazeCenter.y, }; } // ----- unipointer ----- // unipointer.pointerMove = function(event, pointer) { pointerBehavior.pointerMove(event, pointer); }; unipointer.pointerUp = function(event, pointer) { pointerBehavior.pointerUp(event, pointer); this._unbindPostStartEvents(); }; // ----- cubDrag ----- // var dragStartPosition, dragStartPegPosition, rotatePointer; cubDrag.pointerDown = function(event, pointer) { var segments = getCubConnections(); if (!segments || !segments.length) { return; } isCubDragging = true; dragStartPosition = { x: pointer.pageX, y: pointer.pageY }; dragStartPegPosition = { x: cub[maze.orientation].x * gridSize + mazeCenter.x, y: cub[maze.orientation].y * gridSize + mazeCenter.y, }; docElem.classList.add('is-cub-dragging'); }; cubDrag.pointerMove = function(event, pointer) { if (!isCubDragging) { return; } cubDragMove = { x: pointer.pageX - dragStartPosition.x, y: pointer.pageY - dragStartPosition.y, }; }; cubDrag.pointerUp = function() { cubDragMove = null; docElem.classList.remove('is-cub-dragging'); isCubDragging = false; // set at peg cub.setOffset({ x: 0, y: 0 }, maze.orientation); // check level complete if (cub.peg.x == maze.goalPosition.x && cub.peg.y == maze.goalPosition.y) { completeLevel(); console.log('win'); } }; // ----- rotate ----- // var dragStartAngle, dragStartMazeAngle, moveAngle; var mazeRotate = {}; mazeRotate.pointerDown = function(event, pointer) { dragStartAngle = moveAngle = getDragAngle(pointer); dragStartMazeAngle = maze.flyWheel.angle; dragAngle = dragStartMazeAngle; rotatePointer = pointer; }; function getDragAngle(pointer) { var position = getCanvasMazePosition(pointer); return normalizeAngle(Math.atan2(position.y, position.x)); } mazeRotate.pointerMove = function(event, pointer) { rotatePointer = pointer; moveAngle = getDragAngle(pointer); var deltaAngle = moveAngle - dragStartAngle; dragAngle = normalizeAngle(dragStartMazeAngle + deltaAngle); }; mazeRotate.pointerUp = function() { dragAngle = null; rotatePointer = null; }; // ----- animate ----- // function animate() { update(); render(); requestAnimationFrame(animate); } // ----- update ----- // function update() { // drag cub dragCub(); // rotate grid if (dragAngle) { maze.flyWheel.setAngle(dragAngle); } else { maze.attractAlignFlyWheel(); } maze.update(); if (winAnim) { winAnim.update(); } } function dragCub() { if (!cubDragMove) { return; } var segments = getCubConnections(); var dragPosition = { x: dragStartPegPosition.x + cubDragMove.x, y: dragStartPegPosition.y + cubDragMove.y, }; // set peg position var dragPeg = getDragPeg(segments, dragPosition); cub.setPeg(dragPeg, maze.orientation); // set drag offset var cubDragPosition = getDragPosition(segments, dragPosition); var cubPosition = getCubPosition(); var offset = { x: cubDragPosition.x - cubPosition.x, y: cubDragPosition.y - cubPosition.y, }; cub.setOffset(offset, maze.orientation); } function getCubPosition() { return { x: cub[maze.orientation].x * gridSize + mazeCenter.x, y: cub[maze.orientation].y * gridSize + mazeCenter.y, }; } function getCubConnections() { var pegX = cub[maze.orientation].x; var pegY = cub[maze.orientation].y; var key = maze.orientation + ':' + pegX + ',' + pegY; return maze.connections[key]; } function getDragPosition(segments, dragPosition) { if (segments.length == 1) { return getSegmentDragPosition(segments[0], dragPosition); } // get closest segments positions var dragCandidates = segments.map(function(segment) { var position = getSegmentDragPosition(segment, dragPosition); return { position: position, distance: getDistance(dragPosition, position), }; }); dragCandidates.sort(distanceSorter); return dragCandidates[0].position; } function getSegmentDragPosition(segment, dragPosition) { var line = segment[maze.orientation]; var isHorizontal = line.a.y == line.b.y; var x, y; if (isHorizontal) { x = getSegmentDragCoord(line, 'x', dragPosition); y = line.a.y * gridSize + mazeCenter.y; } else { x = line.a.x * gridSize + mazeCenter.x; y = getSegmentDragCoord(line, 'y', dragPosition); } return { x: x, y: y }; } function getSegmentDragCoord(line, axis, dragPosition) { var a = line.a[axis]; var b = line.b[axis]; var min = a < b ? a : b; var max = a > b ? a : b; min = min * gridSize + mazeCenter[axis]; max = max * gridSize + mazeCenter[axis]; return Math.max(min, Math.min(max, dragPosition[axis])); } function distanceSorter(a, b) { return a.distance - b.distance; } function getDragPeg(segments, dragPosition) { var pegs = []; segments.forEach(function(segment) { var line = segment[maze.orientation]; addPegPoint(line.a, pegs); addPegPoint(line.b, pegs); }); var pegCandidates = pegs.map(function(pegKey) { // revert string back to object with integers var parts = pegKey.split(','); var peg = { x: parseInt(parts[0], 10), y: parseInt(parts[1], 10), }; var pegPosition = { x: peg.x * gridSize + mazeCenter.x, y: peg.y * gridSize + mazeCenter.y, }; return { peg: peg, distance: getDistance(dragPosition, pegPosition), }; }); pegCandidates.sort(distanceSorter); return pegCandidates[0].peg; } function getDistance(a, b) { var dx = b.x - a.x; var dy = b.y - a.y; return Math.sqrt(dx * dx + dy * dy); } function addPegPoint(point, pegs) { // use strings to prevent dupes var key = point.x + ',' + point.y; if (pegs.indexOf(key) == -1) { pegs.push(key); } } // ----- hover ----- // function onHoverMousemove(event) { var isInsideCub = getIsInsideCub(event); if (isInsideCub == isCubHovered) { return; } // change isCubHovered = isInsideCub; var changeClass = isInsideCub ? 'add' : 'remove'; docElem.classList[changeClass]('is-cub-hovered'); } // ----- render ----- // function render() { ctx.clearRect(0, 0, canvasWidth, canvasHeight); ctx.save(); ctx.scale(2, 2); renderRotateHandle(); // maze maze.render(ctx, mazeCenter, gridSize, maze.flyWheel.angle); // win animation if (winAnim) { winAnim.render(ctx); } // cub var isHovered = isCubHovered || isCubDragging; cub.render(ctx, mazeCenter, gridSize, maze.flyWheel.angle, isHovered); ctx.restore(); } function renderRotateHandle() { // rotate handle if (!rotatePointer) { return; } ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.lineWidth = gridSize * 0.5; var color = '#EEE'; ctx.strokeStyle = color; ctx.fillStyle = color; // pie slice ctx.beginPath(); var pieRadius = maze.gridMax * gridSize; ctx.moveTo(mazeCenter.x, mazeCenter.y); var pieDirection = normalizeAngle(normalizeAngle(moveAngle) - normalizeAngle(dragStartAngle)) > TAU / 2; ctx.arc(mazeCenter.x, mazeCenter.y, pieRadius, dragStartAngle, moveAngle, pieDirection); ctx.lineTo(mazeCenter.x, mazeCenter.y); ctx.stroke(); ctx.fill(); ctx.closePath(); } // -------------------------- completeLevel -------------------------- // var completedLevels = localStorage.getItem('completedLevels'); completedLevels = completedLevels ? completedLevels.split(',') : []; completedLevels.forEach(function(id) { levelList.querySelector('[data-id="' + id + '"]').classList.add('did-complete'); }); function completeLevel() { var cubPosition = getCubPosition(); winAnim = new WinAnimation(cubPosition.x, cubPosition.y); levelList.querySelector('[data-id="' + maze.id + '"]').classList.add('did-complete'); if (completedLevels.indexOf(maze.id) == -1) { completedLevels.push(maze.id); localStorage.setItem('completedLevels', completedLevels.join(',')); } if (getNextLevel()) { setTimeout(function() { nextLevelButton.classList.add('is-open'); }, 1000); } } function getNextLevel() { var index = levels.indexOf(maze.id); return levels[index + 1]; } // -------------------------- next level -------------------------- // nextLevelButton.addEventListener('click', function() { var nextLevel = getNextLevel(); if (nextLevel) { loadLevel(nextLevel); } }); // -------------------------- utils -------------------------- // function normalizeAngle(angle) { return ((angle % TAU) + TAU) % TAU; }

* { box-sizing: border-box; } body { margin: 0; padding: 0; overflow-x: hidden; font-family: 'Avenir Next', Avenir, sans-serif; font-weight: 500; font-size: 20px; color: #555; } canvas { cursor: move; display: block; position: absolute; max-width: 100%; left: 0; top: 0; } .is-cub-hovered, .is-cub-hovered canvas { cursor: -webkit-grab; cursor: grab; } .is-cub-dragging, .is-cub-dragging canvas { cursor: -webkit-grabbing; cursor: grabbing; } .instruction { padding: 0 10px; text-align: center; position: absolute; width: 100%; padding-bottom: 40px; } .button { font-family: 'Avenir Next', Avenir, sans-serif; font-weight: 500; font-size: 20px; padding: 5px 15px; margin: 10px; background: #BBB; color: white; border-radius: 5px; border: none; cursor: pointer; } .button:hover { background: #09F; } .top-bar { position: absolute; left: 0; top: 0; } .level-select-button { position: relative; z-index: 2; /* above canvas */ } .next-level-button { position: absolute; left: 50%; -webkit-transform: translateX(-110px) scale(0.5); transform: translateX(-110px) scale(0.5); opacity: 0; background: #09F; width: 200px; height: 80px; pointer-events: none; -webkit-transition: -webkit-transform 0.2s, opacity 0.2s; transition: transform 0.2s, opacity 0.2s; } .next-level-button:hover { background: #2BF; } .next-level-button.is-open { display: inline-block; pointer-events: auto; -webkit-transform: translateX(-110px) scale(1); transform: translate(-110px) scale(1); opacity: 1; } /* ---- level list ---- */ .level-list { position: absolute; background: #EEE; width: 100%; min-height: 100%; left: 0; top: 0; margin: 0; list-style: none; padding: 10px; z-index: 3; /* above canvas, level select button */ left: -100%; transition: left 0.2s; } .level-list.is-open { left: 0; } .level-list__item { display: inline-block; background: #DDD; margin: 5px; padding: 10px; width: 80px; height: 80px; text-align: center; border-radius: 10px; position: relative; } .level-list__item:hover { color: #09F; cursor: pointer; background: white; } .level-list__item.is-playing { background: #09F; color: white; } .level-list__item__number { display: block; font-size: 30px; line-height: 35px; } .level-list__item__blurb { display: block; font-size: 16px; } .level-list__item__check { position: absolute; right: -10px; top: -10px; width: 30px; line-height: 30px; background: #555; border-radius: 15px; color: white; display: none; } .level-list__item.did-complete .level-list__item__check { display: block; } /* ---- level pres ---- */ .levels { display: none; }
submitted 6 years ago ago by 346e369614c2418496fad67c1453fada
picture

    blurb: Tutorial
    instruction: Drag cub to star
    ---
    *=.=.
        !
    . . .
        !
    @=.=.
    
    blurb: Tutorial
    instruction: Drag grid to rotate. Cub and star moves with grid. Orange links stay in place.
    ---
    * . .
        !
    . . .
        !
    @=.=.
    
    blurb: ★
    ---
    @=. .
    
    . . .
        !
    *=. .
    
    blurb: Tutorial
    instruction: Blue links move with grid. Rotate grid to connect blue and orange links in different ways.
    ---
    @-. .
    !   | 
    . . .
        |
    *-.-.
    
    blurb: ★
    ---
    . . *
    | | | 
    . . .
    | | | 
    @ .=.
    
    blurb: ★
    ---
    *=.-.
     
    . . .
        | 
    @-. .
    
    blurb: ★
    ---
    . .=. .
      | !  
    . . .-*
      |    
    . . . .
           
    . @-. .
    
    blurb: ★
    ---
    . . . .
           
    * . . @
      | ! |
    . . . .
      !    
    . . . .
    
    blurb: ★
    ---
    . @ . .
    ! |    
    . . . .
          |
    .=.=.-.
    |       
    . * . .
    
    blurb: ★
    ---
    . . . .
           
    * . . .
        !  
    . . .-.
    !      
    .=.=. @
    
    blurb: ★
    ---
    .-.-.-.
    |       
    @ .-.-.
           
    * .=. .
    !   |   
    .-.-. .
    
    blurb: ★
    ---
    . * . .
    
    .-.=. .
      |
    . . . .
    !   |
    .=. @ .
    
    blurb: ★★
    ---
    . . *-.
           
    .-.=. .
          |
    .=. . .
      | |  
    @-.-.=.
    
    blurb: ★★
    ---
    .-@ .=.
           
    . . . .
        |  
    .-. .-*
      |    
    . .=.-.
    
    blurb: ★★
    ---
    . . .=.
      !    
    @-. .-.
         
    . .=. .
           
    . . * .
    
    blurb: ★★
    ---
    . @=. .
      |   
    . .-.-.
           
    .-.-.-.
    !     ! 
    . * . .
    
    . . . . .
      | !   
    . . .-. .
      |     
    . . . . *
      |     
    . . .=. .
      |     
    . @ . . .
    
    @-.-. .-.
        |    
    . . . . .
             
    . . .=. .
             
    . . . .=.
        |    
    . .=.-* .
    
    . . . . .
            
    . .=.-. @
    |       !
    . . . .-.
            
    .=. . .=.
    !       
    * . . . .
    
    . . . .-.
          ! 
    . .-. . .
      !     |
    .=. . . .
    |        
    . . . . *
    |        
    .-@=. .=.
    
    . . . . .
    
    . . .-. *
        !
    . . .-. .
    
    .=. . . .
        |
    . @-. . .
    
    . . .-.-.
    !   !    
    . .=.-. .
    |   
    . .-. .-@
    !
    * .=. . .
          |
    .=. .-.=.
    
    .=* . @=.
    |
    . .=. . .
    |   | |
    .=. . .-.
            |
    . . . .=.
    !    
    . .-.-. .
    
    . * . .-.
      |     
    . . .=.-.
    !       | 
    . . . . .
            
    . .-. .=.
            |
    . . .=.-@
    
    .-.-. . .
        |    
    . . . .-@
      !      
    * . .-. .
    |   !    
    .-. . .=.
        |   !
    . . .=. .
    
    . . . . .
             
    . . . .-@
      !      
    * . .=. .
    |   !    
    .-. . . .
             
    . . . . .
    
    . . . .=.
      |     
    . . . .=.
    |        
    . . .-. .
    ! |     
    . .=. . .
    |   !   !
    .-@ . * .
    
    . . .=.=.
            
    . . . . .
            
    . . . . @
            
    . . . . .
            
    * . .=.=.
    
    . . * . . .
      ! | |  
    . .-. .-. .
              |
    . . . . .-.
          | ! |
    . . .=. . .
        |
    @-.-. .-. .
              |
    . .=. . .-.
    
    @ .=. . .=.
      | | !
    . . . .=. .
      |     |
    . . . .-. .
    |   !
    . . . . . *
    |     |
    .=. .-. . .
      |   | |
    .-. . . .=.
    
    .=. .=.-.-*
      |        
    .-. . . . .
            | !
    . . .-.-. .
    !          
    .-. .=.=. .
               
    @ .=. . . .
      |     !
    . .-. .-. .
    
    instruction: Green links pivot with grid, but point in the same direction
    ---
    . .-* .
      |    
    . . . .
           
    . .>. .
           
    . @ . .
    
    . . .-.-@
            
    . .<. . .
            
    .>. . . .
    | !      
    .-.-. . *
      !     
    . . . . .
    
    . . . . .
          ^ 
    .<. . . *
            
    . . . . .
            
    @ . . .>.
      v     
    . . . . .
    
    . .-. . .
          ^ 
    . .<.=.=.
            
    .>. . .-@
            
    * . . .=.
            
    . . . . .
    
    .=. . .-*
        v   
    . . . . .
             
    . . .-.J.
             
    @-. . . .
        v   
    .<. . . .
    
    .-.-. @>.
    !     ^ 
    . . . . .
      |      
    . . . . .
      |     
    . . . .=*
        ^    
    . . .-. .>
    
    .-. . . *
            
    . .>. . .
    |       v
    .-. . . .
      ^      
    . . .-. .
          v 
    @=.=. . .
    
    . . .>. .
      ! |    
    @=. .-. .
            
    . . . .=.>
             
    . . . . .
             
    . *>.<. .
    
    * . @ . .
    v   |   
    . . . . .
          !  
    . . . . .
    ^     ! !
    . .-. . .
      !     
    . . . . .
        v
    
    . . . . . .
    | v         
    @ . . . . *
      | |      
    . . . . . .
    | !   ^ | K
    . . . .-.=.
    |          
    . .-. . . .
    v          
    .>. . . . .
    
    . @-. .>.-.
              
    . . . . . .
              |
    * .>. .=. .
        !      
    . . . . . .>
          |   ^
    . . . .=. .
               
    . .=. . .=.>
    
    . .-.-. .=.
          v   
    . . . . . .
      |     ! v
    .>. . . . *
        ^      
    . . . . . .
    |          
    . .-.<. . .
    ! |       |
    . . . .>.-@
    
    127

    var canvas = document.getElementById("canvas"), ctx = canvas.getContext("2d"), img = new Image(), effectEl = document.getElementById("effect"), settings = { radius: 4, intensity: 25, ApplyFilter: function() { doOilPaintEffect(); } } img.addEventListener('load', function() { // reduced the size by half for pen and performance. canvas.width = (this.width / 2); canvas.height = (this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }); function chooseFromPhoto(){ window["reddahApi"].album().then(data=>{ img.src=data.replace("file://","http://localhost:8080/_app_file_"); canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } function chooseFromCamera(){ window["reddahApi"].camera().then(data=>{ img.src=data.replace("file://","http://localhost:8080/_app_file_"); canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } img.crossOrigin = "Anonymous"; img.src = "assets/500/musk.jpg"; vl=1; function mt(v){ vl=v } function change(){ let base64Image = canvas.toDataURL('image/jpeg'); window["reddahApi"].qqMusk(vl,base64Image).then(data=>{ //alert(JSON.stringify(data)) if(data.Success==0){ let qqmsg = JSON.parse(data.Message); alert(qqmsg .ret) if(qqmsg .ret===0){ getBase64Image(qqmsg .data.image); } else{ alert('error1:'+JSON.stringify(data)) } } else{ alert('error2:'+JSON.stringify(data)) } }) } function getBase64Image(data){ alert(data) var dimg=document.getElementById("dest-img"); alert(dimg) dimg.src="data:image/jpeg;base64,"+data; dimg.width=img.width; dimg.height=img.height; }; window["reddahApi"].loadCompleted()

    .test{ }
    submitted 6 years ago ago by 054952f0c62a48c980ce39f09ddfcf4b
    picture

    Original

    仿PS油画滤镜特效







    128

    var canvas = document.getElementById("canvas"), ctx = canvas.getContext("2d"), img = new Image(), effectEl = document.getElementById("effect"), settings = { radius: 4, intensity: 25, ApplyFilter: function() { doOilPaintEffect(); } } img.addEventListener('load', function() { // reduced the size by half for pen and performance. canvas.width = (this.width / 2); canvas.height = (this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }); function chooseFromPhoto(){ window["reddahApi"].album().then(data=>{ img.src=data.replace("file://","http://localhost:8080/_app_file_"); canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } function chooseFromCamera(){ window["reddahApi"].camera().then(data=>{ img.src=data.replace("file://","http://localhost:8080/_app_file_"); canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } img.crossOrigin = "Anonymous"; img.src = "assets/500/musk.jpg"; vl=1; function mt(v){ vl=v; change(); } function change(){ let base64Image = canvas.toDataURL('image/jpeg'); window["reddahApi"].qqMusk(vl,base64Image).then(data=>{ //alert(JSON.stringify(data)) if(data.Success==0){ let qqmsg = JSON.parse(data.Message); //alert(qqmsg .ret) if(qqmsg .ret===0){ getBase64Image(qqmsg .data.image); } else{ alert('error1:'+JSON.stringify(data)) } } else{ alert('error2:'+JSON.stringify(data)) } }) } function getBase64Image(data){ //alert(data) var dimg=document.getElementById("dest-img"); //alert(dimg) dimg.src="data:image/jpeg;base64,"+data; dimg.width=img.width; dimg.height=img.height; }; window["reddahApi"].loadCompleted()

    .test{ }
    submitted 6 years ago ago by 054952f0c62a48c980ce39f09ddfcf4b
    picture

    Original

    仿PS油画滤镜特效







    129

    var canvas = document.getElementById("canvas"), ctx = canvas.getContext("2d"), img = new Image(), effectEl = document.getElementById("effect"), settings = { radius: 4, intensity: 25, ApplyFilter: function() { doOilPaintEffect(); } } img.addEventListener('load', function() { // reduced the size by half for pen and performance. canvas.width = (this.width / 2); canvas.height = (this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }); function chooseFromPhoto(){ window["reddahApi"].album().then(data=>{ img.src=data.replace("file://","http://localhost:8080/_app_file_"); canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } function chooseFromCamera(){ window["reddahApi"].camera().then(data=>{ img.src=data.replace("file://","http://localhost:8080/_app_file_"); canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } img.crossOrigin = "Anonymous"; img.src = "assets/500/musk.jpg"; vl=1; function mt(v){ vl=v; change(); } function change(){ let base64Image = canvas.toDataURL('image/jpeg'); window["reddahApi"].qqMusk(vl,base64Image).then(data=>{ //alert(JSON.stringify(data)) if(data.Success==0){ let qqmsg = JSON.parse(data.Message); //alert(qqmsg .ret) if(qqmsg .ret===0){ getBase64Image(qqmsg .data.image); } else{ alert('error1:'+JSON.stringify(data)) } } else{ alert('error2:'+JSON.stringify(data)) } }) } function getBase64Image(data){ //alert(data) //var dimg=document.getElementById("dest-img"); //alert(dimg) //dimg.src="data:image/jpeg;base64,"+data; //dimg.width=img.width; //dimg.height=img.height; window["reddahApi"].viewImage("data:image/jpeg;base64,"+data); }; window["reddahApi"].loadCompleted()

    .test{ }
    submitted 6 years ago ago by 054952f0c62a48c980ce39f09ddfcf4b
    picture

    原图







    130

    var canvas = document.getElementById("canvas"), ctx = canvas.getContext("2d"), img = new Image(), effectEl = document.getElementById("effect"), settings = { radius: 4, intensity: 25, ApplyFilter: function() { doOilPaintEffect(); } } img.addEventListener('load', function() { // reduced the size by half for pen and performance. canvas.width = (this.width / 2); canvas.height = (this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }); function chooseFromPhoto(){ window["reddahApi"].album().then(data=>{ img.src=data.replace("file://","http://localhost:8080/_app_file_"); canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } function chooseFromCamera(){ window["reddahApi"].camera().then(data=>{ img.src=data.replace("file://","http://localhost:8080/_app_file_"); canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } img.crossOrigin = "Anonymous"; img.src = "assets/500/musk.jpg"; vl=1; function mt(v){ vl=v; change(); } function change(){ let base64Image = canvas.toDataURL('image/jpeg'); window["reddahApi"].qqMusk(vl,base64Image).then(data=>{ //alert(JSON.stringify(data)) if(data.Success==0){ let qqmsg = JSON.parse(data.Message); //alert(qqmsg .ret) if(qqmsg .ret===0){ getBase64Image(qqmsg .data.image); } else{ alert('error1:'+JSON.stringify(data)) } } else{ alert('error2:'+JSON.stringify(data)) } }) } function getBase64Image(data){ //alert(data) //var dimg=document.getElementById("dest-img"); //alert(dimg) //dimg.src="data:image/jpeg;base64,"+data; //dimg.width=img.width; //dimg.height=img.height; window["reddahApi"].viewImage("data:image/jpeg;base64,"+data); }; window["reddahApi"].loadCompleted()

    .test{ }
    submitted 6 years ago ago by 054952f0c62a48c980ce39f09ddfcf4b
    picture

    原图







    131
    132

    var canvas = document.getElementById("canvas"), ctx = canvas.getContext("2d"), img = new Image(), effectEl = document.getElementById("effect"), settings = { radius: 4, intensity: 25, ApplyFilter: function() { doOilPaintEffect(); } } img.addEventListener('load', function() { // reduced the size by half for pen and performance. canvas.width = (this.width / 2); canvas.height = (this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }); function chooseFromPhoto(){ window["reddahApi"].album().then(data=>{ img.src=data.replace("file://","http://localhost:8080/_app_file_"); canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } function chooseFromCamera(){ window["reddahApi"].camera().then(data=>{ img.src=data.replace("file://","http://localhost:8080/_app_file_"); canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } img.crossOrigin = "Anonymous"; img.src = "assets/500/musk.jpg"; vl=1; function mt(v){ vl=v; change(); } function change(){ let base64Image = canvas.toDataURL('image/jpeg'); window["reddahApi"].loadingStart('bubbles',2000); window["reddahApi"].qqMusk(vl,base64Image).then(data=>{ //alert(JSON.stringify(data)) if(data.Success==0){ let qqmsg = JSON.parse(data.Message); //alert(qqmsg .ret) if(qqmsg .ret===0){ getBase64Image(qqmsg .data.image); } else{ alert('error1:'+JSON.stringify(data)) } } else{ alert('error2:'+JSON.stringify(data)) } }) } function getBase64Image(data){ //alert(data) //var dimg=document.getElementById("dest-img"); //alert(dimg) //dimg.src="data:image/jpeg;base64,"+data; //dimg.width=img.width; //dimg.height=img.height; window["reddahApi"].viewImage("data:image/jpeg;base64,"+data).then(data=>{ window["reddahApi"].loadingStop(); }); }; window["reddahApi"].loadCompleted()

    .test{ }
    submitted 6 years ago ago by 054952f0c62a48c980ce39f09ddfcf4b
    picture

    原图







    133
    135

    window["reddahApi"].loadCompleted()

    .waifu{position:fixed;bottom:0;z-index:1;font-size:0;-webkit-transform:translateY(3px);transform:translateY(3px)}.waifu:hover{-webkit-transform:translateY(0);transform:translateY(0)}.waifu-tips{opacity:0;margin:-20px 20px;padding:5px 10px;border:1px solid rgba(224,186,140,.62);border-radius:12px;background-color:rgba(236,217,188,.5);box-shadow:0 3px 15px 2px rgba(191,158,118,.2);text-overflow:ellipsis;overflow:hidden;position:absolute;animation-delay:5s;animation-duration:50s;animation-iteration-count:infinite;animation-name:shake;animation-timing-function:ease-in-out}.waifu-tool{display:none;color:#aaa;top:50px;right:10px;position:absolute}.waifu:hover .waifu-tool{display:block}.waifu-tool span{display:block;cursor:pointer;color:#5b6c7d;transition:.2s}.waifu-tool span:hover{color:#34495e}.waifu #live2d{position:relative}@keyframes shake{2%{transform:translate(.5px,-1.5px) rotate(-.5deg)}4%{transform:translate(.5px,1.5px) rotate(1.5deg)}6%{transform:translate(1.5px,1.5px) rotate(1.5deg)}8%{transform:translate(2.5px,1.5px) rotate(.5deg)}10%{transform:translate(.5px,2.5px) rotate(.5deg)}12%{transform:translate(1.5px,1.5px) rotate(.5deg)}14%{transform:translate(.5px,.5px) rotate(.5deg)}16%{transform:translate(-1.5px,-.5px) rotate(1.5deg)}18%{transform:translate(.5px,.5px) rotate(1.5deg)}20%{transform:translate(2.5px,2.5px) rotate(1.5deg)}22%{transform:translate(.5px,-1.5px) rotate(1.5deg)}24%{transform:translate(-1.5px,1.5px) rotate(-.5deg)}26%{transform:translate(1.5px,.5px) rotate(1.5deg)}28%{transform:translate(-.5px,-.5px) rotate(-.5deg)}30%{transform:translate(1.5px,-.5px) rotate(-.5deg)}32%{transform:translate(2.5px,-1.5px) rotate(1.5deg)}34%{transform:translate(2.5px,2.5px) rotate(-.5deg)}36%{transform:translate(.5px,-1.5px) rotate(.5deg)}38%{transform:translate(2.5px,-.5px) rotate(-.5deg)}40%{transform:translate(-.5px,2.5px) rotate(.5deg)}42%{transform:translate(-1.5px,2.5px) rotate(.5deg)}44%{transform:translate(-1.5px,1.5px) rotate(.5deg)}46%{transform:translate(1.5px,-.5px) rotate(-.5deg)}48%{transform:translate(2.5px,-.5px) rotate(.5deg)}50%{transform:translate(-1.5px,1.5px) rotate(.5deg)}52%{transform:translate(-.5px,1.5px) rotate(.5deg)}54%{transform:translate(-1.5px,1.5px) rotate(.5deg)}56%{transform:translate(.5px,2.5px) rotate(1.5deg)}58%{transform:translate(2.5px,2.5px) rotate(.5deg)}60%{transform:translate(2.5px,-1.5px) rotate(1.5deg)}62%{transform:translate(-1.5px,.5px) rotate(1.5deg)}64%{transform:translate(-1.5px,1.5px) rotate(1.5deg)}66%{transform:translate(.5px,2.5px) rotate(1.5deg)}68%{transform:translate(2.5px,-1.5px) rotate(1.5deg)}70%{transform:translate(2.5px,2.5px) rotate(.5deg)}72%{transform:translate(-.5px,-1.5px) rotate(1.5deg)}74%{transform:translate(-1.5px,2.5px) rotate(1.5deg)}76%{transform:translate(-1.5px,2.5px) rotate(1.5deg)}78%{transform:translate(-1.5px,2.5px) rotate(.5deg)}80%{transform:translate(-1.5px,.5px) rotate(-.5deg)}82%{transform:translate(-1.5px,.5px) rotate(-.5deg)}84%{transform:translate(-.5px,.5px) rotate(1.5deg)}86%{transform:translate(2.5px,1.5px) rotate(.5deg)}88%{transform:translate(-1.5px,.5px) rotate(1.5deg)}90%{transform:translate(-1.5px,-.5px) rotate(-.5deg)}92%{transform:translate(-1.5px,-1.5px) rotate(1.5deg)}94%{transform:translate(.5px,.5px) rotate(-.5deg)}96%{transform:translate(2.5px,-.5px) rotate(-.5deg)}98%{transform:translate(-1.5px,-1.5px) rotate(-.5deg)}0%,100%{transform:translate(0,0) rotate(0)}}@font-face{font-family:Flat-UI-Icons;src:url(flat-ui-icons-regular.eot);src:url(flat-ui-icons-regular.eot?#iefix) format('embedded-opentype'),url(flat-ui-icons-regular.woff) format('woff'),url(flat-ui-icons-regular.ttf) format('truetype'),url(flat-ui-icons-regular.svg#flat-ui-icons-regular) format('svg')}[class*=fui-],[class^=fui-]{font-family:Flat-UI-Icons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fui-cross:before{content:"\e609"}.fui-info-circle:before{content:"\e60f"}.fui-photo:before{content:"\e62a"}.fui-eye:before{content:"\e62c"}.fui-chat:before{content:"\e62d"}.fui-home:before{content:"\e62e"}.fui-user:before{content:"\e631"}
    submitted 6 years ago ago by b61637bfb67445dd81c4509874177c10
    picture
    Live2D 看板娘 v1.2 / Demo

    Live2D 看板娘 v1.2 / Demo

    140

    var canvas = document.getElementById("canvas"), ctx = canvas.getContext("2d"), img = new Image(), effectEl = document.getElementById("effect"), settings = { radius: 4, intensity: 25, ApplyFilter: function() { doOilPaintEffect(); } } img.addEventListener('load', function() { var originWidth = this.width; var originHeight = this.height; var maxWidth = 400, maxHeight = 400; var targetWidth = originWidth, targetHeight = originHeight; if (originWidth > maxWidth || originHeight > maxHeight) { if (originWidth / originHeight > maxWidth / maxHeight) { targetWidth = maxWidth; targetHeight = Math.round(maxWidth * (originHeight / originWidth)); } else { targetHeight = maxHeight; targetWidth = Math.round(maxHeight * (originWidth / originHeight)); } } canvas.width = targetWidth; canvas.height = targetHeight; ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }); function chooseFromPhoto(){ window["reddahApi"].album().then(data=>{ img.src=data.webPath; canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } function chooseFromCamera(){ window["reddahApi"].camera().then(data=>{ img.src=data.webPath; canvas.width = "90%"//(this.width / 2); canvas.height = "90%"//(this.height / 2); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); }) } img.crossOrigin = "Anonymous"; img.src = "assets/500/musk.jpg"; function read(){ change(); } function change(){ let base64Image = canvas.toDataURL('image/jpeg').replace("data:image/jpeg;base64,",""); window["reddahApi"].loadingStart('bubbles',20000); console.log(base64Image); window["reddahApi"].qqRead(base64Image).then(data=>{ if(data.Success==0){ let qqmsg = JSON.parse(data.Message); alert(JSON.stringify(qqmsg)) if(qqmsg.ret===0){ getBase64Image(qqmsg.data.image); } else{ let code = qqmsg.ret; if(code==29){ window["reddahApi"].alert("系统繁忙","请稍后重试") } else{ window["reddahApi"].alert("Error"+qqmsg.ret,qqmsg.msg) } } } else{ window["reddahApi"].alert("Error",JSON.stringify(data)) } }) } function getBase64Image(data){ window["reddahApi"].viewImage("data:image/jpeg;base64,"+data).then(data=>{ window["reddahApi"].loadingStop(); }); } window["reddahApi"].loadCompleted()

    .title{ text-align:center; } .btn-box{ margin-top: 10px; display:flex; justify-content:space-around; } .photo{ display:flex; justify-content:center; } .btn1 { box-shadow:inset 0px 1px 0px 0px #ffffff; background-color:#f9f9f9; border-radius:6px; border:1px solid #dcdcdc; display:inline-block; cursor:pointer; color:#666666; font-family:Arial; font-size:15px; font-weight:bold; padding:6px 24px; text-decoration:none; text-shadow:0px 1px 0px #ffffff; margin:3px; } .btn1:hover { background-color:#5cbf2a; } .btn1:active { position:relative; top:1px; } .blueButton { box-shadow:inset 0px -3px 7px 0px #29bbff; background-color:#2dabf9; border-radius:3px; border:1px solid #0b0e07; display:inline-block; cursor:pointer; color:#ffffff; font-family:Arial; font-size:15px; padding:9px 23px; text-decoration:none; text-shadow:0px 1px 0px #263666; } .yellowButton { box-shadow: 0px 1px 0px 0px #fff6af; background-color:#ffec64; border-radius:6px; border:1px solid #ffaa22; display:inline-block; cursor:pointer; color:#333333; font-family:Arial; font-size:15px; font-weight:bold; padding:6px 24px; text-decoration:none; text-shadow:0px 1px 0px #ffee66; }
    submitted 6 years ago ago by 81bda4e02c344e52ab0bc89473a48f30
    picture

    图片翻译





    141
    picture

    Netherlands captain Virgil van Dijk consoles grieving referee

    Netherlands captain Virgil van Dijk consoles grieving referee
    football submitted 7 years ago ago by b8c40ad899c64f9a88cfca87d90e5c34
    picture

    Netherlands captain Virgil van Dijk has been praised for his display of compassion to grieving referee Ovidiu Hategan in the aftermath of his last-gasp equalizer against Germany.

    The Romanian official's mother had recently passed away but the 38-year-old decided to still take charge of the crucial Nations League clash.

    142
    picture

    Fisherman jumps on a thrashing whale's back to save its life

    Fisherman jumps on a thrashing whale's back to save its life
    earth submitted 7 years ago ago by b8c40ad899c64f9a88cfca87d90e5c34
    picture

    The sight of a massive humpback whale thrashing in the sea doesn't usually elicit an invitation to splash around with him.

    Humpbacks can weigh in at a whopping 40 tons and stretch 50 feet from nose to tail. That's the kind of heft that easily overturns small boats. And woe to anyone who should jump on the back of one of these behemoths.

    But that's just what Sam Synstelien did when he saw a humpback in distress in Central California's Morro Bay this week. The animal was hopelessly tangled in a rope that was attached to a buoy.

    Synstelien, along with crewmate Nicholas Taron, had already tried reporting the unfortunate whale to the U.S. Coast Guard — but they were told it would be hours before rescuers could be dispatched.

    Hours, the commercial fishermen figured, this whale didn't have.

    "If we wanted the whale to survive we had to go get it," Taron later told Inside Edition. "We thought there was no other option for the whale; we decided to go for it. We were so pumped up full of adrenaline, I don't think we were that scared."

    Easy for Taron to say, of course. His role in the rescue was mostly in the enthusiastic cheering department.

    In the clip, you can hear him quarterbacking the operation from the side of the boat while filming the entire operation.

    "Swim! Swim!" he yells. "Move! Just get it! Get it!"

    143

    World's best ski resorts in 2018

    picture
    picture
    World's best ski resorts in 2018
    travel submitted 7 years ago ago by b8c40ad899c64f9a88cfca87d90e5c34
    picture

    If there's one takeaway from this year's World's Ski Awards, it's that Europe is the premier skiing destination in the world.

    Again.

    This year marks the sixth for the awards, given at a glitzy ceremony in Austria, at the legendary Kitzbühel resort, this past weekend. Ski representatives from Europe, Asia, North America, South America and Australasia gathered in Austria for three days of alpine events, capped off with the awards ceremony. Voting was done online by both ski professionals and the general public.

    Nearly all of the top honors went to European resorts, hotels and operators.

    For the third consecutive year, Val Thorens in the French Alps was named best ski resort in the world. Europe's highest resort, Val Thorens is part of the 3 Vallees ski area (Courchevel and Meribel are the other two), with ski offerings for all levels and much on offer off the mountain too.

    144
    picture

    Chen Man - Imagining the future

    Chen Man - Imagining the future
    style submitted 7 years ago ago by b8c40ad899c64f9a88cfca87d90e5c34
    picture

    Chen Man is China's go-to fashion photographer. Top celebrities and models, from Asia and beyond, have posed for her highly stylized, otherworldly shoots that present China in a diverse and contemporary light. For her September 2018 CNN Style guest editorship, she explored the theme of imagining the future.

     

    145
    picture

    Trump slams chief justice after Roberts chides the President

    Trump slams chief justice after Roberts chides the President
    politics submitted 7 years ago ago by b8c40ad899c64f9a88cfca87d90e5c34
    picture

    President Donald Trump fired back Wednesday after Chief Justice John Roberts issued a rare rebuke of the President's disparaging remarks about federal judges.

    "We do not have Obama judges or Trump judges, Bush judges or Clinton judges," Roberts said in a statement responding to comments Trump made earlier in the week criticizing the US 9th Circuit Court of Appeals. "What we have is an extraordinary group of dedicated judges doing their level best to do equal right to those appearing before them. That independent judiciary is something we should all be thankful for."

    Trump, in a response later Wednesday, stood by his comments from the previous day that prompted Roberts' statement.

    "Sorry Chief Justice John Roberts, but you do indeed have 'Obama judges,' and they have a much different point of view than the people who are charged with the safety of our country. It would be great if the 9th Circuit was indeed an 'independent judiciary,' but if it is why......" Trump tweeted.

    146
    picture

    Isolated tribespeople believed to have killed US missionary who trespassed on remote island

    Isolated tribespeople believed to have killed US missionary who trespassed on remote island
    word submitted 7 years ago ago by b8c40ad899c64f9a88cfca87d90e5c34
    picture

    Port Blair in the Andaman Islands. The island chain is home to a number of isolated tribes who have acted with hostility and violence towards outsiders.

    An American Christian missionary is thought to have been killed by tribespeople from one of the world's most isolated communities on a remote island hundreds of miles off the coast of India, according to officials.

     

    147
    picture

    When you want a Golden Retriever but are only allowed to get a cat

    When you want a Golden Retriever but are only allowed to get a cat
    cat submitted 7 years ago ago by b8c40ad899c64f9a88cfca87d90e5c34
    picture

    148
    picture

    Wife of jailed British academic calls on UAE to recognize 'misunderstanding'

    The wife of a British academic jailed in the United Arab Emirates on charges of espionage has spoken of her shock at his life sentence and accused the country of mishandling and misinterpreting case
    world submitted 7 years ago ago by b8c40ad899c64f9a88cfca87d90e5c34
    picture

    The wife of a British academic jailed in the United Arab Emirates on charges of espionage has spoken of her shock at his life sentence and accused the country of mishandling and misinterpreting his case.

    Amid signs that Britain and the UAE are looking for a way out of the diplomatic conundrum, Daniela Tejada told CNN's "Hala Gorani Tonight" program Thursday that "the UAE should have the sensibility and the humanity to recognize that it has been a misunderstanding and that Matt has paid for someone's lack of judgment."

    Matthew Hedges, 31, a specialist in Middle Eastern studies at Durham University in England, was arrested by UAE officials at Dubai International Airport in May. He was held in solitary confinement for almost six months before being released on bail last month. Hedges and his wife have repeatedly denied the allegations of spying, but prosecutors insist the British academic confessed.

    In her first TV interview since her husband's sentencing Wednesday, Tejada said, "It's not unheard of that governments -- in authoritarian regimes particularly -- misinterpret research as espionage work or as a threat."

    She continued, "Matt, sadly, is the first person to endure such a travesty in the UAE as a Western academic, but it happens very frequently in other countries in the Gulf and it happens to Emirati academics."

    149
    picture

    'Ralph Breaks the Internet' runs up score on clever plot

    'Ralph Breaks the Internet'
    entertainment submitted 7 years ago ago by b8c40ad899c64f9a88cfca87d90e5c34
    picture

    It's often said that the best animated movies play equally well with adults and children, while bad ones prove an ordeal for kid-squiring parents. If anything, "Ralph Breaks the Internet" bends in the opposite direction: The colorful action should delight tykes, but the smart, media-savvy asides make it especially appealing to grownups.

    Six years removed from the original "Wreck-It Ralph," the sequel reloads with an inspired premise, as the video-game character of its title (voiced by John C. Reilly) -- always eager to help, but prone to make a mess of things -- inadvertently breaks the game that houses his pal Vanellope (Sarah Silverman). So the pair embark on a journey into the Internet, hoping to acquire the part that can fix the machine and get Sugar Rush back up and running again.

    The plan, not surprisingly, yields a host of unintended consequences, one that exposes the vagaries of the web in an amusing variety of ways. Those include, but aren't limited to, the annoying nature of pop-up ads, the "like"-driven calculus of social media, and another reminder that you should never read the comments, especially if you're an unusually sensitive 1980s-era videogame villain.

    Drawing heavily from real websites while creating a few new ones, Ralph and Vanellope's adventures are endlessly inventive, none more so than a self-referential dive into Disney's Internet site, where they're exposed to wide range of studio properties, including an animated version of the late Stan Lee and a room filled with Disney princesses. Even with the sequence having been extensively teased, the princesses' admissions about what they have in common -- from waiting for princes to staring at water -- are utterly riotous, an instant classic that will be replayed for years to come.

    For all its pop-culture passions, though, "Ralph Breaks the Internet" also incorporates very astute lessons about friendship, and the issue of harboring different passions or growing apart. While modern Disney films have been especially good in presenting messages of empowerment and self-esteem, few have been better in communicating the need to accept others without being heavy-handed about it.

    In this case, Vanellope finds a home away from home in a perilous first-person game called Slaughter Race, bonding with its seemingly dangerous leader, Shank ("Wonder Woman's" Gal Gadot). Confused and jealous, Ralph just wants his friend back, which paves the way for the cascading threat that he naively unleashes and must try to fix.

    In most every way "Ralph" improves on its previous outing, in some respects owing a stronger debt to sibling Pixar's "Inside Out" in its approach to childhood insecurities through a lens to which adults can easily relate. (Even Vanellope's glitching when she becomes agitated says something with a genuine sweetness to it.)

    "Ralph Breaks the Internet" leads off a pair of family-friendly sequels that Disney will release this holiday season, the other being the eagerly anticipated follow-up "Mary Poppins Returns." If the latter is anywhere near this satisfying, the studio might not break the Internet, but it has a fair shot at breaking the bank.

    "Ralph Breaks the Internet" opens Nov. 21 in the U.S. It's rated PG.

    150
    picture

    Alexander Zverev thanks 'soft guy' Dad after ATP Finals win

    After sealing the biggest title of his young career, Alexander Zverev embraced his Mum and Dad -- as well as his dog.
    sport submitted 7 years ago ago by b8c40ad899c64f9a88cfca87d90e5c34
    picture

    Having nurtured his son's tennis progression, Sunday was a particularly poignant moment for Alexander Zverev Sr. as he watched the 21-year-old prodigy topple Novak Djokovic in straight sets and win the ATP World Tour Finals the day after ousting Roger Federer in the semifinals in London.

    "There were a lot of emotions hugging him. He had a lot of emotions as well," Zverev told CNN Sport's Christina Macfarlane after Sunday's victory.

    "He's basically been coaching me for 21 years ... I can't thank him enough."

    View more: < Prev Next > or try a Random SubReddah