littlejsengine 1.14.16 → 1.14.19

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.
@@ -56,10 +56,9 @@ async function gameInit()
56
56
  // start up LittleJS Box2D plugin
57
57
  await LJS.box2dInit();
58
58
  //LJS.box2dSetDebug(true); // enable box2d debug draw
59
- LJS.setCanvasClearColor(hsl(0,0,.8));
60
59
 
61
60
  // create a table of all sprites
62
- const gameTile = (i)=> LJS.tile(i, 496, 0, 8);
61
+ const gameTile = (i)=> LJS.tile(i, 124, 0, 2);
63
62
  spriteAtlas =
64
63
  {
65
64
  circle: gameTile(0),
@@ -71,6 +70,8 @@ async function gameInit()
71
70
  squareOutline2: gameTile(6),
72
71
  };
73
72
 
73
+ // startup the demo
74
+ LJS.setCanvasClearColor(hsl(0,0,.8));
74
75
  setScene(startScene);
75
76
  }
76
77
 
Binary file
@@ -104,11 +104,12 @@ function gameRenderPost()
104
104
  {
105
105
  // use built in image font for text
106
106
  const font = new LJS.FontImage;
107
- font.drawText('Score: ' + score, LJS.cameraPos.add(vec2(0,9.7)), .15, true);
107
+
108
+ font.drawTextOverlay('Score: ' + score, LJS.cameraPos.add(vec2(0,9.7)), .15, true);
108
109
  if (!brickCount)
109
- font.drawText('You Win!', LJS.cameraPos.add(vec2(0,-5)), .2, true);
110
+ font.drawTextOverlay('You Win!', LJS.cameraPos.add(vec2(0,-5)), .2, true);
110
111
  else if (!ball)
111
- font.drawText('Click to Play', LJS.cameraPos.add(vec2(0,-5)), .2, true);
112
+ font.drawTextOverlay('Click to Play', LJS.cameraPos.add(vec2(0,-5)), .2, true);
112
113
  }
113
114
 
114
115
  ///////////////////////////////////////////////////////////////////////////////
@@ -167,8 +168,7 @@ function setupPostProcess()
167
168
  c *= 1.-pow((dx*dx + dy*dy)/vignette, vignettePow);
