UNPKG

react-slime-simulation

Version:

A customizable React component for simulating slime mold behavior.

3 lines (2 loc) 13.5 kB
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):(e||self).reactSlimeSimulation=t(e.react)}(this,function(e){function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=/*#__PURE__*/t(e);function n(){return n=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)({}).hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},n.apply(null,arguments)}var i=["useRandomDefaults","svgShape"];function a(e,t,r){if(!e.s){if(r instanceof o){if(!r.s)return void(r.o=a.bind(null,e,t));1&t&&(t=r.s),r=r.v}if(r&&r.then)return void r.then(a.bind(null,e,t),a.bind(null,e,2));e.s=t,e.v=r;var n=e.o;n&&n(e)}}var o=/*#__PURE__*/function(){function e(){}return e.prototype.then=function(t,r){var n=new e,i=this.s;if(i){var o=1&i?t:r;if(o){try{a(n,1,o(this.v))}catch(e){a(n,2,e)}return n}return this}return this.o=function(e){try{var i=e.v;1&e.s?a(n,1,t?t(i):i):r?a(n,1,r(i)):a(n,2,i)}catch(e){a(n,2,e)}},n},e}();function s(e){return e instanceof o&&1&e.s}function u(e,t){return Math.random()*(t-e)+e}function l(e){for(var t=e.length-1;t>0;t--){var r=Math.floor(Math.random()*(t+1)),n=[e[r],e[t]];e[t]=n[0],e[r]=n[1]}}var c=/*#__PURE__*/function(){function e(e,t){this.settingsRef=e,this.simulationDimensionsRef=t,this.position={x:0,y:0},this.angle=Math.random()*Math.PI*2;var r=e.current.baseHue+u(-20,20);this.color="hsl("+r+", 80%, 60%)",this.escapeThreshold=e.current.escapeThreshold,this.isEscaping=!1,this.escapeTime=0}var t=e.prototype;return t.sense=function(e){var t=this.angle+e*(Math.PI/180),r=this.settingsRef.current.sensorOffset,n=this.simulationDimensionsRef.current.width,i=this.simulationDimensionsRef.current.height,a=Math.cos(t),o=Math.sin(t),s={x:this.position.x+a*r,y:this.position.y+o*r};if(s.x<0||s.x>=n||s.y<0||s.y>=i)return{sum:0,maxDensity:0};var u=0,l=0,c=Math.floor(s.x),h=Math.floor(s.y),f=this.settingsRef.current.trailMap;if(!f)return{sum:0,maxDensity:0};for(var d=-1;d<=1;d++){var v=h+d;if(v>=0&&v<i)for(var m=v*n,g=-1;g<=1;g++){var p=c+g;if(p>=0&&p<n){var M=f[m+p];u+=M,M>l&&(l=M)}}}return{sum:u,maxDensity:l}},t.update=function(){var e,t,r,n,i=this.settingsRef.current,a=this.simulationDimensionsRef.current.width,o=this.simulationDimensionsRef.current.height,s=60*i.deltaTime,l=i.agentSpeed,c=i.edgeThreshold,h=this.sense(0).maxDensity>this.escapeThreshold;if(h&&!this.isEscaping?(this.isEscaping=!0,this.escapeTime=0):!h&&this.isEscaping&&this.escapeTime>1&&(this.isEscaping=!1),this.isEscaping){this.escapeTime+=s;var f=this.sense(45),d=this.sense(-45);f.maxDensity>d.maxDensity?this.angle-=.2*s:this.angle+=.2*s;var v=1.3*l,m={x:Math.cos(this.angle),y:Math.sin(this.angle)};e={x:this.position.x+m.x*v,y:this.position.y+m.y*v}}else{var g=this.position.x<c,p=this.position.x>a-c,M=this.position.y<c,y=this.position.y>o-c;if((g||p||M||y)&&i.edgeAvoidance>0){var x=u(-Math.PI*i.edgeAvoidance,Math.PI*i.edgeAvoidance);g?this.angle=x:p?this.angle=Math.PI+x:M?this.angle=Math.PI/2+x:y&&(this.angle=-Math.PI/2+x)}else{var w=this.sense(0).sum,b=this.sense(45).sum,S=this.sense(-45).sum,R=(r=(r=1234.5678*(t={x:this.position.x+.001*performance.now(),y:this.position.y+.001*performance.now()}).x)*r*r*123456+(n=9012.3456*t.y))*(n=n*n*n*654321+r)%4294967295/4294967295;w>b&&w>S?this.angle+=.1*(R-.5)*s:w<b&&w<S?this.angle+=2*(R-.5)*.5*s:S>b?this.angle-=.5*R*s:b>S&&(this.angle+=.5*R*s)}var T={x:Math.cos(this.angle),y:Math.sin(this.angle)};e={x:this.position.x+T.x*l,y:this.position.y+T.y*l}}(e.x<0||e.x>=a||e.y<0||e.y>=o)&&((e.x<0||e.x>=a)&&(this.angle=Math.PI-this.angle+u(-.2,.2)),(e.y<0||e.y>=o)&&(this.angle=-this.angle+u(-.2,.2)),e.x=Math.max(0,Math.min(a-.01,e.x)),e.y=Math.max(0,Math.min(o-.01,e.y))),this.position=e;var P=Math.floor(this.position.x),I=Math.floor(this.position.y),C=i.trailMap;if(P>=0&&P<a&&I>=0&&I<o&&C){var E=I*a+P;C[E]=Math.min(1,C[E]+i.trailStrength)}},e}();return function(t){var h=t.useRandomDefaults,f=void 0===h||h,d=t.svgShape,v=void 0===d?'\n <svg id="spawnShape" width="200" height="200" viewBox="0 0 200 200">\n \x3c!-- Remplacez ceci par votre SVG --\x3e\n <path d="M100,20 L180,180 L20,180 Z" fill="white"/>\n </svg>\n':d,m=function(e,t){if(null==e)return{};var r={};for(var n in e)if({}.hasOwnProperty.call(e,n)){if(-1!==t.indexOf(n))continue;r[n]=e[n]}return r}(t,i),g=e.useRef(null),p=e.useRef({}),M=e.useRef([]),y=e.useRef({width:0,height:0}),x=e.useRef(null),w=e.useRef(null),b=e.useRef(null),S=e.useRef(0),R=e.useRef(!1),T=e.useRef(null),P=e.useCallback(function(e,t,r){try{return console.log("Rasterizing SVG string:",(null==e?void 0:e.substring(0,100))+"..."),Promise.resolve(new Promise(function(n){var i=(new DOMParser).parseFromString(e,"image/svg+xml"),a=i.querySelector("parsererror");if(a)return console.error("Error parsing SVG string:",a.textContent),void n([]);var o=i.documentElement;if(!o||"svg"!==o.nodeName)return console.error("Invalid SVG string provided - Could not find root <svg> element."),void n([]);var s=(new XMLSerializer).serializeToString(o),u="data:image/svg+xml;charset=utf-8,"+encodeURIComponent(s),l=new Image;l.onload=function(){var e=document.createElement("canvas");e.width=t,e.height=r;var i,a,o=e.getContext("2d"),s=l.naturalWidth/l.naturalHeight;t/r>s?i=(a=1.6*r)*s:a=(i=1.6*t)/s;var u=(t-i)/2,c=(r-a)/2;o.clearRect(0,0,t,r),o.drawImage(l,u,c,i,a);try{for(var h=o.getImageData(0,0,t,r).data,f=[],d=0;d<r;d++)for(var v=0;v<t;v++)h[4*(d*t+v)+3]>10&&f.push({x:v,y:d});console.log("Rasterized SVG: Found "+f.length+" valid pixels."),n(f)}catch(e){console.error("Error getting ImageData (possible CORS issue if SVG linked external resources, unlikely with data URL):",e),n([])}},l.onerror=function(e){console.error("Error loading SVG image for rasterization. Event:",e),console.error("SVG URL that failed:",u),n([])},l.src=u}))}catch(e){return Promise.reject(e)}},[]),I=e.useCallback(function(){if(w.current&&p.current.trailMap)for(var e=p.current,t=y.current.width,r=y.current.height,n=e.brushSize,i=e.brushStrength,a=Math.floor(w.current.x),o=Math.floor(w.current.y),s=e.trailMap,u=-n;u<=n;u++)for(var l=-n;l<=n;l++)if(l*l+u*u<=n*n){var c=a+l,h=o+u;if(c>=0&&c<t&&h>=0&&h<r){var f=h*t+c,d=Math.sqrt(l*l+u*u),v=Math.max(0,1-d/n);s[f]=Math.min(1,s[f]+i*v)}}},[]),C=e.useCallback(function(){var e=p.current,t=y.current.width,r=y.current.height,n=e.evaporationRate,i=e.trailMap,a=e.processedTrailMap;if(i&&a){I();for(var o=0;o<r;o++)for(var s=0;s<t;s++){var u=o*t+s,l=i[u];if(l<=.001)a[u]=0;else{for(var c=0,h=0,f=-1;f<=1;f++){var d=o+f;if(d>=0&&d<r)for(var v=d*t,m=-1;m<=1;m++){var g=s+m;g>=0&&g<t&&(c+=i[v+g],h++)}}a[u]=Math.max(0,.9*l+.1*(h>0?c/h:0)-n*e.deltaTime*60)}}p.current.trailMap=a,p.current.processedTrailMap=i}},[I]),E=e.useCallback(function(){var e=g.current;if(e){var t=e.getContext("2d");if(t){var r=p.current,n=y.current.width,i=y.current.height,a=r.trailMap;if(a){t.fillStyle="rgba(0, 0, 0, 1)",t.fillRect(0,0,n,i);for(var o=t.createImageData(n,i),s=o.data,u=0;u<i;u++)for(var l=0;l<n;l++){var c=u*n+l,h=a[c];if(h>.01){var f=Math.min(1,h),d=r.baseHue+r.hueRange*(f-.5)*2,v=50+r.lightnessRange*(f-.5)*2,m=Math.min(255,Math.floor(255*f)),M=v/100,x=1*(1-Math.abs(2*M-1)),w=x*(1-Math.abs(d/60%2-1)),b=M-x/2,S=0,R=0,T=0;0<=d&&d<60?(S=x,R=w,T=0):60<=d&&d<120?(S=w,R=x,T=0):120<=d&&d<180?(S=0,R=x,T=w):180<=d&&d<240?(S=0,R=w,T=x):240<=d&&d<300?(S=w,R=0,T=x):300<=d&&d<360&&(S=x,R=0,T=w),S=Math.round(255*(S+b)),R=Math.round(255*(R+b)),T=Math.round(255*(T+b));var P=4*c;s[P]=S,s[P+1]=R,s[P+2]=T,s[P+3]=m}}t.putImageData(o,0,0)}}}},[]),D=e.useCallback(function(){var e=g.current;if(e){var t=e.getContext("2d");if(t){var r=y.current.width,n=y.current.height;M.current.forEach(function(e){var i=Math.floor(e.position.x),a=Math.floor(e.position.y);i>=0&&i<r&&a>=0&&a<n&&(t.fillStyle=e.color,t.fillRect(i,a,1,1))})}}},[]),k=e.useCallback(function(e,t){try{var r=[],n=c;if(t&&0!==t.length){var i=[].concat(t);l(i);for(var a=0,o=0;o<e;o++){a>=i.length&&(l(i),a=0);var s=new n(p,y),h=i[a];s.position={x:h.x,y:h.y},s.angle=Math.random()*Math.PI*2,r.push(s),a++}}else{console.warn("No valid pixels from SVG rasterization or SVG invalid. Spawning agents randomly.");for(var f=y.current.width,d=y.current.height,v=0;v<e;v++){var m=new n(p,y);m.position={x:u(0,f),y:u(0,d)},m.angle=Math.random()*Math.PI*2,r.push(m)}}return M.current=r,Promise.resolve()}catch(e){return Promise.reject(e)}},[]),F=e.useCallback(function(e,t){try{var r=g.current,n=null==r?void 0:r.getContext("2d");if(!n||!p.current.initialAgents)return Promise.resolve();var i=p.current.initialAgents,u=y.current.width,l=y.current.height,c=0,h=function(e,t,r){for(var n;;){var i=e();if(s(i)&&(i=i.v),!i)return u;if(i.then){n=0;break}var u=r();if(u&&u.then){if(!s(u)){n=1;break}u=u.s}if(t){var l=t();if(l&&l.then&&!s(l)){n=2;break}}}var c=new o,h=a.bind(null,c,2);return(0===n?i.then(d):1===n?u.then(f):l.then(v)).then(void 0,h),c;function f(n){u=n;do{if(t&&(l=t())&&l.then&&!s(l))return void l.then(v).then(void 0,h);if(!(i=e())||s(i)&&!i.v)return void a(c,1,u);if(i.then)return void i.then(d).then(void 0,h);s(u=r())&&(u=u.v)}while(!u||!u.then);u.then(f).then(void 0,h)}function d(e){e?(u=r())&&u.then?u.then(f).then(void 0,h):f(u):a(c,1,u)}function v(){(i=e())?i.then?i.then(d).then(void 0,h):d(i):a(c,1,u)}}(function(){return c<e},function(){return c++},function(){return Promise.resolve(k(i,t)).then(function(){n.fillStyle="rgba(0, 0, 0, 1)",n.fillRect(0,0,u,l),D();var t=function(){if(c<e-1)return Promise.resolve(new Promise(function(e){return setTimeout(e,50)})).then(function(){})}();if(t&&t.then)return t.then(function(){})})});return Promise.resolve(h&&h.then?h.then(function(){}):void 0)}catch(e){return Promise.reject(e)}},[k,D]),z=e.useCallback(function(e){g.current&&R.current&&(p.current.deltaTime=S.current>0?Math.min(.1,(e-S.current)/1e3):1/60,S.current=e,C(),E(),M.current.forEach(function(e){return e.update()}),D(),x.current=requestAnimationFrame(z))},[C,E,D]),A=e.useCallback(function(e){if(g.current){clearTimeout(b.current);var t=g.current.getBoundingClientRect();w.current={x:g.current.width/t.width*(e.clientX-t.left),y:g.current.height/t.height*(e.clientY-t.top)},b.current=setTimeout(function(){w.current=null},500)}},[]),L=e.useCallback(function(){clearTimeout(b.current),w.current=null},[]),O=e.useCallback(function(e){void 0===e&&(e=!1);try{if(!g.current)return Promise.resolve();if(!e&&R.current)return console.log("Simulation already initialized."),Promise.resolve();console.log(e?"Re-initializing simulation due to resize...":"Initializing simulation..."),R.current=!1,cancelAnimationFrame(x.current),x.current=null;var t=g.current;if(!t.getContext("2d",{alpha:!1}))return console.error("Failed to get 2D context"),Promise.resolve();var r={initialAgents:Math.floor(501*Math.random())+600,sensorOffset:Math.floor(25*Math.random())+5,edgeAvoidance:parseFloat(Math.random().toFixed(1)),agentSpeed:parseFloat((1.2*Math.random()+.75).toFixed(1)),trailStrength:parseFloat((2.5*Math.random()+.5).toFixed(1)),evaporationRate:parseFloat((.04*Math.random()+.005).toFixed(3)),baseHue:Math.floor(360*Math.random()),hueRange:Math.floor(60*Math.random())+30,lightnessRange:Math.floor(30*Math.random())+20,escapeThreshold:.5+.5*Math.random(),brushSize:4,brushStrength:1.5,pixelScale:6,edgeThreshold:3,reshuffleCount:10,startDelay:500},i=f?r:n({},r,m);Object.keys(r).forEach(function(e){if("number"==typeof r[e]){var t=i[e];if("string"==typeof t){var n=parseFloat(t);isNaN(n)?(console.warn("Invalid numeric value for prop "+e+': "'+t+'". Using default: '+r[e]),i[e]=r[e]):i[e]=n}else"number"!=typeof t&&(i[e]=r[e])}}),p.current=i;var a=p.current.pixelScale,o=Math.max(10,Math.floor(window.innerWidth/a)),s=Math.max(10,Math.floor(window.innerHeight/a));return y.current={width:o,height:s},t.width=o,t.height=s,t.style.width=window.innerWidth+"px",t.style.height=window.innerHeight+"px",t.style.display="block",t.style.background="#111",t.style.imageRendering="pixelated",t.style.cursor="crosshair",p.current.trailMap=new Float32Array(o*s),p.current.processedTrailMap=new Float32Array(o*s),Promise.resolve(P(v,o,s)).then(function(t){return Promise.resolve(F(p.current.reshuffleCount,t)).then(function(){R.current=!0,console.log("Initialization complete. Starting animation soon..."),p.current.startTimeoutId&&clearTimeout(p.current.startTimeoutId),p.current.startTimeoutId=setTimeout(function(){R.current&&!x.current&&(console.log("Starting animation loop."),S.current=performance.now(),x.current=requestAnimationFrame(z))},e?100:p.current.startDelay)})})}catch(e){return Promise.reject(e)}},[f,JSON.stringify(m),v,P,F,z]),G=e.useCallback(function(){clearTimeout(T.current),T.current=setTimeout(function(){O(!0)},250)},[O]);return e.useEffect(function(){console.log("SlimeSimulation component mounted or dependencies changed."),O(!1),window.addEventListener("resize",G);var e=g.current;return e&&(e.addEventListener("mousemove",A),e.addEventListener("mouseleave",L)),function(){console.log("Cleaning up SlimeSimulation..."),R.current=!1,cancelAnimationFrame(x.current),x.current=null,p.current.startTimeoutId&&clearTimeout(p.current.startTimeoutId),clearTimeout(T.current),clearTimeout(b.current),window.removeEventListener("resize",G),e&&(e.removeEventListener("mousemove",A),e.removeEventListener("mouseleave",L))}},[O,G,A,L]),/*#__PURE__*/r.default.createElement("canvas",{ref:g})}}); //# sourceMappingURL=index.umd.js.map