{"_id":"@11ways/canvas-webgl","_rev":"2-ac9c363283daa578a19cfcb56ed73e74","name":"@11ways/canvas-webgl","description":"Integration of node-canvas and headless-gl.","dist-tags":{"latest":"0.3.1"},"versions":{"0.3.0":{"name":"@11ways/canvas-webgl","version":"0.3.0","keywords":[],"author":{"name":"akira-cn"},"license":"MIT","_id":"@11ways/canvas-webgl@0.3.0","maintainers":[{"name":"skerit","email":"jelle@kipdola.be"}],"dist":{"shasum":"12a464181a52494814abdcae8ab3d49ea44ae727","tarball":"https://registry.npmjs.org/@11ways/canvas-webgl/-/canvas-webgl-0.3.0.tgz","fileCount":24,"integrity":"sha512-God2naLrDKjhQ10bQJcPG0CMmhzqjemmbqSU+Ta8Pe8dRgofwCTvcs5SZCOrbdMEJp6breCRUHOWTgPxziMVfw==","signatures":[{"sig":"MEQCIHIxIqRoU1Q3vrPJuh2pfw1AjzF14zTmBlGyX6J/3n0rAiA+OfKhhwul7PJC/s+Eex9aPuekpBOwLf01GBryckTu7w==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":2364840,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJiCRLgCRA9TVsSAnZWagAAJIYP/REuzV4CBFA46BU7EtwG\n2E0ZjIgKwbTQhePNpTHqQ9MYR3TaKDSape6M56iLau+MlSgC7oXEO1T41tQg\nFBYkmjmMq2qJ6cThHTYp4dBMPRh2ybxgKlMre0qPxLNU846ezFMzMsxvAm/G\nqcWO+f16XyFDCqbjUikdqmm1x8QTBmHdr0f6Iy4UXEly+aw6+CIpr1ATTCfQ\nIFIWnHvo59hpr7QmhqR1RcxdKxBS16nD/78DFQa/b81V8ExLhOl74XN43nfz\nu/rEk4lyD0DZ3b+kyWTa6dSuBoZtoR9ahmhvwumtanMX8ToDrpPmpafo425U\n7auoo/4Qk9deZu0MQKr8OXQUd6lK045vp6TlUO35PIFfcodIr+ATypML+SMt\nUCsK9fLAJP5xo/8AG2Vfs/rdSjaKVXHAozihRgxO0PGimkCzhxk4RwtKscus\nalp2hehvClH7Z97kvIOMifkAxpjLpHRjeSwpcJXo+Bp/9cA97GhgTf2v0eZ6\n85e3eG32w0zX55B40G/NfxyrLehts/u1UTmwa58Wg8W5F10njNl/w2WXQTar\nkA5loHCz1GhYo3I30DGDLL9wMjPYvpA28Mun5la3CkQT5+F0E/hEtFRyB/gP\nGMbL4mQD6f/yXezfvw3BfRMHVakEhNC5sWWOtuO+THndTrU9xu5xVpuzkhub\nCtE5\r\n=euhj\r\n-----END PGP SIGNATURE-----\r\n"},"main":"lib/index.js","gitHead":"88647ec3eb47ed52eca2d0dd3c0f200e4b7f1846","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"skerit","email":"jelle@kipdola.be"},"_npmVersion":"8.1.2","description":"Integration of node-canvas and headless-gl.","directories":{},"_nodeVersion":"16.13.2","dependencies":{"gl":"~5.0.0","canvas":"~2.9.0"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^15.2.1","three":"^0.110.0","claygl":"^1.3.0","eslint":"^5.16.0","babylonjs":"^4.0.3","gifencoder":"^2.0.1","jsdom-global":"^3.0.2","@mesh.js/core":"^0.6.6","eslint-plugin-html":"^5.0.5","eslint-config-sprite":"^1.0.6"},"_npmOperationalInternal":{"tmp":"tmp/canvas-webgl_0.3.0_1644761824742_0.22922236806771834","host":"s3://npm-registry-packages"}},"0.3.1":{"name":"@11ways/canvas-webgl","version":"0.3.1","description":"Integration of node-canvas and headless-gl.","main":"lib/index.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"keywords":[],"author":{"name":"akira-cn"},"license":"MIT","devDependencies":{"@mesh.js/core":"^0.6.6","babylonjs":"^4.0.3","claygl":"^1.3.0","eslint":"^5.16.0","eslint-config-sprite":"^1.0.6","eslint-plugin-html":"^5.0.5","gifencoder":"^2.0.1","jsdom":"^15.2.1","jsdom-global":"^3.0.2","three":"^0.110.0"},"dependencies":{"canvas":"~2.11.2","gl":"~8.0.2"},"_id":"@11ways/canvas-webgl@0.3.1","gitHead":"17a6a5b1f1b8652dd60bce309a9519d96de0ace5","_nodeVersion":"20.13.1","_npmVersion":"10.5.2","dist":{"integrity":"sha512-qyk9RuPK3aDIb4paurge/rVIUxSKd7QPIg5qzVX79LgyY8lKVqv0XUQ8d05mWJV/RA/BI8j/kdf/s5Ymhuelcw==","shasum":"127835b7ad7c1c22fd344fd7cf3b8671c853a2d7","tarball":"https://registry.npmjs.org/@11ways/canvas-webgl/-/canvas-webgl-0.3.1.tgz","fileCount":24,"unpackedSize":2364841,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDo9Dtx2/Rmeqj2EdRAd5WBojASDi+Q3O5tSqYqT1DebgIhAOfG/1svJYruW4YOmNgtQG5bvMeMek31+AanmkN2ER55"}]},"_npmUser":{"name":"skerit","email":"jelle@kipdola.be"},"directories":{},"maintainers":[{"name":"skerit","email":"jelle@kipdola.be"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/canvas-webgl_0.3.1_1720426661154_0.27352341276290026"},"_hasShrinkwrap":false}},"time":{"created":"2022-02-13T14:17:04.692Z","modified":"2024-07-08T08:17:41.548Z","0.3.0":"2022-02-13T14:17:04.970Z","0.3.1":"2024-07-08T08:17:41.372Z"},"maintainers":[{"name":"skerit","email":"jelle@kipdola.be"}],"author":{"name":"akira-cn"},"keywords":[],"license":"MIT","readme":"# canvas-webgl\r\n\r\nIntegration of [node-canvas](https://github.com/Automattic/node-canvas) and [headless-gl](https://github.com/stackgl/headless-gl).\r\n\r\n## Installation\r\n\r\n### System Dependencies\r\n\r\nYou will need to install some system packages in order to compile the required dependencies. Take a look here:\r\n\r\nhttps://www.npmjs.com/package/gl#user-content-system-dependencies\r\n\r\n### Xvfb\r\n\r\nOn headless systems, you'll also have to make sure to install Xvfb and to have it running in the background.\r\n\r\nYou can use this systemd service to make sure Xvfb is always running:\r\n\r\n```systemd\r\n[Unit]\r\nDescription=X Virtual Frame Buffer Service\r\nAfter=network.target\r\n\r\n[Service]\r\nExecStart=/usr/bin/Xvfb :99 -screen 0 1024x768x24\r\n\r\n[Install]\r\nWantedBy=multi-user.target\r\n```\r\n\r\n## Demos:\r\n\r\n#### with threejs\r\n\r\n```js\r\nconst fs = require('fs');\r\nconst THREE = require('three');\r\nconst GIFEncoder = require('gifencoder');\r\nconst {createCanvas} = require('../lib');\r\n\r\nconst width = 512,\r\n  height = 512;\r\n\r\nconst scene = new THREE.Scene();\r\nconst camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);\r\n\r\nconst canvas = createCanvas(width, height);\r\n\r\nconst renderer = new THREE.WebGLRenderer({\r\n  canvas,\r\n});\r\n\r\nconst geometry = new THREE.BoxGeometry(1, 1, 1);\r\nconst material = new THREE.MeshBasicMaterial({color: 0x00ff00});\r\nconst cube = new THREE.Mesh(geometry, material);\r\nscene.add(cube);\r\n\r\ncamera.position.z = 5;\r\n\r\nconst encoder = new GIFEncoder(width, height);\r\nencoder.createReadStream().pipe(fs.createWriteStream('./snapshot/threejs-cube.gif'));\r\nencoder.start();\r\nencoder.setRepeat(0); // 0 for repeat, -1 for no-repeat\r\nencoder.setDelay(16); // frame delay in ms\r\nencoder.setQuality(10); // image quality. 10 is default.\r\n\r\nlet idx = 0;\r\nfunction update() {\r\n  cube.rotation.x += 0.01;\r\n  cube.rotation.y += 0.01;\r\n  renderer.render(scene, camera);\r\n  if(idx > 0) {\r\n    encoder.addFrame(canvas.__ctx__);\r\n    console.log(`add frame ${idx}`);\r\n  }\r\n  idx++;\r\n  if(idx < 500) {\r\n    setTimeout(update, 16);\r\n  }\r\n}\r\nupdate();\r\n```\r\n\r\n![](https://p2.ssl.qhimg.com/t01abe0b6dc18945e43.gif)\r\n\r\n#### with claygl\r\n\r\n```js\r\nconst fs = require('fs');\r\nconst GIFEncoder = require('gifencoder');\r\nconst clay = require('claygl');\r\nconst {createCanvas} = require('../lib');\r\n\r\nconst width = 512,\r\n  height = 512;\r\n\r\nconst canvas = createCanvas(width, height);\r\n\r\nconst encoder = new GIFEncoder(width, height);\r\n\r\nlet idx = 0;\r\n\r\n// polyfill\r\nglobal.document = {\r\n  createElement() {\r\n    return createCanvas(300, 150);\r\n  },\r\n};\r\n\r\nclay.application.create(canvas, {\r\n\r\n  width,\r\n  height,\r\n\r\n  init(app) {\r\n    // Create camera\r\n    this._camera = app.createCamera([0, 2, 5], [0, 0, 0]);\r\n\r\n    // Create a RED cube\r\n    this._cube = app.createCube({\r\n      color: [1, 0, 0],\r\n    });\r\n\r\n    // Create light\r\n    this._mainLight = app.createDirectionalLight([-1, -1, -1]);\r\n    // app.createAmbientLight('#fff', 1.0);\r\n\r\n    encoder.createReadStream().pipe(fs.createWriteStream('./snapshot/claygl-cube.gif'));\r\n    encoder.start();\r\n    encoder.setRepeat(0); // 0 for repeat, -1 for no-repeat\r\n    encoder.setDelay(16); // frame delay in ms\r\n    encoder.setQuality(10); // image quality. 10 is default.\r\n  },\r\n  loop(app) {\r\n    this._cube.rotation.rotateY(16 / 1000);\r\n    if(idx > 0) {\r\n      encoder.addFrame(canvas.__ctx__);\r\n      console.log(`add frame ${idx}`);\r\n    }\r\n    idx++;\r\n    if(idx > 197) {\r\n      process.exit(-1);\r\n    }\r\n  },\r\n});\r\n```\r\n\r\n![](https://p3.ssl.qhimg.com/t011d79d79adb1b649e.gif)\r\n\r\n#### with babylonjs\r\n\r\n```js\r\nconst fs = require('fs');\r\nconst BABYLON = require('babylonjs');\r\nconst {createCanvas} = require('../lib');\r\n\r\n// polyfill\r\nglobal.HTMLElement = function () {};\r\nglobal.window = {\r\n  setTimeout,\r\n  addEventListener() {},\r\n};\r\nglobal.navigator = {};\r\nglobal.document = {\r\n  createElement() {\r\n    return createCanvas(300, 150);\r\n  },\r\n  addEventListener() {},\r\n};\r\n\r\n// Get the canvas DOM element\r\nconst canvas = createCanvas(512, 512);\r\n\r\n// Load the 3D engine\r\nconst engine = new BABYLON.Engine(canvas, true, {preserveDrawingBuffer: true, stencil: true});\r\n\r\n// CreateScene function that creates and return the scene\r\nconst createScene = function () {\r\n  // Create a basic BJS Scene object\r\n  const scene = new BABYLON.Scene(engine);\r\n  // Create a FreeCamera, and set its position to {x: 0, y: 5, z: -10}\r\n  const camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 5, -10), scene);\r\n  // Target the camera to scene origin\r\n  camera.setTarget(BABYLON.Vector3.Zero());\r\n  // Attach the camera to the canvas\r\n  camera.attachControl(canvas, false);\r\n  // Create a basic light, aiming 0, 1, 0 - meaning, to the sky\r\n  const light = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0, 1, 0), scene);\r\n  // Create a built-in \"sphere\" shape; its constructor takes 6 params: name, segment, diameter, scene, updatable, sideOrientation\r\n  const sphere = BABYLON.Mesh.CreateSphere('sphere1', 16, 2, scene, false, BABYLON.Mesh.FRONTSIDE);\r\n  // Move the sphere upward 1/2 of its height\r\n  sphere.position.y = 1;\r\n  // Create a built-in \"ground\" shape; its constructor takes 6 params : name, width, height, subdivision, scene, updatable\r\n  const ground = BABYLON.Mesh.CreateGround('ground1', 6, 6, 2, scene, false);\r\n  // Return the created scene\r\n  return scene;\r\n};\r\n\r\n// call the createScene function\r\nconst scene = createScene();\r\n\r\nscene.render();\r\n\r\nfs.writeFileSync('./snapshot/snap-babylon.png', canvas.toBuffer());\r\n```\r\n\r\n![](https://p5.ssl.qhimg.com/t01d9af9c9428b18585.png)\r\n\r\n#### with mesh.js\r\n\r\n```js\r\nconst fs = require('fs');\r\nconst {Renderer, Figure2D, Mesh2D} = require('@mesh.js/core');\r\nconst {createCanvas, loadImage} = require('../lib');\r\n\r\nconst width = 512,\r\n  height = 512;\r\n\r\nconst canvas = createCanvas(width, height);\r\n\r\nconst renderer = new Renderer(canvas, {contextType: 'webgl'});\r\n\r\nconst f = new Figure2D();\r\nf.rect(0, 0, 512, 512);\r\n\r\nconst m = new Mesh2D(f, canvas);\r\nm.setFill({color: '#ddd'});\r\n\r\nconst url = 'https://p0.ssl.qhimg.com/t01a72262146b87165f.png';\r\n\r\nloadImage(url).then((image) => {\r\n  const texture = renderer.createTexture(image);\r\n  m.setTexture(texture);\r\n  renderer.drawMeshes([m]);\r\n  fs.writeFileSync('./snapshot/snap-spritejs.png', canvas.toBuffer());\r\n});\r\n```\r\n\r\n![](https://p2.ssl.qhimg.com/t01c3b877430c190327.png)\r\n\r\n#### with jsdom\r\n\r\nYou can use canvas2d and webgl as running in web browsers.\r\n\r\n```js\r\nconst fs = require('fs');\r\nconst {Renderer, Figure2D, Mesh2D} = require('@mesh.js/core');\r\n\r\nrequire('jsdom-global')();\r\n\r\nconst {mockDOM} = require('../lib');\r\nmockDOM(window);\r\n\r\nconst canvas = document.createElement('canvas');\r\ncanvas.width = 512;\r\ncanvas.height = 512;\r\n\r\nconst renderer = new Renderer(canvas, {contextType: 'webgl'});\r\n\r\nconst f = new Figure2D();\r\nf.rect(0, 0, 512, 512);\r\n\r\nconst m = new Mesh2D(f, canvas);\r\nm.setFill({color: '#ddd'});\r\n\r\nconst url = 'https://p0.ssl.qhimg.com/t01a72262146b87165f.png';\r\n\r\nrenderer.loadTexture(url).then((texture) => {\r\n  m.setTexture(texture);\r\n  renderer.drawMeshes([m]);\r\n  fs.writeFileSync('./snapshot/snap-meshjs2.png', canvas.toBuffer());\r\n});\r\n```","readmeFilename":"README.md"}