{"id":15146697,"url":"https://github.com/mkungla/webxr-webpack-boilerplate","last_synced_at":"2025-10-24T01:31:00.474Z","repository":{"id":46293808,"uuid":"77335976","full_name":"mkungla/webxr-webpack-boilerplate","owner":"mkungla","description":"Starter Kit for building rich, immersive WebXR prototype projects (featuring A-Frame) PWA with Webpack and SASS","archived":false,"fork":false,"pushed_at":"2020-11-13T06:25:35.000Z","size":4655,"stargazers_count":55,"open_issues_count":8,"forks_count":21,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-01-30T22:18:59.632Z","etag":null,"topics":["aframe","aframe-boilerplate","aframe-vr","aframevr","aframexr","boilerplate","boilerplate-application","pwa","sass","service-workers","starter-kit","webpack","webpack-boilerplate","webvr","webxr","webxr-boilerplate"],"latest_commit_sha":null,"homepage":"https://mkungla.github.io/webxr-webpack-boilerplate/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mkungla.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/contributing.md","funding":null,"license":"LICENSE","code_of_conduct":".github/code_of_conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-25T17:23:29.000Z","updated_at":"2024-12-08T12:25:38.000Z","dependencies_parsed_at":"2022-08-28T02:24:05.157Z","dependency_job_id":null,"html_url":"https://github.com/mkungla/webxr-webpack-boilerplate","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkungla%2Fwebxr-webpack-boilerplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkungla%2Fwebxr-webpack-boilerplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkungla%2Fwebxr-webpack-boilerplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkungla%2Fwebxr-webpack-boilerplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mkungla","download_url":"https://codeload.github.com/mkungla/webxr-webpack-boilerplate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237901410,"owners_count":19384384,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aframe","aframe-boilerplate","aframe-vr","aframevr","aframexr","boilerplate","boilerplate-application","pwa","sass","service-workers","starter-kit","webpack","webpack-boilerplate","webvr","webxr","webxr-boilerplate"],"created_at":"2024-09-26T12:03:55.926Z","updated_at":"2025-10-24T01:30:59.748Z","avatar_url":"https://github.com/mkungla.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebXR Webpack Boilerplate\n\n**Starter Kit for building rich, immersive WebXR projects (featuring [A-Frame][aframe-link]) PWA with Webpack, Handlebars and SASS**\n\n[![Project License][license-img]][license-link] [![A-Frame Version][aframe-img]][aframe-link]\n\n## Introduction\n\nThe goal of WebXR Webpack Boilerplate is to provide a high-quality, high-performance code base to accelerate WebXR development and specially prototyping. It is designed to be flexible in order to support rapid implementation and customization within your project. — **take a look at [demo][demo-link]**  \n\n\u003e Personally I use this boilerplate mostly for quick prototyping WebXR ideas,  \nwhile final product going to production may require major refactoring the code base.  \n[@mkungla](https://github.com/mkungla)\n\n**Project build status**\n\n| Linux | macOS | Windows |\n| --- | --- | --- |\n| [![TravisCI Build Status][travis-img]][travis-link] | [![CircleCI Build Status][circleci-img]][circleci-link] | [![AppveyorCI Build Status][appveyor-img]][appveyor-link] |\n\n[![Grade Badge][codacy-grade-img]][codacy-grade-link]\n[![Coverage Badge][coverage-img]][coverage-link]\n[![Dependencies][dep-status-img]][dep-status-link]\n[![Dev Dependencies][devdep-status-img]][devdep-status-link]\n\n- [Overview](#overview)\n  * [Custom A-Frame Theme](#custom-a-frame-theme)\n  * [Project structure](#project-structure)\n- [Getting Started](#getting-started)\n  * [Setup project based on this repository](#setup-project-based-on-this-repository)\n    + [(option 1) Create fork to contribute back to this repository](#create-fork-to-contribute-back-to-this-repository)\n    + [(option 2) Create new project based on this repository and keep commit history](#create-new-project-based-on-this-repository-and-keep-commit-history)\n    + [(option 3) Create new project based on this repository without commit history](#create-new-project-based-on-this-repository-without-commit-history)\n  * [Build and development server configuration](#build-and-development-server-configuration)\n  * [First run](#first-run)  \n- [Development](#development)\n  * [Minimal example of app.js](#minimal-example-of-app-js)\n  * [Example Addon](#example-addon)\n  * [Add A-Frame components](#add-a-frame-components)\n  * [Add 3rd party libraries](#add-3rd-party-libraries)\n- [Build and deploy](#build-and-deploy)\n  * [Static app](#static-app)\n  * [Build and run Docker image](#build-and-run-docker-image)\n\n\n## Overview\nHere is overview of WebXR Webpack Boilerplate project and what's included.\n\n### Custom A-Frame Theme\n\n| red | blue | green | yellow |\n| :---: | :---: | :---: | :---: |\n| ![Theme red][screeenshot-theme-red] | ![Theme blue][screeenshot-theme-blue]  | ![Theme -green][screeenshot-theme-green]  | ![Theme yellow][screeenshot-theme-yellow] |\n\nYou can change A-Frame themes by modifying [./app.json](app.json) sassTheme property which sets SASS configuration  `$theme` variable\n\n```json\n// Color themes red !default, yellow, green, blue\n{\n    \"sassTheme\": \"red\"\n}\n```\n\nif that property is not set then default theme is used in [src/style/_theme-vars.scss](src/style/_theme-vars.scss)\n\n```scss\n// Color themes red !default, yellow, green, blue\n$theme: red !default;\n```\n\n---\n\n### Project structure\nProject `./src` contains some unnecessary files which are included for demo and example purposes. You can remove all of these files and associated references and imports from your project.\n\n- **.circleci** [CircleCI][circleci-site] Continuous Integration and Delivery configurations, feel free to delete that if you dont use [CircleCI][circleci-site] as your CI provider. This project uses [CircleCI][circleci-site] for macOS builds.\n- **.github** All Github related config files.\n- **build** Build directory `yarn run build`.\n- **devel** Development related files like webpack and project configuration files.\n- **src** Project source files.\n  - **hbs** Project handlebars templates\n    - ***index.hbs*** outputs `./build/index.html`\n    - **partials** handlebars partials used within views\n      - **aframe** partials for A-Frame entities\n      - **app** app partials\n      - **html** common html partials like headrs and footers\n      - **scenes** good place to put markup of your different WebXR scenes.\n\n  - **js** Application javascript code and entry points\n    - **aframe** A-Frame compnents,systems.shaders. Create your custom A-Frame components to this directory.\n    - ***lib-aframe.js*** In this file you would import A-Frame, external npm components and also your custom components which will be bundled into one single file ensuring that your component registration is done right.\n    - ***app.js*** Main app entrypoint. File where you configure the application, while you should avoid writing your application logic code there. Instead use [./src/js/application/addons](src/js/application/addons) for that. Take look at [Minimal example of app.js](#minimal-example-of-app-js)\n    - **application** Application javascript code\n      - **addons** Most of your application logic should be here in application addons. Take a look at [Example Addon](#example-addon)\n      - **core** Application core most of cases you don't need to edit this code however if you find something add or enhance there please consider opening a pull request and contribute your modification to this project.\n    - ***background.worker.js*** Background web Worker if you need to use one, which requires you do modifications in [./src/js/application/core/index.js](src/js/application/core/index.js) how your worker is behaving and change webpack config in [./devel/webpack/configure-app.js](devel/webpack/configure-app.js) to load and build that Worker correctly.\n    - ***vendors.js*** In this file you would import all your external vendor dependencies `e.g. Lodash, jQuery etc.` If any of vendor libraries have embedded styles then these will be extracted to `./buid/app/css/vendors.css` so make sure that you import it in your handlebars header template used `e.g.` [./src/hbs/partials/html/header.hbs](src/hbs/partials/html/header.hbs) If you need to customize some vendor styles then use [./src/style/vendors/vendors-style.scss](src/style/vendors/vendors-style.scss) for that.\n  - **pwa** Progressive Web App entrypoint, service worker and other PWA assets. Everything in this directory could be taken as independent app from main app and since the handlebars templates result html pages in `./build` root then you should make sure that you dont have conflicting file names which would result only one of them being created. If you want to change that behavior edit [./devel/webpack/configure-pwa.js](devel/webpack/configure-pwa.js) config. Also note that even though you can cross reference handlebar templates within webpack cross compiler you should try to avoid that and keep your partials related to views found in `./src/pwa` in `./src/pwa/pwa-partials`\n    - ***logo.png*** Changing that logo will generate all the variations of your logo under `./build/assets/pwa/` using [webapp-webpack-plugin][webapp-webpack-plugin-link]\n    - ***offline.js*** entrypoint you could use for app when application is offline.\n    - ***offline.scss*** example offline style entry\n    - **pwa-partials** handlebars partials related to views found in `./src/pwa`\n  - **static** Static assets copied over to `./build/assets/static`. By default only `CopyWebpackPlugin` is used if you need more control edit [./devel/webpack/configure-static-assets.js](devel/webpack/configure-static-assets.js) config file.\n    - **audio**\n    - **images**\n    - **models**\n    - **video**\n  - **style** Application style scss files\n    - ***app.scss*** main app entrypoint\n    - **theme** directory to contain your theme sass partials\n      - ***_theme-base.scss*** theme base file, if that file grows to big separate your design into smaller partials under same directory and include these in [./src/style/app.scss](src/style/app.scss)\n    - ***_theme-vars.scss*** scss file where you define your theme variables\n    - **vendors** Vendor styles\n      - ***vendors-style.scss*** vendor style entrypoint\n- **tests** tests.\n- **tmp** temporary and local files which are not tracked by git.\n\n---\n\n## Getting Started\ninstructions to set up your project\n\n### Setup project based on this repository\nFollow one of the 3 options below which suits best for your needs. Options below are shown for [github.com](github.com) public and private repositories, so if your project will be hosted elsewhere you know your self what you have to change.  \n\n#### Create fork to contribute back to this repository\n(option 1)\n\n**First** Fork this repository in [github.com](https://github.com/digabrain/webxr-webpack-boilerplate)\n\n**Next** navigate to directory where you keep your projects and set following temporary environment variables\n\n```bash\ncd \u003cyour-projects\u003e\nGITHUB_USERNAME=\"\u003cgithub-username\u003e\"\n```\n\n**Next** clone full copy of this repository and set remotes to be able to sync your repository with upstream\n```bash\ngit clone --origin github/\"$GITHUB_USERNAME\" git@github.com:$GITHUB_USERNAME/webxr-webpack-boilerplate.git\ncd webxr-webpack-boilerplate\ngit remote add github/digaverse git@github.com:digaverse/webxr-webpack-boilerplate.git\n```\n\u003csup\u003eand start hacking.\u003c/sup\u003e\n\n#### Create new project based on this repository and keep commit history\n(option 2)\n\n**First** navigate to directory you keep your projects and set following temporary environment variables\n\n```bash\ncd \u003cyour-projects\u003e\nGITHUB_USERNAME=\"\u003cgithub-username\u003e\"\n# PROJECT_NAME should be valid github repository name\nPROJECT_NAME=\"\u003cyour-new-project-name\u003e\"\n```\n\n**Next** go and create new public or private repository under `$GITHUB_USERNAME` and set project name same as `$PROJECT_NAME`. While creating the repository make sure that no default files are created,\n\n- unselect `Initialize this repository with a README `\n- make sure that both `Add .gitignore and Add a license` are set to NONE  \n\n**Next**\n\n```bash\ngit clone --bare git@github.com:digaverse/webxr-webpack-boilerplate.git\ncd webxr-webpack-boilerplate.git\ngit push --mirror git@github.com:$GITHUB_USERNAME/$PROJECT_NAME.git\ncd ..\nrm -rf webxr-webpack-boilerplate.git\ngit clone --origin github/\"$GITHUB_USERNAME\" git@github.com:$GITHUB_USERNAME/$PROJECT_NAME.git\n```\n\n\u003csup\u003eand start hacking.\u003c/sup\u003e\n\n##### Create new project based on this repository without commit history\n(option 3)\n\n**First** navigate to directory you keep your projects and set following temporary environment variables\n\n```bash\ncd \u003cyour-projects\u003e\nGITHUB_USERNAME=\"\u003cgithub-username\u003e\"\n# PROJECT_NAME should be valid github repository name\nPROJECT_NAME=\"\u003cyour-new-project-name\u003e\"\n```\n\n**Next** go and create new public or private repository under `$GITHUB_USERNAME` and set project name same as `$PROJECT_NAME`. While creating the repository make sure that no default files are created,\n\n- unselect `Initialize this repository with a README `\n- make sure that both `Add .gitignore and Add a license` are set to NONE  \n\n```bash\ngit clone --depth=1 git@github.com:digaverse/webxr-webpack-boilerplate.git $PROJECT_NAME\ncd \"$PROJECT_NAME\"\nrm -rf .git\ngit init\ngit add -A \u0026\u0026 git commit -m\"initial commit\"\ngit remote add github/\"$GITHUB_USERNAME\" git@github.com:$GITHUB_USERNAME/$PROJECT_NAME.git\ngit push -u github/\"$GITHUB_USERNAME\" master\n```\n\n\u003csup\u003eand start hacking.\u003c/sup\u003e\n\n---\n\n### Build and development server configuration\n\nMost of build and configuration options can be set in [./app-dev.json](app-dev.json), but if you need more control or customization look into config files in [./devel](devel) directory.\n\n---\n\n### First run\n\nmake sure you have [yarn](https://yarnpkg.com/lang/en/docs/install/) installed, alternately you can use `npm` command instead `yarn`\n\n```bash\n# copy app-dev.json\ncp example.app-dev.json app-dev.json\n# copy  app.json\ncp example.app.json app.json\n# install and setup\nyarn install\nyarn run setup # first time run generates SSL certificates so we can serve https and http2 locally\nyarn build # creates static assets under ./build directory\n```\n\nto start the dev server run\n\n```bash\nyarn start\n```\n\nYou may need to update/rebuild static assets sometimes then just run `yarn run build` before `yarn start`.\n\nAnd now open your browser https://localhost:9000 and accept self signed certificates.\n\n---\n\n## Development\n\napplication configuration file is [./app.json](app.json) all properties will be available within both in handlebars templates and `PROJECT.{property}` and in application/addon level `this.session.get('config').{property}` while most of webpack config is set in [./app-dev.json](app-dev.json). Keep in mind when you edit these files you have to restart development server in order these changes to take effect.\n\n\n### Minimal example of app js\n\nHere is minimal Example for [./src/js/app.js](src/js/app.js)\n\n```javascript\n/* global PROJECT */\n\nimport Application from './application/core'\n// import application addons you want to register\n// import yourAddon from './application/addons/your-addon'\n\nconst app = new Application(PROJECT)\n\n// Reqister all application addons by calling registerAddon\n// app.registerAddon(yourAddon, addonConfigObject)\n\n// Start the application as soon as possible\napp.start().then((log) =\u003e {\n  log.debug('webapp is running callback')\n}).catch((err) =\u003e {\n  console.error(err)\n})\n```\n\nProject is shipped with example adding controls to `start/stop/play/pause` application.\nNOTE that application `start/stop/play/pause` does not affect A-Frame scene. If you wich to do so then you have to set `{\"ppaframe\": true}` in [./app.json](app.json). Also when you have page which does not have A-Frame scene but in header template you load `lib-aframe.js` then application will not play since A-Frame core system is paused when `\u003ca-scene\u003e` is not found, so you may better create different header file wich you include in pages which do not have a A-Frame scene so that application falls back to using `window.requestAnimationFrame`.\n\n---\n\n### Example Addon\n\nMost of application logic is added to application by creating and registering Addons. bellow is outline of how to define your Addon.\n\n```javascript\n/* ./application/addons/your-addon */\nexport default {\n  name: 'your-addon',\n  // this addon will not be reqistered if aframe is not present on loaded page\n  // default false\n  aframeRequired: true,\n  // You can set configuration defaults to your Addon here\n  // or set that object as second parameter when you register\n  // your Addon by calling app.registerAddon()\n  data: {},\n\n  setup() {\n    // Called once when you register the Addon\n    // Sets the data to values passed to registerAddon 2 param\n\n    // Within addon following properties are set\n    //\n    // this.aframeRequired  - is aframe required\n​    // this.enabled         - is addon enabled\n​    // this.isPlaying       - is addon playing\n    // this.name            - addon given name\n    // this.data            - addon configuration  \n​    // this.app             - reference to app\n    //   this.app.session   - access application session\n    //   this.app.store     - app localStorage\n    //   this.app.addons['addon-name'] - access other registered addons\n    //     ``\n    // this.log             - gives named logger for current addon.\n    //      Displaying these messages depends on\n    //      your ./app.json setting which logLevel is set\n    //        this.log.debug(args...)\n    //        this.log.info(args...)\n    //        this.log.ok(args...)\n    //        this.log.warn(args...)\n    //        this.log.error(args...)\n  },\n\n  start() {\n    // Called every time when you start the application\n    // and everytime when you call application start after stoping it.\n  },\n\n  play() {\n    // Called every time when application play is called\n  },\n\n  pause() {\n    // Called every time when application pause is called\n  },\n\n  tick() {\n    // Called in every render loop when application is playing\n  },\n\n  dispose() {\n    // Called when application stop is called.\n    // Currently dispose does not delete this Addon\n    // so calling application start after stop will call\n    // this objects .start again, but not .setup .\n    // This behavior may change in this project skeleton\n    // in the future allowing you to dispose Addons on\n    // run time and re register Addons on demand.\n    // Therefore the name dispose instead of stop\n    // which it is right now by behavior.\n  }\n}\n\n```\n\n----\n\n#### Add A-Frame components\n\n```\nyarn add \u003csome-aframe-component\u003e\n```\nadd import statement to [./src/js/lib-aframe.js](src/js/lib-aframe.js)\n\n---\n\n#### Add 3rd party libraries\n\n```\nyarn add \u003csome-library\u003e\n```\n\nif needed add import statement to [./src/js/vendors.js](src/js/vendors.js) if you want to bundle that dependency together with other 3rd party libraries or sass import statment to [./src/style/vendors/vendors-style.scss](src/style/vendors/vendors-style.scss) when adding 3rd party styles.\n\n---\n\n## Build and deploy\n\n### Static app\n\nTo build static site just run\n\n```bash\n# (not required): do sign version git tags\nyarn config set version-sign-git-tag true\n# (not required): to remove \"v\" version-tag-prefix\nyarn config set version-tag-prefix \"\"\n# (not required): do update version\nyarn version\n# build everything into ./build directory\nyarn build\n# git push to remote\ngit push \u0026\u0026 git push --tags\n```\n\nContents of [./build](build) directory are ready to be served just copy contents of `./build` directory to your webserver root. e.g. [demo][demo-link] is hosted with github pages, take a look at [gh-pages](https://github.com/digaverse/webxr-wb-test/tree/gh-pages) branch for example\n\n\n### Build and run Docker image\n\nrequires `yarn build` before\n\n```bash\nyarn run build:docker\n```\nand fire up your docker image\n\n```bash\nyarn run start:docker\n```\n\nAnd now open your browser https://localhost:8080\n\n\u003c!-- ASSETS and LINKS --\u003e\n\u003c!-- License --\u003e\n\n[license-img]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square\n[license-link]: https://raw.githubusercontent.com/digaverse/webxr-webpack-boilerplate/master/LICENSE\n\n\u003c!-- A-Frame --\u003e\n[aframe-img]: https://img.shields.io/badge/a--frame-0.8.2-FC3164.svg?style=flat-square\n[aframe-link]: https://aframe.io/\n[aframe-logo]: assets/images/aframe/logo-152.png\n\n\u003c!-- demo --\u003e\n[demo-link]: https://digaverse.github.io/webxr-webpack-boilerplate\n\n\u003c!-- travis-ci --\u003e\n[travis-img]: https://travis-ci.org/digaverse/webxr-webpack-boilerplate.svg?branch=master\n[travis-link]: https://travis-ci.org/digaverse/webxr-webpack-boilerplate\n\n\u003c!-- circleci --\u003e\n[circleci-img]: https://circleci.com/gh/digaverse/webxr-webpack-boilerplate/tree/master.svg?style=svg\n[circleci-link]: https://circleci.com/gh/digaverse/webxr-webpack-boilerplate/tree/master\n\n\u003c!-- appveyor --\u003e\n[appveyor-img]: https://ci.appveyor.com/api/projects/status/fqyc4q7p1tya4dld/branch/master?svg=true\n[appveyor-link]: https://ci.appveyor.com/project/mkungla/webxr-webpack-boilerplate\n\n\u003c!-- Codacy Badge Grade --\u003e\n[codacy-grade-img]: https://api.codacy.com/project/badge/Grade/4210783bda4d4dc9af327a1480cff45b\n[codacy-grade-link]: https://www.codacy.com/app/mkungla/webxr-webpack-boilerplate?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=digaverse/webxr-webpack-boilerplate\u0026amp;utm_campaign=Badge_Grade\n\n\u003c!-- Coverage Badge --\u003e\n[coverage-img]: https://img.shields.io/coveralls/github/digaverse/webxr-webpack-boilerplate.svg\n[coverage-link]: https://github.com/digaverse/webxr-webpack-boilerplate\n\n\u003c!-- Dependencies --\u003e\n[dep-status-img]: https://david-dm.org/digaverse/webxr-webpack-boilerplate/status.svg\n[dep-status-link]: https://david-dm.org/digaverse/webxr-webpack-boilerplate#info=dependencies\n\n[devdep-status-img]: https://david-dm.org/digaverse/webxr-webpack-boilerplate/dev-status.svg\n[devdep-status-link]: https://david-dm.org/digaverse/webxr-webpack-boilerplate#info=devDependencies\n\n[circleci-site]: https://circleci.com/\n\n[webapp-webpack-plugin-link]: https://github.com/brunocodutra/webapp-webpack-plugin\n\n\u003c!-- images --\u003e\n[screeenshot-theme-red]: src/static/images/screenshots/theme-red.png\n[screeenshot-theme-blue]: src/static/images/screenshots/theme-blue.png\n[screeenshot-theme-green]: src/static/images/screenshots/theme-green.png\n[screeenshot-theme-yellow]: src/static/images/screenshots/theme-yellow.png\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkungla%2Fwebxr-webpack-boilerplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmkungla%2Fwebxr-webpack-boilerplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkungla%2Fwebxr-webpack-boilerplate/lists"}