A JavaScript framework for creating 2D WebGL2 applications
- Top View Game Demo
- Card Game Demo
- Displacement Filter
- 2D Lights and Shadows
- Lights, Shadows and Filters
- Journey
- Batch rendering (10.000 elements - 60fps)
- Dynamic 2D lights and shadows
- Element picker (can click on rendered items)
- Image filters (Blur, Pixelate, Distortion, etc.)
- Video textures
- and many other features...
Create your index html ( include pwgl.min.js )
<!DOCTYPE html>
<html>
  <head>
    <script src="pwgl.min.js" type="text/javascript"></script>
  </head>
  <body></body>
</html>Add your script
class Application {
  constructor() {}
}
PWGL.Utils.initApplication(function (isWebGl2Supported) {
  if (!isWebGl2Supported) {
    // WebGL 2 is not supported
    return;
  }
  new Application();
});Create a simple 2d renderer environment
class Application {
  constructor() {
    const width = 800;
    const height = 600;
    this._stageContainer = document.body;
    // create context
    this._context = new PWGL.Context();
    // create stage 2d renderer
    this._stage2DRenderer = new PWGL.Stage2D({
      config: {
        context: this._context,
      },
    });
    this._stageContainer.appendChild(this._context.canvas);
    // create renderable element
    this._image = new PWGL.Image(
      PWGL.Texture.loadImage("your/image/path/here")
    );
    this._image.transform.x = width * 0.5;
    this._image.transform.y = height * 0.5;
    this._image.transform.width = 320;
    this._image.transform.height = 240;
    this._image.transform.anchorX = this._image.transform.anchorY = 0.5;
    this._stage2DRenderer.container.addChild(this._image);
    // resize context and renderers
    this._context.setCanvasSize(width, height);
    this._stage2DRenderer.setSize(width, height);
    this._onBeforeUnloadBound = this._onBeforeUnload.bind(this);
    this._renderBound = this._render.bind(this);
    this._requestAnimationFrameId;
    window.addEventListener("beforeunload", this._onBeforeUnloadBound);
    // set fps meter
    PWGLExtensions.FPS.init();
    // start render cycle
    this._requestAnimationFrameId = requestAnimationFrame(this._renderBound);
  }
  _render() {
    if (this._requestAnimationFrameId) {
      PWGLExtensions.FPS.update();
      let delay = PWGLExtensions.FPS.delay;
      console.log("delay:", PWGLExtensions.FPS.delay);
      console.log("fps:", PWGLExtensions.FPS.fps.toFixed(2));
      // rotate the image
      this._image.transform.rotation += 0.001;
      // render the state
      this._stage2DRenderer.render();
      this._requestAnimationFrameId = requestAnimationFrame(this._renderBound);
    }
  }
  _destruct() {
    cancelAnimationFrame(this._requestAnimationFrameId);
    window.removeEventListener("beforeunload", this._onBeforeUnloadBound);
    this._stageContainer.removeChild(this._context.canvas);
    this._stage2DRenderer.destruct();
  }
  _onBeforeUnload() {
    this._destruct();
  }
}
PWGL.Utils.initApplication(function (isWebGl2Supported) {
  if (!isWebGl2Supported) {
    // WebGL 2 is not supported
    return;
  }
  new Application();
});Add filter renderer
class Application {
  constructor() {
    const width = 800;
    const height = 600;
    this._stageContainer = document.body;
    // create context
    this._context = new PWGL.Context();
    // create framebuffer for the stage 2d renderer
    this._stage2DRendererFramebuffer = new PWGL.Framebuffer();
    // create stage 2d renderer
    this._stage2DRenderer = new PWGL.Stage2D({
      config: {
        context: this._context,
      },
    });
    // create filter renderer and set the framebuffer as texture source
    this._filterRenderer = new PWGL.FilterRenderer({
      config: {
        context: this._context,
      },
      sourceTexture: this._stage2DRendererFramebuffer,
      filters: [
        new PWGL.PixelateFilter(5),
        new PWGL.VignetteFilter(1, 3, 1, 0, 0, 0),
      ],
    });
    this._stageContainer.appendChild(this._context.canvas);
    // create renderable element
    this._image = new PWGL.Image(
      PWGL.Texture.loadImage("your/image/path/here")
    );
    this._image.transform.x = width * 0.5;
    this._image.transform.y = height * 0.5;
    this._image.transform.width = 320;
    this._image.transform.height = 240;
    this._image.transform.anchorX = this._image.transform.anchorY = 0.5;
    this._stage2DRenderer.container.addChild(this._image);
    // resize context and renderers
    this._context.setCanvasSize(width, height);
    this._stage2DRenderer.setSize(width, height);
    this._filterRenderer.setSize(width, height);
    this._onBeforeUnloadBound = this._onBeforeUnload.bind(this);
    this._renderBound = this._render.bind(this);
    this._requestAnimationFrameId;
    window.addEventListener("beforeunload", this._onBeforeUnloadBound);
    // set fps meter
    PWGLExtensions.FPS.init();
    // start render cycle
    this._requestAnimationFrameId = requestAnimationFrame(this._renderBound);
  }
  _render() {
    if (this._requestAnimationFrameId) {
      PWGLExtensions.FPS.update();
      let delay = PWGLExtensions.FPS.delay;
      console.log("delay:", PWGLExtensions.FPS.delay);
      console.log("fps:", PWGLExtensions.FPS.fps.toFixed(2));
      // rotate the image
      this._image.transform.rotation += 0.001;
      // render the state to framebuffer
      this._stage2DRenderer.renderToFramebuffer(
        this._stage2DRendererFramebuffer
      );
      // render filters
      this._filterRenderer.render();
      this._requestAnimationFrameId = requestAnimationFrame(this._renderBound);
    }
  }
  _destruct() {
    cancelAnimationFrame(this._requestAnimationFrameId);
    window.removeEventListener("beforeunload", this._onBeforeUnloadBound);
    this._stageContainer.removeChild(this._context.canvas);
    this._stage2DRenderer.destruct();
    this._filterRenderer.destruct();
  }
  _onBeforeUnload() {
    this._destruct();
  }
}
PWGL.Utils.initApplication(function (isWebGl2Supported) {
  if (!isWebGl2Supported) {
    // WebGL 2 is not supported
    return;
  }
  new Application();
});