/*! * matter-js 0.18.0 by @liabru * http://brm.io/matter-js/ * License MIT */ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("Matter",[],t):"object"==typeof exports?exports.Matter=t():e.Matter=t()}(this,(function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=21)}([function(e,t){var n={};e.exports=n,function(){n._nextId=0,n._seed=0,n._nowStartTime=+new Date,n._warnedOnce={},n._decomp=null,n.extend=function(e,t){var i,o;"boolean"==typeof t?(i=2,o=t):(i=1,o=!0);for(var r=i;r0;t--){var i=Math.floor(n.random()*(t+1)),o=e[t];e[t]=e[i],e[i]=o}return e},n.choose=function(e){return e[Math.floor(n.random()*e.length)]},n.isElement=function(e){return"undefined"!=typeof HTMLElement?e instanceof HTMLElement:!!(e&&e.nodeType&&e.nodeName)},n.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},n.isFunction=function(e){return"function"==typeof e},n.isPlainObject=function(e){return"object"==typeof e&&e.constructor===Object},n.isString=function(e){return"[object String]"===toString.call(e)},n.clamp=function(e,t,n){return en?n:e},n.sign=function(e){return e<0?-1:1},n.now=function(){if("undefined"!=typeof window&&window.performance){if(window.performance.now)return window.performance.now();if(window.performance.webkitNow)return window.performance.webkitNow()}return Date.now?Date.now():new Date-n._nowStartTime},n.random=function(t,n){return n=void 0!==n?n:1,(t=void 0!==t?t:0)+e()*(n-t)};var e=function(){return n._seed=(9301*n._seed+49297)%233280,n._seed/233280};n.colorToNumber=function(e){return 3==(e=e.replace("#","")).length&&(e=e.charAt(0)+e.charAt(0)+e.charAt(1)+e.charAt(1)+e.charAt(2)+e.charAt(2)),parseInt(e,16)},n.logLevel=1,n.log=function(){console&&n.logLevel>0&&n.logLevel<=3&&console.log.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},n.info=function(){console&&n.logLevel>0&&n.logLevel<=2&&console.info.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},n.warn=function(){console&&n.logLevel>0&&n.logLevel<=3&&console.warn.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},n.warnOnce=function(){var e=Array.prototype.slice.call(arguments).join(" ");n._warnedOnce[e]||(n.warn(e),n._warnedOnce[e]=!0)},n.deprecated=function(e,t,i){e[t]=n.chain((function(){n.warnOnce("🔅 deprecated 🔅",i)}),e[t])},n.nextId=function(){return n._nextId++},n.indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0;ne.max.x&&(e.max.x=o.x),o.xe.max.y&&(e.max.y=o.y),o.y0?e.max.x+=n.x:e.min.x+=n.x,n.y>0?e.max.y+=n.y:e.min.y+=n.y)},n.contains=function(e,t){return t.x>=e.min.x&&t.x<=e.max.x&&t.y>=e.min.y&&t.y<=e.max.y},n.overlaps=function(e,t){return e.min.x<=t.max.x&&e.max.x>=t.min.x&&e.max.y>=t.min.y&&e.min.y<=t.max.y},n.translate=function(e,t){e.min.x+=t.x,e.max.x+=t.x,e.min.y+=t.y,e.max.y+=t.y},n.shift=function(e,t){var n=e.max.x-e.min.x,i=e.max.y-e.min.y;e.min.x=t.x,e.max.x=t.x+n,e.min.y=t.y,e.max.y=t.y+i}},function(e,t){var n={};e.exports=n,n.create=function(e,t){return{x:e||0,y:t||0}},n.clone=function(e){return{x:e.x,y:e.y}},n.magnitude=function(e){return Math.sqrt(e.x*e.x+e.y*e.y)},n.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y},n.rotate=function(e,t,n){var i=Math.cos(t),o=Math.sin(t);n||(n={});var r=e.x*i-e.y*o;return n.y=e.x*o+e.y*i,n.x=r,n},n.rotateAbout=function(e,t,n,i){var o=Math.cos(t),r=Math.sin(t);i||(i={});var a=n.x+((e.x-n.x)*o-(e.y-n.y)*r);return i.y=n.y+((e.x-n.x)*r+(e.y-n.y)*o),i.x=a,i},n.normalise=function(e){var t=n.magnitude(e);return 0===t?{x:0,y:0}:{x:e.x/t,y:e.y/t}},n.dot=function(e,t){return e.x*t.x+e.y*t.y},n.cross=function(e,t){return e.x*t.y-e.y*t.x},n.cross3=function(e,t,n){return(t.x-e.x)*(n.y-e.y)-(t.y-e.y)*(n.x-e.x)},n.add=function(e,t,n){return n||(n={}),n.x=e.x+t.x,n.y=e.y+t.y,n},n.sub=function(e,t,n){return n||(n={}),n.x=e.x-t.x,n.y=e.y-t.y,n},n.mult=function(e,t){return{x:e.x*t,y:e.y*t}},n.div=function(e,t){return{x:e.x/t,y:e.y/t}},n.perp=function(e,t){return{x:(t=!0===t?-1:1)*-e.y,y:t*e.x}},n.neg=function(e){return{x:-e.x,y:-e.y}},n.angle=function(e,t){return Math.atan2(t.y-e.y,t.x-e.x)},n._temp=[n.create(),n.create(),n.create(),n.create(),n.create(),n.create()]},function(e,t,n){var i={};e.exports=i;var o=n(2),r=n(0);i.create=function(e,t){for(var n=[],i=0;i0)return!1;a=n}return!0},i.scale=function(e,t,n,r){if(1===t&&1===n)return e;var a,s;r=r||i.centre(e);for(var l=0;l=0?l-1:e.length-1],u=e[l],d=e[(l+1)%e.length],p=t[l0&&(r|=2),3===r)return!1;return 0!==r||null},i.hull=function(e){var t,n,i=[],r=[];for((e=e.slice(0)).sort((function(e,t){var n=e.x-t.x;return 0!==n?n:e.y-t.y})),n=0;n=2&&o.cross3(r[r.length-2],r[r.length-1],t)<=0;)r.pop();r.push(t)}for(n=e.length-1;n>=0;n-=1){for(t=e[n];i.length>=2&&o.cross3(i[i.length-2],i[i.length-1],t)<=0;)i.pop();i.push(t)}return i.pop(),r.pop(),i.concat(r)}},function(e,t,n){var i={};e.exports=i;var o=n(0);i.on=function(e,t,n){for(var i,o=t.split(" "),r=0;r0){n||(n={}),i=t.split(" ");for(var c=0;c0&&r.rotateAbout(a.position,n,e.position,a.position)}},i.setVelocity=function(e,t){e.positionPrev.x=e.position.x-t.x,e.positionPrev.y=e.position.y-t.y,e.velocity.x=t.x,e.velocity.y=t.y,e.speed=r.magnitude(e.velocity)},i.setAngularVelocity=function(e,t){e.anglePrev=e.angle-t,e.angularVelocity=t,e.angularSpeed=Math.abs(e.angularVelocity)},i.translate=function(e,t){i.setPosition(e,r.add(e.position,t))},i.rotate=function(e,t,n){if(n){var o=Math.cos(t),r=Math.sin(t),a=e.position.x-n.x,s=e.position.y-n.y;i.setPosition(e,{x:n.x+(a*o-s*r),y:n.y+(a*r+s*o)}),i.setAngle(e,e.angle+t)}else i.setAngle(e,e.angle+t)},i.scale=function(e,t,n,r){var a=0,s=0;r=r||e.position;for(var u=0;u0&&(a+=d.area,s+=d.inertia),d.position.x=r.x+(d.position.x-r.x)*t,d.position.y=r.y+(d.position.y-r.y)*n,l.update(d.bounds,d.vertices,e.velocity)}e.parts.length>1&&(e.area=a,e.isStatic||(i.setMass(e,e.density*a),i.setInertia(e,s))),e.circleRadius&&(t===n?e.circleRadius*=t:e.circleRadius=null)},i.update=function(e,t,n,i){var a=Math.pow(t*n*e.timeScale,2),s=1-e.frictionAir*n*e.timeScale,u=e.position.x-e.positionPrev.x,d=e.position.y-e.positionPrev.y;e.velocity.x=u*s*i+e.force.x/e.mass*a,e.velocity.y=d*s*i+e.force.y/e.mass*a,e.positionPrev.x=e.position.x,e.positionPrev.y=e.position.y,e.position.x+=e.velocity.x,e.position.y+=e.velocity.y,e.angularVelocity=(e.angle-e.anglePrev)*s*i+e.torque/e.inertia*a,e.anglePrev=e.angle,e.angle+=e.angularVelocity,e.speed=r.magnitude(e.velocity),e.angularSpeed=Math.abs(e.angularVelocity);for(var p=0;p0&&(f.position.x+=e.velocity.x,f.position.y+=e.velocity.y),0!==e.angularVelocity&&(o.rotate(f.vertices,e.angularVelocity,e.position),c.rotate(f.axes,e.angularVelocity),p>0&&r.rotateAbout(f.position,e.angularVelocity,e.position,f.position)),l.update(f.bounds,f.vertices,e.velocity)}},i.applyForce=function(e,t,n){e.force.x+=n.x,e.force.y+=n.y;var i=t.x-e.position.x,o=t.y-e.position.y;e.torque+=i*n.y-o*n.x},i._totalProperties=function(e){for(var t={mass:0,area:0,inertia:0,centre:{x:0,y:0}},n=1===e.parts.length?0:1;n0&&r.motion=r.sleepThreshold&&i.set(r,!0)):r.sleepCounter>0&&(r.sleepCounter-=1)}else i.set(r,!1)}},i.afterCollisions=function(e,t){for(var n=t*t*t,o=0;oi._motionWakeThreshold*n&&i.set(c,!1)}}}},i.set=function(e,t){var n=e.isSleeping;t?(e.isSleeping=!0,e.sleepCounter=e.sleepThreshold,e.positionImpulse.x=0,e.positionImpulse.y=0,e.positionPrev.x=e.position.x,e.positionPrev.y=e.position.y,e.anglePrev=e.angle,e.speed=0,e.angularSpeed=0,e.motion=0,n||o.trigger(e,"sleepStart")):(e.isSleeping=!1,e.sleepCounter=0,n&&o.trigger(e,"sleepEnd"))}},function(e,t,n){var i={};e.exports=i;var o,r,a,s=n(3),l=n(9);o=[],r={overlap:0,axis:null},a={overlap:0,axis:null},i.create=function(e,t){return{pair:null,collided:!1,bodyA:e,bodyB:t,parentA:e.parent,parentB:t.parent,depth:0,normal:{x:0,y:0},tangent:{x:0,y:0},penetration:{x:0,y:0},supports:[]}},i.collides=function(e,t,n){if(i._overlapAxes(r,e.vertices,t.vertices,e.axes),r.overlap<=0)return null;if(i._overlapAxes(a,t.vertices,e.vertices,t.axes),a.overlap<=0)return null;var o,c,u=n&&n.table[l.id(e,t)];u?o=u.collision:((o=i.create(e,t)).collided=!0,o.bodyA=e.idP?P=s:sC?C=s:so?o=a:al.frictionStatic?s.frictionStatic:l.frictionStatic,e.restitution=s.restitution>l.restitution?s.restitution:l.restitution,e.slop=s.slop>l.slop?s.slop:l.slop,t.pair=e,a.length=0;for(var u=0;u0?1:.7),t.damping=t.damping||0,t.angularStiffness=t.angularStiffness||0,t.angleA=t.bodyA?t.bodyA.angle:t.angleA,t.angleB=t.bodyB?t.bodyB.angle:t.angleB,t.plugin={};var a={visible:!0,lineWidth:2,strokeStyle:"#ffffff",type:"line",anchors:!0};return 0===t.length&&t.stiffness>.1?(a.type="pin",a.anchors=!1):t.stiffness<.9&&(a.type="spring"),t.render=c.extend(a,t.render),t},i.preSolveAll=function(e){for(var t=0;t0&&(d.position.x+=c.x,d.position.y+=c.y),0!==c.angle&&(o.rotate(d.vertices,c.angle,n.position),l.rotate(d.axes,c.angle),u>0&&r.rotateAbout(d.position,c.angle,n.position,d.position)),s.update(d.bounds,d.vertices,n.velocity)}c.angle*=i._warming,c.x*=i._warming,c.y*=i._warming}}},i.pointAWorld=function(e){return{x:(e.bodyA?e.bodyA.position.x:0)+e.pointA.x,y:(e.bodyA?e.bodyA.position.y:0)+e.pointA.y}},i.pointBWorld=function(e){return{x:(e.bodyB?e.bodyB.position.x:0)+e.pointB.x,y:(e.bodyB?e.bodyB.position.y:0)+e.pointB.y}}},function(e,t,n){var i={};e.exports=i;var o=n(2),r=n(0);i.fromVertices=function(e){for(var t={},n=0;n0&&o.area(M)1?(v=a.create(r.extend({parts:y.slice(0)},i)),a.setPosition(v,{x:e,y:t}),v):y[0]}},function(e,t,n){var i={};e.exports=i;var o=n(0);i.create=function(e){var t={};return e||o.log("Mouse.create: element was undefined, defaulting to document.body","warn"),t.element=e||document.body,t.absolute={x:0,y:0},t.position={x:0,y:0},t.mousedownPosition={x:0,y:0},t.mouseupPosition={x:0,y:0},t.offset={x:0,y:0},t.scale={x:1,y:1},t.wheelDelta=0,t.button=-1,t.pixelRatio=parseInt(t.element.getAttribute("data-pixel-ratio"),10)||1,t.sourceEvents={mousemove:null,mousedown:null,mouseup:null,mousewheel:null},t.mousemove=function(e){var n=i._getRelativeMousePosition(e,t.element,t.pixelRatio);e.changedTouches&&(t.button=0,e.preventDefault()),t.absolute.x=n.x,t.absolute.y=n.y,t.position.x=t.absolute.x*t.scale.x+t.offset.x,t.position.y=t.absolute.y*t.scale.y+t.offset.y,t.sourceEvents.mousemove=e},t.mousedown=function(e){var n=i._getRelativeMousePosition(e,t.element,t.pixelRatio);e.changedTouches?(t.button=0,e.preventDefault()):t.button=e.button,t.absolute.x=n.x,t.absolute.y=n.y,t.position.x=t.absolute.x*t.scale.x+t.offset.x,t.position.y=t.absolute.y*t.scale.y+t.offset.y,t.mousedownPosition.x=t.position.x,t.mousedownPosition.y=t.position.y,t.sourceEvents.mousedown=e},t.mouseup=function(e){var n=i._getRelativeMousePosition(e,t.element,t.pixelRatio);e.changedTouches&&e.preventDefault(),t.button=-1,t.absolute.x=n.x,t.absolute.y=n.y,t.position.x=t.absolute.x*t.scale.x+t.offset.x,t.position.y=t.absolute.y*t.scale.y+t.offset.y,t.mouseupPosition.x=t.position.x,t.mouseupPosition.y=t.position.y,t.sourceEvents.mouseup=e},t.mousewheel=function(e){t.wheelDelta=Math.max(-1,Math.min(1,e.wheelDelta||-e.detail)),e.preventDefault()},i.setElement(t,t.element),t},i.setElement=function(e,t){e.element=t,t.addEventListener("mousemove",e.mousemove),t.addEventListener("mousedown",e.mousedown),t.addEventListener("mouseup",e.mouseup),t.addEventListener("mousewheel",e.mousewheel),t.addEventListener("DOMMouseScroll",e.mousewheel),t.addEventListener("touchmove",e.mousemove),t.addEventListener("touchstart",e.mousedown),t.addEventListener("touchend",e.mouseup)},i.clearSourceEvents=function(e){e.sourceEvents.mousemove=null,e.sourceEvents.mousedown=null,e.sourceEvents.mouseup=null,e.sourceEvents.mousewheel=null,e.wheelDelta=0},i.setOffset=function(e,t){e.offset.x=t.x,e.offset.y=t.y,e.position.x=e.absolute.x*e.scale.x+e.offset.x,e.position.y=e.absolute.y*e.scale.y+e.offset.y},i.setScale=function(e,t){e.scale.x=t.x,e.scale.y=t.y,e.position.x=e.absolute.x*e.scale.x+e.offset.x,e.position.y=e.absolute.y*e.scale.y+e.offset.y},i._getRelativeMousePosition=function(e,t,n){var i,o,r=t.getBoundingClientRect(),a=document.documentElement||document.body.parentNode||document.body,s=void 0!==window.pageXOffset?window.pageXOffset:a.scrollLeft,l=void 0!==window.pageYOffset?window.pageYOffset:a.scrollTop,c=e.changedTouches;return c?(i=c[0].pageX-r.left-s,o=c[0].pageY-r.top-l):(i=e.pageX-r.left-s,o=e.pageY-r.top-l),{x:i/(t.clientWidth/(t.width||t.clientWidth)*n),y:o/(t.clientHeight/(t.height||t.clientHeight)*n)}}},function(e,t,n){var i={};e.exports=i;var o=n(0),r=n(8);i.create=function(e){return o.extend({bodies:[],pairs:null},e)},i.setBodies=function(e,t){e.bodies=t.slice(0)},i.clear=function(e){e.bodies=[]},i.collisions=function(e){var t,n,o=[],a=e.pairs,s=e.bodies,l=s.length,c=i.canCollide,u=r.collides;for(s.sort(i._compareBoundsX),t=0;tf)break;if(!(vB.max.y)&&(!m||!h.isStatic&&!h.isSleeping)&&c(d.collisionFilter,h.collisionFilter)){var b=h.parts.length;if(x&&1===b)(C=u(d,h,a))&&o.push(C);else for(var S=b>1?1:0,w=g>1?1:0;wB.max.x||p.max.xB.max.y||(C=u(A,M,a))&&o.push(C)}}}}return o},i.canCollide=function(e,t){return e.group===t.group&&0!==e.group?e.group>0:0!=(e.mask&t.category)&&0!=(t.mask&e.category)},i._compareBoundsX=function(e,t){return e.bounds.min.x-t.bounds.min.x}},function(e,t,n){var i={};e.exports=i;var o=n(0);i._registry={},i.register=function(e){if(i.isPlugin(e)||o.warn("Plugin.register:",i.toString(e),"does not implement all required fields."),e.name in i._registry){var t=i._registry[e.name],n=i.versionParse(e.version).number,r=i.versionParse(t.version).number;n>r?(o.warn("Plugin.register:",i.toString(t),"was upgraded to",i.toString(e)),i._registry[e.name]=e):n-1},i.isFor=function(e,t){var n=e.for&&i.dependencyParse(e.for);return!e.for||t.name===n.name&&i.versionSatisfies(t.version,n.range)},i.use=function(e,t){if(e.uses=(e.uses||[]).concat(t||[]),0!==e.uses.length){for(var n=i.dependencies(e),r=o.topologicalSort(n),a=[],s=0;s0&&o.info(a.join(" "))}else o.warn("Plugin.use:",i.toString(e),"does not specify any dependencies to install.")},i.dependencies=function(e,t){var n=i.dependencyParse(e),r=n.name;if(!(r in(t=t||{}))){e=i.resolve(e)||e,t[r]=o.map(e.uses||[],(function(t){i.isPlugin(t)&&i.register(t);var r=i.dependencyParse(t),a=i.resolve(t);return a&&!i.versionSatisfies(a.version,r.range)?(o.warn("Plugin.dependencies:",i.toString(a),"does not satisfy",i.toString(r),"used by",i.toString(n)+"."),a._warned=!0,e._warned=!0):a||(o.warn("Plugin.dependencies:",i.toString(t),"used by",i.toString(n),"could not be resolved."),e._warned=!0),r.name}));for(var a=0;a=|>)?\s*((\d+)\.(\d+)\.(\d+))(-[0-9A-Za-z-+]+)?$/;t.test(e)||o.warn("Plugin.versionParse:",e,"is not a valid version or range.");var n=t.exec(e),i=Number(n[4]),r=Number(n[5]),a=Number(n[6]);return{isRange:Boolean(n[1]||n[2]),version:n[3],range:e,operator:n[1]||n[2]||"",major:i,minor:r,patch:a,parts:[i,r,a],prerelease:n[7],number:1e8*i+1e4*r+a}},i.versionSatisfies=function(e,t){t=t||"*";var n=i.versionParse(t),o=i.versionParse(e);if(n.isRange){if("*"===n.operator||"*"===e)return!0;if(">"===n.operator)return o.number>n.number;if(">="===n.operator)return o.number>=n.number;if("~"===n.operator)return o.major===n.major&&o.minor===n.minor&&o.patch>=n.patch;if("^"===n.operator)return n.major>0?o.major===n.major&&o.number>=n.number:n.minor>0?o.minor===n.minor&&o.patch>=n.patch:o.patch===n.patch}return e===t||"*"===e}},function(e,t,n){var i={};e.exports=i;var o=n(0),r=n(5),a=n(1),s=n(4),l=n(2),c=n(13);!function(){var e,t;"undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout((function(){e(o.now())}),1e3/60)},t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),i._goodFps=30,i._goodDelta=1e3/60,i.create=function(e){var t={controller:i,engine:null,element:null,canvas:null,mouse:null,frameRequestId:null,timing:{historySize:60,delta:0,deltaHistory:[],lastTime:0,lastTimestamp:0,lastElapsed:0,timestampElapsed:0,timestampElapsedHistory:[],engineDeltaHistory:[],engineElapsedHistory:[],elapsedHistory:[]},options:{width:800,height:600,pixelRatio:1,background:"#14151f",wireframeBackground:"#14151f",hasBounds:!!e.bounds,enabled:!0,wireframes:!0,showSleeping:!0,showDebug:!1,showStats:!1,showPerformance:!1,showBounds:!1,showVelocity:!1,showCollisions:!1,showSeparations:!1,showAxes:!1,showPositions:!1,showAngleIndicator:!1,showIds:!1,showVertexNumbers:!1,showConvexHulls:!1,showInternalEdges:!1,showMousePosition:!1}},n=o.extend(t,e);return n.canvas&&(n.canvas.width=n.options.width||n.canvas.width,n.canvas.height=n.options.height||n.canvas.height),n.mouse=e.mouse,n.engine=e.engine,n.canvas=n.canvas||d(n.options.width,n.options.height),n.context=n.canvas.getContext("2d"),n.textures={},n.bounds=n.bounds||{min:{x:0,y:0},max:{x:n.canvas.width,y:n.canvas.height}},n.options.showBroadphase=!1,1!==n.options.pixelRatio&&i.setPixelRatio(n,n.options.pixelRatio),o.isElement(n.element)?n.element.appendChild(n.canvas):n.canvas.parentNode||o.log("Render.create: options.element was undefined, render.canvas was created but not appended","warn"),n},i.run=function(t){!function o(r){t.frameRequestId=e(o),n(t,r),i.world(t,r),(t.options.showStats||t.options.showDebug)&&i.stats(t,t.context,r),(t.options.showPerformance||t.options.showDebug)&&i.performance(t,t.context,r)}()},i.stop=function(e){t(e.frameRequestId)},i.setPixelRatio=function(e,t){var n=e.options,i=e.canvas;"auto"===t&&(t=p(i)),n.pixelRatio=t,i.setAttribute("data-pixel-ratio",t),i.width=n.width*t,i.height=n.height*t,i.style.width=n.width+"px",i.style.height=n.height+"px"},i.lookAt=function(e,t,n,i){i=void 0===i||i,t=o.isArray(t)?t:[t],n=n||{x:0,y:0};for(var r={min:{x:1/0,y:1/0},max:{x:-1/0,y:-1/0}},a=0;ar.max.x&&(r.max.x=u.x),l.yr.max.y&&(r.max.y=u.y))}var d=r.max.x-r.min.x+2*n.x,p=r.max.y-r.min.y+2*n.y,f=e.canvas.height,v=e.canvas.width/f,y=d/p,m=1,g=1;y>v?g=y/v:m=v/y,e.options.hasBounds=!0,e.bounds.min.x=r.min.x,e.bounds.max.x=r.min.x+d*m,e.bounds.min.y=r.min.y,e.bounds.max.y=r.min.y+p*g,i&&(e.bounds.min.x+=.5*d-d*m*.5,e.bounds.max.x+=.5*d-d*m*.5,e.bounds.min.y+=.5*p-p*g*.5,e.bounds.max.y+=.5*p-p*g*.5),e.bounds.min.x-=n.x,e.bounds.max.x-=n.x,e.bounds.min.y-=n.y,e.bounds.max.y-=n.y,e.mouse&&(c.setScale(e.mouse,{x:(e.bounds.max.x-e.bounds.min.x)/e.canvas.width,y:(e.bounds.max.y-e.bounds.min.y)/e.canvas.height}),c.setOffset(e.mouse,e.bounds.min))},i.startViewTransform=function(e){var t=e.bounds.max.x-e.bounds.min.x,n=e.bounds.max.y-e.bounds.min.y,i=t/e.options.width,o=n/e.options.height;e.context.setTransform(e.options.pixelRatio/i,0,0,e.options.pixelRatio/o,0,0),e.context.translate(-e.bounds.min.x,-e.bounds.min.y)},i.endViewTransform=function(e){e.context.setTransform(e.options.pixelRatio,0,0,e.options.pixelRatio,0,0)},i.world=function(e,t){var n,u=o.now(),d=e.engine,p=d.world,f=e.canvas,y=e.context,m=e.options,g=e.timing,x=r.allBodies(p),h=r.allConstraints(p),b=m.wireframes?m.wireframeBackground:m.background,S=[],w=[],A={timestamp:d.timing.timestamp};if(s.trigger(e,"beforeRender",A),e.currentBackground!==b&&v(e,b),y.globalCompositeOperation="source-in",y.fillStyle="transparent",y.fillRect(0,0,f.width,f.height),y.globalCompositeOperation="source-over",m.hasBounds){for(n=0;n1?1:0;a1?1:0;s1?1:0;r1?1:0;s1?1:0;r1?1:0;r1?1:0;o0)){var u=i.activeContacts[0].vertex.x,d=i.activeContacts[0].vertex.y;2===i.activeContacts.length&&(u=(i.activeContacts[0].vertex.x+i.activeContacts[1].vertex.x)/2,d=(i.activeContacts[0].vertex.y+i.activeContacts[1].vertex.y)/2),o.bodyB===o.supports[0].body||!0===o.bodyA.isStatic?s.moveTo(u-8*o.normal.x,d-8*o.normal.y):s.moveTo(u+8*o.normal.x,d+8*o.normal.y),s.lineTo(u,d)}l.wireframes?s.strokeStyle="rgba(255,165,0,0.7)":s.strokeStyle="orange",s.lineWidth=1,s.stroke()},i.separations=function(e,t,n){var i,o,r,a,s,l=n,c=e.options;for(l.beginPath(),s=0;s0&&l.trigger(e,"collisionStart",{pairs:m.collisionStart}),r.preSolvePosition(m.list),f=0;f0&&l.trigger(e,"collisionActive",{pairs:m.collisionActive}),m.collisionEnd.length>0&&l.trigger(e,"collisionEnd",{pairs:m.collisionEnd}),i._bodiesClearForces(b),l.trigger(e,"afterUpdate",h),e.timing.lastElapsed=d.now()-p,e},i.merge=function(e,t){if(d.extend(e,t),t.world){e.world=t.world,i.clear(e);for(var n=c.allBodies(e.world),r=0;rW||-H>W?(o=H>0?H:-H,(n=f.friction*(H>0?1:-1)*s)<-o?n=-o:n>o&&(n=o)):(n=H,o=d);var G=I*b-T*h,N=R*b-E*h,U=C/(M+y.inverseInertia*G*G+m.inverseInertia*N*N),z=(1+f.restitution)*F*U;if(n*=U,F*F>l&&F<0)k.normalImpulse=0;else{var X=k.normalImpulse;k.normalImpulse+=z,k.normalImpulse=Math.min(k.normalImpulse,0),z=k.normalImpulse-X}if(H*H>u)k.tangentImpulse=0;else{var Q=k.tangentImpulse;k.tangentImpulse+=n,k.tangentImpulse<-o&&(k.tangentImpulse=-o),k.tangentImpulse>o&&(k.tangentImpulse=o),n=k.tangentImpulse-Q}var Y=h*z+S*n,Z=b*z+w*n;y.isStatic||y.isSleeping||(y.positionPrev.x+=Y*y.inverseMass,y.positionPrev.y+=Z*y.inverseMass,y.anglePrev+=(I*Z-T*Y)*y.inverseInertia),m.isStatic||m.isSleeping||(m.positionPrev.x-=Y*m.inverseMass,m.positionPrev.y-=Z*m.inverseMass,m.anglePrev-=(R*Z-E*Y)*m.inverseInertia)}}}}},function(e,t,n){var i={};e.exports=i;var o=n(9),r=n(0);i.create=function(e){return r.extend({table:{},list:[],collisionStart:[],collisionActive:[],collisionEnd:[]},e)},i.update=function(e,t,n){var i,r,a,s,l=e.list,c=l.length,u=e.table,d=t.length,p=e.collisionStart,f=e.collisionEnd,v=e.collisionActive;for(p.length=0,f.length=0,v.length=0,s=0;sy&&(y=x),s.translate(g,{x:.5*h,y:.5*x}),d=g.bounds.max.x+r,o.addBody(u,g),c=g,f+=1}else d+=r}p+=y+a,d=e}return u},i.chain=function(e,t,n,i,s,l){for(var c=e.bodies,u=1;u0)for(c=0;c0&&(p=f[c-1+(l-1)*t],o.addConstraint(e,r.create(a.extend({bodyA:p,bodyB:d},s)))),i&&cp||a<(c=p-c)||a>n-1-c))return 1===d&&s.translate(u,{x:(a+(n%2==1?1:-1))*f,y:0}),l(e+(u?a*f:0)+a*r,i,a,c,u,d)}))},i.newtonsCradle=function(e,t,n,i,a){for(var s=o.create({label:"Newtons Cradle"}),c=0;cu.bounds.max.x||f.bounds.max.yu.bounds.max.y))){var v=i._getRegion(e,f);if(!f.region||v.id!==f.region.id||o){f.region&&!o||(f.region=v);var y=i._regionUnion(v,f.region);for(a=y.startCol;a<=y.endCol;a++)for(s=y.startRow;s<=y.endRow;s++){l=d[c=i._getBucketId(a,s)];var m=a>=v.startCol&&a<=v.endCol&&s>=v.startRow&&s<=v.endRow,g=a>=f.region.startCol&&a<=f.region.endCol&&s>=f.region.startRow&&s<=f.region.endRow;!m&&g&&g&&l&&i._bucketRemoveBody(e,l,f),(f.region===v||m&&!g||o)&&(l||(l=i._createBucket(d,c)),i._bucketAddBody(e,l,f))}f.region=v,p=!0}}}p&&(e.pairsList=i._createActivePairsList(e))},a(i,"update","Grid.update ➤ replaced by Matter.Detector"),i.clear=function(e){e.buckets={},e.pairs={},e.pairsList=[]},a(i,"clear","Grid.clear ➤ replaced by Matter.Detector"),i._regionUnion=function(e,t){var n=Math.min(e.startCol,t.startCol),o=Math.max(e.endCol,t.endCol),r=Math.min(e.startRow,t.startRow),a=Math.max(e.endRow,t.endRow);return i._createRegion(n,o,r,a)},i._getRegion=function(e,t){var n=t.bounds,o=Math.floor(n.min.x/e.bucketWidth),r=Math.floor(n.max.x/e.bucketWidth),a=Math.floor(n.min.y/e.bucketHeight),s=Math.floor(n.max.y/e.bucketHeight);return i._createRegion(o,r,a,s)},i._createRegion=function(e,t,n,i){return{id:e+","+t+","+n+","+i,startCol:e,endCol:t,startRow:n,endRow:i}},i._getBucketId=function(e,t){return"C"+e+"R"+t},i._createBucket=function(e,t){return e[t]=[]},i._bucketAddBody=function(e,t,n){var i,r=e.pairs,a=o.id,s=t.length;for(i=0;i0?s.push(t):delete i[o[n]];return s}},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(7),a=n(13),s=n(4),l=n(14),c=n(10),u=n(5),d=n(0),p=n(1);i.create=function(e,t){var n=(e?e.mouse:null)||(t?t.mouse:null);n||(e&&e.render&&e.render.canvas?n=a.create(e.render.canvas):t&&t.element?n=a.create(t.element):(n=a.create(),d.warn("MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected")));var o={type:"mouseConstraint",mouse:n,element:null,body:null,constraint:c.create({label:"Mouse Constraint",pointA:n.position,pointB:{x:0,y:0},length:.01,stiffness:.1,angularStiffness:1,render:{strokeStyle:"#90EE90",lineWidth:3}}),collisionFilter:{category:1,mask:4294967295,group:0}},r=d.extend(o,t);return s.on(e,"beforeUpdate",(function(){var t=u.allBodies(e.world);i.update(r,t),i._triggerEvents(r)})),r},i.update=function(e,t){var n=e.mouse,i=e.constraint,a=e.body;if(0===n.button){if(i.bodyB)r.set(i.bodyB,!1),i.pointA=n.position;else for(var c=0;c1?1:0;ue.deltaMax?e.deltaMax:i)/e.delta,e.delta=i),0!==e.timeScalePrev&&(s*=a.timeScale/e.timeScalePrev),0===a.timeScale&&(s=0),e.timeScalePrev=a.timeScale,e.correction=s,e.frameCounter+=1,n-e.counterTimestamp>=1e3&&(e.fps=e.frameCounter*((n-e.counterTimestamp)/1e3),e.counterTimestamp=n,e.frameCounter=0),o.trigger(e,"tick",l),o.trigger(e,"beforeUpdate",l),r.update(t,i,s),o.trigger(e,"afterUpdate",l),o.trigger(e,"afterTick",l)},i.stop=function(e){t(e.frameRequestId)},i.start=function(e,t){i.run(e,t)}}()},function(e,t,n){var i={};e.exports=i;var o=n(8),r=n(0).deprecated;i.collides=function(e,t){return o.collides(e,t)},r(i,"collides","SAT.collides ➤ replaced by Collision.collides")},function(e,t,n){var i={};e.exports=i;n(1);var o=n(0);i.pathToVertices=function(e,t){"undefined"==typeof window||"SVGPathSeg"in window||o.warn("Svg.pathToVertices: SVGPathSeg not defined, a polyfill is required.");var n,r,a,s,l,c,u,d,p,f,v,y=[],m=0,g=0,x=0;t=t||15;var h=function(e,t,n){var i=n%2==1&&n>1;if(!p||e!=p.x||t!=p.y){p&&i?(f=p.x,v=p.y):(f=0,v=0);var o={x:f+e,y:v+t};!i&&p||(p=o),y.push(o),g=f+e,x=v+t}},b=function(e){var t=e.pathSegTypeAsLetter.toUpperCase();if("Z"!==t){switch(t){case"M":case"L":case"T":case"C":case"S":case"Q":g=e.x,x=e.y;break;case"H":g=e.x;break;case"V":x=e.y}h(g,x,e.pathSegType)}};for(i._svgPathToAbsolute(e),a=e.getTotalLength(),c=[],n=0;n image.height ? image.width / image.height : image.height / image.width; // Split background-size properties into array cssSize = cssSize.split(' '); // First property is width. It is always set to something. computedDim[0] = cssSize[0]; // If height not set, set it to auto computedDim[1] = cssSize.length > 1 ? cssSize[1] : 'auto'; if (cssSize[0] === 'cover') { // Width is greater than height if (elemDim[0] > elemDim[1]) { // Elem's ratio greater than or equal to img ratio if (elemDim[0] / elemDim[1] >= ratio) { computedDim[0] = elemDim[0]; computedDim[1] = 'auto'; } else { computedDim[0] = 'auto'; computedDim[1] = elemDim[1]; } } else { computedDim[0] = 'auto'; computedDim[1] = elemDim[1]; } } else if (cssSize[0] === 'contain') { // Width is less than height if (elemDim[0] < elemDim[1]) { computedDim[0] = elemDim[0]; computedDim[1] = 'auto'; } else { // elem's ratio is greater than or equal to img ratio if (elemDim[0] / elemDim[1] >= ratio) { computedDim[0] = 'auto'; computedDim[1] = elemDim[1]; } else { computedDim[1] = 'auto'; computedDim[0] = elemDim[0]; } } } else { // If not 'cover' or 'contain', loop through the values for (var i = cssSize.length; i--;) { // Check if values are in pixels or in percentage if (cssSize[i].indexOf('px') > -1) { // If in pixels, just remove the 'px' to get the value computedDim[i] = cssSize[i].replace('px', ''); } else if (cssSize[i].indexOf('%') > -1) { // If percentage, get percentage of elem's dimension // and assign it to the computed dimension computedDim[i] = elemDim[i] * (cssSize[i].replace('%', '') / 100); } } } // If both values are set to auto, return image's // original width and height if (computedDim[0] === 'auto' && computedDim[1] === 'auto') { computedDim[0] = image.width; computedDim[1] = image.height; } else { // Depending on whether width or height is auto, // calculate the value in pixels of auto. // ratio in here is just getting proportions. ratio = computedDim[0] === 'auto' ? image.height / computedDim[1] : image.width / computedDim[0]; computedDim[0] = computedDim[0] === 'auto' ? image.width / ratio : computedDim[0]; computedDim[1] = computedDim[1] === 'auto' ? image.height / ratio : computedDim[1]; } // Finally, return an object with the width and height of the // background image. return { width: computedDim[0], height: computedDim[1] }; } function isBodyInViewport(body, x, y, w, h) { return ( body.bounds.max.y <= h + y && body.bounds.max.y >= y ) }; function isInViewport(elem) { var distance = elem.getBoundingClientRect(); return ( distance.top >= 0 && distance.left >= 0 && distance.bottom <= (window.innerHeight || document.documentElement.clientHeight) && distance.right <= (window.innerWidth || document.documentElement.clientWidth) ); }; function shouldWrapElement(element) { const style = window.getComputedStyle(element) return (style.visibility === 'visible' && element.offsetWidth > 5 && element.offsetHeight > 5 && style.display !== 'none' && style.opacity !== '0' && style.opacity !== 0 && !style.filter.includes('opacity(0)')) } function getTextNodes(parent) { var all = []; for (parent = parent.firstChild; parent; parent = parent.nextSibling) { if (['SCRIPT', 'STYLE'].indexOf(parent.tagName) >= 0) continue; if (parent.nodeType === Node.TEXT_NODE) all.push(parent); else all = all.concat(getTextNodes(parent)); } return all } function preprocessPage(bodyElement) { const textNodes = getTextNodes(bodyElement); let benderTextNodes = [] textNodes.forEach(node => { if (node.nodeValue.trim().length != 0 && node.parentElement && shouldWrapElement(node.parentElement)) { if (!benderTextNodes.includes(node.parentElement)) { benderTextNodes.push(node.parentElement) } } }) const toWrap = [] benderTextNodes.forEach(e => { let elementNotIncluded = true benderTextNodes.forEach(e2 => { if (e2 !== e && e2.contains(e)) { elementNotIncluded = false } }) if (elementNotIncluded) { toWrap.push(e) } }) toWrap.forEach(e => { wrapWordsInElement(e) }) const words = Array.from(document.body.querySelectorAll('.bender-word')) const images = getImagesInElement(document.body).filter(i => shouldWrapElement(i)) return { words, images } } function wrapWordsInElement(e) { if (!e.classList.contains('bender-word')) { e.innerHTML = e.innerHTML.replace(/(?]*|&[^;]*))([^\s<]+)/g, '$1$2') } const wrappedWords = Array.from(e.querySelectorAll('.bender-word')) return wrappedWords } function getImagesInElement(element) { const imgTags = element.querySelectorAll('img') const images = Array.from(imgTags) return images } function copyWordElementForPhysics(element) { const newElement = createNewElementFrom(element) newElement.innerText = element.innerText // newElement.style.width = 'unset' //newElement.style.height = 'unset' return { physicsElement: newElement, originalElement: element, type: 'word' } } function copyImgTagElementForPhysics(element) { const newElement = createNewElementFrom(element) newElement.src = element.src return { physicsElement: newElement, originalElement: element, type: 'img' } } function createNewElementFrom(element) { const newElement = document.createElement(element.tagName) newElement.src = element.src const bounds = element.getBoundingClientRect() const computedStyle = window.getComputedStyle(element) newElement.style.width = computedStyle.width newElement.style.height = computedStyle.height newElement.style.position = 'absolute' newElement.style.top = `0` newElement.style.left = `0` newElement.style.transform = `translate3d(${bounds.x + window.scrollX}px, ${bounds.y + window.scrollY}px, 0)` newElement.style.transformOrigin = 'center' newElement.style.zIndex = 9999 newElement.style.margin = "0 0 0 0" newElement.style.padding = "0 0 0 0" newElement.style.border = "0 0 0 0" newElement.style.transition = "all 0s" newElement.style.WebkitTransition = "all 0s" newElement.style.minWidth = 'unset' newElement.style.minHeight = 'unset' newElement.style.maxWidth = 'unset' newElement.style.maxHeight = 'unset' newElement.style.willChange = 'transform' newElement.style.fontStyle = computedStyle.fontStyle newElement.style.fontVariant = computedStyle.fontVariant newElement.style.fontWeight = computedStyle.fontWeight newElement.style.fontSize = computedStyle.fontSize newElement.style.fontFamily = computedStyle.fontFamily newElement.style.lineHeight = computedStyle.fontSize newElement.style.textTransform = computedStyle.textTransform newElement.style.color = computedStyle.color return newElement } function copyBackgroundImageElementForPhysics(element) { newElement = createNewElementFrom(element) return { physicsElement: newElement, originalElement: element, type: 'background-image' } } function copyElementForPhysics(element) { console.log("1") const existingElement = window.benderPhysics.physicsElements.find(e => e.originalElement === element) if (existingElement) { return { existingElement } } console.log("2") console.log("element", element) if (element.classList.contains('bender-word')) { console.log("3") return copyWordElementForPhysics(element) } if (element.tagName === 'IMG') { return copyImgTagElementForPhysics(element) } const style = window.getComputedStyle(element) if (style.backgroundImage !== 'none') { return copyBackgroundImageElementForPhysics(element) } } function createBoundaryWalls(wallThickness) { const top = Matter.Bodies.rectangle(window.scrollX + window.innerWidth / 2, window.scrollY - wallThickness / 2, window.innerWidth * 2, wallThickness, { isStatic: true, label: 'top' }) const bottom = Matter.Bodies.rectangle(window.scrollX + window.innerWidth / 2, window.scrollY + window.innerHeight + wallThickness / 2 - 10, window.innerWidth * 2, wallThickness, { isStatic: true, label: 'bottom' }) const left = Matter.Bodies.rectangle(window.scrollX - wallThickness / 2, window.scrollY + window.innerHeight / 2, wallThickness, window.innerHeight * 2, { isStatic: true, label: 'left' }) const right = Matter.Bodies.rectangle(window.scrollX + window.innerWidth + wallThickness / 2 - 20, window.scrollY + window.innerHeight / 2, wallThickness, window.innerHeight * 2, { isStatic: true, label: 'right' }) return [{ body: top, targetPosition: top.position, name: 'top' }, { body: bottom, targetPosition: bottom.position, name: 'bottom' }, { body: left, targetPosition: left.position, name: 'left' }, { body: right, targetPosition: right.position, name: 'right' }] } function customizeMatterEngine() { // Add optional 'ignoreGravity' property to bodies Matter.Engine._bodiesApplyGravity = function (bodies, gravity) { var gravityScale = typeof gravity.scale !== 'undefined' ? gravity.scale : 0.001; if ((gravity.x === 0 && gravity.y === 0) || gravityScale === 0) { return; } for (var i = 0; i < bodies.length; i++) { var body = bodies[i]; if (body.isStatic || body.isSleeping || body.ignoreGravity) continue; // apply gravity body.force.y += body.mass * gravity.y * gravityScale; body.force.x += body.mass * gravity.x * gravityScale; } }; } function setupMatterEngine(gravity = { x: 0, y: 0 }) { customizeMatterEngine() const engine = Matter.Engine.create({ positionIterations: 14, velocityIterations: 14 }) // engine.enableSleeping = true engine.gravity = gravity return engine } function createBenderPhysics(gravity = { x: 0, y: 0 }) { const wallThickness = 600 const pageData = preprocessPage(document.body) const engine = setupMatterEngine(gravity) const boundaryWalls = createBoundaryWalls(wallThickness) Matter.Composite.add(engine.world, boundaryWalls.map(w => w.body)) window.onscroll = function () { boundaryWalls.forEach(w => { switch (w.name) { case 'top': w.targetPosition = { x: window.scrollX + window.innerWidth / 2, y: window.scrollY - wallThickness / 2 } break case 'bottom': w.targetPosition = { x: window.scrollX + window.innerWidth / 2, y: window.scrollY + window.innerHeight + wallThickness / 2 - 10 } break case 'left': w.targetPosition = { x: window.scrollX - wallThickness / 2, y: window.scrollY + window.innerHeight / 2 } break case 'right': w.targetPosition = { x: window.scrollX + window.innerWidth + wallThickness / 2 - 20, y: window.scrollY + window.innerHeight / 2 } break } }) } let renderThisFrame = true function tick(deltaTime = 16.6667) { Matter.Engine.update(engine, deltaTime) boundaryWalls.forEach(wall => { const { body, targetPosition } = wall const deltaX = targetPosition.x - body.position.x const deltaY = targetPosition.y - body.position.y Matter.Body.setStatic(body, false) Matter.Body.translate(body, { x: deltaX / 10, y: deltaY / 10 }) Matter.Body.setStatic(body, true) }) if (renderThisFrame) { render() } renderThisFrame = !renderThisFrame } function start() { if (!window.benderPhysics.tickInterval) { window.benderPhysics.interval = setInterval(tick, 16.66) } } function stop() { if (window.benderPhysics.tickInterval) { clearInterval(window.benderPhysics.interval) } } function reset() { alert("TODO: implement reset") } function addElements(elements, isStatic) { let physicsDiv = document.querySelector('#bender-physics') if (!physicsDiv) { physicsDiv = document.createElement('div') physicsDiv.id = 'bender-physics' physicsDiv.style.position = 'absolute' physicsDiv.style.top = '0' physicsDiv.style.left = '0' document.body.appendChild(physicsDiv) } let newElements = elements.map(element => copyElementForPhysics(element)) console.log("newElements", newElements) const existingElements = newElements.filter(e => e.existingElement) console.log("existingElements", existingElements) newElements = newElements.filter(e => !e.existingElement) if (newElements.length === 1) { const newElement = newElements[0] physicsDiv.append(newElement.physicsElement) } else { const fragment = document.createDocumentFragment(); newElements.forEach(e => { fragment.appendChild(e.physicsElement) }) physicsDiv.appendChild(fragment) } newElements.forEach(e => { const newElement = e.physicsElement const bounds = newElement.getBoundingClientRect() const bodyBounds = document.body.getBoundingClientRect() const x = window.scrollX + bounds.x + bounds.width / 2 const y = window.scrollY + bounds.y + bounds.height / 2 const originalElement = e.originalElement const box = Matter.Bodies.rectangle( x, y, bounds.width, bounds.height, { isStatic }) Matter.Composite.add(engine.world, [box]) if (e.type === 'img' || e.type === 'word') { originalElement.style.visibility = 'hidden' } else if (e.type === 'background-image') { originalElement.style.backgroundImage = 'none' } benderPhysics.physicsElements.push({ physicsBody: box, domElement: newElement, originalElement, width: bounds.width, height: bounds.height }) }) existingElements.forEach(e => { Matter.Body.setStatic(e.existingElement.physicsBody, isStatic) }) } return { pageData, engine, tick, start, stop, reset, addElements, tickInterval: null, parameterInputs: [], boundaryWalls, physicsElements: [] } } function setTransform(e) { let currentTransform = e.domElement.style.transform let newTransform = `translate3d(${parseFloat((e.physicsBody.position.x - e.width / 2).toFixed(2))}px, ${parseFloat((e.physicsBody.position.y - e.height / 2).toFixed(2))}px, 0px) rotateZ(${e.physicsBody.angle}rad)` if (currentTransform !== newTransform) { e.domElement.style.transform = newTransform } } function render() { const n = window.benderPhysics.physicsElements.length const elements = window.benderPhysics.physicsElements const x = window.scrollX const y = window.scrollY const h = window.innerHeight+10 const w = window.innerWidth for (let i = 0; i < n; i++) { const e = elements[i] if (isBodyInViewport(e.physicsBody, x, y, w, h)) { setTransform(e) } } } function findOrCreateBenderPhysics() { if (window.benderPhysics) { return window.benderPhysics } else { window.benderPhysics = createBenderPhysics({ x: 0, y: 1 }) return window.benderPhysics } } window.benderPhysics = findOrCreateBenderPhysics() const words = benderPhysics.pageData['words'].filter(e => isInViewport(e)) benderPhysics.addElements(words, true) benderPhysics.physicsElements.forEach(e => { e.physicsBody.collisionFilter.group = -1 e.domElement.style.backgroundColor = backgroundColor='rgba(50,50,50,.3)' }) // http://brm.io/matter-js/docs/ // http://brm.io/matter-js/demo/#mixed // https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js // https://en.wikipedia.org/wiki/Rotation_matrix /* ideas change the collision filter group for the body the portal is on if the player touches the portal make the player not able to collide with the wall add in some invisible edges to the portal if the player's center touches the portal teleport to the other portal make portals fireable with ray casting (consider using point checks, not raycasting) https://github.com/liabru/matter-js/issues/181 */ const keysDown = [] function addCharacter() { const engine = benderPhysics.engine const Events = Matter.Events const Bodies = Matter.Bodies function rotateVector(vector, angle) { return { x: vector.x * Math.cos(angle) - vector.y * Math.sin(angle), y: vector.x * Math.sin(angle) + vector.y * Math.cos(angle) } } //add the player const playerRadius = 12 // circle.style.height = `${playerRadius*2}px` // circle.style.width = `${playerRadius*2}px` const circle = document.createElement('span') circle.id = 'player-original' circle.classList.add('bender-word') circle.style.position = 'absolute' circle.style.top = '100px' circle.style.fontSize = `${playerRadius * 2}px` circle.style.left = '100px' circle.style.lineHeight = `${playerRadius * 2}px` circle.innerText = '😺' document.body.appendChild(circle) benderPhysics.addElements([circle]) benderPhysics.physicsElements[benderPhysics.physicsElements.length - 1].domElement.style.backgroundColor = 'transparent' let player = benderPhysics.physicsElements[benderPhysics.physicsElements.length - 1].physicsBody Matter.Body.scale(player, .5, .8) console.log("player", player) player.friction = .7 /*{ density: 0.001, friction: 0.7, frictionStatic: 0, frictionAir: 0.01, restitution: 0.3 }*/ //looks for key presses and logs them document.body.addEventListener("keydown", function (e) { if (e.keyCode > 35 && e.keyCode < 40) { e.preventDefault() } keysDown[e.keyCode] = true; }); document.body.addEventListener("keyup", function (e) { e.preventDefault() keysDown[e.keyCode] = false; }); benderPhysics.engine.gravity.y = .45 const runSpeed = .00075 const jumpForce = .0022 let canJump = true Events.on(engine, "beforeUpdate", function (event) { Matter.Body.setAngularVelocity(player, 0) Matter.Body.setAngle(player, 0) // console.log("keysDown", keysDown) //jump if (keysDown[38] && player.ground && canJump) { Matter.Body.setVelocity(player, { x: player.velocity.x, y: -5 }) }; canJump = false //spin left and right const limit = 2.5; if (keysDown[39] && player.velocity.x < limit) { Matter.Body.applyForce(player, player.position, { x: runSpeed, y: 0 }) } else { if (keysDown[37] && player.velocity.x > -limit) { Matter.Body.applyForce(player, player.position, { x: -runSpeed, y: 0 }) } }; }); const senssorSize = Math.abs(player.bounds.max.x - player.bounds.min.x) * .99 var playerSensor = Bodies.rectangle(0, 0, senssorSize, 5, { isSensor: true //isStatic: true, }) playerSensor.collisionFilter.group = -2 player.collisionFilter.group = -2 Matter.Composite.add(engine.world, [player, playerSensor]) // Matter.Body.setInertia(player, Infinity); function playerGroundCheck(event, ground) { //runs on collisions events var pairs = event.pairs for (var i = 0, j = pairs.length; i != j; ++i) { var pair = pairs[i]; if (pair.bodyA === playerSensor && pair.bodyB !== player) { if (ground){ player.ground = pair.bodyB; } else { player.ground = false } } else if (pair.bodyB === playerSensor && pair.bodyA !== player) { if (ground){ player.ground = pair.bodyA; } else { player.ground = false } } } if (!player.ground) { player.friction = 0 } else { player.friction = 1 } } function checkForBonk(event) { var pairs = event.pairs for (var i = 0, j = pairs.length; i != j; ++i) { const pair = pairs[i] if (pair.bodyA === playerSensor || pair.bodyB === playerSensor) { if (pair.bodyA === player || pair.bodyB === player) { console.log("NOOOOOOOOOOOOOOOOOOOOO") } } let ground = null if (pair.bodyA === player) { ground = pair.bodyB } if (pair.bodyB === player) { ground = pair.bodyA } if (ground && ground.collisionFilter.group === -1 && ground !== player.ground) { Matter.Body.setStatic(ground, false) ground.collisionFilter.group = 0 benderPhysics.physicsElements.find(e => e.physicsBody === ground) .domElement.style.backgroundColor = backgroundColor='rgba(250,50,50,.3)' player.velocity.y = 0 } } } //at the start of a colision for player Events.on(engine, "collisionStart", function (event) { playerGroundCheck(event, true) if (player.velocity.y < 0) { checkForBonk(event) } }); //ongoing checks for collisions for player Events.on(engine, "collisionActive", function (event) { playerGroundCheck(event, true) }); //at the end of a colision for player set ground to false Events.on(engine, 'collisionEnd', function (event) { playerGroundCheck(event, false); canJump = true }) Events.on(engine, "afterUpdate", function (event) { //set sensor velocity to zero so it collides properly Matter.Body.setVelocity(playerSensor, { x: 0, y: 0 }) //move sensor to below the player Matter.Body.setPosition(playerSensor, { x: player.position.x, y: player.position.y + playerRadius }); console.log("player.ground", player.ground) if (!player.ground){ console.log("air friction") Matter.Body.setVelocity(player, { x: player.velocity.x*.8, y: player.velocity.y}) } }); } addCharacter() benderPhysics.start()