create-playcanvas 0.2.6 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +39 -47
  2. package/dist/index.mjs +48 -47
  3. package/package.json +53 -49
  4. package/templates/index.ts +15 -57
  5. package/templates/react-ts/README.md +32 -59
  6. package/templates/react-ts/eslint.config.mjs +14 -0
  7. package/templates/react-ts/index.html +10 -10
  8. package/templates/react-ts/package.json +34 -27
  9. package/templates/react-ts/prettier.config.mjs +1 -0
  10. package/templates/react-ts/src/App.css +37 -49
  11. package/templates/react-ts/src/App.tsx +38 -41
  12. package/templates/react-ts/src/Scene.tsx +50 -50
  13. package/templates/react-ts/src/index.css +30 -52
  14. package/templates/react-ts/src/main.tsx +9 -8
  15. package/templates/react-ts/src/vite-env.d.ts +12 -0
  16. package/templates/react-ts/tsconfig.json +24 -5
  17. package/templates/react-ts/vite.config.ts +4 -4
  18. package/templates/vanilla-ts/README.md +31 -91
  19. package/templates/vanilla-ts/eslint.config.mjs +3 -0
  20. package/templates/vanilla-ts/index.html +10 -10
  21. package/templates/vanilla-ts/package.json +28 -21
  22. package/templates/vanilla-ts/prettier.config.mjs +1 -0
  23. package/templates/vanilla-ts/src/App.ts +149 -151
  24. package/templates/vanilla-ts/src/main.ts +7 -7
  25. package/templates/vanilla-ts/src/style.css +60 -93
  26. package/templates/vanilla-ts/src/utils.ts +9 -8
  27. package/templates/vanilla-ts/src/vite-env.d.ts +12 -0
  28. package/templates/vanilla-ts/tsconfig.json +22 -22
  29. package/index.js +0 -3
  30. package/templates/react-ts/scripts/ensure-node-version.cjs +0 -12
  31. package/templates/react-ts/tsconfig.app.json +0 -27
  32. package/templates/react-ts/tsconfig.node.json +0 -25
  33. package/templates/vanilla-ts/scripts/ensure-node-version.cjs +0 -12
@@ -1,82 +1,55 @@
1
- # @playcanvas/react + TypeScript Starter
1
+ # PlayCanvas React + TypeScript Starter
2
2
 
3
- A modern, batteries-included starter for building PlayCanvas experiences with React and TypeScript, HMR and ESLint.
3
+ A Vite-powered `@playcanvas/react` project with TypeScript, hot module replacement, ESLint and Prettier.
4
4
 
5
5
  ## Prerequisites
6
6
 
