[SOLVED] How to embed playcanvas into Vue programs instead of vice versa

As mentioned above, I am trying to embed playcanvas into the Vue program. I have retrieved some examples that integrate Vue into Playcanvas. Is there any good way to reverse it? I heard that we can consider using the source version, can anyone give me some guidance? thank.

Hi @kprimo,

I donā€™t have much experience with Vue.js but I know it should be similar with react and angular.

If you search the forums for react you will find some insightful posts:

Hi @kprimo
As @Leonidas linked, you can either embed an iframe and run an app through the public folder, or use the more direct approach with NPM.
It is very similar to the webpack template (https://github.com/playcanvas/playcanvas-webpack)
You can simply npm install playcanvas and then import * as pc from 'playcanvas';.

I modified the HelloWorld component from Vue to contain a Playcanvas app;

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <canvas id="game" style="width: 50em; height: 25em"></canvas>
  </div>
</template>
<script>
import * as pc from 'playcanvas';

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data: function() {
    return {
      app: undefined
    }
  },
  mounted(){
    this.app = new pc.Application(document.getElementById('game'));
    this.app.setCanvasResolution(pc.RESOLUTION_AUTO);
    // create box entity
    const box = new pc.Entity('cube');
    box.addComponent('model', {
        type: 'box'
    });
    this.app.root.addChild(box);

    // create camera entity
    const camera = new pc.Entity('camera');
    camera.addComponent('camera', {
        clearColor: new pc.Color(0.1, 0.1, 0.1)
    });
    this.app.root.addChild(camera);
    camera.setPosition(0, 0, 3);

    // create directional light entity
    const light = new pc.Entity('light');
    light.addComponent('light');
    this.app.root.addChild(light);
    light.setEulerAngles(45, 0, 0);

    // rotate the box according to the delta time since the last frame
    this.app.on('update', dt => box.rotate(10 * dt, 20 * dt, 30 * dt));

    this.app.start();
  }
}
</script>

Hope it helps.

3 Likes

Thank you for sharing, @Ivolutio!

1 Like

Iā€™m actually working on a project that uses Vue.JS right now. Ended up going with a little more unconventional way of integrating by forgoing PlayCanvas NPM package entirely. However, it only takes me a second to export a new version of the project from PlayCanvas and have it working in Vue, so Iā€™ve found that convenient. If you stick the exported files right in the ā€œpublicā€ folder, and use a slightly modified index.html then it should work.

If it helps, this is what my public/index.html looks like:

  <body>
    <!-- Vue.JS app root -->
    <div id="app"></div>
    <!-- PlayCanvas -->
    <link rel="manifest" href="./playcanvas/manifest.json">
    <script src="./playcanvas/playcanvas-stable.min.js"></script>
    <script src="./playcanvas/settings.js"></script>
    <script>
      // PlayCanvas project location settings
      var PREFIX = '/playcanvas/';
      var CONFIG_FILENAME = PREFIX + 'config.json';
      var ASSET_PREFIX = PREFIX;
      var SCRIPT_PREFIX = PREFIX;
    </script>
    <script src="./playcanvas/start.js" defer></script>
    <script src="./playcanvas/loading.js" defer></script>
  </body>

When I export the lastest project from PlayCanvas, I unzip everything into the ./public/playcanvas folder.
image

This method is a little less flexible though. I end up moving the <canvas> DOM element into a Vue component on load.

4 Likes

thank you for your sharing. I think Iā€™ll adopt your plan.

1 Like

Hello, do you have any more examplesļ¼Ÿ

@Ivolutio

Thanks for your help!
Iā€™ve got it to work with your instructions, however Iā€™ve tried to load a model file in json format via loadFromUrl() and I only get html response headers. Iā€™m fairly new to vue and not sure if I configured it (or webpack) correctly.

Here is exactly what I did:

  1. npm install -g @vue/cli (newest version)
  2. vue create projectname
  3. cd projectname
  4. vue add router
  5. npm install playcanvas
  6. edit main.js:
    add lines:
    import * as pc from 'playcanvas';
    Vue.prototype.$pc = pc
  7. Vue router created two pages (Home.vue & About.vue) with routes for me, I edited About.vue and added the following code:
