@litecanvas/utils 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/all.js CHANGED
@@ -40,6 +40,7 @@
40
40
  Grid: () => Grid,
41
41
  LEFT: () => LEFT,
42
42
  LINEAR: () => LINEAR,
43
+ Noise: () => Noise,
43
44
  ONE: () => ONE,
44
45
  RIGHT: () => RIGHT,
45
46
  TypedGrid: () => TypedGrid,
@@ -1127,6 +1128,136 @@
1127
1128
  }
1128
1129
  };
1129
1130
 
1131
+ // src/noise/index.js
1132
+ var PERLIN_YWRAPB = 4;
1133
+ var PERLIN_YWRAP = 1 << PERLIN_YWRAPB;
1134
+ var PERLIN_ZWRAPB = 8;
1135
+ var PERLIN_ZWRAP = 1 << PERLIN_ZWRAPB;
1136
+ var PERLIN_SIZE = 4095;
1137
+ var scaled_cosine = (i) => 0.5 * (1 - Math.cos(i * Math.PI));
1138
+ var Noise = class {
1139
+ /**
1140
+ * Array to store Perlin noise values.
1141
+ * @type {number[]}
1142
+ * @private
1143
+ */
1144
+ _p = [];
1145
+ /**
1146
+ * Number of octaves for the Perlin noise. Higher values create more detail.
1147
+ * @type {number}
1148
+ * @private
1149
+ */
1150
+ _po = 4;
1151
+ /**
1152
+ * Amplitude falloff factor for Perlin noise. Determines the reduction of amplitude per octave.
1153
+ * @type {number}
1154
+ * @private
1155
+ */
1156
+ _pf = 0.5;
1157
+ /**
1158
+ * @type {LitecanvasInstance}
1159
+ * @private
1160
+ */
1161
+ _e = null;
1162
+ /**
1163
+ * @param {LitecanvasInstance} engine
1164
+ */
1165
+ constructor(engine) {
1166
+ this._e = engine || globalThis;
1167
+ this.noiseSeed();
1168
+ }
1169
+ /**
1170
+ * Generates Perlin noise for the given coordinates.
1171
+ * @param {number} x - X-coordinate.
1172
+ * @param {number} [y=0] - Y-coordinate (default is 0).
1173
+ * @param {number} [z=0] - Z-coordinate (default is 0).
1174
+ * @returns {number} A noise value in the range [0, 1).
1175
+ */
1176
+ noise(x, y = 0, z = 0) {
1177
+ if (x < 0) {
1178
+ x = -x;
1179
+ }
1180
+ if (y < 0) {
1181
+ y = -y;
1182
+ }
1183
+ if (z < 0) {
1184
+ z = -z;
1185
+ }
1186
+ let xi = Math.floor(x), yi = Math.floor(y), zi = Math.floor(z);
1187
+ let xf = x - xi;
1188
+ let yf = y - yi;
1189
+ let zf = z - zi;
1190
+ let rxf, ryf;
1191
+ let r = 0;
1192
+ let ampl = 0.5;
1193
+ let n1, n2, n3;
1194
+ for (let o = 0; o < this._po; o++) {
1195
+ let of = xi + (yi << PERLIN_YWRAPB) + (zi << PERLIN_ZWRAPB);
1196
+ rxf = scaled_cosine(xf);
1197
+ ryf = scaled_cosine(yf);
1198
+ n1 = this._p[of & PERLIN_SIZE];
1199
+ n1 += rxf * (this._p[of + 1 & PERLIN_SIZE] - n1);
1200
+ n2 = this._p[of + PERLIN_YWRAP & PERLIN_SIZE];
1201
+ n2 += rxf * (this._p[of + PERLIN_YWRAP + 1 & PERLIN_SIZE] - n2);
1202
+ n1 += ryf * (n2 - n1);
1203
+ of += PERLIN_ZWRAP;
1204
+ n2 = this._p[of & PERLIN_SIZE];
1205
+ n2 += rxf * (this._p[of + 1 & PERLIN_SIZE] - n2);
1206
+ n3 = this._p[of + PERLIN_YWRAP & PERLIN_SIZE];
1207
+ n3 += rxf * (this._p[of + PERLIN_YWRAP + 1 & PERLIN_SIZE] - n3);
1208
+ n2 += ryf * (n3 - n2);
1209
+ n1 += scaled_cosine(zf) * (n2 - n1);
1210
+ r += n1 * ampl;
1211
+ ampl *= this._pf;
1212
+ xi <<= 1;
1213
+ xf *= 2;
1214
+ yi <<= 1;
1215
+ yf *= 2;
1216
+ zi <<= 1;
1217
+ zf *= 2;
1218
+ if (xf >= 1) {
1219
+ xi++;
1220
+ xf--;
1221
+ }
1222
+ if (yf >= 1) {
1223
+ yi++;
1224
+ yf--;
1225
+ }
1226
+ if (zf >= 1) {
1227
+ zi++;
1228
+ zf--;
1229
+ }
1230
+ }
1231
+ return r;
1232
+ }
1233
+ /**
1234
+ * Adjusts the detail level of the noise by setting the number of octaves and amplitude falloff.
1235
+ * @param {number} lod - Level of detail (number of octaves).
1236
+ * @param {number} falloff - Amplitude falloff per octave.
1237
+ */
1238
+ noiseDetail(lod, falloff) {
1239
+ if (lod > 0) {
1240
+ this._po = lod;
1241
+ }
1242
+ if (falloff > 0) {
1243
+ this._pf = falloff;
1244
+ }
1245
+ }
1246
+ /**
1247
+ * Sets a seed for the Perlin noise generator, ensuring deterministic results.
1248
+ * @param {number} value - Seed value.
1249
+ */
1250
+ noiseSeed(value = null) {
1251
+ if (value != null) {
1252
+ this._e.seed(value);
1253
+ }
1254
+ const random = this._e.rand || Math.random;
1255
+ for (let i = 0; i < PERLIN_SIZE + 1; i++) {
1256
+ this._p[i] = random();
1257
+ }
1258
+ }
1259
+ };
1260
+
1130
1261
  // src/_web.js
1131
1262
  globalThis.utils = Object.assign(globalThis.utils || {}, src_exports);
1132
1263
  })();
