├── .gitignore
├── README.md
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── src
├── App.css
├── App.test.tsx
├── App.tsx
├── BouncySphere.tsx
├── font-face.d.ts
├── index.css
├── index.tsx
├── logo.svg
├── react-app-env.d.ts
├── reportWebVitals.ts
└── setupTests.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 | yarn.lock
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with Create React App (CRA) v4 and then `babylonjs-react` was added.
2 | For TypeScript
3 | ```bash
4 | npx create-react-app your-babylonjs-app --template typescript
5 | ```
6 |
7 | Add babylonjs dependencies:
8 | ```bash
9 | yarn add react-babylonjs
10 | yarn add @babylonjs/core
11 | yarn add @babylonjs/gui
12 | # loaders are optional
13 | yarn add @babylonjs/loaders
14 | ```
15 |
16 | All of the code for the site is in `/src/App.tsx`
17 |
18 | In the project directory, you can run:
19 |
20 | ### `npm start` / `yarn start`
21 |
22 | Runs the app in the development mode.
23 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
24 |
25 | The page will reload if you make edits.
26 | You will also see any lint errors in the console.
27 |
28 | View [live demo](https://brianzinn.github.io/create-react-app-typescript-babylonjs/)
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "create-react-app-typescript-babylonjs",
3 | "homepage": "https://brianzinn.github.io/create-react-app-typescript-babylonjs",
4 | "version": "0.1.0",
5 | "private": true,
6 | "dependencies": {
7 | "@babylonjs/core": "^5.25.0",
8 | "@babylonjs/gui": "^5.25.0",
9 | "cannon": "^0.6.2",
10 | "react": "^18.2.0",
11 | "react-babylonjs": "^3.1.11",
12 | "react-dom": "^18.2.0",
13 | "react-scripts": "5.0.1",
14 | "typescript": "^4.8.3",
15 | "web-vitals": "^2.1.4"
16 | },
17 | "devDependencies": {
18 | "@testing-library/jest-dom": "^5.16.5",
19 | "@testing-library/react": "^13.4.0",
20 | "@testing-library/user-event": "^13.5.0",
21 | "@types/cannon": "^0.1.5",
22 | "@types/jest": "^27.5.2",
23 | "@types/node": "^16.11.59",
24 | "@types/react": "^18.0.21",
25 | "@types/react-dom": "^18.0.6",
26 | "gh-pages": "^3.1.0"
27 | },
28 | "scripts": {
29 | "start": "react-scripts start",
30 | "build": "react-scripts build",
31 | "test": "react-scripts test",
32 | "eject": "react-scripts eject",
33 | "predeploy": "yarn build",
34 | "deploy": "gh-pages -d build"
35 | },
36 | "eslintConfig": {
37 | "extends": [
38 | "react-app",
39 | "react-app/jest"
40 | ]
41 | },
42 | "browserslist": {
43 | "production": [
44 | ">0.2%",
45 | "not dead",
46 | "not op_mini all"
47 | ],
48 | "development": [
49 | "last 1 chrome version",
50 | "last 1 firefox version",
51 | "last 1 safari version"
52 | ]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzinn/create-react-app-typescript-babylonjs/90d22b90396c6d28e263229f26de844ff6d91fdb/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
21 |
30 | React App
31 |
32 |
33 |
34 |
35 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzinn/create-react-app-typescript-babylonjs/90d22b90396c6d28e263229f26de844ff6d91fdb/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzinn/create-react-app-typescript-babylonjs/90d22b90396c6d28e263229f26de844ff6d91fdb/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 40vmin;
8 | pointer-events: none;
9 | }
10 |
11 | .App-header {
12 | background-color: #282c34;
13 | min-height: 100vh;
14 | display: flex;
15 | flex-direction: column;
16 | align-items: center;
17 | justify-content: center;
18 | font-size: calc(10px + 2vmin);
19 | color: white;
20 | }
21 |
22 | .App-link {
23 | color: #61dafb;
24 | }
25 |
26 | #sample-canvas {
27 | width: 50%;
28 | }
29 |
30 | @keyframes App-logo-spin {
31 | from {
32 | transform: rotate(0deg);
33 | }
34 | to {
35 | transform: rotate(360deg);
36 | }
37 | }
38 |
39 | #sample-canvas {
40 | width: 50%;
41 | }
--------------------------------------------------------------------------------
/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | render();
7 | const linkElement = screen.getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useRef, FC, useEffect } from 'react';
2 |
3 | import "@babylonjs/core/Physics/physicsEngineComponent" // side-effect adds scene.enablePhysics function
4 | import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent"; // side-effect for shadow generator
5 | import { CannonJSPlugin } from '@babylonjs/core/Physics/Plugins'
6 | import { Vector3 } from '@babylonjs/core/Maths/math.vector';
7 | import { PhysicsImpostor } from '@babylonjs/core/Physics/physicsImpostor';
8 |
9 | import { Scene, Engine } from 'react-babylonjs';
10 |
11 | import BouncySphere from './BouncySphere';
12 | import './App.css';
13 |
14 | import * as CANNON from 'cannon';
15 | import { Color3 } from '@babylonjs/core';
16 |
17 | window.CANNON = CANNON;
18 |
19 | const gravityVector = new Vector3(0, -9.81, 0);
20 | const RADIUS = 5;
21 | const NUMBER_OF_BOXES = 8;
22 |
23 | const App: FC = () => {
24 | const [fontsReady, setFontsReady] = useState(false);
25 |
26 | const faLoaded = useRef(false);
27 | useEffect(() => {
28 | if (document.fonts.check("16px FontAwesome") === false) {
29 | document.fonts.load("16px FontAwesome").then(() => {
30 | if (faLoaded.current !== true) {
31 | faLoaded.current = true;
32 | setFontsReady(true);
33 | }
34 | });
35 | } else if (faLoaded.current !== true) {
36 | faLoaded.current = true;
37 | setFontsReady(true);
38 | }
39 | }, []);
40 |
41 | return (
42 |
74 | );
75 | }
76 | export default App;
77 |
--------------------------------------------------------------------------------
/src/BouncySphere.tsx:
--------------------------------------------------------------------------------
1 | import { FresnelParameters } from '@babylonjs/core/Materials/fresnelParameters';
2 | import { Texture } from '@babylonjs/core/Materials/Textures/texture';
3 | import { Color3 } from '@babylonjs/core/Maths/math.color';
4 | import { Vector3 } from '@babylonjs/core/Maths/math.vector';
5 | import { Mesh } from '@babylonjs/core/Meshes/mesh';
6 | import { PhysicsImpostor } from '@babylonjs/core/Physics/physicsImpostor';
7 | import { Nullable } from '@babylonjs/core/types';
8 | import { AdvancedDynamicTexture } from '@babylonjs/gui/2D/advancedDynamicTexture';
9 | import { useRef, useEffect, FC } from 'react';
10 |
11 | type BouncySphereProps = {
12 | fontsReady: boolean
13 | position: Vector3
14 | name: string
15 | color: Color3
16 | }
17 |
18 | const BouncySphere: FC = ({ fontsReady, position, name, color }) => {
19 |
20 | let sphereRef = useRef>(null);
21 | const adtRef = useRef(null);
22 |
23 | useEffect(() => {
24 | if (adtRef.current) {
25 | console.log('marking dirty');
26 | adtRef.current!.markAsDirty();
27 | } else {
28 | console.log('no ref');
29 | }
30 | }, [fontsReady, adtRef])
31 |
32 | const onButtonClicked = () => {
33 | if (sphereRef.current) {
34 | sphereRef.current.physicsImpostor!.applyImpulse(
35 | Vector3.Up().scale(10),
36 | sphereRef.current.getAbsolutePosition()
37 | );
38 | }
39 | };
40 |
41 | return (
42 |
43 |
44 |
55 |
56 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | )
76 | }
77 |
78 | export default BouncySphere;
--------------------------------------------------------------------------------
/src/font-face.d.ts:
--------------------------------------------------------------------------------
1 | // File: src/types/font-face.d.ts
2 | // Spec: https://www.w3.org/TR/css-font-loading/
3 | export {}
4 |
5 | declare global {
6 | const FontFace: FontFace;
7 |
8 | interface Document {
9 | fonts: FontFaceSet
10 | }
11 |
12 | type CSSOMString = string;
13 | type FontFaceLoadStatus = 'unloaded' | 'loading' | 'loaded' | 'error';
14 | type FontFaceSetStatus = 'loading' | 'loaded';
15 |
16 | interface FontFace extends FontFaceDescriptors {
17 | new(family: string, source: string | ArrayBuffer, descriptors?: FontFaceDescriptors): FontFace;
18 | readonly status: FontFaceLoadStatus;
19 | readonly loaded: Promise;
20 | variationSettings: CSSOMString;
21 | display: CSSOMString;
22 | load(): Promise;
23 | }
24 |
25 | interface FontFaceDescriptors {
26 | family: CSSOMString;
27 | style: CSSOMString;
28 | weight: CSSOMString;
29 | stretch: CSSOMString;
30 | unicodeRange: CSSOMString;
31 | variant: CSSOMString;
32 | featureSettings: CSSOMString;
33 | }
34 |
35 | interface FontFaceSet extends Iterable {
36 | readonly status: FontFaceSetStatus;
37 | readonly ready: Promise;
38 | add(font: FontFace): void;
39 | check(font: string, text?: string): Boolean; // throws exception
40 | load(font: string, text?: string): Promise
41 | delete(font: FontFace): void;
42 | clear(): void;
43 | }
44 | }
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(
8 | document.getElementById('root') as HTMLElement
9 | );
10 | root.render(
11 |
12 |
13 |
14 | );
15 |
16 | // If you want to start measuring performance in your app, pass a function
17 | // to log results (for example: reportWebVitals(console.log))
18 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
19 | reportWebVitals();
20 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/reportWebVitals.ts:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from 'web-vitals';
2 |
3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4 | if (onPerfEntry && onPerfEntry instanceof Function) {
5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6 | getCLS(onPerfEntry);
7 | getFID(onPerfEntry);
8 | getFCP(onPerfEntry);
9 | getLCP(onPerfEntry);
10 | getTTFB(onPerfEntry);
11 | });
12 | }
13 | };
14 |
15 | export default reportWebVitals;
16 |
--------------------------------------------------------------------------------
/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react-jsx"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------