<template>
  <div class="about">
    <canvas id="game" style="width: 50em; height: 25em"></canvas>
  </div>
</template>


<script>
export default {
  name: 'About',

  data() {
    return {
      app: undefined
    }
  },

  mounted() {

    this.app = new this.$pc.Application(document.getElementById('game'));
    this.app.setCanvasResolution(this.$pc.RESOLUTION_AUTO);

    const url = "../assets/models/s01.json";
    const environment = new this.$pc.Entity('Environment');

    // load model file
    this.app.assets.loadFromUrl(url, "model", function (err, asset) {
      environment.addComponent("model");
      environment.model.model = asset.resource;
      environment.setLocalPosition(0, 0, 0);
      this.app.root.addChild(environment);
    });


    // create camera entity
    const camera = new this.$pc.Entity('camera');
    camera.addComponent('camera', {
        clearColor: new this.$pc.Color(0.1, 0.1, 0.1)
    });
    this.app.root.addChild(camera);
    camera.setPosition(0, 0, 6);


    // create directional light entity
    const light = new this.$pc.Entity('light');
    light.addComponent('light');
    this.app.root.addChild(light);
    light.setEulerAngles(45, 0, 0);


    this.app.start();

  }

}

</script>

Then when I use npm run serve and check it in the browser, I get the console error:
ā€œError loading model: s01.json [SyntaxError: Unexpected token < in JSON at position 0]ā€

When checking the headers in chrome dev-tools the response headers are:
Content-Type: text/html; charset=UTF-8

Those should be application/json as far as I know, but I donā€™t know how to make that happen :smiley:

Any help is greatly appreciated.
Cheers

Hi @patriboz
Where is your assets/models/s01.json located? If you put it in the src folder, try moving it to the public folder where your index.html is.

You were right, it was located in /src/, but after copying the assets to the public folder, I still get the same error and same html response header.

In that case, I think you should be able to see the request url for that file in the network tab of chrome. Can you share that, as well as your folder structure of your Vue project?

Sure. The request url is: http://localhost:8080/public/models/s01.json
And the folderstructure is:

project
+.git
+node_modules
+public
  +models
    s01.json
+src
  +assets
  +components
  +pages
    About.vue
    Home.vue
  +router
  App.vue
  main.js
package.json
package-lock.json
README.md

In the code I used this url after copying the model to public: ../../public/models/s01.json

Remove public from the url. I think it should be relative from the public folder, as the siteā€™s index.html is located there.
So the correct path: ./models/s01.json

1 Like

Oh yes, that did the trick. Thank you so much!

Iā€™ve got some other errors now, but I think I can fix them myself. If not, Iā€™ll get back to you :smiley:

EDIT: All fixed. Works like a charm now. Thank you!

1 Like

Hi, this works good. Only thing I discovered is that the MiniStats from the playcanvas-extras do not work. It seems that the ā€œpcā€ directive cannot be accessed :frowning: Does anyone have an Idea? I got the error that pc is undefined inside the playcanvas-extras.js script.

Thanks!

Is the order of the scripts correct? (Ie is playcanvas included before extras)

It might be because ā€˜pcā€™ isnt registered on the ā€˜windowā€™. So when you have created your app, try this: window.pc = pc;

2 Likes

Great, that was the cause @Ivolutio ! Thanks a lot - silly me :frowning:

1 Like

Hi I wonder, how you structure your Vue.js projects and how you use components.
Most components are renderless I guess. I found a project which combines Vue and Babylon.js https://github.com/Beg-in/vue-babylonjs
Would it be a good approach if it work similar like this or I guess it es enough to structure components as .js files and import themā€¦

That is an interesting way to structure your apps, thanks for sharing.
I am personally only using JavaScript to add entities and components to my playcanvas app, but if that other kind of structure makes sense for you I donā€™t see why it wouldnā€™t work. It probably depends on what app youā€™re creating and why youā€™re using Vue in the first place.