7
- * **Node.js ≥ 20.19.0** (or ≥ 22.12.0). Use [nvm](https://github.com/nvm-sh/nvm) to install/switch:
7
+ Node.js 22.23.2 or later.
8
8
 
9
- ```bash
10
- nvm install 22 # or 20.19+
11
- nvm use 22
12
- ```
13
-
14
- ---
15
-
16
- ## Getting Started
17
-
18
- Scaffold and install dependencies:
9
+ ## Getting started
19
10
 
20
11
  ```bash
21
- npm create playcanvas@latest -t react-ts
12
+ npm create playcanvas@latest playcanvas-project -- --template react-ts
22
13
  cd playcanvas-project
23
14
  npm install
24
- ```
25
-
26
- Start the dev server with hot-module reload:
27
-
28
- ```bash
29
15
  npm run dev
30
16
  ```
31
17
 
32
- Open <http://localhost:5173> to view the app. Any file changes trigger instant reloads.
33
-
34
- ---
18
+ Open <http://localhost:5173>. Edit `src/Scene.tsx` to test hot module replacement.
35
19
 
36
20
  ## Scripts
37
21
 
38
- | Command | Description |
39
- |--------------------|--------------------------------------|
40
- | `npm run dev` | Start Vite dev server with HMR |
41
- | `npm run build` | Type-check & bundle for production |
42
- | `npm run preview` | Preview the production build locally |
43
- | `npm run lint` | Run ESLint over the codebase |
22
+ | Command | Description |
23
+ | ------------------- | --------------------------------- |
24
+ | `npm run dev` | Start the Vite development server |
25
+ | `npm run build` | Build for production |
26
+ | `npm run start` | Preview the production build |
27
+ | `npm run lint` | Run ESLint |
28
+ | `npm run fmt` | Check formatting |
29
+ | `npm run typecheck` | Run TypeScript checks |
44
30
 
45
- ---
31
+ ## Project structure
46
32
 
47
- ## Project Structure
48
-
49
- ```
33
+ ```text
50
34
  .
51
- ├── public/ # Static assets copied as-is
35
+ ├── public/
36
+ │ └── environment-map.png
52
37
  ├── src/
53
- │ ├── Scene.tsx # React wrapper around a PlayCanvas application
54
- │ ├── App.tsx # Entry component
55
- │ └── main.tsx # Vite/React bootstrap
56
- ├── vite.config.ts # Vite + React plugin config
57
- └── ...
38
+ │ ├── assets/
39
+ │ ├── App.tsx
40
+ │ ├── Scene.tsx
41
+ │ └── main.tsx
42
+ ├── eslint.config.mjs
43
+ ├── index.html
44
+ ├── tsconfig.json
45
+ └── vite.config.ts
58
46
  ```
59
47
 
60
- ## Linting & Formatting
61
-
62
- ESLint is pre-configured with TypeScript, React hooks, React Refresh, and global browser/node globals. Adjust `eslint.config.js` as your codebase grows.
63
-
64
- ---
65
-
66
- ## Deployment
67
-
68
- Run `npm run build` to generate a static production bundle in `dist/`. Deploy the contents of that folder to any static hosting provider (Netlify, Vercel, GitHub Pages, Cloudflare Pages, etc.).
69
-
70
- ---
71
-
72
- ## Further Reading
73
-
74
- * [PlayCanvas Engine Docs](https://developer.playcanvas.com)
75
- * [PlayCanvas React Docs](https://developer.playcanvas.com/user-manual/react/)
76
- * [React Docs](https://react.dev/)
77
- * [Vite Docs](https://vitejs.dev/)
78
- * [TypeScript Handbook](https://www.typescriptlang.org/docs/)
48
+ Run `npm run build` to generate a deployable static site in `dist/`.
79
49
 
80
- ---
50
+ ## Further reading
81
51
 
82
- Made with ❤️. PRs and issues welcome!
52
+ - [PlayCanvas React manual](https://developer.playcanvas.com/user-manual/react/)
53
+ - [React documentation](https://react.dev/)
54
+ - [Vite documentation](https://vite.dev/)
55
+ - [TypeScript documentation](https://www.typescriptlang.org/docs/)
@@ -0,0 +1,14 @@
1
+ import reactConfig from '@playcanvas/eslint-config/react';
2
+ import typescriptConfig from '@playcanvas/eslint-config/typescript';
3
+
4
+ export default [
5
+ ...typescriptConfig,
6
+ ...reactConfig,
7
+ {
8
+ rules: {
9
+ 'react/jsx-uses-react': 'off',
10
+ 'react/prop-types': 'off',
11
+ 'react/react-in-jsx-scope': 'off'
12
+ }
13
+ }
14
+ ];
@@ -1,13 +1,13 @@
1
1
  <!doctype html>
2
2
  <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>PlayCanvas + React + TS</title>
8
- </head>
9
- <body>
10
- <div id="root"></div>
11
- <script type="module" src="/src/main.tsx"></script>
12
- </body>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/png" href="/src/assets/playcanvas.png" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>PlayCanvas + React + TS</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
13
  </html>
@@ -1,29 +1,36 @@
1
1
  {
2
- "name": "playcanvas-project",
3
- "private": true,
4
- "version": "0.0.0",
5
- "type": "module",
6
- "engines": {
7
- "node": "^20.19.0 || >=22.12.0"
8
- },
9
- "scripts": {
10
- "predev": "node ./scripts/ensure-node-version.cjs",
11
- "dev": "vite",
12
- "build": "tsc -b && vite build",
13
- "preview": "vite preview"
14
- },
15
- "dependencies": {
16
- "@playcanvas/react": "^0.11.3",
17
- "playcanvas": "^2.17.2",
18
- "react": "^19.2.5",
19
- "react-dom": "^19.2.5"
20
- },
21
- "devDependencies": {
22
- "@types/react": "^19.2.14",
23
- "@types/react-dom": "^19.2.3",
24
- "@vitejs/plugin-react": "^6.0.1",
25
- "semver": "^7.7.4",
26
- "typescript": "~6.0.2",
27
- "vite": "^8.0.8"
28
- }
2
+ "name": "playcanvas-project",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "description": "A PlayCanvas React project",
6
+ "type": "module",
7
+ "scripts": {
8
+ "build": "vite build",
9
+ "dev": "vite",
10
+ "fmt": "prettier --check .",
11
+ "fmt:fix": "prettier --write .",
12
+ "lint": "eslint .",
13
+ "lint:fix": "eslint . --fix",
14
+ "start": "vite preview",
15
+ "typecheck": "tsc --noEmit"
16
+ },
17
+ "dependencies": {
18
+ "@playcanvas/react": "^0.11.5",
19
+ "playcanvas": "^2.21.3",
20
+ "react": "^19.2.8",
21
+ "react-dom": "^19.2.8"
22
+ },
23
+ "devDependencies": {
24
+ "@playcanvas/eslint-config": "3.0.0-beta.8",
25
+ "@types/react": "^19.2.18",
26
+ "@types/react-dom": "^19.2.4",
27
+ "@vitejs/plugin-react": "^6.0.5",
28
+ "eslint": "^9.39.5",
29
+ "prettier": "^3.9.6",
30
+ "typescript": "~6.0.3",
31
+ "vite": "^8.2.0"
32
+ },
33
+ "engines": {
34
+ "node": ">=22.23.2"
35
+ }
29
36
  }
@@ -0,0 +1 @@
1
+ export { default } from '@playcanvas/eslint-config/prettier';
@@ -1,87 +1,75 @@
1
1
  #root {
2
- display: flex;
3
- flex-direction: column;
4
- height: 100vh;
5
- width: 100vw;
2
+ display: flex;
3
+ flex-direction: column;
4
+ height: 100vh;
5
+ width: 100vw;
6
6
  }
7
7
 
8
8
  header {
9
- display: flex;
10
- flex-direction: row;
11
- align-items: center;
12
- padding: 2rem;
9
+ display: flex;
10
+ flex-direction: row;
11
+ align-items: center;
12
+ padding: 2rem;
13
13
  }
14
14
 
15
15
  .absolute {
16
- position: absolute;
17
- top: 0;
18
- left: 0;
16
+ position: absolute;
17
+ top: 0;
18
+ left: 0;
19
19
  }
20
20
 
21
21
  .full-bleed {
22
- width: 100vw;
23
- height: 100vh;
24
- overflow: hidden;
22
+ width: 100vw;
23
+ height: 100vh;
24
+ overflow: hidden;
25
25
  }
26
26
 
27
27
  .logo {
28
- height: 2em;
29
- padding: .5em;
30
- will-change: filter;
31
- transition: filter 300ms;
28
+ height: 2em;
29
+ padding: 0.5em;
30
+ will-change: filter;
31
+ transition: filter 300ms;
32
32
  }
33
33
 
34
34
  .playcanvas-logo {
35
- border-radius: 100%;
35
+ border-radius: 100%;
36
36
  }
37
37
 
38
38
  .logo:hover {
39
- filter: drop-shadow(0 0 2em #646cffaa);
39
+ filter: drop-shadow(0 0 2em #646cffaa);
40
40
  }
41
41
 
42
42
  .logo.react:hover {
43
- filter: drop-shadow(0 0 2em #61dafbaa);
44
- }
45
-
46
- .card {
47
- padding: 2em;
43
+ filter: drop-shadow(0 0 2em #61dafbaa);
48
44
  }
49
45
 
50
46
  .read-the-docs {
51
- color: #888;
52
- }
53
-
54
- .container{
55
- position: absolute;
56
- top: 0;
57
- left: 0;
58
- display: flex;
47
+ color: #888;
59
48
  }
60
49
 
61
50
  .overlay {
62
- margin: 0 auto;
63
- text-align: center;
64
- display: flex;
65
- flex-direction: column;
66
- align-items: center;
67
- justify-content: stretch;
68
- width: 100vw;
69
- height: 100vh;
70
- pointer-events: none;
51
+ margin: 0 auto;
52
+ text-align: center;
53
+ display: flex;
54
+ flex-direction: column;
55
+ align-items: center;
56
+ justify-content: stretch;
57
+ width: 100vw;
58
+ height: 100vh;
59
+ pointer-events: none;
71
60
  }
72
61
 
73
62
  .overlay a {
74
- pointer-events: auto;
63
+ pointer-events: auto;
75
64
  }
76
65
 
77
66
  .overlay > .grow {
78
- flex-grow: 1;
67
+ flex-grow: 1;
79
68
  }
80
69
 
81
70
  .pill {
82
- background-color: #000;
83
- color: #fff;
84
- padding: 0.5rem 1rem;
85
- border-radius: 0.5rem;
71
+ background-color: #000;
72
+ color: #fff;
73
+ padding: 0.5rem 1rem;
74
+ border-radius: 0.5rem;
86
75
  }
87
-
@@ -1,46 +1,43 @@
1
- import { Application } from "@playcanvas/react";
2
- import { useState } from 'react'
3
- import reactLogo from './assets/react.svg'
4
- import playcanvasLogo from './assets/playcanvas.png'
5
- import './App.css'
6
- import Scene from "./Scene";
1
+ import { Application } from '@playcanvas/react';
2
+ import { useState } from 'react';
3
+
4
+ import playcanvasLogo from './assets/playcanvas.png';
5
+ import reactLogo from './assets/react.svg';
6
+ import './App.css';
7
+ import Scene from './Scene';
7
8
 
8
9
  function App() {
9
- const [count, setCount] = useState(0)
10
+ const [count, setCount] = useState(0);
10
11
 
11
- return (
12
- <>
13
- <div className="full-bleed">
14
- <Application className="playcanvas-app">
15
- <Scene onClick={() => setCount((count) => count + 1)}/>
16
- </Application>
17
- </div>
18
- <div className="absolute overlay">
19
- <div className="grow">
20
- <header>
21
- <h1>PlayCanvas + React</h1>
22
- <a href="https://developer.playcanvas.com/user-manual/react/" target="_blank">
23
- <img src={playcanvasLogo} className="playcanvas-logo logo" alt="PlayCanvas logo" />
24
- </a>
25
- <a href="https://react.dev" target="_blank">
26
- <img src={reactLogo} className="logo react" alt="React logo" />
27
- </a>
28
- </header>
29
- </div>
30
- <div>
31
- <span className="pill">
32
- Click Count: {count}
33
- </span>
34
- <p>
35
- Edit <code>src/Scene.tsx</code> and save to test HMR
36
- </p>
37
- </div>
38
- <p className="read-the-docs">
39
- Click on the PlayCanvas and React logos to learn more
40
- </p>
41
- </div>
42
- </>
43
- )
12
+ return (
13
+ <>
14
+ <div className="full-bleed">
15
+ <Application className="playcanvas-app">
16
+ <Scene onClick={() => setCount((count) => count + 1)} />
17
+ </Application>
18
+ </div>
19
+ <div className="absolute overlay">
20
+ <div className="grow">
21
+ <header>
22
+ <h1>PlayCanvas + React</h1>
23
+ <a href="https://developer.playcanvas.com/user-manual/react/" target="_blank" rel="noreferrer">
24
+ <img src={playcanvasLogo} className="playcanvas-logo logo" alt="PlayCanvas logo" />
25
+ </a>
26
+ <a href="https://react.dev" target="_blank" rel="noreferrer">
27
+ <img src={reactLogo} className="logo react" alt="React logo" />
28
+ </a>
29
+ </header>
30
+ </div>
31
+ <div>
32
+ <span className="pill">Click Count: {count}</span>
33
+ <p>
34
+ Edit <code>src/Scene.tsx</code> and save to test HMR
35
+ </p>
36
+ </div>
37
+ <p className="read-the-docs">Click on the PlayCanvas and React logos to learn more</p>
38
+ </div>
39
+ </>
40
+ );
44
41
  }
45
42
 
46
- export default App
43
+ export default App;
@@ -1,70 +1,70 @@
1
- // @ts-expect-error - PlayCanvas ESM scripts don't have type declarations
2
- import { CameraControls } from "playcanvas/scripts/esm/camera-controls.mjs";
3
- // @ts-expect-error - PlayCanvas ESM scripts don't have type declarations
4
- import { Grid } from "playcanvas/scripts/esm/grid.mjs";
5
- import { useEffect, useState } from "react";
6
- import { Entity } from "@playcanvas/react";
7
- import { useEnvAtlas, useMaterial } from "@playcanvas/react/hooks";
8
- import { Camera, Environment, Render, Script } from "@playcanvas/react/components";
1
+ import { Entity } from '@playcanvas/react';
2
+ import { Camera, Environment, Render, Script } from '@playcanvas/react/components';
3
+ import { useEnvAtlas, useMaterial } from '@playcanvas/react/hooks';
4
+ import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs';
5
+ import { Grid } from 'playcanvas/scripts/esm/grid.mjs';
6
+ import { useEffect, useState } from 'react';
9
7
 
10
8
  /**
11
9
  * The Scene renders a sphere with a grid and camera controls
12
10
  */
13
11
  function Scene({ onClick }: SceneProps) {
12
+ // Track the hover state and set the color based on the hover state
13
+ const [hovering, setHovering] = useState(false);
14
14
 
15
- // Track the hover state and set the color based on the hover state
16
- const [hovering, setHovering] = useState(false);
15
+ // Set a material color based on the hover state
16
+ const diffuse = hovering ? 'orange' : 'lightgrey';
17
17
 
18
- // Set a material color based on the hover state
19
- const diffuse = hovering ? 'orange' : 'lightgrey';
18
+ // Create a material for the sphere
19
+ const material = useMaterial({ diffuse });
20
20
 
21
- // Create a material for the sphere
22
- const material = useMaterial({ diffuse });
21
+ // Load the environment map
22
+ const { asset: envMap } = useEnvAtlas('/environment-map.png');
23
23
 
24
- // Load the environment map
25
- const { asset: envMap } = useEnvAtlas('/environment-map.png');
24
+ // change the mouse cursor based on the hover state
25
+ useEffect(() => {
26
+ document.body.style.cursor = hovering ? 'pointer' : 'default';
26
27
 
27
- // change the mouse cursor based on the hover state
28
- useEffect(() => {
29
- document.body.style.cursor = hovering ? 'pointer' : 'default';
30
- }, [hovering]);
28
+ return () => {
29
+ document.body.style.cursor = '';
30
+ };
31
+ }, [hovering]);
31
32
 
32
- // Don't render until the environment map is loaded
33
- if (!envMap) return null;
33
+ // Don't render until the environment map is loaded
34
+ if (!envMap) return null;
34
35
 
35
- return (
36
- <>
37
- {/* Render some environment lighting using the environment map */}
38
- <Environment envAtlas={envMap} showSkybox={false} />
36
+ return (
37
+ <>
38
+ {/* Render some environment lighting using the environment map */}
39
+ <Environment envAtlas={envMap} showSkybox={false} />
39
40
 
40
- {/* Render a background grid */}
41
- <Entity scale={[1000, 1000, 1000]}>
42
- <Script script={Grid} />
43
- </Entity>
41
+ {/* Render a background grid */}
42
+ <Entity scale={[1000, 1000, 1000]}>
43
+ <Script script={Grid} />
44
+ </Entity>
44
45
 
45
- {/* Create a camera entity with camera controls */}
46
- <Entity name='camera' position={[4, 1, 4]}>
47
- <Camera clearColor='#171717' />
48
- <Script script={CameraControls} />
49
- </Entity>
46
+ {/* Create a camera entity with camera controls */}
47
+ <Entity name="camera" position={[4, 1, 4]}>
48
+ <Camera clearColor="#171717" />
49
+ <Script script={CameraControls} />
50
+ </Entity>
50
51
 
51
- {/* Create and position entity with pointer events */}
52
- <Entity
53
- position={[0, 0.5, 0]}
54
- onClick={onClick}
55
- onPointerOver={() => setHovering(true)}
56
- onPointerOut={() => setHovering(false)}
57
- >
58
-
59
- {/* Render a sphere with the material */}
60
- <Render type="sphere" material={material} />
61
- </Entity>
62
- </>
63
- )
52
+ {/* Create and position entity with pointer events */}
53
+ <Entity
54
+ position={[0, 0.5, 0]}
55
+ onClick={onClick}
56
+ onPointerOver={() => setHovering(true)}
57
+ onPointerOut={() => setHovering(false)}
58
+ >
59
+ {/* Render a sphere with the material */}
60
+ <Render type="sphere" material={material} />
61
+ </Entity>
62
+ </>
63
+ );
64
64
  }
65
65
 
66
66
  type SceneProps = {
67
- onClick: () => void;
68
- }
67
+ onClick: () => void;
68
+ };
69
69
 
70
70
  export default Scene;
@@ -1,73 +1,51 @@
1
1
  :root {
2
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
- line-height: 1.5;
4
- font-weight: 400;
2
+ font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
+ line-height: 1.5;
4
+ font-weight: 400;
5
5
 
6
- color-scheme: light dark;
7
- color: rgba(255, 255, 255, 0.87);
8
- background-color: #242424;
6
+ color-scheme: light dark;
7
+ color: rgba(255, 255, 255, 0.87);
8
+ background-color: #242424;
9
9
 
10
- font-synthesis: none;
11
- text-rendering: optimizeLegibility;
12
- -webkit-font-smoothing: antialiased;
13
- -moz-osx-font-smoothing: grayscale;
10
+ font-synthesis: none;
11
+ text-rendering: optimizeLegibility;
12
+ -webkit-font-smoothing: antialiased;
13
+ -moz-osx-font-smoothing: grayscale;
14
14
  }
15
15
 
16
16
  a {
17
- font-weight: 500;
18
- color: #646cff;
19
- text-decoration: inherit;
17
+ font-weight: 500;
18
+ color: #646cff;
19
+ text-decoration: inherit;
20
20
  }
21
21
  a:hover {
22
- color: #535bf2;
22
+ color: #535bf2;
23
23
  }
24
24
 
25
25
  a > img {
26
- vertical-align: middle;
26
+ vertical-align: middle;
27
27
  }
28
28
 
29
29
  body {
30
- margin: 0;
31
- display: flex;
32
- place-items: center;
33
- min-width: 320px;
34
- min-height: 100vh;
30
+ margin: 0;
31
+ display: flex;
32
+ place-items: center;
33
+ min-width: 320px;
34
+ min-height: 100vh;
35
35
  }
36
36
 
37
37
  h1 {
38
- font-size: 2.4em;
39
- line-height: 1.1;
40
- opacity: 0.85;
41
- }
42
-
43
- button {
44
- border-radius: 8px;
45
- border: 1px solid transparent;
46
- padding: 0.6em 1.2em;
47
- font-size: 1em;
48
- font-weight: 500;
49
- font-family: inherit;
50
- background-color: #1a1a1a;
51
- cursor: pointer;
52
- transition: border-color 0.25s;
53
- }
54
- button:hover {
55
- border-color: #646cff;
56
- }
57
- button:focus,
58
- button:focus-visible {
59
- outline: 4px auto -webkit-focus-ring-color;
38
+ font-size: 2.4em;
39
+ line-height: 1.1;
40
+ opacity: 0.85;
60
41
  }
61
42
 
62
43
  @media (prefers-color-scheme: light) {
63
- :root {
64
- color: #213547;
65
- background-color: #ffffff;
66
- }
67
- a:hover {
68
- color: #747bff;
69
- }
70
- button {
71
- background-color: #f9f9f9;
72
- }
44
+ :root {
45
+ color: #213547;
46
+ background-color: #ffffff;
47
+ }
48
+ a:hover {
49
+ color: #747bff;
50
+ }
73
51
  }