package/dist/all.min.js CHANGED
@@ -1,3 +1,3 @@
1
- (()=>{var Q=Object.defineProperty;var v=(e,t)=>{for(var s in t)Q(e,s,{get:t[s],enumerable:!0})};globalThis.utils=globalThis.utils||{};globalThis.utils.global=()=>{for(let e in globalThis.utils)e!=="global"&&(globalThis[e]=globalThis.utils[e])};var k={};v(k,{ANCHOR_BOT_LEFT:()=>Ht,ANCHOR_BOT_RIGHT:()=>At,ANCHOR_CENTER:()=>It,ANCHOR_TOP_LEFT:()=>G,ANCHOR_TOP_RIGHT:()=>bt,Actor:()=>S,BACK_IN:()=>kt,BACK_IN_OUT:()=>Pt,BACK_OUT:()=>Lt,BOUNCE_IN:()=>J,BOUNCE_IN_OUT:()=>Bt,BOUNCE_OUT:()=>D,Camera:()=>f,DOWN:()=>Et,EASE_IN:()=>St,EASE_IN_OUT:()=>Dt,EASE_OUT:()=>Ct,ELASTIC_IN:()=>Xt,ELASTIC_IN_OUT:()=>Yt,ELASTIC_OUT:()=>Rt,Grid:()=>g,LEFT:()=>Mt,LINEAR:()=>Z,ONE:()=>mt,RIGHT:()=>wt,TypedGrid:()=>M,UP:()=>Tt,Vector:()=>p,ZERO:()=>F,advance:()=>q,diff:()=>V,fract:()=>$,intersection:()=>x,mod:()=>K,range:()=>z,resolve:()=>P,tween:()=>Ot,vec:()=>n,vecAbs:()=>ft,vecAdd:()=>H,vecAngle:()=>ht,vecAngleBetween:()=>at,vecCeil:()=>pt,vecClamp:()=>xt,vecCross:()=>ct,vecDist:()=>ot,vecDist2:()=>nt,vecDiv:()=>y,vecDot:()=>W,vecEq:()=>b,vecFloor:()=>_t,vecIsZero:()=>yt,vecLerp:()=>lt,vecLimit:()=>rt,vecMag:()=>U,vecMag2:()=>N,vecMove:()=>gt,vecMult:()=>_,vecNorm:()=>O,vecRand:()=>ut,vecReflect:()=>st,vecRotate:()=>et,vecRound:()=>dt,vecSet:()=>B,vecSetMag:()=>it,vecSub:()=>A,wave:()=>j});var x=(e,t,s,i,r,o,h,a)=>{let c=Math.max(e,r),L=Math.min(e+s,r+h)-c,d=Math.max(t,o),T=Math.min(t+i,o+a)-d;return[c,d,L,T]};var P=(e,t,s,i,r,o,h,a)=>{let[c,L,d,T]=x(e,t,s,i,r,o,h,a),u="",w=e,E=t;return d<T?e<r?(u="right",w=r-s):(u="left",w=r+h):t<o?(u="bottom",E=o-i):(u="top",E=o+a),{direction:u,x:w,y:E}};var f=class{_engine=null;x=0;y=0;ox=0;oy=0;width=0;height=0;rotation=0;scale=1;_shake={x:0,y:0,removeListener:null};constructor(t=null,s=0,i=0,r=null,o=null){this._engine=t||globalThis,this.ox=s,this.oy=i,this.resize(r||this._engine.WIDTH-s,o||this._engine.HEIGHT-i),this.x=this.width/2,this.y=this.height/2}resize(t,s){this.width=t,this.height=s,this._engine.emit("camera-resized",this)}start(t=!1){if(this._engine.push(),t){let r=path();r.rect(this.ox,this.oy,this.width,this.height),this._engine.clip(r)}let s=this.ox+this.width/2,i=this.oy+this.height/2;this._engine.translate(s,i),this._engine.scale(this.scale),this._engine.rotate(this.rotation),this._engine.translate(-this.x+this._shake.x,-this.y+this._shake.y)}end(){this._engine.pop()}lookAt(t,s){this.x=t,this.y=s}move(t,s){this.x+=t,this.y+=s}zoom(t){this.scale*=t}zoomTo(t){this.scale=t}rotate(t){this.rotation+=t}rotateTo(t){this.rotation=t}getWorldPoint(t,s,i={}){let r=Math.cos(-this.rotation),o=Math.sin(-this.rotation);return t=(t-this.width/2-this.ox)/this.scale,s=(s-this.height/2-this.oy)/this.scale,i.x=r*t-o*s+this.x,i.y=o*t+r*s+this.y,i}getCameraPoint(t,s,i={}){let r=Math.cos(-this.rotation),o=Math.sin(-this.rotation);return t=t-this.x,s=s-this.y,t=r*t-o*s,s=o*t+r*s,i.x=t*this.scale+this.width/2+this.ox,i.y=s*this.scale+this.height/2+this.oy,i}getBounds(){return[this.ox,this.oy,this.width,this.height]}viewing(t,s,i,r){let o=this.width/2-this.x,h=this.height/2-this.y,a=this.width/this.scale,c=this.height/this.scale;return this._engine.colrect(t,s,i,r,o,h,a,c)}shake(t=1,s=.3){this.shaking||(this._shake.removeListener=this._engine.listen("update",i=>{this._shake.x=this._engine.randi(-t,t),this._shake.y=this._engine.randi(-t,t),s-=i,s<=0&&this.unshake()}))}unshake(){this.shaking&&(this._shake.removeListener(),this._shake.removeListener=null,this._shake.x=this._shake.y=0)}get shaking(){return this._shake.removeListener!==null}};var g=class e{_w;_h;_c;constructor(t,s,i=[]){this._w=Math.max(1,~~t),this._h=Math.max(1,~~s),this._c=i}[Symbol.iterator](){let t=0;return{next:()=>({value:[this.indexToPointX(t),this.indexToPointY(t),this._c[t++]],done:t>this._c.length})}}clone(){return new e(this._w,this._h,this._c)}clear(){this.forEach((t,s)=>this.set(t,s,void 0))}get width(){return this._w}get height(){return this._h}set(t,s,i){this._c[this.pointToIndex(t,s)]=i}get(t,s){return this._c[this.pointToIndex(t,s)]}has(t,s){return this.get(t,s)!=null}check(t,s){return t>=0&&t<this._w&&s>=0&&s<this._h}get length(){return this._w*this._h}pointToIndex(t,s){return this.clampX(~~t)+this.clampY(~~s)*this._w}indexToPointX(t){return t%this._w}indexToPointY(t){return Math.floor(t/this._w)}forEach(t,s=!1){let i=s?this.length-1:0,r=s?-1:this.length,o=s?-1:1;for(;i!==r;){let h=this.indexToPointX(i),a=this.indexToPointY(i),c=this._c[i];if(t(h,a,c,this)===!1)break;i+=o}}fill(t){this.forEach((s,i)=>{this.set(s,i,t)})}clampX(t){return X(t,0,this._w-1)}clampY(t){return X(t,0,this._h-1)}toArray(){return this._c.slice()}toString(t=" ",s=!0){if(!s)return this._c.join(t);let i=[];return this.forEach((r,o,h)=>{i[o]=i[o]||"",i[o]+=h+t}),i.join(`
2
- `)}},M=class e extends g{constructor(t,s,i=Uint8Array){super(t,s,null),this._c=new i(this._w*this._h)}has(t,s){return this.get(t,s)!==0}clone(){let t=new e(this._w,this._h,this._c.constructor);return this.forEach((s,i,r)=>{t.set(s,i,r)}),t}};function X(e,t,s){return e<t?t:e>s?s:e}var I=Math.sqrt,R=Math.cos,Y=Math.sin,tt=2*Math.PI,p=class{x;y;constructor(t=0,s=t){this.x=t,this.y=s}toString(){return`Vector (${this.x}, ${this.y})`}},l=e=>e instanceof p,n=(e=0,t=e)=>(l(e)&&(t=e.y,e=e.x),new p(e,t)),b=(e,t,s=t)=>l(t)?b(e,t.x,t.y):e.x===t&&e.y===s,B=(e,t,s=t)=>(l(t)?B(e,t.x,t.y):(e.x=t,e.y=s),e),H=(e,t,s=t)=>l(t)?H(e,t.x,t.y):(e.x+=t,e.y+=s,e),A=(e,t,s=t)=>l(t)?A(e,t.x,t.y):(e.x-=t,e.y-=s,e),_=(e,t,s=t)=>l(t)?_(e,t.x,t.y):(e.x*=t,e.y*=s,e),y=(e,t,s=t)=>l(t)?y(e,t.x,t.y):(e.x/=t||1,e.y/=s||1,e),et=(e,t)=>{let s=R(t),i=Y(t);return e.x=s*e.x-i*e.y,e.y=i*e.x+s*e.y,e},st=(e,t)=>{let s=O(n(t));return A(e,_(s,2*W(e,s)))},it=(e,t)=>(O(e),_(e,t),e),U=e=>I(e.x*e.x+e.y*e.y),N=e=>e.x*e.x+e.y*e.y,O=e=>{let t=U(e);return t>0&&y(e,t),e},rt=(e,t=1)=>{let s=N(e);return s>t*t&&(y(e,I(s)),_(e,t)),e},ot=(e,t)=>{let s=e.x-t.x,i=e.y-t.y;return I(s*s+i*i)},nt=(e,t)=>{let s=e.x-t.x,i=e.y-t.y;return s*s+i*i},ht=e=>Math.atan2(e.y,e.x),at=(e,t)=>Math.atan2(t.y-e.y,t.x-e.x),W=(e,t)=>e.x*t.x+e.y*t.y,ct=(e,t)=>e.x*t.y-e.y*t.x,lt=(e,t,s)=>(e.x+=(t.x-e.x)*s||0,e.y+=(t.y-e.y)*s||0,e),ut=(e=1,t=e,s=globalThis.rand||Math.random)=>{let i=s()*tt,r=s()*(t-e)+e;return n(R(i)*r,Y(i)*r)},ft=e=>(e.x=Math.abs(e.x),e.y=Math.abs(e.y),e),pt=e=>(e.x=Math.ceil(e.x),e.y=Math.ceil(e.y),e),_t=e=>(e.x=Math.floor(e.x),e.y=Math.floor(e.y),e),dt=e=>(e.x=Math.round(e.x),e.y=Math.round(e.y),e),xt=(e,t,s)=>(e.x<t.x&&(e.x=t.x),e.x>s.x&&(e.x=s.x),e.y<t.y&&(e.y=t.y),e.y>s.y&&(e.y=s.y),e),gt=(e,t,s=1)=>H(e,t.x*s,t.y*s),yt=e=>b(e,F),F=n(0,0),mt=n(1,1),Tt=n(0,-1),wt=n(1,0),Et=n(0,1),Mt=n(-1,0);var It=n(.5,.5),G=n(0,0),bt=n(1,0),Ht=n(0,1),At=n(1,1),S=class{sprite;pos;_o;_s;flipX=!1;flipY=!1;angle=0;opacity=1;hidden=!1;constructor(t,s,i=G){this.sprite=t,this.pos=s||n(0),this._o=n(i),this._s=n(1,1)}set x(t){this.pos.x=t}get x(){return this.pos.x}set y(t){this.pos.y=t}get y(){return this.pos.y}set anchor(t){this._o.x=t.x,this._o.y=t.y}get anchor(){return this._o}get width(){return this.sprite.width*this._s.x}get height(){return this.sprite.height*this._s.y}get scale(){return this._s}scaleTo(t,s=t){this._s.x=t,this._s.y=s}scaleBy(t,s=t){this._s.x*=t,this._s.y*=s}getBounds(t=!0){let s=this.sprite.width*(t?this._s.x:1),i=this.sprite.height*(t?this._s.y:1),r=this.pos.x-s*this.anchor.x,o=this.pos.y-i*this.anchor.y;return[r,o,s,i]}draw(t=globalThis,s=!0){this.hidden||this.opacity<=0||(s&&t.push(),this.transform(t),this.drawImage(t),s&&t.pop())}transform(t){t.translate(this.pos.x,this.pos.y),t.rotate(t.deg2rad(this.angle)),t.scale((this.flipX?-1:1)*this._s.x,(this.flipY?-1:1)*this._s.y)}drawImage(t,s=!0){let i=this.anchor,r=-this.sprite.width*(this.flipX?1-i.x:i.x),o=-this.sprite.height*(this.flipY?1-i.y:i.y);s&&t.alpha(this.opacity),t.image(r,o,this.sprite)}};var V=(e,t)=>Math.abs(t-e)||0;var j=(e,t,s,i=Math.sin)=>e+(i(s)+1)/2*(t-e);var $=e=>e%1||0;var z=e=>Array.from(Array(e).keys());var q=advance=(e,t,s,i=1)=>{s&&(t.x+=s.x*i,t.y+=s.y*i),e.x+=t.x*i,e.y+=t.y*i};var K=(e,t)=>(t+e%t)%t;var m=Math.PI/2,Ot=(e,t,s,i=1,r=Z)=>new C(e,t,s,i,r),Z=e=>e,St=e=>e*e,Ct=e=>-e*(e-2),Dt=e=>e<.5?2*e*e:-2*e*e+4*e-1,kt=e=>e*e*e-e*Math.sin(e*Math.PI),Lt=e=>{let t=1-e;return 1-(t*t*t-t*Math.sin(t*Math.PI))},Pt=e=>{if(e<.5){let s=2*e;return .5*(s*s*s-s*Math.sin(s*Math.PI))}let t=1-(2*e-1);return .5*(1-(t*t*t-t*Math.sin(e*Math.PI)))+.5},Xt=e=>Math.sin(13*m*e)*Math.pow(2,10*(e-1)),Rt=e=>Math.sin(-13*m*(e+1))*Math.pow(2,-10*e)+1,Yt=e=>{if(e<.5){let i=Math.sin(13*m*(2*e)),r=Math.pow(2,10*(2*e-1));return .5*i*r}let t=Math.sin(-13*m*(2*e-1+1)),s=Math.pow(2,-10*(2*e-1));return .5*(t*s+2)},J=e=>1-D(1-e),D=e=>e<4/11?121*e*e/16:e<8/11?363/40*e*e-99/10*e+17/5:e<9/10?4356/361*e*e-35442/1805*e+16061/1805:54/5*e*e-513/25*e+268/25,Bt=e=>e<.5?.5*J(e*2):.5*D(e*2-1)+.5,C=class{running=!1;_o;_p;_x;_d;_w;_e;_rel;_cb=[];_t=0;_u=0;_ch=this;_cu=this;_lc;constructor(t,s,i,r,o){this._o=t,this._p=s,this._x=i,this._d=r,this._e=o,this._w=0}start(t){if(this.running)return this;this._cu.stop(!1),this._ch=this._cu=this,this.running=!0;let s=this._o[this._p]||0,i=this._rel?s+this._x:this._x;return this._lc=this._lc||t||globalThis,this._u=this._lc.listen("update",r=>{if(this._t<=this._w){this._t+=r;return}let o=this._t-this._w;this._o[this._p]=this._lc.lerp(s,i,this._e(o/this._d)),this._t+=r,o>=this._d&&(this._o[this._p]=i,this.stop())}),this}stop(t=!0){if(!this._u)return this;if(this.running=!1,this._u(),this._t=0,t)for(let s of this._cb)s(this._o);return this}restart(t=null,s=!1){return this.stop(s).restart(t)}onEnd(t){return this._cb.push(t),this}chain(t){return this._ch.onEnd(()=>{this._cu=t.start(this._lc)}),this._ch=t,this}reset(){return this._cb.length=0,this.stop()}relative(t=!0){return this._rel=t,this}delay(t){return this._w=t,this}get current(){return this._cu}get progress(){return this.running&&this._t>this._w?(this._t-this._w)/this._d:0}};globalThis.utils=Object.assign(globalThis.utils||{},k);})();
1
+ (()=>{var at=Object.defineProperty;var ct=(e,t)=>{for(var s in t)at(e,s,{get:t[s],enumerable:!0})};globalThis.utils=globalThis.utils||{};globalThis.utils.global=()=>{for(let e in globalThis.utils)e!=="global"&&(globalThis[e]=globalThis.utils[e])};var B={};ct(B,{ANCHOR_BOT_LEFT:()=>Xt,ANCHOR_BOT_RIGHT:()=>Yt,ANCHOR_CENTER:()=>Lt,ANCHOR_TOP_LEFT:()=>J,ANCHOR_TOP_RIGHT:()=>Rt,Actor:()=>R,BACK_IN:()=>Ft,BACK_IN_OUT:()=>Vt,BACK_OUT:()=>Gt,BOUNCE_IN:()=>ot,BOUNCE_IN_OUT:()=>zt,BOUNCE_OUT:()=>Y,Camera:()=>T,DOWN:()=>Ct,EASE_IN:()=>Wt,EASE_IN_OUT:()=>Ut,EASE_OUT:()=>Bt,ELASTIC_IN:()=>jt,ELASTIC_IN_OUT:()=>Zt,ELASTIC_OUT:()=>$t,Grid:()=>b,LEFT:()=>kt,LINEAR:()=>rt,Noise:()=>W,ONE:()=>St,RIGHT:()=>Pt,TypedGrid:()=>S,UP:()=>Dt,Vector:()=>w,ZERO:()=>K,advance:()=>st,diff:()=>Q,fract:()=>tt,intersection:()=>I,mod:()=>it,range:()=>et,resolve:()=>F,tween:()=>Nt,vec:()=>n,vecAbs:()=>Et,vecAdd:()=>C,vecAngle:()=>gt,vecAngleBetween:()=>yt,vecCeil:()=>Mt,vecClamp:()=>Ht,vecCross:()=>mt,vecDist:()=>dt,vecDist2:()=>xt,vecDiv:()=>H,vecDot:()=>q,vecEq:()=>P,vecFloor:()=>It,vecIsZero:()=>Ot,vecLerp:()=>Tt,vecLimit:()=>_t,vecMag:()=>Z,vecMag2:()=>z,vecMove:()=>At,vecMult:()=>E,vecNorm:()=>L,vecRand:()=>wt,vecReflect:()=>ft,vecRotate:()=>ut,vecRound:()=>bt,vecSet:()=>$,vecSetMag:()=>pt,vecSub:()=>k,wave:()=>v});var I=(e,t,s,i,r,o,h,a)=>{let c=Math.max(e,r),x=Math.min(e+s,r+h)-c,u=Math.max(t,o),g=Math.min(t+i,o+a)-u;return[c,u,x,g]};var F=(e,t,s,i,r,o,h,a)=>{let[c,x,u,g]=I(e,t,s,i,r,o,h,a),d="",m=e,l=t;return u<g?e<r?(d="right",m=r-s):(d="left",m=r+h):t<o?(d="bottom",l=o-i):(d="top",l=o+a),{direction:d,x:m,y:l}};var T=class{_engine=null;x=0;y=0;ox=0;oy=0;width=0;height=0;rotation=0;scale=1;_shake={x:0,y:0,removeListener:null};constructor(t=null,s=0,i=0,r=null,o=null){this._engine=t||globalThis,this.ox=s,this.oy=i,this.resize(r||this._engine.WIDTH-s,o||this._engine.HEIGHT-i),this.x=this.width/2,this.y=this.height/2}resize(t,s){this.width=t,this.height=s,this._engine.emit("camera-resized",this)}start(t=!1){if(this._engine.push(),t){let r=path();r.rect(this.ox,this.oy,this.width,this.height),this._engine.clip(r)}let s=this.ox+this.width/2,i=this.oy+this.height/2;this._engine.translate(s,i),this._engine.scale(this.scale),this._engine.rotate(this.rotation),this._engine.translate(-this.x+this._shake.x,-this.y+this._shake.y)}end(){this._engine.pop()}lookAt(t,s){this.x=t,this.y=s}move(t,s){this.x+=t,this.y+=s}zoom(t){this.scale*=t}zoomTo(t){this.scale=t}rotate(t){this.rotation+=t}rotateTo(t){this.rotation=t}getWorldPoint(t,s,i={}){let r=Math.cos(-this.rotation),o=Math.sin(-this.rotation);return t=(t-this.width/2-this.ox)/this.scale,s=(s-this.height/2-this.oy)/this.scale,i.x=r*t-o*s+this.x,i.y=o*t+r*s+this.y,i}getCameraPoint(t,s,i={}){let r=Math.cos(-this.rotation),o=Math.sin(-this.rotation);return t=t-this.x,s=s-this.y,t=r*t-o*s,s=o*t+r*s,i.x=t*this.scale+this.width/2+this.ox,i.y=s*this.scale+this.height/2+this.oy,i}getBounds(){return[this.ox,this.oy,this.width,this.height]}viewing(t,s,i,r){let o=this.width/2-this.x,h=this.height/2-this.y,a=this.width/this.scale,c=this.height/this.scale;return this._engine.colrect(t,s,i,r,o,h,a,c)}shake(t=1,s=.3){this.shaking||(this._shake.removeListener=this._engine.listen("update",i=>{this._shake.x=this._engine.randi(-t,t),this._shake.y=this._engine.randi(-t,t),s-=i,s<=0&&this.unshake()}))}unshake(){this.shaking&&(this._shake.removeListener(),this._shake.removeListener=null,this._shake.x=this._shake.y=0)}get shaking(){return this._shake.removeListener!==null}};var b=class e{_w;_h;_c;constructor(t,s,i=[]){this._w=Math.max(1,~~t),this._h=Math.max(1,~~s),this._c=i}[Symbol.iterator](){let t=0;return{next:()=>({value:[this.indexToPointX(t),this.indexToPointY(t),this._c[t++]],done:t>this._c.length})}}clone(){return new e(this._w,this._h,this._c)}clear(){this.forEach((t,s)=>this.set(t,s,void 0))}get width(){return this._w}get height(){return this._h}set(t,s,i){this._c[this.pointToIndex(t,s)]=i}get(t,s){return this._c[this.pointToIndex(t,s)]}has(t,s){return this.get(t,s)!=null}check(t,s){return t>=0&&t<this._w&&s>=0&&s<this._h}get length(){return this._w*this._h}pointToIndex(t,s){return this.clampX(~~t)+this.clampY(~~s)*this._w}indexToPointX(t){return t%this._w}indexToPointY(t){return Math.floor(t/this._w)}forEach(t,s=!1){let i=s?this.length-1:0,r=s?-1:this.length,o=s?-1:1;for(;i!==r;){let h=this.indexToPointX(i),a=this.indexToPointY(i),c=this._c[i];if(t(h,a,c,this)===!1)break;i+=o}}fill(t){this.forEach((s,i)=>{this.set(s,i,t)})}clampX(t){return G(t,0,this._w-1)}clampY(t){return G(t,0,this._h-1)}toArray(){return this._c.slice()}toString(t=" ",s=!0){if(!s)return this._c.join(t);let i=[];return this.forEach((r,o,h)=>{i[o]=i[o]||"",i[o]+=h+t}),i.join(`
2
+ `)}},S=class e extends b{constructor(t,s,i=Uint8Array){super(t,s,null),this._c=new i(this._w*this._h)}has(t,s){return this.get(t,s)!==0}clone(){let t=new e(this._w,this._h,this._c.constructor);return this.forEach((s,i,r)=>{t.set(s,i,r)}),t}};function G(e,t,s){return e<t?t:e>s?s:e}var D=Math.sqrt,V=Math.cos,j=Math.sin,lt=2*Math.PI,w=class{x;y;constructor(t=0,s=t){this.x=t,this.y=s}toString(){return`Vector (${this.x}, ${this.y})`}},y=e=>e instanceof w,n=(e=0,t=e)=>(y(e)&&(t=e.y,e=e.x),new w(e,t)),P=(e,t,s=t)=>y(t)?P(e,t.x,t.y):e.x===t&&e.y===s,$=(e,t,s=t)=>(y(t)?$(e,t.x,t.y):(e.x=t,e.y=s),e),C=(e,t,s=t)=>y(t)?C(e,t.x,t.y):(e.x+=t,e.y+=s,e),k=(e,t,s=t)=>y(t)?k(e,t.x,t.y):(e.x-=t,e.y-=s,e),E=(e,t,s=t)=>y(t)?E(e,t.x,t.y):(e.x*=t,e.y*=s,e),H=(e,t,s=t)=>y(t)?H(e,t.x,t.y):(e.x/=t||1,e.y/=s||1,e),ut=(e,t)=>{let s=V(t),i=j(t);return e.x=s*e.x-i*e.y,e.y=i*e.x+s*e.y,e},ft=(e,t)=>{let s=L(n(t));return k(e,E(s,2*q(e,s)))},pt=(e,t)=>(L(e),E(e,t),e),Z=e=>D(e.x*e.x+e.y*e.y),z=e=>e.x*e.x+e.y*e.y,L=e=>{let t=Z(e);return t>0&&H(e,t),e},_t=(e,t=1)=>{let s=z(e);return s>t*t&&(H(e,D(s)),E(e,t)),e},dt=(e,t)=>{let s=e.x-t.x,i=e.y-t.y;return D(s*s+i*i)},xt=(e,t)=>{let s=e.x-t.x,i=e.y-t.y;return s*s+i*i},gt=e=>Math.atan2(e.y,e.x),yt=(e,t)=>Math.atan2(t.y-e.y,t.x-e.x),q=(e,t)=>e.x*t.x+e.y*t.y,mt=(e,t)=>e.x*t.y-e.y*t.x,Tt=(e,t,s)=>(e.x+=(t.x-e.x)*s||0,e.y+=(t.y-e.y)*s||0,e),wt=(e=1,t=e,s=globalThis.rand||Math.random)=>{let i=s()*lt,r=s()*(t-e)+e;return n(V(i)*r,j(i)*r)},Et=e=>(e.x=Math.abs(e.x),e.y=Math.abs(e.y),e),Mt=e=>(e.x=Math.ceil(e.x),e.y=Math.ceil(e.y),e),It=e=>(e.x=Math.floor(e.x),e.y=Math.floor(e.y),e),bt=e=>(e.x=Math.round(e.x),e.y=Math.round(e.y),e),Ht=(e,t,s)=>(e.x<t.x&&(e.x=t.x),e.x>s.x&&(e.x=s.x),e.y<t.y&&(e.y=t.y),e.y>s.y&&(e.y=s.y),e),At=(e,t,s=1)=>C(e,t.x*s,t.y*s),Ot=e=>P(e,K),K=n(0,0),St=n(1,1),Dt=n(0,-1),Pt=n(1,0),Ct=n(0,1),kt=n(-1,0);var Lt=n(.5,.5),J=n(0,0),Rt=n(1,0),Xt=n(0,1),Yt=n(1,1),R=class{sprite;pos;_o;_s;flipX=!1;flipY=!1;angle=0;opacity=1;hidden=!1;constructor(t,s,i=J){this.sprite=t,this.pos=s||n(0),this._o=n(i),this._s=n(1,1)}set x(t){this.pos.x=t}get x(){return this.pos.x}set y(t){this.pos.y=t}get y(){return this.pos.y}set anchor(t){this._o.x=t.x,this._o.y=t.y}get anchor(){return this._o}get width(){return this.sprite.width*this._s.x}get height(){return this.sprite.height*this._s.y}get scale(){return this._s}scaleTo(t,s=t){this._s.x=t,this._s.y=s}scaleBy(t,s=t){this._s.x*=t,this._s.y*=s}getBounds(t=!0){let s=this.sprite.width*(t?this._s.x:1),i=this.sprite.height*(t?this._s.y:1),r=this.pos.x-s*this.anchor.x,o=this.pos.y-i*this.anchor.y;return[r,o,s,i]}draw(t=globalThis,s=!0){this.hidden||this.opacity<=0||(s&&t.push(),this.transform(t),this.drawImage(t),s&&t.pop())}transform(t){t.translate(this.pos.x,this.pos.y),t.rotate(t.deg2rad(this.angle)),t.scale((this.flipX?-1:1)*this._s.x,(this.flipY?-1:1)*this._s.y)}drawImage(t,s=!0){let i=this.anchor,r=-this.sprite.width*(this.flipX?1-i.x:i.x),o=-this.sprite.height*(this.flipY?1-i.y:i.y);s&&t.alpha(this.opacity),t.image(r,o,this.sprite)}};var Q=(e,t)=>Math.abs(t-e)||0;var v=(e,t,s,i=Math.sin)=>e+(i(s)+1)/2*(t-e);var tt=e=>e%1||0;var et=e=>Array.from(Array(e).keys());var st=advance=(e,t,s,i=1)=>{s&&(t.x+=s.x*i,t.y+=s.y*i),e.x+=t.x*i,e.y+=t.y*i};var it=(e,t)=>(t+e%t)%t;var A=Math.PI/2,Nt=(e,t,s,i=1,r=rt)=>new X(e,t,s,i,r),rt=e=>e,Wt=e=>e*e,Bt=e=>-e*(e-2),Ut=e=>e<.5?2*e*e:-2*e*e+4*e-1,Ft=e=>e*e*e-e*Math.sin(e*Math.PI),Gt=e=>{let t=1-e;return 1-(t*t*t-t*Math.sin(t*Math.PI))},Vt=e=>{if(e<.5){let s=2*e;return .5*(s*s*s-s*Math.sin(s*Math.PI))}let t=1-(2*e-1);return .5*(1-(t*t*t-t*Math.sin(e*Math.PI)))+.5},jt=e=>Math.sin(13*A*e)*Math.pow(2,10*(e-1)),$t=e=>Math.sin(-13*A*(e+1))*Math.pow(2,-10*e)+1,Zt=e=>{if(e<.5){let i=Math.sin(13*A*(2*e)),r=Math.pow(2,10*(2*e-1));return .5*i*r}let t=Math.sin(-13*A*(2*e-1+1)),s=Math.pow(2,-10*(2*e-1));return .5*(t*s+2)},ot=e=>1-Y(1-e),Y=e=>e<4/11?121*e*e/16:e<8/11?363/40*e*e-99/10*e+17/5:e<9/10?4356/361*e*e-35442/1805*e+16061/1805:54/5*e*e-513/25*e+268/25,zt=e=>e<.5?.5*ot(e*2):.5*Y(e*2-1)+.5,X=class{running=!1;_o;_p;_x;_d;_w;_e;_rel;_cb=[];_t=0;_u=0;_ch=this;_cu=this;_lc;constructor(t,s,i,r,o){this._o=t,this._p=s,this._x=i,this._d=r,this._e=o,this._w=0}start(t){if(this.running)return this;this._cu.stop(!1),this._ch=this._cu=this,this.running=!0;let s=this._o[this._p]||0,i=this._rel?s+this._x:this._x;return this._lc=this._lc||t||globalThis,this._u=this._lc.listen("update",r=>{if(this._t<=this._w){this._t+=r;return}let o=this._t-this._w;this._o[this._p]=this._lc.lerp(s,i,this._e(o/this._d)),this._t+=r,o>=this._d&&(this._o[this._p]=i,this.stop())}),this}stop(t=!0){if(!this._u)return this;if(this.running=!1,this._u(),this._t=0,t)for(let s of this._cb)s(this._o);return this}restart(t=null,s=!1){return this.stop(s).restart(t)}onEnd(t){return this._cb.push(t),this}chain(t){return this._ch.onEnd(()=>{this._cu=t.start(this._lc)}),this._ch=t,this}reset(){return this._cb.length=0,this.stop()}relative(t=!0){return this._rel=t,this}delay(t){return this._w=t,this}get current(){return this._cu}get progress(){return this.running&&this._t>this._w?(this._t-this._w)/this._d:0}};var nt=4,O=1<<nt,ht=8,qt=1<<ht,_=4095,N=e=>.5*(1-Math.cos(e*Math.PI)),W=class{_p=[];_po=4;_pf=.5;_e=null;constructor(t){this._e=t||globalThis,this.noiseSeed()}noise(t,s=0,i=0){t<0&&(t=-t),s<0&&(s=-s),i<0&&(i=-i);let r=Math.floor(t),o=Math.floor(s),h=Math.floor(i),a=t-r,c=s-o,x=i-h,u,g,d=0,m=.5,l,f,M;for(let U=0;U<this._po;U++){let p=r+(o<<nt)+(h<<ht);u=N(a),g=N(c),l=this._p[p&_],l+=u*(this._p[p+1&_]-l),f=this._p[p+O&_],f+=u*(this._p[p+O+1&_]-f),l+=g*(f-l),p+=qt,f=this._p[p&_],f+=u*(this._p[p+1&_]-f),M=this._p[p+O&_],M+=u*(this._p[p+O+1&_]-M),f+=g*(M-f),l+=N(x)*(f-l),d+=l*m,m*=this._pf,r<<=1,a*=2,o<<=1,c*=2,h<<=1,x*=2,a>=1&&(r++,a--),c>=1&&(o++,c--),x>=1&&(h++,x--)}return d}noiseDetail(t,s){t>0&&(this._po=t),s>0&&(this._pf=s)}noiseSeed(t=null){t!=null&&this._e.seed(t);let s=this._e.rand||Math.random;for(let i=0;i<_+1;i++)this._p[i]=s()}};globalThis.utils=Object.assign(globalThis.utils||{},B);})();
3
3
  /*! @litecanvas/utils by Luiz Bills | MIT Licensed */
