├── plugin-build
├── .gitkeep
└── .gitignore
├── inc
├── threeobjectloaderinit
│ ├── index.css
│ └── index.js
├── hooks.php
├── functions.php
├── avatars
│ ├── Idle.fbx
│ ├── Running.fbx
│ ├── talking.fbx
│ ├── walking.fbx
│ ├── friendly.fbx
│ └── 3ov_default_avatar.vrm
├── fonts
│ └── roboto.woff
└── assets
│ ├── audio_icon.png
│ ├── light_icon.png
│ └── default_grid.glb
├── .eslintrc
├── .prettierrc
├── assets
└── wporg
│ ├── banner-772x250.jpg
│ ├── icon-128x128.png
│ ├── icon-256x256.png
│ └── banner-1544x500.jpg
├── languages
├── three-object-viewer.mo
├── three-object-viewer-ja.mo
├── three-object-viewer-es_MX.mo
├── three-object-viewer-es_MX-three-object-viewer-spawn-point-block-editor-script.json
├── three-object-viewer-ja-three-object-viewer-spawn-point-block-editor-script.json
├── three-object-viewer-es_MX-three-object-viewer-three-text-block-editor-script.json
├── three-object-viewer-es_MX-three-object-viewer-three-light-block-editor-script.json
├── three-object-viewer-ja-three-object-viewer-three-text-block-editor-script.json
├── three-object-viewer-es_MX-three-object-viewer-three-image-block-editor-script.json
├── three-object-viewer-es_MX-three-object-viewer-sky-block-editor-script.json
├── three-object-viewer-ja-three-object-viewer-three-light-block-editor-script.json
├── three-object-viewer-ja-three-object-viewer-three-image-block-editor-script.json
├── three-object-viewer-ja-three-object-viewer-sky-block-editor-script.json
├── three-object-viewer-es_MX-three-object-viewer-three-video-block-editor-script.json
├── three-object-viewer-es_MX-three-object-viewer-npc-block-editor-script.json
├── three-object-viewer-es_MX-three-object-viewer-environment-editor-script.json
├── three-object-viewer-es_MX-three-object-viewer-model-block-editor-script.json
├── three-object-viewer-es_MX-three-object-viewer-settings.json
├── three-object-viewer-es_MX-three-object-viewer-three-portal-block-editor-script.json
├── three-object-viewer-ja-three-object-viewer-three-video-block-editor-script.json
├── three-object-viewer-ja-three-object-viewer-npc-block-editor-script.json
├── three-object-viewer-ja-three-object-viewer-environment-editor-script.json
├── three-object-viewer-ja-three-object-viewer-settings.json
├── three-object-viewer-ja-three-object-viewer-model-block-editor-script.json
├── three-object-viewer-ja-three-object-viewer-three-portal-block-editor-script.json
├── three-object-viewer-es_MX-three-object-viewer-three-audio-block-editor-script.json
└── three-object-viewer.po
├── babel.config.js
├── tests
├── Unit
│ ├── TestCase.php
│ └── EnvironmentTest.php
├── Integration
│ └── EnvironmentTest.php
└── bootstrap.php
├── .vscode
└── settings.json
├── blocks
├── three-object-block
│ ├── init.php
│ ├── style.scss
│ ├── editor.scss
│ ├── Save.js
│ ├── block.json
│ ├── frontend.js
│ └── components
│ │ ├── TeleportTravel.js
│ │ └── ThreeObjectEdit.js
├── sky-block
│ ├── init.php
│ ├── Save.js
│ ├── editor.scss
│ ├── style.scss
│ ├── block.json
│ ├── index.js
│ └── Edit.test.js
├── model-block
│ ├── init.php
│ ├── style.scss
│ ├── editor.scss
│ ├── Save.js
│ ├── Edit.test.js
│ ├── block.json
│ ├── components
│ │ └── ModelEdit.js
│ └── index.js
├── three-text-block
│ ├── init.php
│ ├── style.scss
│ ├── editor.scss
│ ├── Save.js
│ ├── Edit.test.js
│ └── block.json
├── npc-block
│ ├── init.php
│ ├── style.scss
│ ├── editor.scss
│ ├── Save.js
│ ├── block.json
│ ├── Edit.test.js
│ └── components
│ │ └── ModelEdit.js
├── three-portal-block
│ ├── init.php
│ ├── style.scss
│ ├── editor.scss
│ ├── Edit.test.js
│ ├── Save.js
│ └── block.json
├── spawn-point-block
│ ├── init.php
│ ├── editor.scss
│ ├── Save.js
│ ├── style.scss
│ ├── block.json
│ └── Edit.test.js
├── three-audio-block
│ ├── init.php
│ ├── editor.scss
│ ├── style.scss
│ ├── Edit.test.js
│ ├── Save.js
│ └── block.json
├── three-light-block
│ ├── init.php
│ ├── index.js
│ ├── editor.scss
│ ├── style.scss
│ ├── Edit.test.js
│ ├── Save.js
│ └── block.json
├── three-image-block
│ ├── init.php
│ ├── editor.scss
│ ├── style.scss
│ ├── Save.js
│ ├── Edit.test.js
│ └── block.json
├── three-video-block
│ ├── init.php
│ ├── editor.scss
│ ├── style.scss
│ ├── Edit.test.js
│ ├── Save.js
│ ├── block.json
│ └── index.js
└── environment
│ ├── init.php
│ ├── style.scss
│ ├── components
│ ├── core
│ │ └── front
│ │ │ ├── TextObject.js
│ │ │ ├── ThreeImage.js
│ │ │ ├── ThreeSky.js
│ │ │ ├── ThreeLight.js
│ │ │ └── ThreeAudio.js
│ ├── EditorPluginProvider.js
│ ├── FrontPluginProvider.js
│ ├── ContextBridgeComponent.js
│ ├── Controls.js
│ ├── EditControls.js
│ └── Networking.js
│ ├── Save.js
│ ├── Edit.test.js
│ └── block.json
├── admin
└── three-object-viewer-settings
│ ├── App.test.js.test
│ └── index.js
├── phpunit-unit.xml
├── phpunit-integration.xml
├── .github
└── workflows
│ ├── test-js.yml
│ ├── php-unit.yml
│ └── wordpress.yml
├── .gitignore
├── .svnignore
├── phpcs.xml.dist
├── composer.json
├── package.js
├── pluginMachine.json
├── docker-compose.yml
├── rename.js
├── README.md
├── package.json
└── webpack.config.js
/plugin-build/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inc/threeobjectloaderinit/index.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/plugin-build/.gitignore:
--------------------------------------------------------------------------------
1 | !.gitignore
2 | !.gitkeep
3 |
--------------------------------------------------------------------------------
/inc/hooks.php:
--------------------------------------------------------------------------------
1 | {
5 | const div = document.createElement("div");
6 | ReactDOM.render( , div);
7 | ReactDOM.unmountComponentAtNode(div);
8 | });
9 |
--------------------------------------------------------------------------------
/phpunit-unit.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | ./tests/Unit
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/phpunit-integration.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | ./tests/Integration
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-spawn-point-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"blocks\/spawn-point-block\/Edit.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Settings":["Ajustes"],"Rotation":["Rotaci\u00f3n"],"Spawn Point":["Punto de Aparici\u00f3n"]}}}
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-spawn-point-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"blocks\/spawn-point-block\/Edit.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"Settings":["\u8a2d\u5b9a"],"Rotation":["\u56de\u8ee2"],"Spawn Point":["\u30b9\u30dd\u30fc\u30f3\u30dd\u30a4\u30f3\u30c8"]}}}
--------------------------------------------------------------------------------
/.github/workflows/test-js.yml:
--------------------------------------------------------------------------------
1 | name: JavaScripts
2 |
3 | on: [push]
4 |
5 | jobs:
6 | buildAndTest:
7 | name: Test
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v1
11 | - uses: actions/setup-node@v1
12 | with:
13 | node-version: '12'
14 | - name: Install dependencies
15 | run: yarn
16 | - name: Test
17 | run: yarn test --ci
18 |
--------------------------------------------------------------------------------
/blocks/sky-block/init.php:
--------------------------------------------------------------------------------
1 | _x( 'Sky Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'A sky your environment', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/blocks/model-block/init.php:
--------------------------------------------------------------------------------
1 | _x( 'Model Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'A 3D model for your environment', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/blocks/three-text-block/init.php:
--------------------------------------------------------------------------------
1 | _x( 'Text Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'A 3D Text Block', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/blocks/npc-block/init.php:
--------------------------------------------------------------------------------
1 | _x( 'NPC Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'A NPC to live in your environment', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/blocks/three-portal-block/init.php:
--------------------------------------------------------------------------------
1 | _x( 'Portal Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'A portal for traversal', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/blocks/spawn-point-block/init.php:
--------------------------------------------------------------------------------
1 | _x( 'Spawn Point Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'A spawn point for your users', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/blocks/three-audio-block/init.php:
--------------------------------------------------------------------------------
1 | _x( 'Audio Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'An audio block for your environment', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/blocks/three-light-block/init.php:
--------------------------------------------------------------------------------
1 | _x( 'Light Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'A light block for your environment', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/blocks/three-image-block/init.php:
--------------------------------------------------------------------------------
1 | _x( '3D Image Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'An image block for your environment', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/blocks/three-video-block/init.php:
--------------------------------------------------------------------------------
1 | _x( '3D Video Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'A video block for your environment', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/blocks/environment/init.php:
--------------------------------------------------------------------------------
1 | _x( 'Environment Block', 'block title', 'three-object-viewer' ),
10 | 'description' => _x( 'A 3D environment component', 'block description', 'three-object-viewer' ),
11 | ] );
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-three-text-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"blocks\/three-text-block\/Edit.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Scale":["Escala"],"Position":["Posici\u00f3n"],"Rotation":["Rotaci\u00f3n"],"Text Color":["Color de Texto"],"Text Attributes":["Atributos de Texto"],"Text":["Texto"],"Write here.":["Escribe aqu\u00ed."],"Text Block":["Bloque de Texto"]}}}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Logs
3 | logs
4 | *.log
5 | npm-debug.log*
6 | yarn-debug.log*
7 | yarn-error.log*
8 | lerna-debug.log*
9 | .DS_Store
10 |
11 | # Diagnostic reports (https://nodejs.org/api/report.html)
12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
13 |
14 | # Dependency directories
15 | node_modules/
16 | vendor/
17 |
18 | # dotenv environment variables file
19 | .env
20 | .env.test
21 |
22 | vendor
23 | wordpress
24 | build
25 | pro/
26 | .phpunit.result.cache
27 | plugin-build/pro/three-object-viewer/*
28 | !plugin-build/pro/three-object-viewer/.gitkeep
29 | plugin-build/free/three-object-viewer/*
30 | !plugin-build/free/three-object-viewer/.gitkeep
31 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-three-light-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-three-light-block.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Settings":["Ajustes"],"Position":["Posici\u00f3n"],"Rotation":["Rotaci\u00f3n"],"Light Object":["Objeto de Luz"],"Light Type":["Tipo de Luz"],"Point":["Punto"],"Ambient":["Ambiental"],"Directional":["Directional"],"Intensity":["Intensidad"],"Distance":["Distancia"],"Decay":["Decaimiento"],"Angle":["\u00c1ngulo"],"Penumbra":["Penumbra"],"Light Block":["Bloque de Luz"]}}}
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-three-text-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"blocks\/three-text-block\/Edit.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"Scale":["\u30b9\u30b1\u30fc\u30eb"],"Position":["\u4f4d\u7f6e"],"Rotation":["\u56de\u8ee2"],"Text Color":["\u30c6\u30ad\u30b9\u30c8\u306e\u8272"],"Text Attributes":["\u30c6\u30ad\u30b9\u30c8\u5c5e\u6027"],"Text":["\u30c6\u30ad\u30b9\u30c8"],"Write here.":["\u3053\u3053\u306b\u66f8\u3044\u3066\u304f\u3060\u3055\u3044\u3002"],"Text Block":["\u30c6\u30ad\u30b9\u30c8\u30d6\u30ed\u30c3\u30af"]}}}
--------------------------------------------------------------------------------
/blocks/sky-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
{attributes.skyUrl}
10 |
{attributes.distance}
11 |
{attributes.rayleigh}
12 |
{attributes.sunPositionX}
13 |
{attributes.sunPositionY}
14 |
{attributes.sunPositionZ}
15 |
16 | >
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-three-image-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-three-image-block.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Replace Image":["Reemplazar Imagen"],"Select Image":["Seleccionar Imagen"],"Scale":["Escala"],"Rotation":["Rotaci\u00f3n"],"Image Object":["Objeto de Imagen"],"Select an image to render in your environment:":["Selecciona una imagen para renderizar en tu entorno:"],"Image File":["Archivo de Imagen"],"Item is transparent.":["El elemento es transparente."],"Item is not transparent.":["El elemento no es transparente."],"Image block":["Bloque de Imagen"]}}}
--------------------------------------------------------------------------------
/tests/Integration/EnvironmentTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(is_object($wpdb));
25 | $id = wp_insert_post([
26 | 'post_type' => 'post',
27 | 'post_title' => 'roy',
28 | 'post_content' => 'sivan'
29 | ]);
30 | $this->assertTrue(is_numeric($id));
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-sky-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-sky-block.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Settings":["Ajustes"],"Sky Object":["Objeto de Cielo"],"Select an image to be used as your skybox. 360 panoramics recommended:":["Selecciona una imagen para usar como tu skybox. Se recomiendan panor\u00e1micas de 360 grados:"],"Sky File":["Archivo de Cielo"],"Replace Sky":["Reemplazar Cielo"],"Select Sky":["Seleccionar Cielo"],"Remove Image":["Eliminar Imagen"],"distance":["distancia"],"rayleigh":["rayleigh"],"Sun Position":["Posici\u00f3n del Sol"],"Sky block":["Bloque de Cielo"]}}}
--------------------------------------------------------------------------------
/.svnignore:
--------------------------------------------------------------------------------
1 | .git
2 | .github
3 | .gitignore
4 | .gitattributes
5 | .DS_Store
6 | .babelrc
7 | .cache
8 | .codeclimate*
9 | .idea
10 | .parcel-cache
11 | .eslintignore
12 | .eslintrc.json
13 | .eslintrc.js
14 | .circleci
15 | .sass-cache
16 | .editorconfig
17 | .husky
18 | .env.testing*
19 | .prettier*
20 | .husky
21 | .phpcs.xml.dist
22 | .svnignore
23 | .zipignore
24 | .docker
25 | docs
26 | node_modules
27 | scripts
28 | tests
29 | *phpunit*
30 | *bin*
31 | *config*
32 | *tests*
33 | *composer.json*
34 | *composer.lock*
35 | webpack.config.js
36 | pluginMachine.json
37 | babel.config.json
38 | phpunit-unit.xml
39 | phpunit-integration.xml
40 | phpcs.xml.dist
41 | yarn.lock
42 | yarn-error.log
43 | jest.config.js
44 | package.json
45 | package-lock.json
46 | docker-compose.yml
47 | docker-composer-phpunit.yml
48 | Makefile
49 | *vendor*
--------------------------------------------------------------------------------
/blocks/three-light-block/index.js:
--------------------------------------------------------------------------------
1 | import { registerBlockType } from "@wordpress/blocks";
2 | import Edit from "./Edit";
3 | import Save from "./Save";
4 | import { useBlockProps } from "@wordpress/block-editor";
5 |
6 | const icon = (
7 |
13 |
14 |
15 |
16 |
17 | );
18 |
19 | const blockConfig = require("./block.json");
20 | registerBlockType(blockConfig.name, {
21 | ...blockConfig,
22 | icon,
23 | apiVersion: 2,
24 | edit: Edit,
25 | save: Save
26 | });
27 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-three-light-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-three-light-block.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"Settings":["\u8a2d\u5b9a"],"Position":["\u4f4d\u7f6e"],"Rotation":["\u56de\u8ee2"],"Light Object":["\u30e9\u30a4\u30c8\u30aa\u30d6\u30b8\u30a7\u30af\u30c8"],"Light Type":["\u30e9\u30a4\u30c8\u306e\u7a2e\u985e"],"Point":["\u30dd\u30a4\u30f3\u30c8"],"Ambient":["\u30a2\u30f3\u30d3\u30a8\u30f3\u30c8"],"Directional":["\u30c7\u30a3\u30ec\u30af\u30b7\u30e7\u30ca\u30eb"],"Intensity":["\u5f37\u5ea6"],"Distance":["\u8ddd\u96e2"],"Decay":["\u6e1b\u8870"],"Angle":["\u89d2\u5ea6"],"Penumbra":["\u30da\u30cc\u30f3\u30d6\u30e9"],"Light Block":["\u30e9\u30a4\u30c8\u30d6\u30ed\u30c3\u30af"]}}}
--------------------------------------------------------------------------------
/blocks/spawn-point-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .three-object-viewer-button {
19 | color: black;
20 | border: solid 1.5px black;
21 | }
22 |
23 | .three-object-block-tip {
24 | overflow-wrap: break-word;
25 | background-color: black;
26 | color: white;
27 | padding: 10px;
28 | font-weight: 500;
29 | max-width: 160px;
30 | font-size: 12px;
31 | margin-top: 0px;
32 | margin: 0 auto;
33 | text-align: center;
34 | }
35 |
36 | .three-object-block-url-input {
37 | padding-bottom: 20px;
38 | }
39 |
40 | .three-object-block-url-input input{
41 | height: 40px;
42 | }
43 |
--------------------------------------------------------------------------------
/blocks/three-image-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .three-object-viewer-button {
19 | color: black;
20 | border: solid 1.5px black;
21 | }
22 |
23 | .three-object-block-tip {
24 | overflow-wrap: break-word;
25 | background-color: black;
26 | color: white;
27 | padding: 10px;
28 | font-weight: 500;
29 | max-width: 160px;
30 | font-size: 12px;
31 | margin-top: 0px;
32 | margin: 0 auto;
33 | text-align: center;
34 | }
35 |
36 | .three-object-block-url-input {
37 | padding-bottom: 20px;
38 | }
39 |
40 | .three-object-block-url-input input{
41 | height: 40px;
42 | }
43 |
--------------------------------------------------------------------------------
/blocks/sky-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .glb-preview-container button:hover{
19 | border-radius: 30px;
20 | background-color:rgb(156, 199, 0);
21 | cursor: pointer;
22 | }
23 | .three-object-block-tip {
24 | overflow-wrap: break-word;
25 | background-color: black;
26 | color: white;
27 | padding: 10px;
28 | font-weight: 500;
29 | max-width: 160px;
30 | font-size: 12px;
31 | margin-top: 0px;
32 | margin: 0 auto;
33 | text-align: center;
34 | }
35 |
36 | .three-object-block-url-input {
37 | padding-bottom: 20px;
38 | }
39 |
40 | .three-object-block-url-input input{
41 | height: 40px;
42 | }
43 |
--------------------------------------------------------------------------------
/blocks/three-audio-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .glb-preview-container button:hover{
19 | border-radius: 30px;
20 | background-color:rgb(156, 199, 0);
21 | cursor: pointer;
22 | }
23 | .three-object-block-tip {
24 | overflow-wrap: break-word;
25 | background-color: black;
26 | color: white;
27 | padding: 10px;
28 | font-weight: 500;
29 | max-width: 160px;
30 | font-size: 12px;
31 | margin-top: 0px;
32 | margin: 0 auto;
33 | text-align: center;
34 | }
35 |
36 | .three-object-block-url-input {
37 | padding-bottom: 20px;
38 | }
39 |
40 | .three-object-block-url-input input{
41 | height: 40px;
42 | }
43 |
--------------------------------------------------------------------------------
/blocks/three-light-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .glb-preview-container button:hover{
19 | border-radius: 30px;
20 | background-color:rgb(156, 199, 0);
21 | cursor: pointer;
22 | }
23 | .three-object-block-tip {
24 | overflow-wrap: break-word;
25 | background-color: black;
26 | color: white;
27 | padding: 10px;
28 | font-weight: 500;
29 | max-width: 160px;
30 | font-size: 12px;
31 | margin-top: 0px;
32 | margin: 0 auto;
33 | text-align: center;
34 | }
35 |
36 | .three-object-block-url-input {
37 | padding-bottom: 20px;
38 | }
39 |
40 | .three-object-block-url-input input{
41 | height: 40px;
42 | }
43 |
--------------------------------------------------------------------------------
/blocks/three-video-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .glb-preview-container button:hover{
19 | border-radius: 30px;
20 | background-color:rgb(156, 199, 0);
21 | cursor: pointer;
22 | }
23 | .three-object-block-tip {
24 | overflow-wrap: break-word;
25 | background-color: black;
26 | color: white;
27 | padding: 10px;
28 | font-weight: 500;
29 | max-width: 160px;
30 | font-size: 12px;
31 | margin-top: 0px;
32 | margin: 0 auto;
33 | text-align: center;
34 | }
35 |
36 | .three-object-block-url-input {
37 | padding-bottom: 20px;
38 | }
39 |
40 | .three-object-block-url-input input{
41 | height: 40px;
42 | }
43 |
--------------------------------------------------------------------------------
/admin/three-object-viewer-settings/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@wordpress/element';
3 | import App from './App';
4 | import apiFetch from '@wordpress/api-fetch';
5 |
6 | window.addEventListener( 'load', async function () {
7 | //Endpoint URL
8 | const path = '/three-object-viewer/v1/three-object-viewer-settings/';
9 |
10 | //Get settings from the REST API endpoint
11 | const getSettings = async () => {
12 | let data = await apiFetch( {
13 | path,
14 | method: 'GET',
15 | } );
16 | return data;
17 | };
18 |
19 | //Update settings via the REST API endpoint
20 | const updateSettings = async ( data ) => {
21 | let updatedData = apiFetch( {
22 | path,
23 | data,
24 | method: 'POST',
25 | } );
26 | return updatedData;
27 | };
28 |
29 | render(
30 | ,
31 | document.getElementById( 'three-object-viewer-settings' )
32 | );
33 | } );
34 |
--------------------------------------------------------------------------------
/blocks/spawn-point-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
10 | {attributes.positionX}
11 |
12 |
13 | {attributes.positionY}
14 |
15 |
16 | {attributes.positionZ}
17 |
18 |
19 | {attributes.rotationX}
20 |
21 |
22 | {attributes.rotationY}
23 |
24 |
25 | {attributes.rotationZ}
26 |
27 |
28 | >
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PSR2 with tabs instead of spaces.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/blocks/environment/style.scss:
--------------------------------------------------------------------------------
1 | .wp-block-three-object-block {
2 | background-color: #fff;
3 | color: #000;
4 | padding: 2px;
5 | }
6 |
7 | #networking {
8 | display: none !important;
9 | }
10 |
11 | .wp-block-three-object-block {
12 | border: 1px dotted #f00;
13 | }
14 | .glb-preview-container {
15 | padding: 100px;
16 | text-align: center;
17 | align-items: center;
18 | align-content: center;
19 | background-color:#f2f2f2;
20 | }
21 |
22 | .glb-preview-container button{
23 | padding: 10px;
24 | border-radius: 30px;
25 | background-color:#333;
26 | color: white;
27 | }
28 |
29 | .three-object-block-tip {
30 | overflow-wrap: break-word;
31 | background-color: black;
32 | color: white;
33 | padding: 10px;
34 | font-weight: 500;
35 | max-width: 160px;
36 | font-size: 14px;
37 | margin-top: 0px;
38 | margin: 0 auto;
39 | text-align: center;
40 | }
41 |
42 | .glb-preview-container button:hover{
43 | padding: 10px;
44 | border-radius: 30px;
45 | background-color:rgb(69, 69, 69);
46 | color: white;
47 | cursor: pointer;
48 | }
--------------------------------------------------------------------------------
/blocks/environment/components/core/front/TextObject.js:
--------------------------------------------------------------------------------
1 | import React, { useRef } from "react";
2 | import {
3 | Text,
4 | } from "@react-three/drei";
5 |
6 | /**
7 | * Represents a text object in a virtual reality scene.
8 | *
9 | * @param {Object} model - The props for the text object.
10 | *
11 | * @return {JSX.Element} The text object.
12 | */
13 | export function TextObject(model) {
14 | const htmlObj = useRef();
15 | return (
16 | <>
17 |
23 |
33 | {model.textContent}
34 |
35 |
36 | >
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/blocks/sky-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/sky-block",
3 | "attributes": {
4 | "skyUrl": {
5 | "type": "string",
6 | "default": null
7 | },
8 | "distance": {
9 | "type": "int",
10 | "default": 170000
11 | },
12 | "rayleigh": {
13 | "type": "int",
14 | "default": 1
15 | },
16 | "sunPositionX": {
17 | "type": "int",
18 | "default": 0
19 | },
20 | "sunPositionY": {
21 | "type": "int",
22 | "default": 10000
23 | },
24 | "sunPositionZ": {
25 | "type": "int",
26 | "default": -10000
27 | }
28 | },
29 | "category": "design",
30 | "parent": [ "three-object-viewer/environment" ],
31 | "apiVersion": 2,
32 | "supports": {
33 | "html": false,
34 | "multiple": false
35 | },
36 | "textdomain": "three-object-viewer",
37 | "editorScript": "file:../../build/block-sky-block.js",
38 | "editorStyle": "file:../../build/block-sky-block.css",
39 | "style": "file:../../build/block-sky-block.css"
40 | }
41 |
--------------------------------------------------------------------------------
/blocks/environment/components/EditorPluginProvider.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useContext, useEffect, useCallback } from "react";
2 |
3 | export const EditorPluginContext = React.createContext();
4 |
5 | export function EditorPluginProvider({ children }) {
6 |
7 | const [plugins, setPlugins] = useState([]);
8 |
9 | const registerEditorPlugin = useCallback((plugin) => {
10 | setPlugins(prevPlugins => [...prevPlugins, plugin]);
11 | }, []);
12 |
13 | useEffect(() => {
14 | // Expose the registerPlugin method globally
15 | window.registerEditorPlugin = registerEditorPlugin;
16 | window.dispatchEvent(new Event('registerEditorPluginReady'));
17 |
18 | return () => {
19 | // Cleanup
20 | window.registerEditorPlugin = null;
21 | };
22 | }, [registerEditorPlugin]);
23 |
24 | return (
25 |
26 | {children}
27 |
28 | );
29 | }
30 |
31 | export const useEditorPlugins = () => useContext(EditorPluginContext);
32 |
--------------------------------------------------------------------------------
/blocks/three-object-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .three-object-viewer-button {
19 | background-color:rgb(199, 254, 0);
20 | color: black;
21 | border: solid 1.5px black;
22 | }
23 |
24 | .glb-preview-container button:hover{
25 | border-radius: 30px;
26 | background-color:rgb(156, 199, 0);
27 | cursor: pointer;
28 | }
29 | .three-object-block-tip {
30 | overflow-wrap: break-word;
31 | background-color: black;
32 | color: white;
33 | padding: 10px;
34 | font-weight: 500;
35 | max-width: 160px;
36 | font-size: 12px;
37 | margin-top: 0px;
38 | margin: 0 auto;
39 | text-align: center;
40 | }
41 |
42 | .three-object-block-url-input {
43 | padding-bottom: 20px;
44 | }
45 |
46 | .three-object-block-url-input input{
47 | height: 40px;
48 | }
49 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "antpb/three-object-viewer",
3 | "description": "threeObjectViewer",
4 | "require": {
5 | "php": "^7.2|^8.0",
6 | "wp-cli/i18n-command": "^2.4"
7 | },
8 | "type": "wordpress-plugin",
9 | "autoload": {
10 | "psr-4": {
11 | "threeObjectViewer\\": "./php"
12 | }
13 | },
14 | "autoload-dev": {
15 | "psr-4": {
16 | "threeObjectViewer\\Tests\\": "./tests"
17 | }
18 | },
19 | "require-dev": {
20 | "phpunit/phpunit": "^7.0",
21 | "yoast/phpunit-polyfills": "^1.0.1",
22 | "mockery/mockery": "1.2",
23 | "brain/monkey": "2.*",
24 | "squizlabs/php_codesniffer": "^3.6"
25 | },
26 | "scripts": {
27 | "test": "composer test:unit && composer test:wordpress",
28 | "test:unit": "phpunit --config=phpunit-unit.xml",
29 | "test:wordpress": "phpunit --config=phpunit-integration.xml",
30 | "sniffs": "phpcs php/ && phpcs tests/",
31 | "fixes": "phpcbf php/ && phpcbf tests/"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-three-image-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-three-image-block.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"Replace Image":["\u753b\u50cf\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select Image":["\u753b\u50cf\u3092\u9078\u629e\u3059\u308b"],"Scale":["\u30b9\u30b1\u30fc\u30eb"],"Rotation":["\u56de\u8ee2"],"Image Object":["\u30a4\u30e1\u30fc\u30b8\u30aa\u30d6\u30b8\u30a7\u30af\u30c8"],"Select an image to render in your environment:":["\u74b0\u5883\u5185\u306b\u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u3059\u308b\u753b\u50cf\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002"],"Image File":["\u753b\u50cf\u30d5\u30a1\u30a4\u30eb"],"Item is transparent.":["\u30a2\u30a4\u30c6\u30e0\u306f\u900f\u660e\u3067\u3059\u3002"],"Item is not transparent.":["\u30a2\u30a4\u30c6\u30e0\u306f\u900f\u660e\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002"],"Image block":["\u30a4\u30e1\u30fc\u30b8\u30d6\u30ed\u30c3\u30af"]}}}
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-sky-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-sky-block.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"Settings":["\u8a2d\u5b9a"],"Sky Object":["\u30b9\u30ab\u30a4\u30aa\u30d6\u30b8\u30a7\u30af\u30c8"],"Select an image to be used as your skybox. 360 panoramics recommended:":["\u30b9\u30ab\u30a4\u30dc\u30c3\u30af\u30b9\u306b\u4f7f\u7528\u3059\u308b\u753b\u50cf\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002360\u5ea6\u306e\u30d1\u30ce\u30e9\u30df\u30c3\u30af\u753b\u50cf\u304c\u63a8\u5968\u3055\u308c\u307e\u3059\u3002"],"Sky File":["\u30b9\u30ab\u30a4\u30d5\u30a1\u30a4\u30eb"],"Replace Sky":["\u30b9\u30ab\u30a4\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select Sky":["\u30b9\u30ab\u30a4\u3092\u9078\u629e\u3059\u308b"],"Remove Image":["\u753b\u50cf\u3092\u524a\u9664\u3059\u308b"],"distance":["\u8ddd\u96e2"],"rayleigh":["\u30ec\u30a4\u30ea\u30fc"],"Sun Position":["\u592a\u967d\u306e\u4f4d\u7f6e"],"Sky block":["\u30b9\u30ab\u30a4\u30d6\u30ed\u30c3\u30af"]}}}
--------------------------------------------------------------------------------
/blocks/environment/components/FrontPluginProvider.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useContext, useState, useEffect, useCallback } from "react";
2 | import { useThree } from '@react-three/fiber';
3 |
4 | export const FrontPluginContext = React.createContext();
5 |
6 | export function FrontPluginProvider({ children }) {
7 |
8 | const [plugins, setPlugins] = useState([]);
9 | const { scene, camera } = useThree();
10 |
11 | const registerFrontPlugin = useCallback((plugin) => {
12 | setPlugins(prevPlugins => [...prevPlugins, plugin]);
13 | }, []);
14 |
15 | useEffect(() => {
16 | // Expose the registerPlugin method globally
17 | window.registerFrontPlugin = registerFrontPlugin;
18 | window.dispatchEvent(new Event('registerFrontPluginReady'));
19 |
20 | return () => {
21 | // Cleanup
22 | window.registerFrontPlugin = null;
23 | };
24 | }, [registerFrontPlugin]);
25 |
26 | return (
27 |
28 | {children}
29 |
30 | );
31 | }
32 |
33 | export const useFrontPlugins = () => useContext(FrontPluginContext);
34 |
--------------------------------------------------------------------------------
/blocks/spawn-point-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/spawn-point-block",
3 | "attributes": {
4 | "positionX": {
5 | "type": "int",
6 | "default":0
7 | },
8 | "positionY": {
9 | "type": "int",
10 | "default":0
11 | },
12 | "positionZ": {
13 | "type": "int",
14 | "default":0
15 | },
16 | "rotationX": {
17 | "type": "int",
18 | "default":0
19 | },
20 | "rotationY": {
21 | "type": "int",
22 | "default":0
23 | },
24 | "rotationZ": {
25 | "type": "int",
26 | "default":0
27 | }
28 | },
29 | "category": "design",
30 | "parent": [ "three-object-viewer/environment" ],
31 | "apiVersion": 2,
32 | "supports": {
33 | "html": false,
34 | "multiple": false
35 | },
36 | "textdomain": "three-object-viewer",
37 | "editorScript": "file:../../build/block-spawn-point-block.js",
38 | "editorStyle": "file:../../build/block-spawn-point-block.css",
39 | "style": "file:../../build/block-spawn-point-block.css"
40 | }
41 |
--------------------------------------------------------------------------------
/blocks/three-text-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .glb-preview-container button:hover{
19 | border-radius: 30px;
20 | background-color:rgb(156, 199, 0);
21 | cursor: pointer;
22 | }
23 | .three-object-block-tip {
24 | overflow-wrap: break-word;
25 | background-color: black;
26 | color: white;
27 | padding: 10px;
28 | font-weight: 500;
29 | max-width: 160px;
30 | font-size: 12px;
31 | margin-top: 0px;
32 | margin: 0 auto;
33 | text-align: center;
34 | }
35 |
36 | .three-object-block-url-input {
37 | padding-bottom: 20px;
38 | }
39 |
40 | .three-object-block-url-input input{
41 | height: 40px;
42 | }
43 |
44 | .block-editor-block-inspector .components-base-control.position-inputs:last-child {
45 | margin-bottom: 24px !important;
46 | }
47 | .block-editor-block-inspector .components-base-control.position-inputs {
48 | padding-right: 5px;
49 | }
50 |
--------------------------------------------------------------------------------
/blocks/model-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .glb-preview-container button:hover{
19 | border-radius: 30px;
20 | // background-color:rgb(156, 199, 0);
21 | cursor: pointer;
22 | }
23 |
24 | .three-object-block-tip {
25 | overflow-wrap: break-word;
26 | background-color: black;
27 | color: white;
28 | padding: 10px;
29 | font-weight: 500;
30 | max-width: 160px;
31 | font-size: 12px;
32 | margin-top: 0px;
33 | margin: 0 auto;
34 | text-align: center;
35 | }
36 |
37 | .three-object-block-url-input {
38 | padding-bottom: 20px;
39 | }
40 |
41 | .three-object-block-url-input input{
42 | height: 40px;
43 | }
44 |
45 | .block-editor-block-inspector .components-base-control.position-inputs:last-child {
46 | margin-bottom: 24px !important;
47 | }
48 | .block-editor-block-inspector .components-base-control.position-inputs {
49 | padding-right: 5px;
50 | }
51 |
--------------------------------------------------------------------------------
/blocks/npc-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .glb-preview-container button:hover{
19 | border-radius: 30px;
20 | // background-color:rgb(156, 199, 0);
21 | cursor: pointer;
22 | }
23 |
24 | .three-object-block-tip {
25 | overflow-wrap: break-word;
26 | background-color: black;
27 | color: white;
28 | padding: 10px;
29 | font-weight: 500;
30 | max-width: 160px;
31 | font-size: 12px;
32 | margin-top: 0px;
33 | margin: 0 auto;
34 | text-align: center;
35 | }
36 |
37 | .three-object-block-url-input {
38 | padding-bottom: 20px;
39 | }
40 |
41 | .three-object-block-url-input input{
42 | height: 40px;
43 | }
44 |
45 | .block-editor-block-inspector .components-base-control.position-inputs:last-child {
46 | margin-bottom: 24px !important;
47 | }
48 | .block-editor-block-inspector .components-base-control.position-inputs {
49 | padding-right: 5px;
50 | }
51 |
--------------------------------------------------------------------------------
/blocks/three-portal-block/editor.scss:
--------------------------------------------------------------------------------
1 |
2 | .wp-block-three-object-block {
3 | border: 1px dotted #f00;
4 | }
5 | .glb-preview-container {
6 | padding: 100px;
7 | text-align: center;
8 | align-items: center;
9 | align-content: center;
10 | background-color:#f2f2f2;
11 | }
12 |
13 | .glb-preview-container button{
14 | padding: 15px;
15 | border-radius: 30px;
16 | }
17 |
18 | .glb-preview-container button:hover{
19 | border-radius: 30px;
20 | background-color:rgb(156, 199, 0);
21 | cursor: pointer;
22 | }
23 | .three-object-block-tip {
24 | overflow-wrap: break-word;
25 | background-color: black;
26 | color: white;
27 | padding: 10px;
28 | font-weight: 500;
29 | max-width: 160px;
30 | font-size: 12px;
31 | margin-top: 0px;
32 | margin: 0 auto;
33 | text-align: center;
34 | }
35 |
36 | .three-object-block-url-input {
37 | padding-bottom: 20px;
38 | }
39 |
40 | .three-object-block-url-input input{
41 | height: 40px;
42 | }
43 |
44 | .block-editor-block-inspector .components-base-control.position-inputs:last-child {
45 | margin-bottom: 24px !important;
46 | }
47 | .block-editor-block-inspector .components-base-control.position-inputs {
48 | padding-right: 5px;
49 | }
50 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-three-video-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"blocks\/three-video-block\/Edit.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Scale":["Escala"],"Settings":["Ajustes"],"Replace Object":["Reemplazar Objeto"],"Rotation":["Rotaci\u00f3n"],"Item will autoplay.":["El elemento se reproducir\u00e1 autom\u00e1ticamente."],"Item will not autoplay.":["El elemento no se reproducir\u00e1 autom\u00e1ticamente."],"Select an image to render in your environment:":["Selecciona una imagen para renderizar en tu entorno:"],"Video File":["Archivo de Video"],"Replace Video":["Reemplazar Video"],"Select Video":["Seleccionar Video"],"Custom Model":["Modelo Personalizado"],"Item will use a custom model. Name your faces 'screen'.":["El elemento usar\u00e1 un modelo personalizado. Nombra tus caras como \u2018screen\u2019."],"Item will not use a custom model.":["El elemento no usar\u00e1 un modelo personalizado."],"Replace model":["Reemplazar modelo"],"Select model":["Seleccionar modelo"],"Video block":["Bloque de Video"]}}}
--------------------------------------------------------------------------------
/blocks/environment/components/core/front/ThreeImage.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useLoader, useThree } from "@react-three/fiber";
3 | import { TextureLoader, DoubleSide } from "three";
4 |
5 | /**
6 | * Renders an image in a three.js scene.
7 | *
8 | * @param {Object} threeImage - The props for the image.
9 | *
10 | * @return {JSX.Element} The image.
11 | */
12 | export function ThreeImage(threeImage) {
13 | const texture2 = useLoader(TextureLoader, threeImage.url);
14 | return (
15 |
29 |
35 | {threeImage.transparent == "1" ? (
36 |
41 | ) : (
42 |
43 | )}
44 |
45 | );
46 | }
--------------------------------------------------------------------------------
/blocks/three-text-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
10 | {attributes.textContent}
11 |
12 |
13 | {attributes.positionX}
14 |
15 |
16 | {attributes.positionY}
17 |
18 |
19 | {attributes.positionZ}
20 |
21 |
22 | {attributes.rotationX}
23 |
24 |
25 | {attributes.rotationY}
26 |
27 |
28 | {attributes.rotationZ}
29 |
30 |
{attributes.scaleX}
31 |
{attributes.scaleY}
32 |
{attributes.scaleZ}
33 |
{attributes.textColor}
34 |
35 | >
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/blocks/sky-block/index.js:
--------------------------------------------------------------------------------
1 | import { registerBlockType } from "@wordpress/blocks";
2 | import Edit from "./Edit";
3 | import Save from "./Save";
4 | import { useBlockProps } from "@wordpress/block-editor";
5 |
6 | const icon = (
7 |
13 |
14 |
15 |
16 |
17 | );
18 |
19 | const blockConfig = require("./block.json");
20 | registerBlockType(blockConfig.name, {
21 | ...blockConfig,
22 | icon,
23 | apiVersion: 2,
24 | edit: Edit,
25 | save: Save,
26 | deprecated: [
27 | {
28 | attributes: {
29 | skyUrl: {
30 | type: "string",
31 | default: null
32 | },
33 | },
34 | save(props) {
35 | return (
36 |
37 | <>
38 |
39 |
{props.attributes.skyUrl}
40 |
41 | >
42 |
43 | );
44 | }
45 | }
46 | ]
47 | });
48 |
--------------------------------------------------------------------------------
/package.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra');
2 | const path = require('path');
3 |
4 | const isPro = process.argv.includes('pro');
5 |
6 | const sourceDirectory = path.join(__dirname);
7 | const targetDirectory = path.join(__dirname, 'plugin-build', isPro ? 'pro/three-object-viewer' : 'free/three-object-viewer');
8 |
9 | // Explicitly specify directories or files you want to copy for the free version
10 | const itemsToCopy = [
11 | 'LICENSE',
12 | 'admin',
13 | 'blocks',
14 | 'build',
15 | 'inc',
16 | 'languages',
17 | 'php',
18 | 'readme.txt',
19 | 'three-object-viewer.php',
20 | ];
21 |
22 | // Ensure the target directory is clean before copying
23 | fs.removeSync(targetDirectory);
24 | fs.ensureDirSync(targetDirectory);
25 |
26 | itemsToCopy.forEach(item => {
27 | const sourcePath = path.join(sourceDirectory, item);
28 | const targetPath = path.join(targetDirectory, item);
29 | fs.copySync(sourcePath, targetPath);
30 | });
31 |
32 | // If it's the pro build, include the 'pro' directory plus all free version files/directories
33 | if (isPro) {
34 | const sourcePro = path.join(sourceDirectory, 'pro');
35 | const targetPro = path.join(targetDirectory, 'pro');
36 | fs.copySync(sourcePro, targetPro);
37 | }
38 |
39 | console.log(`Packaged the ${isPro ? 'pro' : 'free'} version to ${targetDirectory}`);
40 |
--------------------------------------------------------------------------------
/blocks/three-object-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from '@wordpress/i18n';
2 | import { useBlockProps } from '@wordpress/block-editor';
3 |
4 | export default function save( { attributes } ) {
5 | return (
6 |
7 | <>
8 |
9 |
10 | { attributes.deviceTarget }
11 |
12 |
13 | { attributes.threeObjectUrl }
14 |
15 |
{ attributes.scale }
16 |
17 | { attributes.bg_color }
18 |
19 |
{ attributes.zoom }
20 |
21 | { attributes.hasZoom ? 1 : 0 }
22 |
23 |
24 | { attributes.hasTip ? 1 : 0 }
25 |
26 |
27 | { attributes.positionY }
28 |
29 |
30 | { attributes.rotationY }
31 |
32 |
{ attributes.scale }
33 |
34 | { attributes.animations }
35 |
36 |
37 | >
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-npc-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"blocks\/npc-block\/Edit.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Settings":["Ajustes"],"Name":["Nombre"],"Position":["Posici\u00f3n"],"Rotation":["Rotaci\u00f3n"],"NPC Options":["Opciones de PNJ"],"Give your avatar a name.":["Asigna un nombre a tu avatar."],"Personality":["Personalidad"],"Give your avatar a personality in 600 characters.":["Asigna una personalidad a tu avatar en 600 caracteres."],"Default Message":["Mensaje Predeterminado"],"Give your avatar a default message to initialize with.":["Asigna un mensaje predeterminado a tu avatar para la inicializaci\u00f3n."],"Select a VRM file to be used as your NPC in world:":["Selecciona un archivo VRM para usar como tu PNJ en el mundo:"],"Advanced Settings":["Ajustes Avanzados"],"Include World Objects in Prompt":["Incluir Objetos del Mundo en la Sugerencia"],"If enabled, will result in higher token costs with your AI service provider. Use with caution.":["Si est\u00e1 activado, resultar\u00e1 en costos de tokens m\u00e1s altos con tu proveedor de servicios de IA. \u00dasalo con precauci\u00f3n."],"NPC block":["Bloque de PNJ"],"Replace NPC":["Reemplazar PNJ"],"Select NPC":["Seleccionar PNJ"]}}}
--------------------------------------------------------------------------------
/blocks/npc-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
10 | {attributes.threeObjectUrl}
11 |
12 |
13 | {attributes.positionX}
14 |
15 |
16 | {attributes.positionY}
17 |
18 |
19 | {attributes.positionZ}
20 |
21 |
22 | {attributes.rotationX}
23 |
24 |
25 | {attributes.rotationY}
26 |
27 |
28 | {attributes.rotationZ}
29 |
30 |
31 | {attributes.name}
32 |
33 |
34 | {attributes.defaultMessage}
35 |
36 |
37 | {attributes.personality}
38 |
39 |
40 | {attributes.objectAwareness ? 1 : 0}
41 |
42 |
43 | >
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/.github/workflows/php-unit.yml:
--------------------------------------------------------------------------------
1 | name: PHP Unit Tests
2 |
3 | on: push
4 |
5 | jobs:
6 | test:
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | php-versions: [7.2, 7.3, 7.4]
11 |
12 | steps:
13 | - uses: actions/checkout@v2
14 | - name: Setup PHP
15 | uses: shivammathur/setup-php@v2
16 | with:
17 | php-version: ${{ matrix.php-versions }}
18 | # Install composer with cache
19 | - name: Get Composer Cache Directory
20 | id: get-composer-cache-dir # Instead of composer-cache
21 | run: |
22 | echo "::set-output name=dir::$(composer config cache-files-dir)"
23 |
24 | - name: Cache Composer packages
25 | id: composer-cache
26 | uses: actions/cache@v2
27 | with:
28 | path: vendor
29 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
30 | restore-keys: |
31 | ${{ runner.os }}-php-
32 |
33 | - name: Install dependencies
34 | if: steps.composer-cache.outputs.cache-hit != 'true'
35 | run: composer install --prefer-dist --no-progress
36 |
37 | # Run unit tests
38 | - name: Unit Tests
39 | run: composer test:unit
40 |
--------------------------------------------------------------------------------
/blocks/environment/components/ContextBridgeComponent.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { useFrontPlugins, FrontPluginContext } from './FrontPluginProvider';
3 | import { useContextBridge } from "@react-three/drei";
4 |
5 | //import contextBridgef
6 | // add function for context
7 | export function ContextBridgeComponent(props) {
8 | const { plugins } = useFrontPlugins(); // From your own context
9 | const [registeredThreeovBlocks, setRegisteredThreeovBlocks] = useState([]);
10 | const ContextBridge = useContextBridge(FrontPluginContext);
11 |
12 | useEffect(() => {
13 | if (plugins.length > 0) {
14 | plugins.forEach((plugin) => {
15 | // add the plugin to the registered blocks
16 | setRegisteredThreeovBlocks((registeredThreeovBlocks) => [
17 | ...registeredThreeovBlocks,
18 | plugin,
19 | ]);
20 | });
21 | }
22 | }, [plugins]);
23 |
24 | return (
25 |
26 | {
27 | registeredThreeovBlocks.length > 0 && registeredThreeovBlocks.map((blockElement, index) => {
28 | const BlockComponent = blockElement.type;
29 | return (
30 |
36 |
37 |
38 | )
39 | })
40 | }
41 |
42 | )
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/blocks/model-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
10 | {attributes.threeObjectUrl}
11 |
12 |
{attributes.scaleX}
13 |
{attributes.scaleY}
14 |
{attributes.scaleZ}
15 |
16 | {attributes.positionX}
17 |
18 |
19 | {attributes.positionY}
20 |
21 |
22 | {attributes.positionZ}
23 |
24 |
25 | {attributes.rotationX}
26 |
27 |
28 | {attributes.rotationY}
29 |
30 |
31 | {attributes.rotationZ}
32 |
33 |
34 | {attributes.animations}
35 |
36 |
37 | {attributes.collidable ? 1 : 0}
38 |
39 |
{attributes.alt}
40 |
41 | >
42 |
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/tests/Unit/EnvironmentTest.php:
--------------------------------------------------------------------------------
1 | assertIsBool(true);
24 | self::assertIsNotIterable(new \stdClass());
25 | }
26 |
27 | /**
28 | * A test ensuring that the composer autoloader works
29 | */
30 | public function testAutoloaderWorks()
31 | {
32 | $this->assertSame('Hey, Listen!', (new Plugin())->listen());
33 | }
34 |
35 | /**
36 | * Test that we can mock WordPress functions
37 | *
38 | * @see https://giuseppe-mazzapica.gitbook.io/brain-monkey/functions-testing-tools/functions-when#justreturn
39 | */
40 | public function testMockWordPressFunction()
41 | {
42 | //A fake wp_insert_post() that always returns 1
43 | Functions\when('wp_insert_post')->justReturn(1);
44 | $this->assertIsNumeric(
45 | wp_insert_post([
46 | 'post_title' => 'If I learn it again, I would recommend:',
47 | 'post_content' => 'grow aloe. then grow cactus. then grow sempervivum. then grow lithops and echeveria'
48 | ])
49 | );
50 | $this->assertSame(1, wp_insert_post());
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/blocks/three-image-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
{attributes.imageUrl}
10 |
{attributes.scaleX}
11 |
{attributes.scaleY}
12 |
{attributes.scaleZ}
13 |
14 | {attributes.positionX}
15 |
16 |
17 | {attributes.positionY}
18 |
19 |
20 | {attributes.positionZ}
21 |
22 |
23 | {attributes.rotationX}
24 |
25 |
26 | {attributes.rotationY}
27 |
28 |
29 | {attributes.rotationZ}
30 |
31 |
32 | {attributes.aspectHeight}
33 |
34 |
35 | {attributes.aspectWidth}
36 |
37 |
38 | {attributes.transparent ? 1 : 0}
39 |
40 |
41 | >
42 |
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-environment-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-environment.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Environment Settings":["Configuraci\u00f3n de Entorno"],"Environment Object (Changing this value changes your scene ground planes)":["Objeto de Entorno (Cambiar este valor cambia los planos de suelo de la escena)"],"Select a glb file from your media library. This will be treated as a collidable mesh that visitors can walk on:":["Selecciona un archivo .glb de tu biblioteca de medios. Esto ser\u00e1 tratado como una malla colisionable sobre la cual los visitantes pueden caminar:"],"Replace Environment":["Reemplazar Entorno"],"Select Environment":["Seleccionar Entorno"],"Select an image to be used as the preview image:":["Selecciona una imagen para usar como imagen de vista previa:"],"Replace Image":["Reemplazar Imagen"],"Select Image":["Seleccionar Imagen"],"Replace HDR":["Reemplazar HDR"],"Select HDR":["Seleccionar HDR"],"Remove HDR":["Eliminar HDR"],"Scene Settings":["Configuraci\u00f3n de Escena"],"Object Display Type:":["Tipo de Visualizaci\u00f3n del Objeto:"],"Loop Animations":["Repetir Animaciones"],"Separate each animation name you wish to loop with a comma":["Separa cada nombre de animaci\u00f3n que deseas repetir con una coma"],"Scale":["Escala"],"Position Y":["Posici\u00f3n Y"],"Rotation Y":["Rotaci\u00f3n Y"]}}}
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-model-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-model-block.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Loop Animations":["Repetir Animaciones"],"Separate each animation name you wish to loop with a comma":["Separa cada nombre de animaci\u00f3n que deseas repetir con una coma"],"Scale":["Escala"],"Settings":["Ajustes"],"GLB Object":["Objeto GLB"],"Name":["Nombre"],"Give your object a name.":["Asigna un nombre a tu objeto."],"select a glb file from your media library to render an object in the canvas:":["selecciona un archivo glb de tu biblioteca de medios para renderizar un objeto en el lienzo:"],"GLB File":["Archivo GLB"],"Replace Object":["Reemplazar Objeto"],"Select Object":["Seleccionar Objeto"],"Model Attributes":["Atributos del Modelo"],"Collidable":["Colisionable"],"Item is currently collidable.":["El elemento es actualmente colisionable."],"Item is not collidable. Users will walk through it.":["El elemento no es colisionable. Los usuarios podr\u00e1n atravesarlo."],"Model Alt Text":["Texto Alternativo del Modelo"],"Describe your model to provide context for screen readers.":["Describe tu modelo para proporcionar contexto a los lectores de pantalla."],"Position":["Posici\u00f3n"],"Rotation":["Rotaci\u00f3n"],"Model block":["Bloque de Modelo"],"Replace Model":["Reemplazar Modelo"],"Select Model":["Seleccionar Modelo"]}}}
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-settings.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"admin\/three-object-viewer-settings\/App.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"3OV Settings":["Ajustes 3OV"],"Select or Upload Media":["Seleccionar o Subir Medios"],"Use this media":["Usar este medio"],"Here you can manage the settings for 3OV to tweak global configuration options and save your API keys for connected serivces.":["Aqu\u00ed puedes gestionar la configuraci\u00f3n de 3OV para ajustar las opciones de configuraci\u00f3n global y guardar tus claves de API para los servicios conectados."],"Avatar Settings":["Ajustes de Avatar"],"Default animation":["Animaci\u00f3n predeterminada"],"No custom default animation set":["Sin conjunto de animaci\u00f3n predeterminada personalizada"],"Set Default Animation":["Establecer Animaci\u00f3n Predeterminada"],"Clear Default Animation":["Borrar Animaci\u00f3n Predeterminada"],"No custom default avatar set":["Sin conjunto de avatar predeterminado personalizado"],"Set Default Avatar":["Establecer Avatar Predeterminado"],"Clear Default Avatar":["Borrar Avatar Predeterminado"],"AI Settings":["Ajustes de IA"],"NPC Settings":["Ajustes de PNJ"],"Enable":["Habilitar"],"AI Endpoint URL":["URL del Punto de Extremo de la IA"],"OpenAI API Token":["Token de API de OpenAI"],"AI Access Level":["Nivel de Acceso de la IA"],"Public":["P\u00fablico"],"Logged In":["Sesi\u00f3n Iniciada"],"Saving...":["Guardando\u2026"]}}}
--------------------------------------------------------------------------------
/blocks/environment/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps, InnerBlocks } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
10 | {attributes.deviceTarget}
11 |
12 |
13 | {attributes.threeObjectUrl}
14 |
15 |
16 | {attributes.hdr}
17 |
18 |
{attributes.scale}
19 |
20 | {attributes.bg_color}
21 |
22 |
{attributes.zoom}
23 |
24 | {attributes.hasZoom ? 1 : 0}
25 |
26 |
27 | {attributes.hasTip ? 1 : 0}
28 |
29 |
30 | {attributes.positionY}
31 |
32 |
33 | {attributes.rotationY}
34 |
35 |
{attributes.scale}
36 |
37 | {attributes.threePreviewImage}
38 |
39 |
40 | {attributes.animations}
41 |
42 |
43 |
44 | >
45 |
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/blocks/npc-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/npc-block",
3 | "attributes": {
4 | "name": {
5 | "type": "string"
6 | },
7 | "personality": {
8 | "type": "string"
9 | },
10 | "defaultMessage": {
11 | "type": "string"
12 | },
13 | "positionX": {
14 | "type": "int",
15 | "default":0
16 | },
17 | "positionY": {
18 | "type": "int",
19 | "default":0
20 | },
21 | "positionZ": {
22 | "type": "int",
23 | "default":0
24 | },
25 | "rotationX": {
26 | "type": "int",
27 | "default":0
28 | },
29 | "rotationY": {
30 | "type": "int",
31 | "default":0
32 | },
33 | "rotationZ": {
34 | "type": "int",
35 | "default":0
36 | },
37 | "threeObjectUrl": {
38 | "type": "string",
39 | "default": null
40 | },
41 | "objectAwareness": {
42 | "type": "boolean",
43 | "default": false
44 | }
45 | },
46 | "category": "design",
47 | "parent": [ "three-object-viewer/environment" ],
48 | "apiVersion": 2,
49 | "supports": {
50 | "html": false,
51 | "multiple": false
52 | },
53 | "textdomain": "three-object-viewer",
54 | "editorScript": "file:../../build/block-npc-block.js",
55 | "editorStyle": "file:../../build/block-npc-block.css",
56 | "style": "file:../../build/block-npc-block.css"
57 | }
58 |
--------------------------------------------------------------------------------
/blocks/environment/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/model-block/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/npc-block/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/sky-block/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/spawn-point-block/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/three-audio-block/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/three-image-block/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/three-light-block/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/three-text-block/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/three-video-block/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/three-portal-block/Edit.test.js:
--------------------------------------------------------------------------------
1 | //Import React
2 | import React from "react";
3 | //Import test renderer
4 | import { render, fireEvent, cleanup } from "@testing-library/react";
5 | //Import component to test
6 | import { Editor } from "./Edit";
7 |
8 | describe("Editor componet", () => {
9 | afterEach(cleanup);
10 | it("matches snapshot when selected", () => {
11 | const onChange = jest.fn();
12 | const { container } = render(
13 |
14 | );
15 | expect(container).toMatchSnapshot();
16 | });
17 |
18 | it("matches snapshot when not selected", () => {
19 | const onChange = jest.fn();
20 | const { container } = render(
21 |
22 | );
23 | expect(container).toMatchSnapshot();
24 | });
25 |
26 | it("Calls the onchange function", () => {
27 | const onChange = jest.fn();
28 | const { getByDisplayValue } = render(
29 |
30 | );
31 | fireEvent.change(getByDisplayValue("Salad"), {
32 | target: { value: "New Value" }
33 | });
34 | expect(onChange).toHaveBeenCalledTimes(1);
35 | });
36 |
37 | it("Passes updated value, not event to onChange callback", () => {
38 | const onChange = jest.fn();
39 | const { getByDisplayValue } = render(
40 |
41 | );
42 | fireEvent.change(getByDisplayValue("Seltzer"), {
43 | target: { value: "Boring Water" }
44 | });
45 | expect(onChange).toHaveBeenCalledWith("Boring Water");
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/blocks/environment/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/environment",
3 | "attributes": {
4 | "align": {
5 | "type": "string",
6 | "default": "full"
7 | },
8 | "scale": {
9 | "type": "integer",
10 | "default": 1
11 | },
12 | "positionX": {
13 | "type": "integer",
14 | "default": 0
15 | },
16 | "positionY": {
17 | "type": "integer",
18 | "default": 0
19 | },
20 | "rotationY": {
21 | "type": "integer",
22 | "default": 0
23 | },
24 | "threeObjectUrl": {
25 | "type": "string",
26 | "default": null
27 | },
28 | "threePreviewImage": {
29 | "type": "string",
30 | "default": null
31 | },
32 | "hdr": {
33 | "type": "string",
34 | "default": null
35 | },
36 | "deviceTarget": {
37 | "type": "string",
38 | "default": "vr"
39 | },
40 | "animations": {
41 | "type": "string",
42 | "default": ""
43 | }
44 | },
45 | "category": "design",
46 | "apiVersion": 2,
47 | "supports": {
48 | "html": false,
49 | "multiple": false,
50 | "hasOverlay": false,
51 | "align": ["full"]
52 | },
53 | "textdomain": "three-object-viewer",
54 | "editorScript": "file:../../build/block-environment.js",
55 | "editorStyle": "file:../../build/block-environment.css",
56 | "style": "file:../../build/block-environment.css"
57 | }
58 |
--------------------------------------------------------------------------------
/pluginMachine.json:
--------------------------------------------------------------------------------
1 | {
2 | "slug": "three-object-viewer",
3 | "pluginId": 166,
4 | "buildId": 172,
5 | "entryPoints": {
6 | "adminPages": [
7 | "three-object-viewer-settings"
8 | ],
9 | "proAdminPages": [
10 | "three-object-viewer-pro-settings"
11 | ],
12 | "blocks": [
13 | "three-object-block",
14 | "environment",
15 | "model-block",
16 | "npc-block",
17 | "sky-block",
18 | "three-image-block",
19 | "three-video-block",
20 | "three-audio-block",
21 | "three-light-block",
22 | "three-portal-block",
23 | "three-text-block",
24 | "spawn-point-block"
25 | ],
26 | "proBlocks": [
27 | "three-mirror-block"
28 | ]
29 | },
30 | "buildIncludes": [
31 | "three-object-viewer.php",
32 | "readme.txt",
33 | "php",
34 | "vendor",
35 | "build",
36 | "blocks/three-object-block/init.php",
37 | "blocks/environment/init.php",
38 | "blocks/model-block/init.php",
39 | "blocks/npc-block/init.php",
40 | "blocks/sky-block/init.php",
41 | "blocks/three-text-block/init.php",
42 | "blocks/three-image-block/init.php",
43 | "blocks/three-video-block/init.php",
44 | "blocks/three-portal-block/init.php",
45 | "blocks/spawn-point-block/init.php",
46 | "blocks/three-mirror-block/init.php",
47 | "admin/three-object-viewer-settings/init.php",
48 | "pro/admin/three-object-viewer-pro-settings/init.php"
49 | ]
50 | }
--------------------------------------------------------------------------------
/blocks/three-video-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
{attributes.videoUrl}
10 |
{attributes.scaleX}
11 |
{attributes.scaleY}
12 |
{attributes.scaleZ}
13 |
14 | {attributes.positionX}
15 |
16 |
17 | {attributes.positionY}
18 |
19 |
20 | {attributes.positionZ}
21 |
22 |
23 | {attributes.rotationX}
24 |
25 |
26 | {attributes.rotationY}
27 |
28 |
29 | {attributes.rotationZ}
30 |
31 |
32 | {attributes.autoPlay ? 1 : 0}
33 |
34 |
35 | {attributes.customModel ? 1 : 0}
36 |
37 |
38 | {attributes.aspectHeight}
39 |
40 |
41 | {attributes.aspectWidth}
42 |
43 |
{attributes.modelUrl}
44 |
45 | >
46 |
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-three-portal-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"blocks\/three-portal-block\/Edit.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Loop Animations":["Repetir Animaciones"],"Separate each animation name you wish to loop with a comma":["Separa cada nombre de animaci\u00f3n que deseas repetir con una coma"],"Scale":["Escala"],"Settings":["Ajustes"],"GLB Object":["Objeto GLB"],"Replace Object":["Reemplazar Objeto"],"Select Object":["Seleccionar Objeto"],"Model Attributes":["Atributos del Modelo"],"Collidable":["Colisionable"],"Item is currently collidable.":["El elemento es actualmente colisionable."],"Item is not collidable. Users will walk through it.":["El elemento no es colisionable. Los usuarios podr\u00e1n atravesarlo."],"Rotation":["Rotaci\u00f3n"],"Select a glb file from your media library to render an object in the canvas:":["Selecciona un archivo glb de tu biblioteca de medios para renderizar un objeto en el lienzo:"],"Destination URL":["URL de Destino"],"Define a url.":["Define una URL."],"Link Label":["Etiqueta del Enlace"],"This text will describe where the link goes. If blank, will use the url as the label.":["Este texto describir\u00e1 a d\u00f3nde lleva el enlace. Si est\u00e1 en blanco, se usar\u00e1 la URL como etiqueta."],"Text Color":["Color de Texto"],"Label Offset":["Desplazamiento de Etiqueta"],"X Offset":["Desplazamiento de X"],"Y Offset":["Desplazamiento de Y"],"Z Offset":["Desplazamiento de Z"],"Portal block":["Bloque de Portal"],"Select Portal":["Seleccionar Portal"]}}}
--------------------------------------------------------------------------------
/blocks/three-object-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/three-object-block",
3 | "title": "Three Object Block",
4 | "description": "A 3D object viewer focused on glTF",
5 | "attributes": {
6 | "bg_color": {
7 | "type": "string",
8 | "default": "#FFFFFF"
9 | },
10 | "zoom": {
11 | "type": "integer",
12 | "default": 1
13 | },
14 | "scale": {
15 | "type": "integer",
16 | "default": 1
17 | },
18 | "positionX": {
19 | "type": "integer",
20 | "default": 0
21 | },
22 | "positionY": {
23 | "type": "integer",
24 | "default": 0
25 | },
26 | "rotationY": {
27 | "type": "integer",
28 | "default": 0
29 | },
30 | "threeObjectUrl": {
31 | "type": "string",
32 | "default": null
33 | },
34 | "hasZoom": {
35 | "type": "bool",
36 | "default": false
37 | },
38 | "hasTip": {
39 | "type": "bool",
40 | "default": true
41 | },
42 | "deviceTarget": {
43 | "type": "string",
44 | "default": "2d"
45 | },
46 | "animations": {
47 | "type": "string",
48 | "default": ""
49 | }
50 | },
51 | "category": "media",
52 | "apiVersion": 2,
53 | "supports": {
54 | "html": false,
55 | "multiple": true
56 | },
57 | "editorScript": ["file:../../build/block-three-object-block.js"],
58 | "editorStyle": "file:../../build/block-three-object-block.css",
59 | "style": "file:../../build/block-three-object-block.css"
60 | }
61 |
--------------------------------------------------------------------------------
/blocks/three-light-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
10 | {attributes.positionX}
11 |
12 |
13 | {attributes.positionY}
14 |
15 |
16 | {attributes.positionZ}
17 |
18 |
19 | {attributes.rotationX}
20 |
21 |
22 | {attributes.rotationY}
23 |
24 |
25 | {attributes.rotationZ}
26 |
27 |
28 | {attributes.type}
29 |
30 |
31 | {attributes.color}
32 |
33 |
34 | {attributes.intensity}
35 |
36 |
37 | {attributes.distance}
38 |
39 |
40 | {attributes.decay}
41 |
42 |
43 | {attributes.targetX}
44 |
45 |
46 | {attributes.targetY}
47 |
48 |
49 | {attributes.targetZ}
50 |
51 |
52 | {attributes.angle}
53 |
54 |
55 | {attributes.penumbra}
56 |
57 |
58 | >
59 |
60 | );
61 | }
62 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-three-video-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"blocks\/three-video-block\/Edit.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"Scale":["\u30b9\u30b1\u30fc\u30eb"],"Settings":["\u8a2d\u5b9a"],"Replace Object":["\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Rotation":["\u56de\u8ee2"],"Item will autoplay.":["\u30a2\u30a4\u30c6\u30e0\u306f\u81ea\u52d5\u518d\u751f\u3055\u308c\u307e\u3059\u3002"],"Item will not autoplay.":["\u30a2\u30a4\u30c6\u30e0\u306f\u81ea\u52d5\u518d\u751f\u3055\u308c\u307e\u305b\u3093\u3002"],"Select an image to render in your environment:":["\u74b0\u5883\u5185\u306b\u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u3059\u308b\u753b\u50cf\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002"],"Video File":["\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb"],"Replace Video":["\u30d3\u30c7\u30aa\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select Video":["\u30d3\u30c7\u30aa\u3092\u9078\u629e\u3059\u308b"],"Custom Model":["\u30ab\u30b9\u30bf\u30e0\u30e2\u30c7\u30eb"],"Item will use a custom model. Name your faces 'screen'.":["\u30a2\u30a4\u30c6\u30e0\u306f\u30ab\u30b9\u30bf\u30e0\u30e2\u30c7\u30eb\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002\u30d5\u30a7\u30fc\u30b9\u3092 \u2018screen\u2019 \u3068\u540d\u524d\u3092\u4ed8\u3051\u3066\u304f\u3060\u3055\u3044\u3002"],"Item will not use a custom model.":["\u30a2\u30a4\u30c6\u30e0\u306f\u30ab\u30b9\u30bf\u30e0\u30e2\u30c7\u30eb\u3092\u4f7f\u7528\u3057\u307e\u305b\u3093\u3002"],"Replace model":["\u30e2\u30c7\u30eb\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select model":["\u30e2\u30c7\u30eb\u3092\u9078\u629e\u3059\u308b"],"Video block":["\u30d3\u30c7\u30aa\u30d6\u30ed\u30c3\u30af"]}}}
--------------------------------------------------------------------------------
/blocks/three-image-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/three-image-block",
3 | "attributes": {
4 | "imageUrl": {
5 | "type": "string",
6 | "default": null
7 | },
8 | "transparent": {
9 | "type": "boolean",
10 | "default": false
11 | },
12 | "scaleX": {
13 | "type": "int",
14 | "default":1
15 | },
16 | "scaleY": {
17 | "type": "int",
18 | "default":1
19 | },
20 | "scaleZ": {
21 | "type": "int",
22 | "default":1
23 | },
24 | "positionX": {
25 | "type": "int",
26 | "default":0
27 | },
28 | "positionY": {
29 | "type": "int",
30 | "default":0
31 | },
32 | "positionZ": {
33 | "type": "int",
34 | "default":0
35 | },
36 | "rotationX": {
37 | "type": "int",
38 | "default":0
39 | },
40 | "rotationY": {
41 | "type": "int",
42 | "default":0
43 | },
44 | "rotationZ": {
45 | "type": "int",
46 | "default":0
47 | },
48 | "aspectHeight": {
49 | "type": "int",
50 | "default":0
51 | },
52 | "aspectWidth": {
53 | "type": "int",
54 | "default":0
55 | }
56 | },
57 | "category": "design",
58 | "parent": [ "three-object-viewer/environment" ],
59 | "apiVersion": 2,
60 | "supports": {
61 | "html": false,
62 | "multiple": true
63 | },
64 | "textdomain": "three-object-viewer",
65 | "editorScript": "file:../../build/block-three-image-block.js",
66 | "editorStyle": "file:../../build/block-three-image-block.css",
67 | "style": "file:../../build/block-three-image-block.css"
68 | }
69 |
--------------------------------------------------------------------------------
/blocks/model-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/model-block",
3 | "attributes": {
4 | "scaleX": {
5 | "type": "int",
6 | "default":1
7 | },
8 | "name": {
9 | "type": "string"
10 | },
11 | "scaleY": {
12 | "type": "int",
13 | "default":1
14 | },
15 | "scaleZ": {
16 | "type": "int",
17 | "default":1
18 | },
19 | "positionX": {
20 | "type": "int",
21 | "default":0
22 | },
23 | "positionY": {
24 | "type": "int",
25 | "default":0
26 | },
27 | "positionZ": {
28 | "type": "int",
29 | "default":0
30 | },
31 | "rotationX": {
32 | "type": "int",
33 | "default":0
34 | },
35 | "rotationY": {
36 | "type": "int",
37 | "default":0
38 | },
39 | "rotationZ": {
40 | "type": "int",
41 | "default":0
42 | },
43 | "threeObjectUrl": {
44 | "type": "string",
45 | "default": null
46 | },
47 | "animations": {
48 | "type": "string",
49 | "default": ""
50 | },
51 | "alt": {
52 | "type": "string",
53 | "default": ""
54 | },
55 | "collidable": {
56 | "type": "boolean",
57 | "default": true
58 | }
59 | },
60 | "category": "design",
61 | "parent": [ "three-object-viewer/environment" ],
62 | "apiVersion": 2,
63 | "supports": {
64 | "html": false,
65 | "multiple": true
66 | },
67 | "textdomain": "three-object-viewer",
68 | "editorScript": "file:../../build/block-model-block.js",
69 | "editorStyle": "file:../../build/block-model-block.css",
70 | "style": "file:../../build/block-model-block.css"
71 | }
72 |
--------------------------------------------------------------------------------
/blocks/three-light-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/three-light-block",
3 | "attributes": {
4 | "type": {
5 | "type": "string",
6 | "default": "ambient"
7 | },
8 | "color": {
9 | "type": "string",
10 | "default": "0xffffff"
11 | },
12 | "intensity": {
13 | "type": "float",
14 | "default": 0.7
15 | },
16 | "distance": {
17 | "type": "int",
18 | "default": 100
19 | },
20 | "decay": {
21 | "type": "int",
22 | "default": 1
23 | },
24 | "positionX": {
25 | "type": "float",
26 | "default": 0
27 | },
28 | "positionY": {
29 | "type": "float",
30 | "default": 0
31 | },
32 | "positionZ": {
33 | "type": "float",
34 | "default": 0
35 | },
36 | "rotationX": {
37 | "type": "float",
38 | "default": 0
39 | },
40 | "rotationY": {
41 | "type": "float",
42 | "default": 0
43 | },
44 | "rotationZ": {
45 | "type": "float",
46 | "default": 0
47 | },
48 | "angle": {
49 | "type": "float",
50 | "default": 0.78539816339
51 | },
52 | "penumbra": {
53 | "type": "float",
54 | "default": 0.1
55 | }
56 | },
57 | "category": "design",
58 | "parent": [ "three-object-viewer/environment" ],
59 | "apiVersion": 2,
60 | "supports": {
61 | "html": false,
62 | "multiple": true
63 | },
64 | "textdomain": "three-object-viewer",
65 | "editorScript": "file:../../build/block-three-light-block.js",
66 | "editorStyle": "file:../../build/block-three-light-block.css",
67 | "style": "file:../../build/block-three-light-block.css"
68 | }
69 |
--------------------------------------------------------------------------------
/blocks/environment/components/core/front/ThreeSky.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useLoader } from "@react-three/fiber";
3 | import { TextureLoader, DoubleSide } from "three";
4 | import {
5 | Sky
6 | } from "@react-three/drei";
7 |
8 | /**
9 | * Represents a sky in a virtual reality scene.
10 | *
11 | * @param {Object} sky - The props for the sky.
12 | *
13 | * @return {JSX.Element} The sky.
14 | */
15 | export function ThreeSky(sky) {
16 | const skyUrl = sky.src[0].querySelector("p.sky-block-url")
17 | ? sky.src[0].querySelector("p.sky-block-url").innerText
18 | : "";
19 |
20 | const distance = sky.src[0].querySelector("p.sky-block-distance")
21 | ? sky.src[0].querySelector("p.sky-block-distance").innerText
22 | : "";
23 |
24 | const rayleigh = sky.src[0].querySelector("p.sky-block-rayleigh")
25 | ? sky.src[0].querySelector("p.sky-block-rayleigh").innerText
26 | : "";
27 |
28 | const sunPositionX = sky.src[0].querySelector("p.sky-block-sunPositionX")
29 | ? sky.src[0].querySelector("p.sky-block-sunPositionX").innerText
30 | : "";
31 |
32 | const sunPositionY = sky.src[0].querySelector("p.sky-block-sunPositionY")
33 | ? sky.src[0].querySelector("p.sky-block-sunPositionY").innerText
34 | : "";
35 |
36 | const sunPositionZ = sky.src[0].querySelector("p.sky-block-sunPositionZ")
37 | ? sky.src[0].querySelector("p.sky-block-sunPositionZ").innerText
38 | : "";
39 |
40 | if(skyUrl === "" || skyUrl === undefined || skyUrl === null) {
41 | return (
42 |
47 | );
48 | } else {
49 | const texture1 = useLoader(TextureLoader, skyUrl);
50 | return (
51 | <>
52 |
58 |
59 |
60 |
61 | >
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/.github/workflows/wordpress.yml:
--------------------------------------------------------------------------------
1 | name: WordPress Tests
2 |
3 | on: [push]
4 |
5 | env:
6 | WP_TESTS_DIR: /github/home/wp-tests/wordpress-tests-lib
7 | WP_CORE_DIR: /github/home/wp-tests/wordpress
8 |
9 | jobs:
10 | test:
11 | runs-on: ubuntu-latest
12 | strategy:
13 | matrix:
14 | php-version: [7.2, 7.3, 7.4]
15 | wordpress-version: [latest]
16 | container:
17 | image: junaidbhura/wp-tests:php-${{ matrix.php-version }}
18 | services:
19 | mysql:
20 | image: mysql:5.7.27
21 | options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
22 | env:
23 | MYSQL_ROOT_PASSWORD: root
24 |
25 | steps:
26 | # Setup
27 | - name: Checkout repository
28 | uses: actions/checkout@v1
29 |
30 | ## Install
31 | - name: Get Composer Cache Directory
32 | id: get-composer-cache-dir # Instead of composer-cache
33 | run: |
34 | echo "::set-output name=dir::$(composer config cache-files-dir)"
35 |
36 | - name: Cache Composer packages
37 | id: composer-cache
38 | uses: actions/cache@v2
39 | with:
40 | path: vendor
41 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
42 | restore-keys: |
43 | ${{ runner.os }}-php-
44 |
45 | - name: Install dependencies
46 | if: steps.composer-cache.outputs.cache-hit != 'true'
47 | run: composer install --prefer-dist --no-progress
48 |
49 | ## Install test suite
50 | - name: Install WordPress test suite
51 | run: bash bin/install-wp-tests.sh wordpress_test root root mysql ${{ matrix.wordpress-version }}
52 |
53 | ## Run integration tests
54 | - name: Tests
55 | run: composer test:wordpress
56 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-npc-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"blocks\/npc-block\/Edit.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"Settings":["\u8a2d\u5b9a"],"Name":["\u540d\u524d"],"Position":["\u4f4d\u7f6e"],"Rotation":["\u56de\u8ee2"],"NPC Options":["NPC\u30aa\u30d7\u30b7\u30e7\u30f3"],"Give your avatar a name.":["\u30a2\u30d0\u30bf\u30fc\u306b\u540d\u524d\u3092\u4ed8\u3051\u3066\u304f\u3060\u3055\u3044\u3002"],"Personality":["\u6027\u683c"],"Give your avatar a personality in 600 characters.":["600\u6587\u5b57\u3067\u30a2\u30d0\u30bf\u30fc\u306b\u6027\u683c\u3092\u4e0e\u3048\u3066\u304f\u3060\u3055\u3044\u3002"],"Default Message":["\u30c7\u30d5\u30a9\u30eb\u30c8\u30e1\u30c3\u30bb\u30fc\u30b8"],"Give your avatar a default message to initialize with.":["\u30a2\u30d0\u30bf\u30fc\u306b\u521d\u671f\u5316\u6642\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u8a2d\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002"],"Select a VRM file to be used as your NPC in world:":["\u30ef\u30fc\u30eb\u30c9\u5185\u3067NPC\u3068\u3057\u3066\u4f7f\u7528\u3059\u308b\u305f\u3081\u306eVRM\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002"],"Advanced Settings":["\u9ad8\u5ea6\u306a\u8a2d\u5b9a"],"Include World Objects in Prompt":["\u30d7\u30ed\u30f3\u30d7\u30c8\u306b\u30ef\u30fc\u30eb\u30c9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u542b\u3081\u308b"],"If enabled, will result in higher token costs with your AI service provider. Use with caution.":["\u6709\u52b9\u306b\u3059\u308b\u3068\u3001AI\u30b5\u30fc\u30d3\u30b9\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u306e\u30c8\u30fc\u30af\u30f3\u30b3\u30b9\u30c8\u304c\u5897\u52a0\u3059\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002\u6ce8\u610f\u3057\u3066\u4f7f\u7528\u3057\u3066\u304f\u3060\u3055\u3044\u3002"],"NPC block":["NPC\u30d6\u30ed\u30c3\u30af"],"Replace NPC":["NPC\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select NPC":["NPC\u3092\u9078\u629e\u3059\u308b"]}}}
--------------------------------------------------------------------------------
/blocks/three-portal-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
10 | {attributes.threeObjectUrl}
11 |
12 |
13 | {attributes.destinationUrl}
14 |
15 |
16 | {attributes.scaleX}
17 |
18 |
19 | {attributes.scaleY}
20 |
21 |
22 | {attributes.scaleZ}
23 |
24 |
25 | {attributes.positionX}
26 |
27 |
28 | {attributes.positionY}
29 |
30 |
31 | {attributes.positionZ}
32 |
33 |
34 | {attributes.rotationX}
35 |
36 |
37 | {attributes.rotationY}
38 |
39 |
40 | {attributes.rotationZ}
41 |
42 |
43 | {attributes.animations}
44 |
45 |
46 | {attributes.label}
47 |
48 |
49 | {attributes.labelOffsetX}
50 |
51 |
52 | {attributes.labelOffsetY}
53 |
54 |
55 | {attributes.labelOffsetZ}
56 |
57 |
58 | {attributes.labelTextColor}
59 |
60 |
61 | >
62 |
63 | );
64 | }
65 |
--------------------------------------------------------------------------------
/blocks/three-video-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/three-video-block",
3 | "attributes": {
4 | "videoUrl": {
5 | "type": "string",
6 | "default": null
7 | },
8 | "modelUrl": {
9 | "type": "string",
10 | "default": null
11 | },
12 | "autoPlay": {
13 | "type": "bool",
14 | "default": true
15 | },
16 | "scaleX": {
17 | "type": "int",
18 | "default":1
19 | },
20 | "scaleY": {
21 | "type": "int",
22 | "default":1
23 | },
24 | "scaleZ": {
25 | "type": "int",
26 | "default":1
27 | },
28 | "positionX": {
29 | "type": "int",
30 | "default":0
31 | },
32 | "positionY": {
33 | "type": "int",
34 | "default":0
35 | },
36 | "positionZ": {
37 | "type": "int",
38 | "default":0
39 | },
40 | "rotationX": {
41 | "type": "int",
42 | "default":0
43 | },
44 | "rotationY": {
45 | "type": "int",
46 | "default":0
47 | },
48 | "rotationZ": {
49 | "type": "int",
50 | "default":0
51 | },
52 | "aspectHeight": {
53 | "type": "int",
54 | "default":0
55 | },
56 | "aspectWidth": {
57 | "type": "int",
58 | "default":0
59 | },
60 | "customModel": {
61 | "type": "bool",
62 | "default": false
63 | }
64 | },
65 | "category": "design",
66 | "parent": [ "three-object-viewer/environment" ],
67 | "apiVersion": 2,
68 | "supports": {
69 | "html": false,
70 | "multiple": true
71 | },
72 | "textdomain": "three-object-viewer",
73 | "editorScript": "file:../../build/block-three-video-block.js",
74 | "editorStyle": "file:../../build/block-three-video-block.css",
75 | "style": "file:../../build/block-three-video-block.css"
76 | }
77 |
--------------------------------------------------------------------------------
/blocks/three-text-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/three-text-block",
3 | "attributes": {
4 | "scaleX": {
5 | "type": "int",
6 | "default":1
7 | },
8 | "scaleY": {
9 | "type": "int",
10 | "default":1
11 | },
12 | "scaleZ": {
13 | "type": "int",
14 | "default":1
15 | },
16 | "positionX": {
17 | "type": "int",
18 | "default":0
19 | },
20 | "positionY": {
21 | "type": "int",
22 | "default":0
23 | },
24 | "positionZ": {
25 | "type": "int",
26 | "default":0
27 | },
28 | "rotationX": {
29 | "type": "int",
30 | "default":0
31 | },
32 | "rotationY": {
33 | "type": "int",
34 | "default":0
35 | },
36 | "rotationZ": {
37 | "type": "int",
38 | "default":0
39 | },
40 | "threeObjectUrl": {
41 | "type": "string",
42 | "default": null
43 | },
44 | "destinationUrl": {
45 | "type": "string",
46 | "default": null
47 | },
48 | "textContent": {
49 | "type": "string",
50 | "default": null
51 | },
52 | "textColor": {
53 | "type": "string",
54 | "default": "0x000000"
55 | },
56 | "animations": {
57 | "type": "string",
58 | "default": ""
59 | },
60 | "collidable": {
61 | "type": "boolean",
62 | "default": false
63 | }
64 | },
65 | "category": "design",
66 | "parent": [ "three-object-viewer/environment" ],
67 | "apiVersion": 2,
68 | "supports": {
69 | "html": false,
70 | "multiple": true
71 | },
72 | "textdomain": "three-object-viewer",
73 | "editorScript": "file:../../build/block-three-text-block.js",
74 | "editorStyle": "file:../../build/block-three-text-block.css",
75 | "style": "file:../../build/block-three-text-block.css"
76 | }
77 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-environment-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-environment.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"Environment Settings":["\u74b0\u5883\u8a2d\u5b9a"],"Environment Object (Changing this value changes your scene ground planes)":["\u74b0\u5883\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff08\u3053\u306e\u5024\u3092\u5909\u66f4\u3059\u308b\u3068\u3001\u30b7\u30fc\u30f3\u306e\u5730\u9762\u304c\u5909\u308f\u308a\u307e\u3059\uff09"],"Select a glb file from your media library. This will be treated as a collidable mesh that visitors can walk on:":["\u30e1\u30c7\u30a3\u30a2\u30e9\u30a4\u30d6\u30e9\u30ea\u304b\u3089glb\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u3053\u308c\u306f\u8a2a\u554f\u8005\u304c\u6b69\u884c\u3067\u304d\u308b\u885d\u7a81\u30e1\u30c3\u30b7\u30e5\u3068\u3057\u3066\u6271\u308f\u308c\u307e\u3059\u3002"],"Replace Environment":["\u74b0\u5883\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select Environment":["\u74b0\u5883\u3092\u9078\u629e\u3059\u308b"],"Select an image to be used as the preview image:":["\u30d7\u30ec\u30d3\u30e5\u30fc\u753b\u50cf\u3068\u3057\u3066\u4f7f\u7528\u3059\u308b\u753b\u50cf\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002"],"Replace Image":["\u753b\u50cf\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select Image":["\u753b\u50cf\u3092\u9078\u629e\u3059\u308b"],"Replace HDR":["HDR\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select HDR":["HDR\u3092\u9078\u629e\u3059\u308b"],"Remove HDR":["HDR\u3092\u524a\u9664\u3059\u308b"],"Scene Settings":["\u30b7\u30fc\u30f3\u8a2d\u5b9a"],"Object Display Type:":["\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u8868\u793a\u30bf\u30a4\u30d7\uff1a"],"Loop Animations":["\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u3092\u30eb\u30fc\u30d7\u3059\u308b"],"Separate each animation name you wish to loop with a comma":["\u5404\u30eb\u30fc\u30d7\u3055\u305b\u305f\u3044\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u540d\u3092\u30b3\u30f3\u30de\u3067\u533a\u5207\u3063\u3066\u304f\u3060\u3055\u3044\u3002"],"Scale":["\u30b9\u30b1\u30fc\u30eb"],"Position Y":["Y\u5ea7\u6a19"],"Rotation Y":["Y\u8ef8\u56de\u8ee2"]}}}
--------------------------------------------------------------------------------
/blocks/three-audio-block/Save.js:
--------------------------------------------------------------------------------
1 | import { __ } from "@wordpress/i18n";
2 | import { useBlockProps } from "@wordpress/block-editor";
3 |
4 | export default function save({ attributes }) {
5 | return (
6 |
7 | <>
8 |
9 |
{attributes.audioUrl}
10 |
{attributes.scaleX}
11 |
{attributes.scaleY}
12 |
{attributes.scaleZ}
13 |
14 | {attributes.positionX}
15 |
16 |
17 | {attributes.positionY}
18 |
19 |
20 | {attributes.positionZ}
21 |
22 |
23 | {attributes.rotationX}
24 |
25 |
26 | {attributes.rotationY}
27 |
28 |
29 | {attributes.rotationZ}
30 |
31 |
32 | {attributes.autoPlay ? '1' : '0'}
33 |
34 |
35 | {attributes.loop ? '1' : '0'}
36 |
37 |
38 | {attributes.volume}
39 |
40 |
41 | {attributes.positional ? '1' : '0'}
42 |
43 |
44 | {attributes.coneInnerAngle}
45 |
46 |
47 | {attributes.coneOuterAngle}
48 |
49 |
50 | {attributes.coneOuterGain}
51 |
52 |
53 | {attributes.distanceModel}
54 |
55 |
56 | {attributes.maxDistance}
57 |
58 |
59 | {attributes.refDistance}
60 |
61 |
62 | {attributes.rolloffFactor}
63 |
64 |
65 | >
66 |
67 | );
68 | }
69 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.9"
2 |
3 | services:
4 |
5 | wordpress:
6 | depends_on:
7 | wpdb:
8 | condition: service_healthy
9 | image: wordpress:latest
10 | volumes:
11 | - wordpress_data:/var/www/html
12 | - ./:/var/www/html/wp-content/plugins/three-object-viewer
13 | ports:
14 | - "6039:80"
15 | restart: always
16 | environment:
17 | WORDPRESS_DB_HOST: wpdb:3306
18 | WORDPRESS_DB_USER: wordpress
19 | WORDPRESS_DB_PASSWORD: wordpress
20 | WORDPRESS_DB_NAME: wordpress
21 |
22 | wpdb:
23 | image: mariadb:10.5.8
24 | volumes:
25 | - db_data:/var/lib/mysql
26 | restart: always
27 | environment:
28 | MYSQL_ROOT_PASSWORD: wordpress
29 | MYSQL_DATABASE: wordpress
30 | MYSQL_USER: wordpress
31 | MYSQL_PASSWORD: wordpress
32 | healthcheck:
33 | test: "/usr/bin/mysql --user=wordpress --password=wordpress --execute \"SHOW DATABASES;\""
34 | interval: 3s
35 | timeout: 1s
36 | retries: 5
37 |
38 | wpcli:
39 | image: wordpress:cli
40 | depends_on:
41 | wpdb:
42 | condition: service_healthy
43 | volumes:
44 | - wordpress_data:/var/www/html
45 | - ./:/var/www/html/wp-content/plugins/three-object-viewer
46 | - ./db:/var/www/html/db
47 | environment:
48 | WORDPRESS_DB_HOST: wpdb:3306
49 | WORDPRESS_DB_USER: wordpress
50 | WORDPRESS_DB_PASSWORD: wordpress
51 | WORDPRESS_DB_NAME: wordpress
52 | ABSPATH: /usr/src/wordpress/
53 |
54 | phpunit:
55 | image: futureys/phpunit-wordpress-plugin
56 | depends_on:
57 | testwpdb:
58 | condition: service_healthy
59 | command:
60 | - bash
61 | depends_on:
62 | - testwpdb
63 | environment:
64 | DATABASE_PASSWORD: examplepass
65 | DATABASE_HOST: testwpdb
66 | stdin_open: true
67 | tty: true
68 | volumes:
69 | - ./:/plugin
70 |
71 | testwpdb:
72 | environment:
73 | MYSQL_ROOT_PASSWORD: examplepass
74 | image: mariadb:10.5.8
75 | healthcheck:
76 | test: "/usr/bin/mysql --user=wordpress --password=wordpress --execute \"SHOW DATABASES;\""
77 | interval: 3s
78 | timeout: 1s
79 | retries: 5
80 | volumes:
81 | db_data: {}
82 | wordpress_data: {}
83 |
--------------------------------------------------------------------------------
/rename.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | const HASH_to_file = [
5 | { '51af751c2048f283b39a777e1a3fae1b': 'three-object-viewer-three-portal-block-editor-script' },
6 | { 'bd2a3e7576d2e549fc22bfab35d48ca0': 'three-object-viewer-three-text-block-editor-script' },
7 | { 'a302549a555228fc26253251cff757bd': 'three-object-viewer-model-block-editor-script' },
8 | { 'a6625e41527a4ebb684bf747e8040213': 'three-object-viewer-three-audio-block-editor-script' },
9 | { 'f38ba41c49ce087276f6fb65a04d09f5': 'three-object-viewer-three-light-block-editor-script' },
10 | { '99e744b4fac1824cd9bd14f27bcce02b': 'three-object-viewer-npc-block-editor-script' },
11 | { '1c9eb460996b98bed51790c80e90f705': 'three-object-viewer-sky-block-editor-script' },
12 | { '760f26759af0cf80372c18dbbff3b8af': 'three-object-viewer-three-image-block-editor-script' },
13 | { '2f1be97f0700f196acecdfec131ed2a4': 'three-object-viewer-three-video-block-editor-script' },
14 | { 'db711d0e65eaf2e9518213c2fa3f74ff': 'three-object-viewer-spawn-point-block-editor-script' },
15 | { '05c0f6b04d52130d2210e3b0b4859a63': 'three-object-viewer-environment-editor-script' },
16 | { 'dd10ea5e2a0076c36967f4c3fdb50a0b': 'three-object-viewer-settings'}
17 | ];
18 |
19 | const folderPath = 'languages';
20 |
21 | fs.readdirSync(folderPath).forEach((file) => {
22 | const match = file.match(/three-object-viewer-es_MX-(.*).json/);
23 |
24 | if (match && match[1]) {
25 | const hash = match[1];
26 | const mapping = HASH_to_file.find((obj) => Object.keys(obj)[0] === hash);
27 |
28 | if (mapping) {
29 | const newName = 'three-object-viewer-es_MX-' + Object.values(mapping)[0] + '.json';
30 | fs.renameSync(path.join(folderPath, file), path.join(folderPath, newName));
31 | }
32 | }
33 | });
34 |
35 | fs.readdirSync(folderPath).forEach((file) => {
36 | const match = file.match(/three-object-viewer-ja-(.*).json/);
37 |
38 | if (match && match[1]) {
39 | const hash = match[1];
40 | const mapping = HASH_to_file.find((obj) => Object.keys(obj)[0] === hash);
41 |
42 | if (mapping) {
43 | const newName = 'three-object-viewer-ja-' + Object.values(mapping)[0] + '.json';
44 | fs.renameSync(path.join(folderPath, file), path.join(folderPath, newName));
45 | }
46 | }
47 | });
48 |
49 |
--------------------------------------------------------------------------------
/blocks/environment/components/Controls.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from 'react';
2 |
3 | export function useKeyboardControls() {
4 | const movement = useRef({
5 | forward: false,
6 | backward: false,
7 | left: false,
8 | right: false,
9 | shift: false,
10 | space: false
11 | });
12 |
13 | useEffect(() => {
14 | const handleKeyDown = (e) => {
15 | let element = e.target;
16 | // if the element is an input, dont move
17 | if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') return;
18 | if (e.key === 'w' || e.key === 'W' && ! movement.current.forward) movement.current.forward = true;
19 | else if (e.key === 's' || e.key === 'S' && ! movement.current.backward) movement.current.backward = true;
20 | else if (e.key === 'a' || e.key === 'A' && ! movement.current.left) movement.current.left = true;
21 | else if (e.key === 'd' || e.key === 'D' && ! movement.current.right) movement.current.right = true;
22 | else if (e.key === 'space') movement.current.space = true;
23 | else if (e.key === 'Shift') movement.current.shift = true;
24 | else if (e.key === 'r' || e.key === 'R'){
25 | if (e.metaKey || e.ctrlKey){
26 | movement.current.respawn = false;
27 | } else {
28 | movement.current.respawn = true;
29 | }
30 |
31 | }
32 |
33 | }
34 |
35 | const handleKeyUp = (e) => {
36 | if (e.key === 'w' || e.key === 'W') movement.current.forward = false;
37 | else if (e.key === 's' || e.key === 'S') movement.current.backward = false;
38 | else if (e.key === 'a' || e.key === 'A') movement.current.left = false;
39 | else if (e.key === 'd' || e.key === 'D') movement.current.right = false;
40 | else if (e.key === 'space') movement.current.space = false;
41 | else if (e.key === 'Shift') movement.current.shift = false;
42 | else if (e.key === 'r' || e.key === 'R') movement.current.respawn = false;
43 | }
44 |
45 | window.addEventListener('keydown', handleKeyDown);
46 | window.addEventListener('keyup', handleKeyUp);
47 |
48 | return () => {
49 | window.removeEventListener('keydown', handleKeyDown);
50 | window.removeEventListener('keyup', handleKeyUp);
51 | }
52 | }, []);
53 |
54 | return movement;
55 | }
56 |
--------------------------------------------------------------------------------
/blocks/three-object-block/frontend.js:
--------------------------------------------------------------------------------
1 | const { Component, render } = wp.element;
2 |
3 | import ThreeObjectFront from "./components/ThreeObjectFront";
4 |
5 | const threeApp = document.querySelectorAll(".three-object-three-app");
6 |
7 | threeApp.forEach((threeApp) => {
8 | if (threeApp) {
9 | const threeUrl = threeApp.querySelector("p.three-object-block-url")
10 | ? threeApp.querySelector("p.three-object-block-url").innerText
11 | : "";
12 | const deviceTarget = threeApp.querySelector(
13 | "p.three-object-block-device-target"
14 | )
15 | ? threeApp.querySelector("p.three-object-block-device-target")
16 | .innerText
17 | : "2D";
18 | const backgroundColor = threeApp.querySelector(
19 | "p.three-object-background-color"
20 | )
21 | ? threeApp.querySelector("p.three-object-background-color")
22 | .innerText
23 | : "#ffffff";
24 | const zoom = threeApp.querySelector("p.three-object-zoom")
25 | ? threeApp.querySelector("p.three-object-zoom").innerText
26 | : 90;
27 | const scale = threeApp.querySelector("p.three-object-scale")
28 | ? threeApp.querySelector("p.three-object-scale").innerText
29 | : 1;
30 | const hasZoom = threeApp.querySelector("p.three-object-has-zoom")
31 | ? threeApp.querySelector("p.three-object-has-zoom").innerText
32 | : false;
33 | const hasTip = threeApp.querySelector("p.three-object-has-tip")
34 | ? threeApp.querySelector("p.three-object-has-tip").innerText
35 | : true;
36 | const positionY = threeApp.querySelector("p.three-object-position-y")
37 | ? threeApp.querySelector("p.three-object-position-y").innerText
38 | : 0;
39 | const rotationY = threeApp.querySelector("p.three-object-rotation-y")
40 | ? threeApp.querySelector("p.three-object-rotation-y").innerText
41 | : 0;
42 | const animations = threeApp.querySelector("p.three-object-animations")
43 | ? threeApp.querySelector("p.three-object-animations").innerText
44 | : "";
45 |
46 | render(
47 | ,
61 | threeApp
62 | );
63 | }
64 | });
65 |
--------------------------------------------------------------------------------
/blocks/three-portal-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/three-portal-block",
3 | "attributes": {
4 | "scaleX": {
5 | "type": "int",
6 | "default":1
7 | },
8 | "scaleY": {
9 | "type": "int",
10 | "default":1
11 | },
12 | "scaleZ": {
13 | "type": "int",
14 | "default":1
15 | },
16 | "positionX": {
17 | "type": "int",
18 | "default":0
19 | },
20 | "positionY": {
21 | "type": "int",
22 | "default":0
23 | },
24 | "positionZ": {
25 | "type": "int",
26 | "default":0
27 | },
28 | "rotationX": {
29 | "type": "int",
30 | "default":0
31 | },
32 | "rotationY": {
33 | "type": "int",
34 | "default":0
35 | },
36 | "rotationZ": {
37 | "type": "int",
38 | "default":0
39 | },
40 | "threeObjectUrl": {
41 | "type": "string",
42 | "default": null
43 | },
44 | "destinationUrl": {
45 | "type": "string",
46 | "default": null
47 | },
48 | "label": {
49 | "type": "string",
50 | "default": null
51 | },
52 | "labelTextColor": {
53 | "type": "string",
54 | "default": "0x000000"
55 | },
56 | "labelOffsetX": {
57 | "type": "int",
58 | "default":0
59 | },
60 | "labelOffsetY": {
61 | "type": "int",
62 | "default":0
63 | },
64 | "labelOffsetZ": {
65 | "type": "int",
66 | "default":0
67 | },
68 | "animations": {
69 | "type": "string",
70 | "default": ""
71 | },
72 | "collidable": {
73 | "type": "boolean",
74 | "default": false
75 | }
76 | },
77 | "category": "design",
78 | "parent": [ "three-object-viewer/environment" ],
79 | "apiVersion": 2,
80 | "supports": {
81 | "html": false,
82 | "multiple": true
83 | },
84 | "textdomain": "three-object-viewer",
85 | "editorScript": "file:../../build/block-three-portal-block.js",
86 | "editorStyle": "file:../../build/block-three-portal-block.css",
87 | "style": "file:../../build/block-three-portal-block.css"
88 | }
89 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-settings.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"admin\/three-object-viewer-settings\/App.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"3OV Settings":["3OV\u8a2d\u5b9a"],"Select or Upload Media":["\u30e1\u30c7\u30a3\u30a2\u306e\u9078\u629e\u307e\u305f\u306f\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9"],"Use this media":["\u3053\u306e\u30e1\u30c7\u30a3\u30a2\u3092\u4f7f\u7528\u3059\u308b"],"Here you can manage the settings for 3OV to tweak global configuration options and save your API keys for connected serivces.":["\u3053\u3053\u3067\u306f\u30013OV\u306e\u8a2d\u5b9a\u3092\u7ba1\u7406\u3057\u3066\u3001\u30b0\u30ed\u30fc\u30d0\u30eb\u306a\u69cb\u6210\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u8abf\u6574\u3057\u3001\u63a5\u7d9a\u3055\u308c\u305f\u30b5\u30fc\u30d3\u30b9\u306eAPI\u30ad\u30fc\u3092\u4fdd\u5b58\u3067\u304d\u307e\u3059\u3002"],"Avatar Settings":["\u30a2\u30d0\u30bf\u30fc\u8a2d\u5b9a"],"Default animation":["\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3"],"No custom default animation set":["\u30ab\u30b9\u30bf\u30e0\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u306f\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002"],"Set Default Animation":["\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u3092\u8a2d\u5b9a\u3059\u308b"],"Clear Default Animation":["\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u3092\u30af\u30ea\u30a2\u3059\u308b"],"No custom default avatar set":["\u30ab\u30b9\u30bf\u30e0\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30a2\u30d0\u30bf\u30fc\u306f\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002"],"Set Default Avatar":["\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30a2\u30d0\u30bf\u30fc\u3092\u8a2d\u5b9a\u3059\u308b"],"Clear Default Avatar":["\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30a2\u30d0\u30bf\u30fc\u3092\u30af\u30ea\u30a2\u3059\u308b"],"AI Settings":["AI\u8a2d\u5b9a"],"NPC Settings":["NPC\u8a2d\u5b9a"],"Enable":["\u6709\u52b9\u306b\u3059\u308b"],"AI Endpoint URL":["AI\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306eURL"],"OpenAI API Token":["OpenAI API\u30c8\u30fc\u30af\u30f3"],"AI Access Level":["AI\u30a2\u30af\u30bb\u30b9\u30ec\u30d9\u30eb"],"Public":["\u30d1\u30d6\u30ea\u30c3\u30af"],"Logged In":["\u30ed\u30b0\u30a4\u30f3\u6e08\u307f"],"Saving...":["\u4fdd\u5b58\u4e2d\u2026"]}}}
--------------------------------------------------------------------------------
/blocks/three-audio-block/block.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-object-viewer/three-audio-block",
3 | "attributes": {
4 | "name": {
5 | "type": "string",
6 | "default": null
7 | },
8 | "audioUrl": {
9 | "type": "string",
10 | "default": null
11 | },
12 | "autoPlay": {
13 | "type": "bool",
14 | "default": true
15 | },
16 | "loop": {
17 | "type": "bool",
18 | "default": true
19 | },
20 | "volume": {
21 | "type": "int",
22 | "default": 1
23 | },
24 | "positional": {
25 | "type": "bool",
26 | "default": true
27 | },
28 | "coneInnerAngle": {
29 | "type": "int",
30 | "default":360
31 | },
32 | "coneOuterAngle": {
33 | "type": "int",
34 | "default":0
35 | },
36 | "coneOuterGain": {
37 | "type": "int",
38 | "default":0.8
39 | },
40 | "distanceModel": {
41 | "type": "string",
42 | "default": "inverse"
43 | },
44 | "maxDistance": {
45 | "type": "int",
46 | "default":10000
47 | },
48 | "refDistance": {
49 | "type": "int",
50 | "default":5
51 | },
52 | "rolloffFactor": {
53 | "type": "int",
54 | "default":5
55 | },
56 | "positionX": {
57 | "type": "int",
58 | "default":0
59 | },
60 | "positionY": {
61 | "type": "int",
62 | "default":0
63 | },
64 | "positionZ": {
65 | "type": "int",
66 | "default":0
67 | },
68 | "rotationX": {
69 | "type": "int",
70 | "default":0
71 | },
72 | "rotationY": {
73 | "type": "int",
74 | "default":0
75 | },
76 | "rotationZ": {
77 | "type": "int",
78 | "default":0
79 | }
80 | },
81 | "category": "design",
82 | "parent": [ "three-object-viewer/environment" ],
83 | "apiVersion": 2,
84 | "supports": {
85 | "html": false,
86 | "multiple": true
87 | },
88 | "textdomain": "three-object-viewer",
89 | "editorScript": "file:../../build/block-three-audio-block.js",
90 | "editorStyle": "file:../../build/block-three-audio-block.css",
91 | "style": "file:../../build/block-three-audio-block.css"
92 | }
93 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-model-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-model-block.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"Loop Animations":["\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u3092\u30eb\u30fc\u30d7\u3059\u308b"],"Separate each animation name you wish to loop with a comma":["\u5404\u30eb\u30fc\u30d7\u3055\u305b\u305f\u3044\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u540d\u3092\u30b3\u30f3\u30de\u3067\u533a\u5207\u3063\u3066\u304f\u3060\u3055\u3044\u3002"],"Scale":["\u30b9\u30b1\u30fc\u30eb"],"Settings":["\u8a2d\u5b9a"],"GLB Object":["GLB\u30aa\u30d6\u30b8\u30a7\u30af\u30c8"],"Name":["\u540d\u524d"],"Give your object a name.":["\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306b\u540d\u524d\u3092\u4ed8\u3051\u3066\u304f\u3060\u3055\u3044\u3002"],"select a glb file from your media library to render an object in the canvas:":["\u30ad\u30e3\u30f3\u30d0\u30b9\u4e0a\u306b\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u3059\u308b\u305f\u3081\u306b\u3001\u30e1\u30c7\u30a3\u30a2\u30e9\u30a4\u30d6\u30e9\u30ea\u304b\u3089glb\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002"],"GLB File":["GLB\u30d5\u30a1\u30a4\u30eb"],"Replace Object":["\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select Object":["\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u9078\u629e\u3059\u308b"],"Model Attributes":["\u30e2\u30c7\u30eb\u306e\u5c5e\u6027"],"Collidable":["\u885d\u7a81\u53ef\u80fd"],"Item is currently collidable.":["\u30a2\u30a4\u30c6\u30e0\u306f\u73fe\u5728\u885d\u7a81\u53ef\u80fd\u3067\u3059\u3002"],"Item is not collidable. Users will walk through it.":["\u30a2\u30a4\u30c6\u30e0\u306f\u885d\u7a81\u3057\u306a\u3044\u8a2d\u5b9a\u3067\u3059\u3002\u30e6\u30fc\u30b6\u30fc\u306f\u305d\u308c\u3092\u901a\u308a\u629c\u3051\u307e\u3059\u3002"],"Model Alt Text":["\u30e2\u30c7\u30eb\u306e\u4ee3\u66ff\u30c6\u30ad\u30b9\u30c8"],"Describe your model to provide context for screen readers.":["\u753b\u9762\u8aad\u307f\u4e0a\u3052\u30bd\u30d5\u30c8\u30a6\u30a7\u30a2\u306b\u5bfe\u3057\u3066\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3092\u63d0\u4f9b\u3059\u308b\u305f\u3081\u306b\u3001\u30e2\u30c7\u30eb\u3092\u8aac\u660e\u3057\u3066\u304f\u3060\u3055\u3044\u3002"],"Position":["\u4f4d\u7f6e"],"Rotation":["\u56de\u8ee2"],"Model block":["\u30e2\u30c7\u30eb\u30d6\u30ed\u30c3\u30af"],"Replace Model":["\u30e2\u30c7\u30eb\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select Model":["\u30e2\u30c7\u30eb\u3092\u9078\u629e\u3059\u308b"]}}}
--------------------------------------------------------------------------------
/languages/three-object-viewer-ja-three-object-viewer-three-portal-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:23-0500","generator":"WP-CLI\/2.8.1","source":"blocks\/three-portal-block\/Edit.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"ja","plural-forms":"nplurals=2; plural=(n != 1);"},"Loop Animations":["\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u3092\u30eb\u30fc\u30d7\u3059\u308b"],"Separate each animation name you wish to loop with a comma":["\u5404\u30eb\u30fc\u30d7\u3055\u305b\u305f\u3044\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u540d\u3092\u30b3\u30f3\u30de\u3067\u533a\u5207\u3063\u3066\u304f\u3060\u3055\u3044\u3002"],"Scale":["\u30b9\u30b1\u30fc\u30eb"],"Settings":["\u8a2d\u5b9a"],"GLB Object":["GLB\u30aa\u30d6\u30b8\u30a7\u30af\u30c8"],"Replace Object":["\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u7f6e\u304d\u63db\u3048\u308b"],"Select Object":["\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u9078\u629e\u3059\u308b"],"Model Attributes":["\u30e2\u30c7\u30eb\u306e\u5c5e\u6027"],"Collidable":["\u885d\u7a81\u53ef\u80fd"],"Item is currently collidable.":["\u30a2\u30a4\u30c6\u30e0\u306f\u73fe\u5728\u885d\u7a81\u53ef\u80fd\u3067\u3059\u3002"],"Item is not collidable. Users will walk through it.":["\u30a2\u30a4\u30c6\u30e0\u306f\u885d\u7a81\u3057\u306a\u3044\u8a2d\u5b9a\u3067\u3059\u3002\u30e6\u30fc\u30b6\u30fc\u306f\u305d\u308c\u3092\u901a\u308a\u629c\u3051\u307e\u3059\u3002"],"Rotation":["\u56de\u8ee2"],"Select a glb file from your media library to render an object in the canvas:":["\u30e1\u30c7\u30a3\u30a2\u30e9\u30a4\u30d6\u30e9\u30ea\u304b\u3089GLB\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3057\u3066\u3001\u30ad\u30e3\u30f3\u30d0\u30b9\u306b\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u3057\u3066\u304f\u3060\u3055\u3044\u3002"],"Destination URL":["\u5b9b\u5148\u306eURL"],"Define a url.":["URL\u3092\u5b9a\u7fa9\u3057\u3066\u304f\u3060\u3055\u3044\u3002"],"Link Label":["\u30ea\u30f3\u30af\u306e\u30e9\u30d9\u30eb"],"This text will describe where the link goes. If blank, will use the url as the label.":["\u3053\u306e\u30c6\u30ad\u30b9\u30c8\u306f\u30ea\u30f3\u30af\u5148\u3092\u8aac\u660e\u3057\u307e\u3059\u3002\u7a7a\u767d\u306e\u5834\u5408\u3001URL\u304c\u30e9\u30d9\u30eb\u3068\u3057\u3066\u4f7f\u7528\u3055\u308c\u307e\u3059\u3002"],"Text Color":["\u30c6\u30ad\u30b9\u30c8\u306e\u8272"],"Label Offset":["\u30e9\u30d9\u30eb\u306e\u30aa\u30d5\u30bb\u30c3\u30c8"],"X Offset":["X\u30aa\u30d5\u30bb\u30c3\u30c8"],"Y Offset":["Y\u30aa\u30d5\u30bb\u30c3\u30c8"],"Z Offset":["Z\u30aa\u30d5\u30bb\u30c3\u30c8"],"Portal block":["\u30dd\u30fc\u30bf\u30eb\u30d6\u30ed\u30c3\u30af"],"Select Portal":["\u30dd\u30fc\u30bf\u30eb\u3092\u9078\u629e\u3059\u308b"]}}}
--------------------------------------------------------------------------------
/blocks/three-object-block/components/TeleportTravel.js:
--------------------------------------------------------------------------------
1 | import { Raycaster, Vector3 } from "three";
2 | import { useXR, Interactive } from "@react-three/xr";
3 | import { useFrame } from "@react-three/fiber";
4 | import { useCallback, useRef, useState } from "react";
5 |
6 | export function TeleportIndicator(props) {
7 | return (
8 | <>
9 |
10 |
11 |
12 |
13 |
14 | >
15 | );
16 | }
17 |
18 | export default function TeleportTravel(props) {
19 | const {
20 | centerOnTeleport,
21 | Indicator = TeleportIndicator,
22 | useNormal = true
23 | } = props;
24 | const [isHovered, setIsHovered] = useState(false);
25 | const target = useRef();
26 | const targetLoc = useRef();
27 | const ray = useRef(new Raycaster());
28 |
29 | const rayDir = useRef({
30 | pos: new Vector3(),
31 | dir: new Vector3()
32 | });
33 |
34 | const { controllers, player } = useXR();
35 |
36 | useFrame(() => {
37 | if (
38 | isHovered &&
39 | controllers.length > 0 &&
40 | ray.current &&
41 | target.current &&
42 | targetLoc.current
43 | ) {
44 | controllers[0].controller.getWorldDirection(rayDir.current.dir);
45 | controllers[0].controller.getWorldPosition(rayDir.current.pos);
46 | rayDir.current.dir.multiplyScalar(-1);
47 | ray.current.set(rayDir.current.pos, rayDir.current.dir);
48 |
49 | const [intersection] = ray.current.intersectObject(target.current);
50 |
51 | if (intersection) {
52 | if (useNormal) {
53 | const p = intersection.point;
54 |
55 | targetLoc.current.position.set(0, 0, 0);
56 |
57 | const n = intersection.face.normal.clone();
58 | n.transformDirection(intersection.object.matrixWorld);
59 |
60 | targetLoc.current.lookAt(n);
61 | targetLoc.current.rotateOnAxis(
62 | new Vector3(1, 0, 0),
63 | Math.PI / 2
64 | );
65 | targetLoc.current.position.copy(p);
66 | } else {
67 | targetLoc.current.position.copy(intersection.point);
68 | }
69 | }
70 | }
71 | });
72 |
73 | const click = useCallback(() => {
74 | if (isHovered) {
75 | player.position.copy(targetLoc.current.position);
76 | }
77 | }, [centerOnTeleport, isHovered, useNormal]);
78 |
79 | return (
80 | <>
81 | {isHovered && (
82 |
83 |
84 |
85 | )}
86 | setIsHovered(true)}
89 | onBlur={() => setIsHovered(false)}
90 | >
91 | {props.children}
92 |
93 | >
94 | );
95 | }
96 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Three Object Viewer
2 |
3 | [](https://pluginmachine.com)
4 |
5 | ## Installation
6 |
7 | Download the from WordPress or install by searching for "Three Object Viewer" in the plugin repository in wp-admin.
8 | https://wordpress.org/plugins/three-object-viewer/
9 |
10 |
11 | ## Local Development
12 |
13 | - Git clone:
14 | - `git clone git@github.com:antpb/three-object-viewer.git`
15 | - Install javascript dependencies
16 | - `yarn`
17 | - Install php dependencies
18 | - `composer install`
19 |
20 | ## Working With JavaScript
21 |
22 | - Build JS/CSS
23 | - `yarn build`
24 | - Start JS/CSS for development - currently broken
25 | - `yarn start`
26 | - Test changed files - pending tests
27 | - `yarn test --watch`
28 | - Test all files once
29 | - `yarn test`
30 | - `yarn test --ci`
31 |
32 |
33 | ## Working With PHP
34 |
35 | ### Autoloader
36 |
37 | PHP classes should be located in the "php" directory and follow the [PSR-4 standard](https://www.php-fig.org/psr/psr-4/).
38 |
39 | The root namespace is `threeObjectViewer`.
40 |
41 |
42 |
43 | ### Tests
44 | - Run unit tests
45 | - `composer test:unit`
46 | - Run WordPress tests
47 | - `composer test:wordpress`
48 | - See local development instructions for how to run with Docker.
49 | - Run unit tests and WordPress tests
50 | - `composer test`
51 |
52 | ### Linter
53 |
54 | [PHPCS](https://github.com/squizlabs/PHP_CodeSniffer) is installed for linting and [automatic code fixing](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Fixing-Errors-Automatically).
55 |
56 | - Run linter and autofix
57 | - `composer fixes`
58 | - Run linter to identify issues.
59 | - `compose sniffs`
60 |
61 | ## Local Development Environment
62 |
63 | A [docker-compose](https://docs.docker.com/samples/wordpress/)-based local development environment is provided.
64 |
65 | - Start server
66 | - `docker-compose up -d`
67 | - Acess Site
68 | - [http://localhost:6039](http://localhost:6039)
69 | - WP CLI
70 | - Run any WP CLI command in container:
71 | - `docker-compose run wpcli wp ...`
72 | - Setup site with WP CLI
73 | - `docker-compose run wpcli wp core install --url=http://localhost:6039 --title="Three Object Viewer" --admin_user=admin0 --admin_email=something@example.com`
74 | - `docker-compose run wpcli wp user create admin admin@example.com --role=administrator --user_pass=pass`
75 |
76 |
77 | There is a special phpunit container for running WordPress tests, with WordPress and MySQL configured.
78 |
79 | - Enter container
80 | - `docker-compose run phpunit`
81 | - Composer install
82 | - `composer install`
83 | - Test
84 | - `composer test:wordpress`
85 |
86 |
--------------------------------------------------------------------------------
/blocks/environment/components/core/front/ThreeLight.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { useThree } from "@react-three/fiber";
3 | import {
4 | DirectionalLight,
5 | AmbientLight,
6 | PointLight,
7 | SpotLight,
8 | Color
9 | } from "three";
10 |
11 | /**
12 | * Light component that creates various Three.js light objects based on the provided configuration.
13 | *
14 | * @param {Object} threeLight - An object containing light configuration options.
15 | * @param {string} threeLight.type - The type of light: "directional", "ambient", "point", "spot".
16 | * @param {number} threeLight.color - The color of the light.
17 | * @param {number} threeLight.intensity - The intensity of the light.
18 | * @param {number} threeLight.distance - Maximum range of the point light (for PointLight).
19 | * @param {number} threeLight.decay - The amount the light dims along the distance of the point light (for PointLight).
20 | * @param {number} threeLight.positionX - The X-coordinate of the light's position.
21 | * @param {number} threeLight.positionY - The Y-coordinate of the light's position.
22 | * @param {number} threeLight.positionZ - The Z-coordinate of the light's position.
23 | * @param {number} threeLight.angle - Maximum extent of the spotlight, in radians (for SpotLight).
24 | * @param {number} threeLight.penumbra - Percentage of the spotlight cone that is attenuated due to penumbra (for SpotLight).
25 | *
26 | * @returns {JSX.Element} - Returns a JSX element containing a Three.js light object.
27 | */
28 | export function ThreeLight(threeLight) {
29 | const { scene } = useThree();
30 |
31 | useEffect(() => {
32 | let lightInstance;
33 | const color = new Color( threeLight.color );
34 |
35 | switch (threeLight.type) {
36 | case "directional":
37 | lightInstance = new DirectionalLight(color, threeLight.intensity);
38 | lightInstance.position.set(threeLight.positionX, threeLight.positionY, threeLight.positionZ);
39 | break;
40 |
41 | case "ambient":
42 | lightInstance = new AmbientLight(color, Number(threeLight.intensity));
43 | break;
44 |
45 | case "point":
46 | lightInstance = new PointLight(color, threeLight.intensity, threeLight.distance, threeLight.decay);
47 | lightInstance.position.set(threeLight.positionX, threeLight.positionY, threeLight.positionZ);
48 | break;
49 |
50 | case "spot":
51 | lightInstance = new SpotLight(color, threeLight.intensity, threeLight.distance, threeLight.angle, threeLight.penumbra);
52 | lightInstance.position.set(threeLight.positionX, threeLight.positionY, threeLight.positionZ);
53 | break;
54 |
55 | default:
56 | console.warn("Invalid light type provided");
57 | }
58 |
59 | // add the light to the scene
60 | scene.add(lightInstance);
61 | }, []);
62 |
63 | return;
64 | }
65 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@antpb/three-object-viewer",
3 | "private": true,
4 | "version": "0.6.3",
5 | "license": "GPL-2.0-or-later",
6 | "main": "build/index.js",
7 | "scripts": {
8 | "test": "yarn test:unit",
9 | "test:unit": "wp-scripts test-unit-js",
10 | "build": "wp-scripts build",
11 | "build:pro": "ISPRO=true wp-scripts build && node package.js pro",
12 | "build:free": "wp-scripts build && node package.js free",
13 | "test:ci": "wp-scripts test-unit-js --passWithNoTests",
14 | "format:js": "wp-scripts format-js",
15 | "lint:css": "wp-scripts lint-style",
16 | "lint:js": "wp-scripts lint-js",
17 | "start": "wp-scripts start",
18 | "rename": "node rename.js",
19 | "make-pot": "vendor/bin/wp i18n make-pot . ./languages/three-object-viewer.pot --slug=three-object-viewer --domain=three-object-viewer",
20 | "make-json": "vendor/bin/wp i18n make-json ./languages/ --no-purge"
21 | },
22 | "devDependencies": {
23 | "@babel/core": "^7",
24 | "@testing-library/react": "^12",
25 | "@wordpress/eslint-plugin": "^13.5.0",
26 | "@wordpress/scripts": "^16",
27 | "airtap": "^4.0.4",
28 | "browserify": "^17.0.0",
29 | "esbuild": "^0.15.5",
30 | "eslint": "^8.7.0",
31 | "fs-extra": "^11.1.1",
32 | "lint-staged": "^13.0.3",
33 | "prettier": "^2.7.1",
34 | "prettier-standard": "^16.4.1",
35 | "standard": "^17.0.0",
36 | "tape": "^5.6.0",
37 | "tinyify": "^3.1.0"
38 | },
39 | "dependencies": {
40 | "@babel/plugin-proposal-optional-chaining": "^7.18.9",
41 | "@babel/preset-env": "^7.20.2",
42 | "@babel/preset-react": "^7.18.6",
43 | "@pixiv/three-vrm": "2.0.1",
44 | "@react-three/a11y": "2.2.4",
45 | "@react-three/drei": "8.20.2",
46 | "@react-three/fiber": "8.12.0",
47 | "@react-three/rapier": "1.0.1",
48 | "@react-three/xr": "^3.5.0",
49 | "@wordpress/block-editor": "^6",
50 | "@wordpress/blocks": "^9",
51 | "@wordpress/components": "^14",
52 | "@wordpress/element": "^3",
53 | "@wordpress/i18n": "^4.40.0",
54 | "@wordpress/icons": "^9.17.0",
55 | "array-buffer-to-hex": "^1.0.0",
56 | "axios": "^1.2.1",
57 | "babel-loader": "8",
58 | "base64-arraybuffer": "^1.0.2",
59 | "camera-controls": "^2.7.0",
60 | "convert-hex": "^0.1.0",
61 | "events": "^3.3.0",
62 | "get-browser-rtc": "^1.1.0",
63 | "image-webpack-loader": "^8.1.0",
64 | "json-loader": "^0.5.7",
65 | "r3f-perf": "4.9.1",
66 | "re-resizable": "^6.9.9",
67 | "react-nipple": "^1.0.2",
68 | "react-scrollable-feed": "^1.3.1",
69 | "sass-loader": "^13.2.0",
70 | "style-loader": "2.0.0",
71 | "three": "0.151.1",
72 | "three-icosa": "^0.4.0",
73 | "three-omi": "^0.1.5",
74 | "tiny-simple-peer": "^10.1.1",
75 | "webpack-glsl-loader": "^1.0.1"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/blocks/environment/components/EditControls.js:
--------------------------------------------------------------------------------
1 | import React, { useRef, useState } from "react";
2 |
3 | import { useFrame, useThree } from "@react-three/fiber";
4 | import { PointerLockControls, OrbitControls } from "@react-three/drei";
5 |
6 | const EditControls = (props) => {
7 | const controlsRef = useRef();
8 | const isLocked = useRef(false);
9 | const [moveForward, setMoveForward] = useState(false);
10 | const [moveBackward, setMoveBackward] = useState(false);
11 | const [moveLeft, setMoveLeft] = useState(false);
12 | const [moveRight, setMoveRight] = useState(false);
13 | const [jump, setJump] = useState(false);
14 |
15 | useFrame(() => {
16 | const velocity = 0.5;
17 |
18 | if (moveForward) {
19 | // playerThing.applyImpulse({x:0, y:0, z:0.1}, true);
20 | controlsRef.current.moveForward(velocity);
21 | } else if (moveLeft) {
22 | controlsRef.current.moveRight(-velocity);
23 | } else if (moveBackward) {
24 | controlsRef.current.moveForward(-velocity);
25 | } else if (moveRight) {
26 | controlsRef.current.moveRight(velocity);
27 | } else if (jump) {
28 | }
29 | });
30 |
31 | const onKeyDown = function (event, props) {
32 | switch (event.code) {
33 | case "ArrowUp":
34 | case "KeyW":
35 | setMoveForward(true);
36 | break;
37 |
38 | case "ArrowLeft":
39 | case "KeyA":
40 | setMoveLeft(true);
41 | break;
42 |
43 | case "ArrowDown":
44 | case "KeyS":
45 | setMoveBackward(true);
46 | break;
47 |
48 | case "ArrowRight":
49 | case "KeyD":
50 | setMoveRight(true);
51 | break;
52 | case "Space":
53 | window.addEventListener("keydown", (e) => {
54 | if (e.keyCode === 32 && e.target === document.body) {
55 | e.preventDefault();
56 | }
57 | });
58 | setJump(true);
59 | break;
60 | default:
61 | }
62 | };
63 |
64 | const onKeyUp = function (event) {
65 | switch (event.code) {
66 | case "ArrowUp":
67 | case "KeyW":
68 | setMoveForward(false);
69 | break;
70 |
71 | case "ArrowLeft":
72 | case "KeyA":
73 | setMoveLeft(false);
74 | break;
75 |
76 | case "ArrowDown":
77 | case "KeyS":
78 | setMoveBackward(false);
79 | break;
80 |
81 | case "Space":
82 | setJump(false);
83 | break;
84 |
85 | case "ArrowRight":
86 | case "KeyD":
87 | setMoveRight(false);
88 | break;
89 |
90 | default:
91 | }
92 | };
93 |
94 | document.addEventListener("keydown", onKeyDown);
95 | document.addEventListener("keyup", onKeyUp);
96 | const { gl } = useThree();
97 | if (gl) {
98 | return (
99 | {
102 | if (controlsRef.current) {
103 | renderer.addEventListener("lock", () => {
104 | console.log("lock");
105 | isLocked.current = true;
106 | });
107 | controlsRef.current.addEventListener("unlock", () => {
108 | console.log("unlock");
109 | isLocked.current = false;
110 | });
111 | }
112 | }}
113 | ref={controlsRef}
114 | />
115 | );
116 | }
117 | };
118 |
119 | export default EditControls;
120 |
--------------------------------------------------------------------------------
/blocks/model-block/components/ModelEdit.js:
--------------------------------------------------------------------------------
1 | import * as THREE from "three";
2 | import React, { Suspense, useRef, useState, useEffect } from "react";
3 | import { Canvas, useLoader, useFrame, useThree } from "@react-three/fiber";
4 | import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
5 | import {
6 | OrthographicCamera,
7 | PerspectiveCamera,
8 | OrbitControls,
9 | useAnimations
10 | } from "@react-three/drei";
11 | import { VRM, VRMUtils, VRMSchema, VRMLoaderPlugin } from "@pixiv/three-vrm";
12 | import { GLTFAudioEmitterExtension } from "three-omi";
13 |
14 | function ThreeObject(props) {
15 | const [url, set] = useState(props.url);
16 | useEffect(() => {
17 | setTimeout(() => set(props.url), 2000);
18 | }, []);
19 | const [listener] = useState(() => new THREE.AudioListener());
20 |
21 | useThree(({ camera }) => {
22 | camera.add(listener);
23 | });
24 |
25 | const gltf = useLoader(GLTFLoader, url, (loader) => {
26 | loader.register(
27 | (parser) => new GLTFAudioEmitterExtension(parser, listener)
28 | );
29 | loader.register((parser) => {
30 | return new VRMLoaderPlugin(parser);
31 | });
32 | });
33 |
34 | const { actions } = useAnimations(gltf.animations, gltf.scene);
35 |
36 | const animationList = props.animations ? props.animations.split(",") : "";
37 |
38 | useEffect(() => {
39 | if (animationList) {
40 | animationList.forEach((name) => {
41 | if (Object.keys(actions).includes(name)) {
42 | actions[name].play();
43 | }
44 | });
45 | }
46 | }, []);
47 |
48 | if (gltf?.userData?.gltfExtensions?.VRM) {
49 | const vrm = gltf.userData.vrm;
50 | vrm.scene.position.set(0, props.positionY, 0);
51 | VRMUtils.rotateVRM0(vrm);
52 | const rotationVRM = vrm.scene.rotation.y + parseFloat(props.rotationY);
53 | vrm.scene.rotation.set(0, rotationVRM, 0);
54 | // vrm.scene.scale.set( props.scaleX, props.scaleY, props.scaleZ );
55 | return ;
56 | }
57 | gltf.scene.position.set(0, 0, 0);
58 | gltf.scene.rotation.set(0, 0, 0);
59 | gltf.scene.scale.set(1, 1, 1);
60 | return ;
61 | }
62 |
63 | export default function ModelEdit(props) {
64 | return (
65 | <>
66 |
76 |
82 |
83 |
90 | {props.url && (
91 |
92 |
97 |
98 | )}
99 |
100 |
101 | {props.hasTip && (
102 | Click and drag ^
103 | )}
104 | >
105 | );
106 | }
107 |
--------------------------------------------------------------------------------
/blocks/npc-block/components/ModelEdit.js:
--------------------------------------------------------------------------------
1 | import * as THREE from "three";
2 | import React, { Suspense, useRef, useState, useEffect } from "react";
3 | import { Canvas, useLoader, useFrame, useThree } from "@react-three/fiber";
4 | import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
5 | import {
6 | OrthographicCamera,
7 | PerspectiveCamera,
8 | OrbitControls,
9 | useAnimations
10 | } from "@react-three/drei";
11 | import { VRM, VRMUtils, VRMSchema, VRMLoaderPlugin } from "@pixiv/three-vrm";
12 | import { GLTFAudioEmitterExtension } from "three-omi";
13 |
14 | function ThreeObject(props) {
15 | const [url, set] = useState(props.url);
16 | useEffect(() => {
17 | setTimeout(() => set(props.url), 2000);
18 | }, []);
19 | const [listener] = useState(() => new THREE.AudioListener());
20 |
21 | useThree(({ camera }) => {
22 | camera.add(listener);
23 | });
24 |
25 | const gltf = useLoader(GLTFLoader, url, (loader) => {
26 | loader.register(
27 | (parser) => new GLTFAudioEmitterExtension(parser, listener)
28 | );
29 | loader.register((parser) => {
30 | return new VRMLoaderPlugin(parser);
31 | });
32 | });
33 |
34 | const { actions } = useAnimations(gltf.animations, gltf.scene);
35 |
36 | const animationList = props.animations ? props.animations.split(",") : "";
37 |
38 | useEffect(() => {
39 | if (animationList) {
40 | animationList.forEach((name) => {
41 | if (Object.keys(actions).includes(name)) {
42 | actions[name].play();
43 | }
44 | });
45 | }
46 | }, []);
47 |
48 | if (gltf?.userData?.gltfExtensions?.VRM) {
49 | const vrm = gltf.userData.vrm;
50 | vrm.scene.position.set(0, props.positionY, 0);
51 | VRMUtils.rotateVRM0(vrm);
52 | const rotationVRM = vrm.scene.rotation.y + parseFloat(props.rotationY);
53 | vrm.scene.rotation.set(0, rotationVRM, 0);
54 | // vrm.scene.scale.set( props.scaleX, props.scaleY, props.scaleZ );
55 | return ;
56 | }
57 | gltf.scene.position.set(0, 0, 0);
58 | gltf.scene.rotation.set(0, 0, 0);
59 | gltf.scene.scale.set(1, 1, 1);
60 | return ;
61 | }
62 |
63 | export default function ModelEdit(props) {
64 | return (
65 | <>
66 |
76 |
82 |
83 |
90 | {props.url && (
91 |
92 |
97 |
98 | )}
99 |
100 |
101 | {props.hasTip && (
102 | Click and drag ^
103 | )}
104 | >
105 | );
106 | }
107 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const defaultConfig = require("@wordpress/scripts/config/webpack.config");
2 | const path = require("path");
3 | const isProduction = "production" === process.env.NODE_ENV;
4 | const { entryPoints } = require("./pluginMachine.json");
5 | const isPro = process.env.ISPRO === 'true';
6 |
7 | const entry = {};
8 | if (entryPoints.hasOwnProperty("blocks")) {
9 | entryPoints.blocks.forEach((entryPoint) => {
10 | entry[`block-${entryPoint}`] = path.resolve(
11 | process.cwd(),
12 | `blocks/${entryPoint}/index.js`
13 | );
14 | });
15 | }
16 |
17 | if (isPro) {
18 | if (entryPoints.hasOwnProperty("proBlocks")) {
19 | entryPoints.proBlocks.forEach((entryPoint) => {
20 | entry[`block-${entryPoint}`] = path.resolve(
21 | process.cwd(),
22 | `pro/blocks/${entryPoint}/index.js`
23 | );
24 | });
25 | }
26 | }
27 |
28 | if (entryPoints.hasOwnProperty("adminPages")) {
29 | entryPoints.adminPages.forEach((entryPoint) => {
30 | entry[`admin-page-${entryPoint}`] = path.resolve(
31 | process.cwd(),
32 | `admin/${entryPoint}/index.js`
33 | );
34 | });
35 | }
36 |
37 | if (isPro) {
38 | if (entryPoints.hasOwnProperty("proAdminPages")) {
39 | entryPoints.proAdminPages.forEach((entryPoint) => {
40 | entry[`admin-page-${entryPoint}`] = path.resolve(
41 | process.cwd(),
42 | `pro/admin/${entryPoint}/index.js`
43 | );
44 | });
45 | }
46 | }
47 |
48 | entry[`./assets/js/blocks.frontend`] = "./blocks/three-object-block/frontend.js";
49 |
50 | entry[`./assets/js/blocks.frontend-versepress`] = "./blocks/environment/frontend.js";
51 |
52 | if (isPro) {
53 | entry[`./assets/js/blocks.three-mirror-block`] = "./pro/blocks/three-mirror-block/three-mirror-block-front.js";
54 | }
55 |
56 | module.exports = {
57 | mode: isProduction ? "production" : "development",
58 | ...defaultConfig,
59 | module: {
60 | ...defaultConfig.module,
61 |
62 | rules: [
63 | ...defaultConfig.module.rules,
64 | {
65 | test: /\.js$/,
66 | exclude: /node_modules/,
67 | use: 'babel-loader'
68 | },
69 | {
70 | test: /\.css$/,
71 | use: ["style-loader", "sass-loader", "css-loader"]
72 | },
73 | {
74 | test: /\.glsl$/,
75 | include: [path.resolve(__dirname, "node_modules/three-icosa")],
76 | use: "webpack-glsl"
77 | },
78 | {
79 | test: /\.js$/,
80 | include: [path.resolve(__dirname, "node_modules/three-icosa")],
81 | use: "babel-loader"
82 | },
83 | {
84 | test: /\.vrm$/,
85 | use: [
86 | {
87 | loader: "file-loader"
88 | }
89 | ]
90 | },
91 | {
92 | test: /\.glb$/,
93 | use: [
94 | {
95 | loader: "file-loader"
96 | }
97 | ]
98 | },
99 | {
100 | test: /\.fbx$/,
101 | use: [
102 | {
103 | loader: "file-loader"
104 | }
105 | ]
106 | }
107 | ]
108 | },
109 | entry,
110 | output: {
111 | filename: "[name].js",
112 | path: path.join(__dirname, "./build")
113 | },
114 | externals: {
115 | react: "React",
116 | "react-dom": "ReactDOM",
117 | },
118 | resolve: {
119 | modules: ['node_modules'],
120 | extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
121 | alias: {
122 | Brushes: path.resolve(__dirname, "brushes"),
123 | '@magickml/editor': path.resolve(__dirname, 'node_modules/@magickml/editor'),
124 | 'draco-decoder': path.resolve(__dirname, 'node_modules/draco3d/')
125 | }
126 | }
127 | };
128 |
--------------------------------------------------------------------------------
/languages/three-object-viewer-es_MX-three-object-viewer-three-audio-block-editor-script.json:
--------------------------------------------------------------------------------
1 | {"translation-revision-date":"2023-08-20 22:28-0500","generator":"WP-CLI\/2.8.1","source":"build\/block-three-audio-block.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"es_MX","plural-forms":"nplurals=2; plural=(n != 1);"},"Settings":["Ajustes"],"Name":["Nombre"],"Position":["Posici\u00f3n"],"Rotation":["Rotaci\u00f3n"],"Audio Object":["Objeto de Audio"],"Give your audio a name.":["Asigna un nombre a tu audio."],"Select an audio file to add to your scene.":["Selecciona un archivo de audio para a\u00f1adir a tu escena."],"Audio File":["Archivo de Audio"],"Replace Audio":["Reemplazar Audio"],"Select Audio":["Seleccionar Audio"],"AutoPlay":["Reproducci\u00f3n Autom\u00e1tica"],"Item will autoplay.":["El elemento se reproducir\u00e1 autom\u00e1ticamente."],"Item will not autoplay.":["El elemento no se reproducir\u00e1 autom\u00e1ticamente."],"Item will loop.":["El elemento se repetir\u00e1 en bucle."],"Item will not loop.":["El elemento no se repetir\u00e1 en bucle."],"Item will be spatial audio.":["El elemento ser\u00e1 audio espacial."],"Item will be global audio.":["El elemento ser\u00e1 audio global."],"Volume":["Volumen"],"Unitless multiplier against original source volume for determining emitter loudness.":["Multiplicador sin unidades contra el volumen original de la fuente para determinar la intensidad del emisor."],"Positional Volume Settings":["Ajustes de Volumen Posicional"],"Cone Inner angle":["\u00c1ngulo Interior del Cono"],"The angle, in radians, of a cone outside of which the volume will be reduced to a constant value ofconeOuterGain.":["El \u00e1ngulo, en radianes, de un cono fuera del cual el volumen se reducir\u00e1 a un valor constante de coneOuterGain."],"Cone Outer Angle":["\u00c1ngulo Exterior del Cono"],"Cone Outer Gain":["Ganancia Exterior del Cono"],"The gain of the audio emitter set when outside the cone defined by the coneOuterAngle property.":["La ganancia del emisor de audio establecida cuando est\u00e1 fuera del cono definido por la propiedad coneOuterAngle."],"Distance Model":["Modelo de Distancia"],"Specifies the distance model for the audio emitter.":["Especifica el modelo de distancia para el emisor de audio."],"Inverse":["Inverso"],"Linear":["Lineal"],"Exponential":["Exponencial"],"Max Distance":["Distancia M\u00e1xima"],"The maximum distance between the emitter and listener, after which the volume will not be reduced any further. maximumDistance may only be applied when the distanceModel is set to linear. Otherwise, it should be ignored.":["La distancia m\u00e1xima entre el emisor y el oyente, despu\u00e9s de la cual el volumen no se reducir\u00e1 m\u00e1s. maximumDistance solo se puede aplicar cuando el modelo de distancia est\u00e1 configurado en lineal. De lo contrario, debe ignorarse."],"Ref Distance":["Distancia de Referencia"],"A reference distance for reducing volume as the emitter moves further from the listener. For distances less than this, the volume is not reduced.":["Una distancia de referencia para reducir el volumen a medida que el emisor se aleja del oyente. Para distancias menores que esta, el volumen no se reduce."],"Rolloff Factor":["Factor de Atenuaci\u00f3n"],"Describes how quickly the volume is reduced as the emitter moves away from listener. When distanceModel is set to linear, the maximum value is 1 otherwise there is no upper limit.":["Describe qu\u00e9 tan r\u00e1pido se reduce el volumen a medida que el emisor se aleja del oyente. Cuando el modelo de distancia est\u00e1 configurado en lineal, el valor m\u00e1ximo es 1; de lo contrario, no hay l\u00edmite superior."],"Audio block":["Bloque de Audio"]}}}
--------------------------------------------------------------------------------
/blocks/model-block/index.js:
--------------------------------------------------------------------------------
1 | import { registerBlockType } from "@wordpress/blocks";
2 | import Edit from "./Edit";
3 | import Save from "./Save";
4 | import { useBlockProps } from "@wordpress/block-editor";
5 |
6 | const icon = (
7 |
13 |
14 |
15 |
16 |
17 | );
18 |
19 | const blockConfig = require("./block.json");
20 | registerBlockType(blockConfig.name, {
21 | ...blockConfig,
22 | icon,
23 | apiVersion: 2,
24 | edit: Edit,
25 | save: Save,
26 | deprecated: [
27 | {
28 | attributes: {
29 | scaleX: {
30 | type: "int",
31 | default:1
32 | },
33 | name: {
34 | type: "string"
35 | },
36 | scaleY: {
37 | type: "int",
38 | default:1
39 | },
40 | scaleZ: {
41 | type: "int",
42 | default:1
43 | },
44 | positionX: {
45 | type: "int",
46 | default:0
47 | },
48 | positionY: {
49 | type: "int",
50 | default:0
51 | },
52 | positionZ: {
53 | type: "int",
54 | default:0
55 | },
56 | rotationX: {
57 | type: "int",
58 | default:0
59 | },
60 | rotationY: {
61 | type: "int",
62 | default:0
63 | },
64 | rotationZ: {
65 | type: "int",
66 | default:0
67 | },
68 | threeObjectUrl: {
69 | type: "string",
70 | default: null
71 | },
72 | animations: {
73 | type: "string",
74 | default: ""
75 | },
76 | alt: {
77 | type: "string",
78 | default: ""
79 | },
80 | collidable: {
81 | type: "boolean",
82 | default: false
83 | }
84 | },
85 | save(props) {
86 | return (
87 |
88 | <>
89 |
90 |
91 | {props.attributes.threeObjectUrl}
92 |
93 |
{props.attributes.scaleX}
94 |
{props.attributes.scaleY}
95 |
{props.attributes.scaleZ}
96 |
97 | {props.attributes.positionX}
98 |
99 |
100 | {props.attributes.positionY}
101 |
102 |
103 | {props.attributes.positionZ}
104 |
105 |
106 | {props.attributes.rotationX}
107 |
108 |
109 | {props.attributes.rotationY}
110 |
111 |
112 | {props.attributes.rotationZ}
113 |
114 |
115 | {props.attributes.animations}
116 |
117 |
118 | {props.attributes.collidable ? 1 : 0}
119 |
120 |
{props.attributes.alt}
121 |
122 | >
123 |
124 | );
125 | }
126 | }
127 | ]
128 | });
129 |
--------------------------------------------------------------------------------
/blocks/three-video-block/index.js:
--------------------------------------------------------------------------------
1 | import { registerBlockType } from "@wordpress/blocks";
2 | import Edit from "./Edit";
3 | import Save from "./Save";
4 | import { useBlockProps } from "@wordpress/block-editor";
5 |
6 | const icon = (
7 |
13 |
14 |
15 |
16 |
17 | );
18 |
19 | const blockConfig = require("./block.json");
20 | registerBlockType(blockConfig.name, {
21 | ...blockConfig,
22 | icon,
23 | apiVersion: 2,
24 | edit: Edit,
25 | save: Save,
26 | deprecated: [
27 | {
28 | attributes: {
29 | videoUrl: {
30 | type: "string",
31 | default: null
32 | },
33 | modelUrl: {
34 | type: "string",
35 | default: null
36 | },
37 | autoPlay: {
38 | type: "bool",
39 | default: true
40 | },
41 | scaleX: {
42 | type: "int",
43 | default: 1
44 | },
45 | scaleY: {
46 | type: "int",
47 | default: 1
48 | },
49 | scaleZ: {
50 | type: "int",
51 | default: 1
52 | },
53 | positionX: {
54 | type: "int",
55 | default: 0
56 | },
57 | positionY: {
58 | type: "int",
59 | default: 0
60 | },
61 | positionZ: {
62 | type: "int",
63 | default: 0
64 | },
65 | rotationX: {
66 | type: "int",
67 | default: 0
68 | },
69 | rotationY: {
70 | type: "int",
71 | default: 0
72 | },
73 | rotationZ: {
74 | type: "int",
75 | default: 0
76 | },
77 | aspectHeight: {
78 | type: "int",
79 | default: 0
80 | },
81 | aspectWidth: {
82 | type: "int",
83 | default: 0
84 | }
85 | },
86 | save(props) {
87 | return (
88 |
89 | <>
90 |
91 |
{props.attributes.videoUrl}
92 |
{props.attributes.scaleX}
93 |
{props.attributes.scaleY}
94 |
{props.attributes.scaleZ}
95 |
96 | {props.attributes.positionX}
97 |
98 |
99 | {props.attributes.positionY}
100 |
101 |
102 | {props.attributes.positionZ}
103 |
104 |
105 | {props.attributes.rotationX}
106 |
107 |
108 | {props.attributes.rotationY}
109 |
110 |
111 | {props.attributes.rotationZ}
112 |
113 |
114 | {props.attributes.aspectHeight}
115 |
116 |
117 | {props.attributes.aspectWidth}
118 |
119 |
120 | {props.attributes.autoPlay ? 1 : 0}
121 |
122 |
123 | >
124 |
125 | );
126 | }
127 | }
128 | ]
129 | });
130 |
--------------------------------------------------------------------------------
/blocks/environment/components/Networking.js:
--------------------------------------------------------------------------------
1 | import P2PCF from "./p2pcf/p2pcf.js";
2 |
3 | const Networking = (props) => {
4 | if (!document.location.hash) {
5 | document.location =
6 | document.location.toString() + `#xpp-${props.postSlug}`;
7 | }
8 |
9 | const userProfileName =
10 | userData.userId === ""
11 | ? Math.floor(Math.random() * 100000)
12 | : userData.userId;
13 | const p2pcf = new P2PCF(
14 | "user-" + userProfileName,
15 | document.location.hash.substring(1),
16 | {
17 | workerUrl: "https://p2pcf.sxpdigital.workers.dev/",
18 | slowPollingRateMs: 5000,
19 | fastPollingRateMs: 1500
20 | }
21 | );
22 | window.p2pcf = p2pcf;
23 | console.log("client id:", p2pcf.clientId);
24 |
25 | const removePeerUi = (clientId) => {
26 | document.getElementById(clientId)?.remove();
27 | document.getElementById(`${clientId}-video`)?.remove();
28 | };
29 |
30 | const addPeerUi = (sessionId) => {
31 | if (document.getElementById(sessionId)) return;
32 |
33 | const peerEl = document.createElement("div");
34 | peerEl.style = "display: flex;";
35 |
36 | const name = document.createElement("div");
37 | name.innerText = sessionId.substring(0, 5);
38 |
39 | peerEl.id = sessionId;
40 | peerEl.appendChild(name);
41 |
42 | document.getElementById("peers").appendChild(peerEl);
43 | };
44 | const addMessage = (message) => {
45 | const messageEl = document.createElement("div");
46 | messageEl.innerText = message;
47 |
48 | document.getElementById("messages").appendChild(messageEl);
49 | };
50 | let stream;
51 | p2pcf.on("peerconnect", (peer) => {
52 | console.log("Peer connect", peer.id, peer);
53 | console.log(peer.client_id);
54 |
55 | if (stream) {
56 | peer.addStream(stream);
57 | }
58 | peer.on("track", (track, stream) => {
59 | console.log("got track", track);
60 | const video = document.createElement("audio");
61 | video.id = `${peer.id}-audio`;
62 | video.srcObject = stream;
63 | video.setAttribute("playsinline", true);
64 | document.getElementById("videos").appendChild(video);
65 | video.play();
66 | });
67 | addPeerUi(peer.id);
68 | });
69 |
70 | p2pcf.on("peerclose", (peer) => {
71 | console.log("Peer close", peer.id, peer);
72 | removePeerUi(peer.id);
73 | });
74 |
75 | p2pcf.on("msg", (peer, data) => {
76 | addMessage(
77 | peer.id.substring(0, 5) +
78 | ": " +
79 | new TextDecoder("utf-8").decode(data)
80 | );
81 | });
82 |
83 | const go = () => {
84 | document.getElementById("session-id").innerText =
85 | p2pcf.sessionId.substring(0, 5) + "@" + p2pcf.roomId + ":";
86 |
87 | // document.getElementById('send-button').addEventListener('click', () => {
88 | // const box = document.getElementById('send-box');
89 | // addMessage(p2pcf.sessionId.substring(0, 5) + ': ' + box.value);
90 | // p2pcf.broadcast(new TextEncoder().encode(box.value));
91 | // box.value = '';
92 | // })
93 |
94 | document
95 | .getElementById("audio-button")
96 | .addEventListener("click", async () => {
97 | stream = await navigator.mediaDevices.getUserMedia({
98 | audio: true
99 | });
100 |
101 | for (const peer of p2pcf.peers.values()) {
102 | peer.addStream(stream);
103 | }
104 | });
105 |
106 | p2pcf.start();
107 | };
108 | if (
109 | document.readyState === "complete" ||
110 | document.readyState === "interactive"
111 | ) {
112 | document
113 | .getElementById("join-button")
114 | .addEventListener("click", async () => {
115 | window.addEventListener("DOMContentLoaded", audio, {
116 | once: true
117 | });
118 | // window.addEventListener('DOMContentLoaded', go, { once: true })
119 | });
120 | } else {
121 | window.addEventListener("DOMContentLoaded", go, { once: true });
122 | }
123 |
124 | return <>>;
125 | };
126 |
127 | export default Networking;
--------------------------------------------------------------------------------
/blocks/environment/components/core/front/ThreeAudio.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { useThree } from "@react-three/fiber";
3 | import {
4 | AudioListener,
5 | PositionalAudio,
6 | AudioLoader,
7 | Audio
8 | } from "three";
9 |
10 | /**
11 | * Audio component that creates an Audio or PositionalAudio object and attaches it to the Three.js camera.
12 | *
13 | * @param {Object} threeAudio - An object containing audio configuration options.
14 | * @param {string} threeAudio.positional - Indicates if the audio should be positional ("1") or not ("0").
15 | * @param {string} threeAudio.audioUrl - The URL of the audio file to be loaded and played.
16 | * @param {string} threeAudio.loop - Indicates if the audio should loop ("1") or not ("0").
17 | * @param {number} threeAudio.volume - The volume level of the audio (0 to 1).
18 | * @param {string} threeAudio.autoPlay - Indicates if the audio should play automatically ("1") or not ("0").
19 | * @param {number} threeAudio.refDistance - The reference distance for positional audio.
20 | * @param {number} threeAudio.maxDistance - The maximum distance for positional audio.
21 | * @param {number} threeAudio.rolloffFactor - The rolloff factor for positional audio.
22 | * @param {number} threeAudio.coneInnerAngle - The inner cone angle for positional audio (in degrees).
23 | * @param {number} threeAudio.coneOuterAngle - The outer cone angle for positional audio (in degrees).
24 | * @param {number} threeAudio.coneOuterGain - The outer cone gain for positional audio.
25 | * @param {string} threeAudio.distanceModel - The distance model for positional audio.
26 | * @param {number} threeAudio.positionX - The X-coordinate of the audio's position for positional audio.
27 | * @param {number} threeAudio.positionY - The Y-coordinate of the audio's position for positional audio.
28 | * @param {number} threeAudio.positionZ - The Z-coordinate of the audio's position for positional audio.
29 | * @param {number} threeAudio.rotationX - The X-coordinate of the audio's rotation for positional audio (in radians).
30 | * @param {number} threeAudio.rotationY - The Y-coordinate of the audio's rotation for positional audio (in radians).
31 | * @param {number} threeAudio.rotationZ - The Z-coordinate of the audio's rotation for positional audio (in radians).
32 | *
33 | * @returns {JSX.Element} - Returns a JSX element containing a Three.js primitive object (Audio/PositionalAudio).
34 | */
35 | export function ThreeAudio(threeAudio) {
36 | const { camera } = useThree();
37 | const [audio, setAudio] = useState(null);
38 |
39 | useEffect(() => {
40 | const listener = new AudioListener();
41 | camera.add(listener);
42 |
43 | // Create either a PositionalAudio object or a normal Audio object based on the positional attribute
44 | const audio = threeAudio.positional === "1" ? new PositionalAudio(listener) : new Audio(listener);
45 |
46 | if (threeAudio.audioUrl) {
47 | const audioLoader = new AudioLoader();
48 | audioLoader.load(threeAudio.audioUrl, (buffer) => {
49 | audio.setBuffer(buffer);
50 | audio.setLoop(threeAudio.loop === "1" ? true : false);
51 | audio.setVolume(threeAudio.volume);
52 | if (threeAudio.autoPlay === "1") audio.play();
53 | });
54 | }
55 |
56 | if (threeAudio.positional === "1") {
57 | audio.refDistance = threeAudio.refDistance;
58 | audio.maxDistance = threeAudio.maxDistance;
59 | audio.rolloffFactor = threeAudio.rolloffFactor;
60 | audio.coneInnerAngle = threeAudio.coneInnerAngle;
61 | audio.coneOuterAngle = threeAudio.coneOuterAngle;
62 | audio.coneOuterGain = threeAudio.coneOuterGain;
63 | audio.distanceModel = threeAudio.distanceModel;
64 | audio.position.set(threeAudio.positionX, threeAudio.positionY, threeAudio.positionZ);
65 | audio.rotation.set(threeAudio.rotationX, threeAudio.rotationY, threeAudio.rotationZ);
66 | }
67 |
68 | setAudio(audio);
69 |
70 | return () => {
71 | audio.stop();
72 | camera.remove(listener);
73 | }
74 | }, []);
75 |
76 | return (
77 | <>
78 | {audio && }
79 | >
80 | );
81 | }
82 |
--------------------------------------------------------------------------------
/blocks/three-object-block/components/ThreeObjectEdit.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'three';
2 | import { USDZLoader } from 'three/examples/jsm/loaders/USDZLoader';
3 | import React, { Suspense, useRef, useState, useEffect } from 'react';
4 | import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
5 | import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
6 | import {
7 | OrthographicCamera,
8 | PerspectiveCamera,
9 | OrbitControls,
10 | useAnimations,
11 | } from '@react-three/drei';
12 | import { VRM, VRMUtils, VRMSchema, VRMLoaderPlugin } from '@pixiv/three-vrm'
13 | import { GLTFAudioEmitterExtension } from 'three-omi';
14 |
15 |
16 | function ThreeObject( props ) {
17 | const [ url, set ] = useState( props.url );
18 | const {scene} = useThree();
19 | useEffect( () => {
20 | setTimeout( () => set( props.url ), 2000 );
21 | }, [] );
22 | const [ listener ] = useState( () => new THREE.AudioListener() );
23 |
24 | useThree( ( { camera } ) => {
25 | camera.add( listener );
26 | } );
27 |
28 | // USDZ loader.
29 | if(props.url.split(/[#?]/)[0].split('.').pop().trim() === "usdz") {
30 |
31 | const usdz = useLoader( USDZLoader, url);
32 |
33 | return ;
34 | }
35 |
36 | const gltf = useLoader( GLTFLoader, url, ( loader ) => {
37 | loader.register(
38 | ( parser ) => new GLTFAudioEmitterExtension( parser, listener )
39 | );
40 | loader.register( ( parser ) => {
41 |
42 | return new VRMLoaderPlugin( parser );
43 |
44 | } );
45 | } );
46 | const { actions } = useAnimations( gltf.animations, gltf.scene );
47 |
48 | const animationList = props.animations ? props.animations.split( ',' ) : '';
49 |
50 | useEffect( () => {
51 | if ( animationList ) {
52 | animationList.forEach( ( name ) => {
53 | if ( Object.keys( actions ).includes( name ) ) {
54 | actions[ name ].play();
55 | }
56 | } );
57 | }
58 | }, [] );
59 |
60 | if(gltf?.userData?.gltfExtensions?.VRM){
61 | const vrm = gltf.userData.vrm;
62 | vrm.scene.position.set( 0, props.positionY, 0 );
63 | VRMUtils.rotateVRM0( vrm );
64 | const rotationVRM = vrm.scene.rotation.y + parseFloat(props.rotationY);
65 | vrm.scene.rotation.set( 0, rotationVRM, 0 );
66 | vrm.scene.scale.set( props.scale, props.scale, props.scale );
67 | return ;
68 | }
69 |
70 | gltf.scene.position.set( 0, props.positionY, 0 );
71 | gltf.scene.rotation.set( 0, props.rotationY, 0 );
72 | gltf.scene.scale.set( props.scale, props.scale, props.scale );
73 | return ;
74 | }
75 |
76 | export default function ThreeObjectEdit( props ) {
77 | return (
78 | <>
79 |
89 |
90 |
91 |
98 | { props.url && (
99 |
100 |
109 |
110 | ) }
111 |
112 |
113 | { props.hasTip && (
114 | Click and drag ^
115 | ) }
116 | >
117 | );
118 | }
119 |
--------------------------------------------------------------------------------
/languages/three-object-viewer.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "Project-Id-Version: Three Object Viewer 1.5.2\n"
4 | "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/three-object-viewer\n"
5 | "Last-Translator: FULL NAME \n"
6 | "Language-Team: LANGUAGE \n"
7 | "MIME-Version: 1.0\n"
8 | "Content-Type: text/plain; charset=UTF-8\n"
9 | "Content-Transfer-Encoding: 8bit\n"
10 | "POT-Creation-Date: 2023-08-19T05:20:49+00:00\n"
11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12 | "Language: \n"
13 | "X-Generator: WP-CLI 2.8.1\n"
14 | "X-Domain: three-object-viewer\n"
15 |
16 | #. Plugin Name of the plugin
17 | msgid "Three Object Viewer"
18 | msgstr ""
19 |
20 | #. Plugin URI of the plugin
21 | msgid "https://3ov.xyz/"
22 | msgstr ""
23 |
24 | #. Description of the plugin
25 | msgid "A plugin for viewing 3D files with support for WebXR and Open Metaverse Interoperability GLTF Extensions."
26 | msgstr ""
27 |
28 | #. Author of the plugin
29 | msgid "antpb"
30 | msgstr ""
31 |
32 | #. Author URI of the plugin
33 | msgid "https://antpb.com"
34 | msgstr ""
35 |
36 | #: admin/three-object-viewer-settings/init.php:75
37 | #: admin/three-object-viewer-settings/init.php:76
38 | msgid "3OV Settings"
39 | msgstr ""
40 |
41 | #: blocks/environment/block.json
42 | msgctxt "block title"
43 | msgid "3D Environment"
44 | msgstr ""
45 |
46 | #: blocks/environment/block.json
47 | msgctxt "block description"
48 | msgid "A 3D environment component"
49 | msgstr ""
50 |
51 | #: blocks/model-block/block.json
52 | msgctxt "block title"
53 | msgid "3D Model"
54 | msgstr ""
55 |
56 | #: blocks/model-block/block.json
57 | msgctxt "block description"
58 | msgid "A 3D model for your environment"
59 | msgstr ""
60 |
61 | #: blocks/npc-block/block.json
62 | msgctxt "block title"
63 | msgid "NPC Block"
64 | msgstr ""
65 |
66 | #: blocks/npc-block/block.json
67 | msgctxt "block description"
68 | msgid "A NPC to live in your environment"
69 | msgstr ""
70 |
71 | #: blocks/sky-block/block.json
72 | msgctxt "block title"
73 | msgid "3D Sky Block"
74 | msgstr ""
75 |
76 | #: blocks/sky-block/block.json
77 | msgctxt "block description"
78 | msgid "A sky your environment"
79 | msgstr ""
80 |
81 | #: blocks/spawn-point-block/block.json
82 | msgctxt "block title"
83 | msgid "Spawn Point"
84 | msgstr ""
85 |
86 | #: blocks/spawn-point-block/block.json
87 | msgctxt "block description"
88 | msgid "A spawn point for your users"
89 | msgstr ""
90 |
91 | #: blocks/three-audio-block/block.json
92 | msgctxt "block title"
93 | msgid "3D Audio"
94 | msgstr ""
95 |
96 | #: blocks/three-audio-block/block.json
97 | msgctxt "block description"
98 | msgid "An audio block for your environment"
99 | msgstr ""
100 |
101 | #: blocks/three-image-block/block.json
102 | msgctxt "block title"
103 | msgid "3D Image"
104 | msgstr ""
105 |
106 | #: blocks/three-image-block/block.json
107 | msgctxt "block description"
108 | msgid "An image block for your environment"
109 | msgstr ""
110 |
111 | #: blocks/three-light-block/block.json
112 | msgctxt "block title"
113 | msgid "3D Light"
114 | msgstr ""
115 |
116 | #: blocks/three-light-block/block.json
117 | msgctxt "block description"
118 | msgid "A light block for your environment"
119 | msgstr ""
120 |
121 | #: blocks/three-object-block/block.json
122 | msgctxt "block title"
123 | msgid "Three Object Block"
124 | msgstr ""
125 |
126 | #: blocks/three-object-block/block.json
127 | msgctxt "block description"
128 | msgid "A 3D object viewer focused on glTF"
129 | msgstr ""
130 |
131 | #: blocks/three-portal-block/block.json
132 | msgctxt "block title"
133 | msgid "3D Portal"
134 | msgstr ""
135 |
136 | #: blocks/three-portal-block/block.json
137 | msgctxt "block description"
138 | msgid "A 3D portal"
139 | msgstr ""
140 |
141 | #: blocks/three-text-block/block.json
142 | msgctxt "block title"
143 | msgid "Three Text Block"
144 | msgstr ""
145 |
146 | #: blocks/three-text-block/block.json
147 | msgctxt "block description"
148 | msgid "A 3D Text Block"
149 | msgstr ""
150 |
151 | #: blocks/three-video-block/block.json
152 | msgctxt "block title"
153 | msgid "3D Video"
154 | msgstr ""
155 |
156 | #: blocks/three-video-block/block.json
157 | msgctxt "block description"
158 | msgid "A video block for your environment"
159 | msgstr ""
160 |
--------------------------------------------------------------------------------