168
169
  }`;
169
170
 
170
- const includeOverlay = true;
171
- new LJS.PostProcessPlugin(televisionShader, includeOverlay);
171
+ new LJS.PostProcessPlugin(televisionShader);
172
172
  }
173
173
 
174
174
  ///////////////////////////////////////////////////////////////////////////////
@@ -69,12 +69,12 @@ function gameInit()
69
69
  tile(0, 16), // tileIndex, tileSize
70
70
  hsl(1,1,1), hsl(0,0,0), // colorStartA, colorStartB
71
71
  hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
72
- 2, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
72
+ 1, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
73
73
  .99, 1, 1, PI, // damping, angleDamping, gravityScale, cone
74
74
  .05, .5, true, true // fadeRate, randomness, collide, additive
75
75
  );
76
76
  particleEmitter.restitution = .3; // bounce when it collides
77
- particleEmitter.trailScale = 2; // stretch as it moves
77
+ particleEmitter.trailScale = 2; // stretch as it moves
78
78
  }
79
79
 
80
80
  ///////////////////////////////////////////////////////////////////////////////
@@ -7,7 +7,7 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- LittleJS Engine -->
10
- <script src=../../dist/littlejs.js?11416></script>
10
+ <script src=../../dist/littlejs.js?11417></script>
11
11
 
12
12
  <!-- Add your game scripts here -->
13
- <script src=game.js?11416></script>
13
+ <script src=game.js?11417></script>
@@ -4,6 +4,17 @@
4
4
  <link rel=stylesheet href=style.css?9>
5
5
  <meta charset=utf-8>
6
6
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
7
+ <!-- meta tags for social media -->
8
+ <meta name='twitter:title' content='LittleJS Example Browser'>
9
+ <meta property='og:title' content='LittleJS Example Browser'>
10
+ <meta name='description' content='Tiny fast HTML5 game engine!'>
11
+ <meta name='twitter:description' content='Tiny fast HTML5 game engine!'>
12
+ <meta property='og:description' content='Tiny fast HTML5 game engine!'>
13
+ <meta name='twitter:image' content='https://3d2k.com/images/LittleJSExamples.png'>
14
+ <meta property='og:image' content='https://3d2k.com/images/LittleJSExamples.png'>
15
+ <meta name='keywords' content='JavaScript, HTML5, Game, Engine'>
16
+ <meta name='twitter:creator' content='@KilledByAPixel'>
17
+ <meta name='twitter:card' content='summary_large_image'>
7
18
  </head><body>
8
19
  <div id=container1>
9
20
  <div id=container3>
@@ -21,8 +32,7 @@ Theme:
21
32
  <option value=20px>L</option>
22
33
  <option value=24px>XL</option>
23
34
  </select>
24
- <span class=nowrap><input type=checkbox id=checkboxLiveEdit checked>Live Edit</span>
25
- <span class=nowrap><input type=checkbox id=checkboxJumpToErrors>Jump to Errors</span>
35
+ <span class=nowrap><input type=checkbox id=checkboxLiveEdit onchange=writeSaveData() checked>Live Edit</span>
26
36
  </div>
27
37
  <div id=divTextareas>
28
38
  <textarea id=textareaCode oninput=codeInput() spellcheck=false></textarea>
@@ -97,6 +107,7 @@ const exampleList =
97
107
  new ExampleInfo('Piano', 'piano.js', 'Interactive piano keyboard', false, 'music, sound, audio, notes, ui, instrument'),
98
108
  new ExampleInfo('Step Sequencer', 'sequencer.js', 'Simple music loop creation tool', false, 'music, sound, audio, notes, ui, instrument'),
99
109
  new ExampleInfo('Music Player', 'musicPlayer.js', 'Advanced music player with audio seeking and drag and drop', false, 'music, sound, audio, streaming, volume, ui'),
110
+ new ExampleInfo('WebGL Shader', 'shader.js', 'Full canvas webgl shader', false, 'webgl, visual, effect'),
100
111
  new ExampleInfo('--- MINI GAMES ---'),
101
112
  new ExampleInfo('Pong Game', 'pongGame.js', 'Classic paddle ball bouncing', false, 'objects, collision'),
102
113
  new ExampleInfo('Platformer Game', 'platformer.js', 'Jump and run side view', false, 'objects, gravity, level, tiles, camera'),
@@ -141,7 +152,7 @@ function initExampleBrowser()
141
152
  // set the selected example from the URL parameters
142
153
  const urlParams = new URLSearchParams(window.location.search);
143
154
  const selectedExample = urlParams.get('example') || '';
144
- let exampleIndex = exampleList.findIndex((example) => example.filename === selectedExample);
155
+ let exampleIndex = exampleList.findIndex((example) => example.name === selectedExample);
145
156
  if (exampleIndex < 0)
146
157
  exampleIndex = 1;
147
158
  selectExample.selectedIndex = exampleIndex;
@@ -240,7 +251,7 @@ function setExample()
240
251
 
241
252
  // update URL parameter
242
253
  const url = new URL(window.location);
243
- url.searchParams.set('example', example.filename);
254
+ url.searchParams.set('example', example.name);
244
255
  window.history.replaceState({}, '', url);
245
256
 
246
257
  loadFile(example.filename, example.largeExample);
@@ -616,35 +627,6 @@ function setErrorLine(lineNumber)
616
627
  clearErrorLine();
617
628
  --lineNumber; // codeMirror uses 0-based line numbers
618
629
  errorLineMarker = codeMirror.getDoc().addLineClass(lineNumber, 'background', 'error-line');
619
- if (checkboxJumpToErrors.checked)
620
- {
621
- codeMirror.scrollIntoView({line: lineNumber, ch: 0});
622
- codeMirror.focus();
623
- }
624
- }
625
- else if (textareaCode && checkboxJumpToErrors.checked)
626
- {
627
- // for textarea, calculate character position and set cursor
628
- const lines = textareaCode.value.split('\n');
629
- let charPos = 0;
630
- for (let i = 0; i < lineNumber - 1 && i < lines.length; i++)
631
- {
632
- charPos += lines[i].length + 1; // +1 for newline character
633
- }
634
- textareaCode.setSelectionRange(charPos, charPos);
635
- if (checkboxJumpToErrors.checked)
636
- {
637
- const line = textareaCode.value.split('\n');
638
- lineNumber = Math.min(Math.max(0, lineNumber-1), lines.length-1);
639
-
640
- // select error line in textarea
641
- let start = 0;
642
- for (let i = 0; i < lineNumber; i++)
643
- start += lines[i].length + 1;
644
- textareaCode.selectionStart = start;
645
- textareaCode.selectionEnd = start + lines[lineNumber].length;
646
- textareaCode.focus();
647
- }
648
630
  }
649
631
  }
650
632
 
@@ -669,13 +651,41 @@ textareaConsole.addEventListener('scroll', onScrollConsole);
669
651
 
670
652
  ///////////////////////////////////////////////////////////////////////////////
671
653
  // load saved preferences from localStorage
672
- const defaultTheme = 'littlejs';
673
- const defaultFontSize = '16px';
674
- const savePrefix = 'LittleJSExamples_';
675
- const savedTheme = localStorage.getItem(savePrefix+'theme') || defaultTheme;
676
- const savedFontSize = localStorage.getItem(savePrefix+'fontSize') || defaultFontSize;
677
- selectFontSize.value = savedFontSize;
678
- textareaCode.style.fontSize = savedFontSize;
654
+ const saveName = 'LittleJSExamples';
655
+ let savedTheme;
656
+
657
+ function readSaveData()
658
+ {
659
+ // load saved preferences
660
+ const defaultTheme = 'littlejs';
661
+ const defaultFontSize = '16px';
662
+ const saveDataJSON = localStorage.getItem(saveName);
663
+ const saveData = saveDataJSON ? JSON.parse(saveDataJSON) : {};
664
+ selectTheme.value = savedTheme = saveData.theme ?? defaultTheme;
665
+ selectFontSize.value = saveData.fontSize ?? defaultFontSize;
666
+ }
667
+ readSaveData();
668
+
669
+ function writeSaveData()
670
+ {
671
+ // Save preferences to localStorage
672
+ const theme = selectTheme.value;
673
+ const fontSize = selectFontSize.value;
674
+ const saveData =
675
+ {
676
+ theme,
677
+ fontSize
678
+ };
679
+ const saveDataJSON = JSON.stringify(saveData);
680
+ localStorage.setItem(saveName, saveDataJSON);
681
+ }
682
+
683
+ function resetDefaults()
684
+ {
685
+ localStorage.removeItem(saveName);
686
+ readSaveData();
687
+ loadTheme();
688
+ }
679
689
 
680
690
  ///////////////////////////////////////////////////////////////////////////////
681
691
  // setup code mirror
@@ -753,20 +763,18 @@ function addCodeMirrorElement(filename, type, rel)
753
763
 
754
764
  function loadTheme()
755
765
  {
756
- const theme = selectTheme.value;
757
- const size = selectFontSize.value;
758
-
759
- // Save preferences to localStorage
760
- localStorage.setItem(savePrefix+'theme', theme);
761
- localStorage.setItem(savePrefix+'fontSize', size);
762
-
763
766
  // Apply the theme and font size
764
- textareaCode.style.fontSize = size;
767
+ const theme = selectTheme.value;
768
+ const fontSize = selectFontSize.value;
769
+ textareaCode.style.fontSize = fontSize;
765
770
  if (codeMirror)
766
771
  {
767
- codeMirror.getWrapperElement().style.fontSize = size;
772
+ codeMirror.getWrapperElement().style.fontSize = fontSize;
768
773
  codeMirror.setOption('theme', theme);
769
774
  }
775
+
776
+ // Save preferences to localStorage
777
+ writeSaveData();
770
778
  }
771
779
 
772
780
  ///////////////////////////////////////////////////////////////////////////////
@@ -73,12 +73,12 @@ function gameInit()
73
73
  tile(0, 16), // tileIndex, tileSize
74
74
  hsl(1,1,1), hsl(0,0,0), // colorStartA, colorStartB
75
75
  hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
76
- 2, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
76
+ 1, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
77
77
  .99, 1, 1, Math.PI, // damping, angleDamping, gravityScale, cone
78
78
  .05, .5, true, true // fadeRate, randomness, collide, additive
79
79
  );
80
80
  particleEmitter.restitution = .3; // bounce when it collides
81
- particleEmitter.trailScale = 2; // stretch as it moves
81
+ particleEmitter.trailScale = 2; // stretch as it moves
82
82
  }
83
83
 
84
84
  ///////////////////////////////////////////////////////////////////////////////
@@ -255,7 +255,7 @@ export class ParallaxLayer extends LJS.CanvasLayer
255
255
  this.context.clearRect(0,0,1,h);
256
256
 
257
257
  // make WebGL texture
258
- this.useWebGL(LJS.glEnable);
258
+ this.useWebGL();
259
259
  }
260
260
 
261
261
  render()
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html><meta charset=utf-8><body>
2
- <script src=../../dist/littlejs.js?11416></script>
2
+ <script src=../../dist/littlejs.js?11417></script>
3
3
  <script src=../../dist/box2d.wasm.js></script>
4
4
 
5
5
  <!-- LittleJS Engine Source
@@ -9,6 +9,7 @@ function gameInit()
9
9
  uiSystem.defaultSoundPress = new Sound([.5,0,220]);
10
10
  uiSystem.defaultSoundClick = new Sound([.5,0,440]);
11
11
  uiSystem.defaultCornerRadius = 20;
12
+ uiSystem.defaultGradientColor = WHITE;
12
13
  canvasClearColor = hsl(.9,.3,.2);
13
14
 
14
15
  // setup music player UI
@@ -53,7 +53,7 @@ class ParallaxLayer extends CanvasLayer
53
53
  this.context.clearRect(0,0,1,h);
54
54
 
55
55
  // make WebGL texture
56
- this.useWebGL(glEnable);
56
+ this.useWebGL();
57
57
  }
58
58
 
59
59
  render()
@@ -3,7 +3,7 @@ let currentStep = 0, stepTime = 0, tempo = 240;
3
3
  let isPlaying = false, eraseMode = false;
4
4
 
5
5
  // sound sequencer instruments
6
- const sound_piano = new Sound([.4,0,220,,.1]);
6
+ const sound_piano = new Sound([.3,0,220,,.1]);
7
7
  const sound_drumKick = new Sound([,,99,,,.02,,,,,,,,2]);
8
8
  const sound_drumHat = new Sound([,,1e3,,,.01,4,,,,,,,,,,,,,,4e3]);
9
9
 
@@ -57,7 +57,7 @@ class UISequencerButton extends UIButton
57
57
  {
58
58
  this.activeColor = eraseMode ? RED : WHITE;
59
59
  this.color = this.isActiveObject() ? BLACK :
60
- hsl(this.hue, this.isOn ? 1 : .5, this.isOn ? .5 : .1);
60
+ hsl(this.hue, this.isOn ? 1 : .5, this.isOn ? .5 : .15);
61
61
  if (isPlaying && this.step == currentStep)
62
62
  this.color = this.color.lerp(WHITE, .5);
63
63
  super.render();
@@ -0,0 +1,29 @@
1
+ const shader = `
2
+ void mainImage(out vec4 c, vec2 p)
3
+ {
4
+ // normalize coordinates
5
+ vec2 uv = (p - iResolution.xy * .5) / iResolution.y;
6
+
7
+ // get distance and angle from center
8
+ float distance = length(uv);
9
+ float angle = atan(uv.y, uv.x);
10
+
11
+ // color based on angle and distance
12
+ c.rgb = vec3(
13
+ .5 + .5 * sin(angle + iTime),
14
+ .5 + .5 * sin(angle + iTime * 2.),
15
+ .5 + .5 * sin(distance * 5. - iTime)
16
+ );
17
+
18
+ // apply glow in center
19
+ c += .1 / (distance + .1);
20
+
21
+ // apply sine wave brightness
22
+ c *= .5 + .5 * sin(distance * 20. - iTime * 3.);
23
+ }
24
+ `;
25
+
26
+ function gameInit()
27
+ {
28
+ new PostProcessPlugin(shader);
29
+ }
@@ -43,6 +43,6 @@ function gameUpdate()
43
43
  .05, .8, true
44
44
  );
45
45
  particleEmitter.restitution = .5; // bounce when it collides
46
- particleEmitter.trailScale = 2; // stretch as it moves
46
+ particleEmitter.trailScale = 2; // stretch as it moves
47
47
  }
48
48
  }
@@ -9,9 +9,10 @@ class GameObject extends EngineObject
9
9
  render()
10
10
  {
11
11
  // adjust draw postion to be at the bottom of the object
12
- const offset = vec2(0,this.size.y/2).rotate(this.angle);
12
+ const drawSize = this.drawSize || this.size;
13
+ const offset = vec2(0,drawSize.y/2).rotate(this.angle);
13
14
  const pos = this.pos.add(offset);
14
- drawTile(pos, this.size, this.tileInfo, this.color, this.angle);
15
+ drawTile(pos, drawSize, this.tileInfo, this.color, this.angle);
15
16
  }
16
17
  }
17
18
 
@@ -24,6 +25,7 @@ class Player extends GameObject
24
25
  // apply movement controls
25
26
  const moveInput = keyDirection().clampLength(1).scale(.2);
26
27
  this.velocity = this.velocity.add(moveInput);
28
+ this.setCollision(); // make object collide
27
29
 
28
30
  // move camera with player
29
31
  cameraPos = this.pos.add(vec2(0,2));
@@ -34,7 +36,8 @@ function gameInit()
34
36
  {
35
37
  // setup level
36
38
  objectDefaultDamping = .7;
37
- new Player(vec2(), vec2(3), tile(5), 0, RED);
39
+ const player = new Player(vec2(), vec2(3,1), tile(5), 0, RED);
40
+ player.drawSize = vec2(3);
38
41
 
39
42
  // create background objects
40
43
  for (let i=1; i<300; ++i)
@@ -49,8 +52,13 @@ function gameInit()
49
52
  for (let i=1; i<1e3; ++i)
50
53
  {
51
54
  const pos = randInCircle(7+i,7);
52
- const size = vec2(rand(1,2),rand(4,9));
53
- const color = hsl(.1,.5,rand(.2,.3));
54
- new GameObject(pos, size, 0, 0, color);
55
+ const isRock = randBool();
56
+ const size = vec2(isRock ? rand(2,4) : rand(1,2));
57
+ const color = hsl(.1,isRock ? 0 : .5,rand(.2,.3));
58
+ const o = new GameObject(pos, size, 0, 0, color);
59
+ o.setCollision(); // make object collide
60
+ o.mass = 0; // make object have static physics
61
+ o.angle = rand(-.1,.1); // random tilt
62
+ o.drawSize = vec2(size.x, isRock ? rand(2,4) : rand(5,10));
55
63
  }
56
64
  }
@@ -32,7 +32,7 @@ function gameInit()
32
32
  {
33
33
  const pos = randInCircle(15+i,7);
34
34
  const size = vec2(rand(4,9),rand(4,9));
35
- const color = hsl(.1,.5,rand(.2,.3));
35
+ const color = hsl(.1,.5,rand(.2));
36
36
  const o = new EngineObject(pos, size, 0, 0, color);
37
37
  o.setCollision(); // make object collide
38
38
  o.mass = 0; // make object have static physics
@@ -69,12 +69,12 @@ function gameInit()
69
69
  tile(0, 16), // tileIndex, tileSize
70
70
  hsl(1,1,1), hsl(0,0,0), // colorStartA, colorStartB
71
71
  hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
72
- 2, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
72
+ 1, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
73
73
  .99, 1, 1, PI, // damping, angleDamping, gravityScale, cone
74
74
  .05, .5, true, true // fadeRate, randomness, collide, additive
75
75
  );
76
76
  particleEmitter.restitution = .3; // bounce when it collides
77
- particleEmitter.trailScale = 2; // stretch as it moves
77
+ particleEmitter.trailScale = 2; // stretch as it moves
78
78
  }
79
79
 
80
80
  ///////////////////////////////////////////////////////////////////////////////
@@ -7,7 +7,7 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- LittleJS Engine -->
10
- <script src=../../dist/littlejs.js?11416></script>
10
+ <script src=../../dist/littlejs.js?11417></script>
11
11
 
12
12
  <!-- LittleJS Engine Source
13
13
  <script src=../../src/engineDebug.js></script>
@@ -31,4 +31,4 @@
31
31
  -->
32
32
 
33
33
  <!-- Add your game scripts here -->
34
- <script src=game.js?11416></script>
34
+ <script src=game.js?11417></script>
@@ -73,6 +73,7 @@ iframe
73
73
  margin: 5px;
74
74
  text-align: center;
75
75
  font-size: 40px;
76
+ font-weight: bold;
76
77
  }
77
78
  #exampleInfo
78
79
  {
@@ -56,12 +56,12 @@ function gameInit() {
56
56
  tile(0, 16), // tileIndex, tileSize
57
57
  hsl(1, 1, 1), hsl(0, 0, 0), // colorStartA, colorStartB
58
58
  hsl(0, 0, 0, 0), hsl(0, 0, 0, 0), // colorEndA, colorEndB
59
- 2, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
59
+ 1, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
60
60
  .99, 1, 1, Math.PI, // damping, angleDamping, gravityScale, cone
61
61
  .05, .5, true, true // fadeRate, randomness, collide, additive
62
62
  );
63
63
  particleEmitter.restitution = .3; // bounce when it collides
64
- particleEmitter.trailScale = 2; // stretch as it moves
64
+ particleEmitter.trailScale = 2; // stretch as it moves
65
65
  }
66
66
  ///////////////////////////////////////////////////////////////////////////////
67
67
  function gameUpdate() {
@@ -73,7 +73,7 @@ function gameInit()
73
73
  tile(0, 16), // tileIndex, tileSize
74
74
  hsl(1,1,1), hsl(0,0,0), // colorStartA, colorStartB
75
75
  hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
76
- 2, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
76
+ 1, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
77
77
  .99, 1, 1, Math.PI, // damping, angleDamping, gravityScale, cone
78
78
  .05, .5, true, true // fadeRate, randomness, collide, additive
79
79
  );
@@ -24,6 +24,7 @@ function createUI()
24
24
  LJS.uiSystem.defaultSoundPress = new LJS.Sound([.5,0,220]);
25
25
  LJS.uiSystem.defaultSoundClick = new LJS.Sound([.5,0,440]);
26
26
  LJS.uiSystem.defaultCornerRadius = 8;
27
+ LJS.uiSystem.defaultGradientColor = LJS.WHITE;
27
28
 
28
29
  // setup root to attach all ui elements to
29
30
  uiRoot = new LJS.UIObject;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "littlejsengine",
3
- "version": "1.14.16",
3
+ "version": "1.14.19",
4
4
  "description": "LittleJS - Tiny and Fast HTML5 Game Engine",
5
5
  "main": "dist/littlejs.esm.js",
6
6
  "types": "dist/littlejs.d.ts",