package/dist/noise.js ADDED
@@ -0,0 +1,153 @@
1
+ (() => {
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
7
+
8
+ // src/_global.js
9
+ globalThis.utils = globalThis.utils || {};
10
+ globalThis.utils.global = () => {
11
+ for (const key in globalThis.utils) {
12
+ if ("global" === key) continue;
13
+ globalThis[key] = globalThis.utils[key];
14
+ }
15
+ };
16
+
17
+ // src/noise/index.js
18
+ var noise_exports = {};
19
+ __export(noise_exports, {
20
+ Noise: () => Noise
21
+ });
22
+ var PERLIN_YWRAPB = 4;
23
+ var PERLIN_YWRAP = 1 << PERLIN_YWRAPB;
24
+ var PERLIN_ZWRAPB = 8;
25
+ var PERLIN_ZWRAP = 1 << PERLIN_ZWRAPB;
26
+ var PERLIN_SIZE = 4095;
27
+ var scaled_cosine = (i) => 0.5 * (1 - Math.cos(i * Math.PI));
28
+ var Noise = class {
29
+ /**
30
+ * Array to store Perlin noise values.
31
+ * @type {number[]}
32
+ * @private
33
+ */
34
+ _p = [];
35
+ /**
36
+ * Number of octaves for the Perlin noise. Higher values create more detail.
37
+ * @type {number}
38
+ * @private
39
+ */
40
+ _po = 4;
41
+ /**
42
+ * Amplitude falloff factor for Perlin noise. Determines the reduction of amplitude per octave.
43
+ * @type {number}
44
+ * @private
45
+ */
46
+ _pf = 0.5;
47
+ /**
48
+ * @type {LitecanvasInstance}
49
+ * @private
50
+ */
51
+ _e = null;
52
+ /**
53
+ * @param {LitecanvasInstance} engine
54
+ */
55
+ constructor(engine) {
56
+ this._e = engine || globalThis;
57
+ this.noiseSeed();
58
+ }
59
+ /**
60
+ * Generates Perlin noise for the given coordinates.
61
+ * @param {number} x - X-coordinate.
62
+ * @param {number} [y=0] - Y-coordinate (default is 0).
63
+ * @param {number} [z=0] - Z-coordinate (default is 0).
64
+ * @returns {number} A noise value in the range [0, 1).
65
+ */
66
+ noise(x, y = 0, z = 0) {
67
+ if (x < 0) {
68
+ x = -x;
69
+ }
70
+ if (y < 0) {
71
+ y = -y;
72
+ }
73
+ if (z < 0) {
74
+ z = -z;
75
+ }
76
+ let xi = Math.floor(x), yi = Math.floor(y), zi = Math.floor(z);
77
+ let xf = x - xi;
78
+ let yf = y - yi;
79
+ let zf = z - zi;
80
+ let rxf, ryf;
81
+ let r = 0;
82
+ let ampl = 0.5;
83
+ let n1, n2, n3;
84
+ for (let o = 0; o < this._po; o++) {
85
+ let of = xi + (yi << PERLIN_YWRAPB) + (zi << PERLIN_ZWRAPB);
86
+ rxf = scaled_cosine(xf);
87
+ ryf = scaled_cosine(yf);
88
+ n1 = this._p[of & PERLIN_SIZE];
89
+ n1 += rxf * (this._p[of + 1 & PERLIN_SIZE] - n1);
90
+ n2 = this._p[of + PERLIN_YWRAP & PERLIN_SIZE];
91
+ n2 += rxf * (this._p[of + PERLIN_YWRAP + 1 & PERLIN_SIZE] - n2);
92
+ n1 += ryf * (n2 - n1);
93
+ of += PERLIN_ZWRAP;
94
+ n2 = this._p[of & PERLIN_SIZE];
95
+ n2 += rxf * (this._p[of + 1 & PERLIN_SIZE] - n2);
96
+ n3 = this._p[of + PERLIN_YWRAP & PERLIN_SIZE];
97
+ n3 += rxf * (this._p[of + PERLIN_YWRAP + 1 & PERLIN_SIZE] - n3);
98
+ n2 += ryf * (n3 - n2);
99
+ n1 += scaled_cosine(zf) * (n2 - n1);
100
+ r += n1 * ampl;
101
+ ampl *= this._pf;
102
+ xi <<= 1;
103
+ xf *= 2;
104
+ yi <<= 1;
105
+ yf *= 2;
106
+ zi <<= 1;
107
+ zf *= 2;
108
+ if (xf >= 1) {
109
+ xi++;
110
+ xf--;
111
+ }
112
+ if (yf >= 1) {
113
+ yi++;
114
+ yf--;
115
+ }
116
+ if (zf >= 1) {
117
+ zi++;
118
+ zf--;
119
+ }
120
+ }
121
+ return r;
122
+ }
123
+ /**
124
+ * Adjusts the detail level of the noise by setting the number of octaves and amplitude falloff.
125
+ * @param {number} lod - Level of detail (number of octaves).
126
+ * @param {number} falloff - Amplitude falloff per octave.
127
+ */
128
+ noiseDetail(lod, falloff) {
129
+ if (lod > 0) {
130
+ this._po = lod;
131
+ }
132
+ if (falloff > 0) {
133
+ this._pf = falloff;
134
+ }
135
+ }
136
+ /**
137
+ * Sets a seed for the Perlin noise generator, ensuring deterministic results.
138
+ * @param {number} value - Seed value.
139
+ */
140
+ noiseSeed(value = null) {
141
+ if (value != null) {
142
+ this._e.seed(value);
143
+ }
144
+ const random = this._e.rand || Math.random;
145
+ for (let i = 0; i < PERLIN_SIZE + 1; i++) {
146
+ this._p[i] = random();
147
+ }
148
+ }
149
+ };
150
+
151
+ // src/noise/_web.js
152
+ globalThis.utils = Object.assign(globalThis.utils || {}, noise_exports);
153
+ })();
@@ -0,0 +1 @@
1
+ (()=>{var w=Object.defineProperty;var S=(s,t)=>{for(var e in t)w(s,e,{get:t[e],enumerable:!0})};globalThis.utils=globalThis.utils||{};globalThis.utils.global=()=>{for(let s in globalThis.utils)s!=="global"&&(globalThis[s]=globalThis.utils[s])};var b={};S(b,{Noise:()=>E});var H=4,_=1<<H,D=8,v=1<<D,a=4095,T=s=>.5*(1-Math.cos(s*Math.PI)),E=class{_p=[];_po=4;_pf=.5;_e=null;constructor(t){this._e=t||globalThis,this.noiseSeed()}noise(t,e=0,n=0){t<0&&(t=-t),e<0&&(e=-e),n<0&&(n=-n);let c=Math.floor(t),f=Math.floor(e),u=Math.floor(n),p=t-c,h=e-f,d=n-u,r,m,y=0,x=.5,l,o,g;for(let I=0;I<this._po;I++){let i=c+(f<<H)+(u<<D);r=T(p),m=T(h),l=this._p[i&a],l+=r*(this._p[i+1&a]-l),o=this._p[i+_&a],o+=r*(this._p[i+_+1&a]-o),l+=m*(o-l),i+=v,o=this._p[i&a],o+=r*(this._p[i+1&a]-o),g=this._p[i+_&a],g+=r*(this._p[i+_+1&a]-g),o+=m*(g-o),l+=T(d)*(o-l),y+=l*x,x*=this._pf,c<<=1,p*=2,f<<=1,h*=2,u<<=1,d*=2,p>=1&&(c++,p--),h>=1&&(f++,h--),d>=1&&(u++,d--)}return y}noiseDetail(t,e){t>0&&(this._po=t),e>0&&(this._pf=e)}noiseSeed(t=null){t!=null&&this._e.seed(t);let e=this._e.rand||Math.random;for(let n=0;n<a+1;n++)this._p[n]=e()}};globalThis.utils=Object.assign(globalThis.utils||{},b);})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litecanvas/utils",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "Utilities to help build litecanvas games",
5
5
  "author": "Luiz Bills <luizbills@pm.me>",
6
6
  "license": "MIT",
@@ -26,7 +26,8 @@
26
26
  "dev": "esbuild src/_web.js --bundle --watch --outfile=dist/all.js --servedir=.",
27
27
  "build": "node scripts/build.js",
28
28
  "prepare": "npm run build",
29
- "prepublishOnly": "npm run build"
29
+ "prepublishOnly": "npm run build",
30
+ "format": "npx prettier -w ."
30
31
  },
31
32
  "files": [
32
33
  "src",
@@ -37,6 +38,7 @@
37
38
  },
38
39
  "devDependencies": {
39
40
  "esbuild": "^0.23.1",
40
- "gzip-size": "^7.0.0"
41
+ "gzip-size": "^7.0.0",
42
+ "prettier": "^3.3.3"
41
43
  }
42
44
  }
@@ -24,7 +24,7 @@ export default (x1, y1, w1, h1, x2, y2, w2, h2) => {
24
24
  x2,
25
25
  y2,
26
26
  w2,
27
- h2,
27
+ h2
28
28
  )
29
29
 
30
30
  let direction = ""
package/src/index.js CHANGED
@@ -6,3 +6,4 @@ export * from "./vector/index.js"
6
6
  export * from "./actor/index.js"
7
7
  export * from "./math/index.js"
8
8
  export * from "./tween/index.js"
9
+ export * from "./noise/index.js"
@@ -0,0 +1,74 @@
1
+ # Noise utils
2
+
3
+ **CDN**: https://unpkg.com/@litecanvas/utils/dist/noise.js
4
+
5
+ ## Usage
6
+
7
+ Generate procedural Perlin noise to use in your projects, such as terrain generation, animations, or particle effects.
8
+
9
+ ```js
10
+ import litecanvas from "litecanvas"
11
+ import { Noise } from "@litecanvas/utils"
12
+
13
+ const e = litecanvas()
14
+
15
+ // Create a new Noise instance
16
+ const noise = new Noise(e)
17
+
18
+ // Generate a noise value at 2D coordinates (x, y)
19
+ const value = noise.noise(0.5, 0.8)
20
+ console.log("Noise value at (0.5, 0.8):", value)
21
+
22
+ // Generate a noise value at 3D coordinates (x, y, z)
23
+ const value3D = noise.noise(1.2, 0.4, 0.9)
24
+ console.log("Noise value at (1.2, 0.4, 0.9):", value3D)
25
+ ```
26
+
27
+ ### Adjusting Noise Detail
28
+
29
+ You can configure the number of octaves and amplitude falloff to control the detail of the noise.
30
+
31
+ ```js
32
+ // Set 8 octaves and a 60% amplitude falloff
33
+ noise.noiseDetail(8, 0.6)
34
+
35
+ // Generate a new noise value with the updated settings
36
+ const detailedValue = noise.noise(0.3, 0.7)
37
+ console.log("Detailed noise value:", detailedValue)
38
+ ```
39
+
40
+ ## Seeding Noise
41
+
42
+ Ensure deterministic results by setting a seed for the noise generator.
43
+
44
+ ```js
45
+ // Set a specific seed
46
+ noise.noiseSeed(42)
47
+
48
+ // Generate consistent noise values
49
+ const seededValue = noise.noise(0.1, 0.1)
50
+ console.log("Seeded noise value at (0.1, 0.1):", seededValue)
51
+ ```
52
+
53
+ ## 2D Noise Grid
54
+
55
+ Create a grid of Perlin noise values and display them as ASCII art.
56
+
57
+ ```js
58
+ const noise = new utils.Noise()
59
+ noise.noiseDetail(4, 0.5)
60
+
61
+ // Generate a 8 by 8 noise grid
62
+ const gridSize = 8
63
+ let grid = ""
64
+
65
+ for (let y = 0; y < gridSize; y++) {
66
+ for (let x = 0; x < gridSize; x++) {
67
+ const value = noise.noise(x / gridSize, y / gridSize)
68
+ grid += value > 0.5 ? "#" : "."
69
+ }
70
+ grid += "\n"
71
+ }
72
+
73
+ console.log(grid)
74
+ ```
@@ -0,0 +1,4 @@
1
+ import "../_global.js"
2
+ import * as noiseUtils from "./index.js"
3
+
4
+ globalThis.utils = Object.assign(globalThis.utils || {}, noiseUtils)
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Further adapted from p5 Noise module
3
+ * https://github.com/processing/p5.js/blob/v1.11.1/src/math/noise.js
4
+ */
5
+
6
+ // import litecanvas types
7
+ import "litecanvas"
8
+
9
+ /**
10
+ * Constants for Perlin noise calculations.
11
+ */
12
+ const PERLIN_YWRAPB = 4
13
+ const PERLIN_YWRAP = 1 << PERLIN_YWRAPB
14
+ const PERLIN_ZWRAPB = 8
15
+ const PERLIN_ZWRAP = 1 << PERLIN_ZWRAPB
16
+ const PERLIN_SIZE = 4095
17
+
18
+ /**
19
+ * Scaled cosine function used for smoothing transitions in Perlin noise.
20
+ * @param {number} i - Input value.
21
+ * @returns {number} Scaled cosine value.
22
+ */
23
+ const scaled_cosine = (i) => 0.5 * (1.0 - Math.cos(i * Math.PI))
24
+
25
+ /**
26
+ * Class for generating Perlin noise, a type of gradient noise often used in procedural generation.
27
+ */
28
+ export class Noise {
29
+ /**
30
+ * Array to store Perlin noise values.
31
+ * @type {number[]}
32
+ * @private
33
+ */
34
+ _p = []
35
+
36
+ /**
37
+ * Number of octaves for the Perlin noise. Higher values create more detail.
38
+ * @type {number}
39
+ * @private
40
+ */
41
+ _po = 4
42
+
43
+ /**
44
+ * Amplitude falloff factor for Perlin noise. Determines the reduction of amplitude per octave.
45
+ * @type {number}
46
+ * @private
47
+ */
48
+ _pf = 0.5
49
+
50
+ /**
51
+ * @type {LitecanvasInstance}
52
+ * @private
53
+ */
54
+ _e = null
55
+
56
+ /**
57
+ * @param {LitecanvasInstance} engine
58
+ */
59
+ constructor(engine) {
60
+ this._e = engine || globalThis
61
+
62
+ this.noiseSeed()
63
+ }
64
+
65
+ /**
66
+ * Generates Perlin noise for the given coordinates.
67
+ * @param {number} x - X-coordinate.
68
+ * @param {number} [y=0] - Y-coordinate (default is 0).
69
+ * @param {number} [z=0] - Z-coordinate (default is 0).
70
+ * @returns {number} A noise value in the range [0, 1).
71
+ */
72
+ noise(x, y = 0, z = 0) {
73
+ if (x < 0) {
74
+ x = -x
75
+ }
76
+ if (y < 0) {
77
+ y = -y
78
+ }
79
+ if (z < 0) {
80
+ z = -z
81
+ }
82
+
83
+ let xi = Math.floor(x),
84
+ yi = Math.floor(y),
85
+ zi = Math.floor(z)
86
+ let xf = x - xi
87
+ let yf = y - yi
88
+ let zf = z - zi
89
+ let rxf, ryf
90
+
91
+ let r = 0
92
+ let ampl = 0.5
93
+
94
+ let n1, n2, n3
95
+
96
+ for (let o = 0; o < this._po; o++) {
97
+ let of = xi + (yi << PERLIN_YWRAPB) + (zi << PERLIN_ZWRAPB)
98
+
99
+ rxf = scaled_cosine(xf)
100
+ ryf = scaled_cosine(yf)
101
+
102
+ n1 = this._p[of & PERLIN_SIZE]
103
+ n1 += rxf * (this._p[(of + 1) & PERLIN_SIZE] - n1)
104
+ n2 = this._p[(of + PERLIN_YWRAP) & PERLIN_SIZE]
105
+ n2 += rxf * (this._p[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n2)
106
+ n1 += ryf * (n2 - n1)
107
+
108
+ of += PERLIN_ZWRAP
109
+ n2 = this._p[of & PERLIN_SIZE]
110
+ n2 += rxf * (this._p[(of + 1) & PERLIN_SIZE] - n2)
111
+ n3 = this._p[(of + PERLIN_YWRAP) & PERLIN_SIZE]
112
+ n3 += rxf * (this._p[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n3)
113
+ n2 += ryf * (n3 - n2)
114
+
115
+ n1 += scaled_cosine(zf) * (n2 - n1)
116
+
117
+ r += n1 * ampl
118
+ ampl *= this._pf
119
+ xi <<= 1
120
+ xf *= 2
121
+ yi <<= 1
122
+ yf *= 2
123
+ zi <<= 1
124
+ zf *= 2
125
+
126
+ if (xf >= 1.0) {
127
+ xi++
128
+ xf--
129
+ }
130
+ if (yf >= 1.0) {
131
+ yi++
132
+ yf--
133
+ }
134
+ if (zf >= 1.0) {
135
+ zi++
136
+ zf--
137
+ }
138
+ }
139
+ return r
140
+ }
141
+
142
+ /**
143
+ * Adjusts the detail level of the noise by setting the number of octaves and amplitude falloff.
144
+ * @param {number} lod - Level of detail (number of octaves).
145
+ * @param {number} falloff - Amplitude falloff per octave.
146
+ */
147
+ noiseDetail(lod, falloff) {
148
+ if (lod > 0) {
149
+ this._po = lod
150
+ }
151
+ if (falloff > 0) {
152
+ this._pf = falloff
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Sets a seed for the Perlin noise generator, ensuring deterministic results.
158
+ * @param {number} value - Seed value.
159
+ */
160
+ noiseSeed(value = null) {
161
+ if (value != null) {
162
+ this._e.seed(value)
163
+ }
164
+ const random = this._e.rand || Math.random
165
+ for (let i = 0; i < PERLIN_SIZE + 1; i++) {
166
+ this._p[i] = random()
167
+ }
168
+ }
169
+ }
@@ -69,7 +69,7 @@ const engine = litecanvas({
69
69
  })
70
70
 
71
71
  function init () {
72
- engine.tween(...).start(engine)
72
+ tween(...).start(engine)
73
73
  }
74
74
  ```
75
75
 
@@ -81,7 +81,7 @@ const engine = litecanvas({
81
81
 
82
82
  function init () {
83
83
  // just call start
84
- engine.tween(...).start()
84
+ tween(...).start()
85
85
  }
86
86
  ```
87
87
 
@@ -120,7 +120,6 @@ const obj = { x: 0, angle: 0 }
120
120
 
121
121
  const moveRight = tween(obj, "x", 100, 1).relative()
122
122
  const moveLeft = tween(obj, "x", -100, 1).relative()
123
- const moveLeft = tween(obj, "angle", Math.PI, 1).relative()
124
123
 
125
124
  // move 100px to right, move 100px to left and rotate
126
125
  moveRight.chain(moveLeft)