Compare commits
5 Commits
1a3ce1fe97
...
83ce5a2499
Author | SHA1 | Date |
---|---|---|
Alexander Popov | 83ce5a2499 | |
Alexander Popov | 5d95cfff9f | |
Alexander Popov | 36160839ff | |
Alexander Popov | da9efcc3c5 | |
Alexander Popov | 5bcabc9e73 |
|
@ -13,7 +13,7 @@ fi
|
||||||
|
|
||||||
# editorconfig
|
# editorconfig
|
||||||
echo "Checking by EditorConfig..."
|
echo "Checking by EditorConfig..."
|
||||||
ec -exclude 'node_modules' . &> /dev/null
|
ec -exclude 'node_modules' -exclude 'venv' . &> /dev/null
|
||||||
|
|
||||||
if [[ "$?" == 0 ]]; then
|
if [[ "$?" == 0 ]]; then
|
||||||
echo "✅ EditorConfig"
|
echo "✅ EditorConfig"
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
dist/
|
dist/
|
||||||
|
test/
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
**/.git
|
**/.git
|
||||||
**/node_modules
|
**/node_modules
|
||||||
**/dist
|
**/dist
|
||||||
|
**/venv
|
||||||
test/js/engine.js
|
test/js/engine.js
|
||||||
|
|
||||||
*.html
|
*.html
|
||||||
|
|
2
TODO.md
2
TODO.md
|
@ -1 +1 @@
|
||||||
- [ ] Неправильно отрабатывает один из Git хуков
|
- [x] Неправильно отрабатывает один из Git хуков
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
# ⚠️ IN DEVELOPMENT
|
|
||||||
|
|
||||||
## 🧻 Documentation
|
|
||||||
|
|
||||||
- [API](us/api.md)
|
|
|
@ -1,2 +0,0 @@
|
||||||
- 🇷🇺 [Russian](/ru/)
|
|
||||||
- 🇺🇸 [English](/)
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
# 🧰 Докуменация API
|
||||||
|
|
||||||
|
## Класс `App`
|
||||||
|
|
||||||
|
Основной класс приложения **ujs**.
|
||||||
|
|
||||||
|
### 🟢 Методы
|
||||||
|
|
||||||
|
### 🔷 Параметры
|
||||||
|
|
||||||
|
- `width` — `int` ширина холста
|
||||||
|
- `height` — `int` высота холста
|
||||||
|
- `options` — (_необязательный_) `obj` дополнительные опции
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let options = {
|
||||||
|
backgroundColor: '#ffcc68', // фоновый цвет холста
|
||||||
|
welcome: true, // отображение приметствия в консоли
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🐎 Примеры использования
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Создаём приложение app с размером холста 320 на 240 пикселей
|
||||||
|
let app = new ujs.App(320, 240);
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Добавляем холст игры/приложения на страницу в элемент <body>
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
document.body.appendChild(app.view);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Класс `Scene`
|
||||||
|
|
||||||
|
Класс сцены.
|
||||||
|
|
||||||
|
### 🟢 Методы
|
||||||
|
|
||||||
|
### 🔷 Параметры
|
||||||
|
|
||||||
|
- `one` — `int` параметр
|
||||||
|
- `two` — `int` параметр
|
||||||
|
- `three` — (_необязательный_) `obj` параметр
|
||||||
|
|
||||||
|
### 🐎 Примеры использования
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Пример `Объекта`
|
||||||
|
|
||||||
|
Описание `Объекта`
|
||||||
|
|
||||||
|
### 🟢 Методы
|
||||||
|
|
||||||
|
### 🔷 Параметры
|
||||||
|
|
||||||
|
- `one` — `int` параметр
|
||||||
|
- `two` — `int` параметр
|
||||||
|
- `three` — (_необязательный_) `obj` параметр
|
||||||
|
|
||||||
|
### 🐎 Примеры использования
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ...
|
||||||
|
```
|
|
@ -1 +0,0 @@
|
||||||
../../test/icons/apple-touch-icon.png
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
# 📦 Примеры
|
||||||
|
|
||||||
|
`⚠️ Этот раздел документации в разработке`
|
|
@ -1,47 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>ujs</title>
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
|
||||||
<meta name="description" content="Description">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.$docsify = {
|
|
||||||
name: 'ujs',
|
|
||||||
repo: 'https://git.a2s.su/emilecok/ujs',
|
|
||||||
logo: '/assets/icon.png',
|
|
||||||
nativeEmoji: true,
|
|
||||||
loadNavbar: true,
|
|
||||||
nameLink: {
|
|
||||||
'/ru/': '#/ru/',
|
|
||||||
'/': '#/',
|
|
||||||
},
|
|
||||||
alias: {
|
|
||||||
'/ru/(.*)': '/ru/$1',
|
|
||||||
},
|
|
||||||
search: {
|
|
||||||
noData: {
|
|
||||||
'/ru/': 'Нет результатов!',
|
|
||||||
'/': 'No results!',
|
|
||||||
},
|
|
||||||
paths: 'auto',
|
|
||||||
placeholder: {
|
|
||||||
'/ru/': 'Поиск',
|
|
||||||
'/': 'Search',
|
|
||||||
},
|
|
||||||
pathNamespaces: ['/ru'],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Docsify v4 -->
|
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/search.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
# 🏠 ujs
|
||||||
|
|
||||||
|
**ujs** — JavaScript библиотека для разработки игр на HTML5/Canvas
|
||||||
|
|
||||||
|
## 💽 Установка и использование
|
||||||
|
|
||||||
|
### 💾 Установка
|
||||||
|
|
||||||
|
Необходимо скачать файл `ujs.js` и разместить его в директории проекта,
|
||||||
|
например по слеющуему пути `assets/js`.
|
||||||
|
|
||||||
|
По [этой ссылке](http://a2s.su/) (**_в данный момент ссылка не работает_**)
|
||||||
|
расположена последняя версия (`ujs-beta`) библиотеки.
|
||||||
|
|
||||||
|
Старые версии и историю изменений можно найти на старнице [🗒️ История версий](versions.md).
|
||||||
|
|
||||||
|
### ⌨️ Использование
|
||||||
|
|
||||||
|
Библиотека подключается как модуль из вашего JavaScript файла.
|
||||||
|
|
||||||
|
Предположим, что файл с Вашим основным кодом игры/приложения называется `game.js`
|
||||||
|
и подключён к проекту следующим образом.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Файл index.html -->
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<!-- ... -->
|
||||||
|
<script src="./game.js" type="module"></script>
|
||||||
|
<!-- ... -->
|
||||||
|
</head>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
Для подключения библиотеки необходимо импортировать необходимые объекты библиотеки **ujs** (в данном случае импортируем все объекты)
|
||||||
|
с помощью директивы `import`.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
/* Файл game.js */
|
||||||
|
|
||||||
|
import * as ujs from './ujs.js';
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📦 Примеры использования библиотеки
|
||||||
|
|
||||||
|
`⚠️ Этот раздел документации в разработке`
|
||||||
|
|
||||||
|
## 🧰 Докуменация API
|
||||||
|
|
||||||
|
Документация по [API](api.md) представлена на [следующей](api.md) странице.
|
|
@ -1,5 +0,0 @@
|
||||||
# ⚠️ В РАЗРАБОТКЕ
|
|
||||||
|
|
||||||
## 🧻 Документация
|
|
||||||
|
|
||||||
- [API](/ru/api.md)
|
|
150
docs/ru/api.md
150
docs/ru/api.md
|
@ -1,150 +0,0 @@
|
||||||
# 🔵 App
|
|
||||||
|
|
||||||
Основной класс движка.
|
|
||||||
|
|
||||||
При инициализации самостоятельно добавляет HTML элемент `<canvas>`
|
|
||||||
в тег `<body>`.
|
|
||||||
|
|
||||||
## 🎛️ Параметры
|
|
||||||
|
|
||||||
- `w` — ширина холста в пикселях.
|
|
||||||
- `h` — высота холста в пикселях.
|
|
||||||
- `options` — объект опций.
|
|
||||||
|
|
||||||
### options
|
|
||||||
|
|
||||||
```text
|
|
||||||
{
|
|
||||||
backgroundColor: '#ffcc68',
|
|
||||||
welcome: true,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- `backgroundColor` — фон холста.
|
|
||||||
По умолчанию `#ffcc68`.
|
|
||||||
|
|
||||||
- `welcome` — `bool` тип.
|
|
||||||
Отображает информацию о движке в **Console**.
|
|
||||||
По умолчанию `true`.
|
|
||||||
|
|
||||||
## 🩻 Методы
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎮 Пример использования
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// init app
|
|
||||||
let app = new App(400, 400);
|
|
||||||
|
|
||||||
// add app view in document
|
|
||||||
window.addEventListener('DOMContentLoaded', () => {
|
|
||||||
document.body.appendChild(app.view);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
# 🔵 Scene
|
|
||||||
|
|
||||||
Класс сцены.
|
|
||||||
|
|
||||||
## 🎛️ Параметры
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🩻 Методы
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎮 Пример использования
|
|
||||||
|
|
||||||
```text
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
# 🔵 SceneLayer
|
|
||||||
|
|
||||||
Класс слоя сцены.
|
|
||||||
|
|
||||||
## 🎛️ Параметры
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🩻 Методы
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎮 Пример использования
|
|
||||||
|
|
||||||
```text
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
# 🔵 Object
|
|
||||||
|
|
||||||
Класс объекта.
|
|
||||||
|
|
||||||
## 🎛️ Параметры
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎮 Пример использования
|
|
||||||
|
|
||||||
```text
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
# 🔵 Rect
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎛️ Параметры
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎮 Пример использования
|
|
||||||
|
|
||||||
```text
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
# 🔵 StrokeRect
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎛️ Параметры
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎮 Пример использования
|
|
||||||
|
|
||||||
```text
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
# 🔵 Sprite
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎛️ Параметры
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎮 Пример использования
|
|
||||||
|
|
||||||
```text
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
# 🔵 TiledSprite
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎛️ Параметры
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
## 🎮 Пример использования
|
|
||||||
|
|
||||||
```text
|
|
||||||
...
|
|
||||||
```
|
|
|
@ -1 +0,0 @@
|
||||||
`contribute`
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
# 🗒️ История версий
|
||||||
|
|
||||||
|
`⚠️ Этот раздел документации в разработке`
|
|
@ -1,4 +1,4 @@
|
||||||
import * as ujs from './engine.js';
|
import * as ujs from './ujs.js';
|
||||||
|
|
||||||
let app = new ujs.App(400, 400);
|
let app = new ujs.App(400, 400);
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ player.obj.ticker = () => {
|
||||||
player.obj.x = player.x;
|
player.obj.x = player.x;
|
||||||
};
|
};
|
||||||
|
|
||||||
let firstScene = new ujs.Scene(app.canvas, app.context, 400, 400);
|
let firstScene = new ujs.Scene(app, 400, 400);
|
||||||
let layerInstances = new ujs.SceneLayer('Instances', [player.obj]);
|
let layerInstances = new ujs.SceneLayer('Instances', [player.obj]);
|
||||||
firstScene.addLayer(layerInstances);
|
firstScene.addLayer(layerInstances);
|
||||||
app.scene = firstScene;
|
app.scene = firstScene;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
../../dist/ujs.js
|
|
@ -0,0 +1 @@
|
||||||
|
site_name: ujs docs
|
|
@ -1,15 +1,14 @@
|
||||||
import terser from '@rollup/plugin-terser';
|
import terser from '@rollup/plugin-terser';
|
||||||
import pkg from './package.json' assert { type: 'json' };
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
input: 'src/main.js',
|
input: 'src/main.js',
|
||||||
output: [
|
output: [
|
||||||
{
|
{
|
||||||
file: `dist/engine-${pkg.version}.js`,
|
file: `dist/ujs.js`,
|
||||||
format: 'es',
|
format: 'es',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
file: `dist/engine-${pkg.version}.min.js`,
|
file: `dist/ujs.min.js`,
|
||||||
format: 'es',
|
format: 'es',
|
||||||
plugins: [terser()],
|
plugins: [terser()],
|
||||||
},
|
},
|
||||||
|
|
|
@ -30,7 +30,7 @@ export class App {
|
||||||
this.options.welcome = true;
|
this.options.welcome = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scene = new Scene(this.canvas, this.context, width, height);
|
this.scene = new Scene(this, width, height);
|
||||||
|
|
||||||
const logStrings = [
|
const logStrings = [
|
||||||
'ujs engine',
|
'ujs engine',
|
||||||
|
@ -49,10 +49,10 @@ export class App {
|
||||||
Settings.fpsPrevTime = Date.now();
|
Settings.fpsPrevTime = Date.now();
|
||||||
|
|
||||||
// Start :)
|
// Start :)
|
||||||
this.run();
|
this.#run();
|
||||||
}
|
}
|
||||||
|
|
||||||
run = () => {
|
#run = () => {
|
||||||
// Calculating FPS
|
// Calculating FPS
|
||||||
let fpsNewTime = Date.now();
|
let fpsNewTime = Date.now();
|
||||||
Settings.fpsDelta = (fpsNewTime - Settings.fpsPrevTime) / 1000;
|
Settings.fpsDelta = (fpsNewTime - Settings.fpsPrevTime) / 1000;
|
||||||
|
@ -69,7 +69,7 @@ export class App {
|
||||||
// Draw scene
|
// Draw scene
|
||||||
this.scene.run();
|
this.scene.run();
|
||||||
|
|
||||||
requestAnimationFrame(this.run);
|
requestAnimationFrame(this.#run);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ export class Scene {
|
||||||
#context;
|
#context;
|
||||||
#layers;
|
#layers;
|
||||||
|
|
||||||
constructor(canvas, context, width, height) {
|
constructor(app, width, height) {
|
||||||
this.#canvas = canvas;
|
this.#canvas = app.canvas;
|
||||||
this.#context = context;
|
this.#context = app.context;
|
||||||
this.#layers = Array();
|
this.#layers = Array();
|
||||||
|
|
||||||
this.setScreenSize(width, height);
|
this.setScreenSize(width, height);
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
fonts/monogram*
|
|
||||||
assets/
|
|
||||||
js/game.js
|
|
BIN
test/favicon.ico
BIN
test/favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
Binary file not shown.
Before Width: | Height: | Size: 43 KiB |
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 766 B |
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
|
@ -1,16 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>ujs</title>
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png">
|
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png">
|
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png">
|
|
||||||
<link rel="manifest" href="/site.webmanifest">
|
|
||||||
<script src="./js/game.js" type="module"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1 +0,0 @@
|
||||||
../../dist/engine-beeeeeeta.js
|
|
|
@ -1,60 +0,0 @@
|
||||||
import { App, Scene, SceneLayer, Rect, StrokeRect, Sprite } from './engine.js';
|
|
||||||
|
|
||||||
// init player
|
|
||||||
let Player = {
|
|
||||||
x: 400 / 2 - 5,
|
|
||||||
y: 400 / 2 - 5,
|
|
||||||
rect: null,
|
|
||||||
};
|
|
||||||
Player.rect = new Rect(Player.x, Player.y, 10, 10, 'black');
|
|
||||||
Player.rect.ticker = () => {
|
|
||||||
Player.rect.y = Player.y;
|
|
||||||
Player.rect.x = Player.x;
|
|
||||||
};
|
|
||||||
|
|
||||||
// init scene layers
|
|
||||||
let layerBg = new SceneLayer('background', [
|
|
||||||
new Rect(50, 50, 100, 100, 'red'),
|
|
||||||
new StrokeRect(150, 150, 40, 40, 'green', 'blue', 1),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let layerHud = new SceneLayer('hud', [
|
|
||||||
new Sprite('/assets/compass.png', 15, 15),
|
|
||||||
new Sprite('/assets/compass-arrow.png', 27, 21),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let layerInstances = new SceneLayer('Instances', [Player.rect], { debug: true });
|
|
||||||
|
|
||||||
// init app
|
|
||||||
let app = new App(400, 400);
|
|
||||||
|
|
||||||
// init scene
|
|
||||||
let firstScene = new Scene(app.canvas, app.context, 400, 400);
|
|
||||||
firstScene.addLayer(layerBg);
|
|
||||||
firstScene.addLayer(layerInstances);
|
|
||||||
firstScene.addLayer(layerHud);
|
|
||||||
|
|
||||||
app.scene = firstScene;
|
|
||||||
|
|
||||||
// add app view in document
|
|
||||||
window.addEventListener('DOMContentLoaded', () => {
|
|
||||||
document.body.appendChild(app.view);
|
|
||||||
});
|
|
||||||
|
|
||||||
// player key press listener
|
|
||||||
document.addEventListener('keydown', (e) => {
|
|
||||||
switch (e.code) {
|
|
||||||
case 'ArrowUp':
|
|
||||||
Player.y -= 1;
|
|
||||||
break;
|
|
||||||
case 'ArrowDown':
|
|
||||||
Player.y += 1;
|
|
||||||
break;
|
|
||||||
case 'ArrowLeft':
|
|
||||||
Player.x -= 1;
|
|
||||||
break;
|
|
||||||
case 'ArrowRight':
|
|
||||||
Player.x += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"short_name": "",
|
|
||||||
"icons": [
|
|
||||||
{ "src": "/icons/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" },
|
|
||||||
{ "src": "/icons/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" }
|
|
||||||
],
|
|
||||||
"theme_color": "#ffffff",
|
|
||||||
"background_color": "#ffffff",
|
|
||||||
"display": "standalone"
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
@font-face {
|
|
||||||
font-family: 'Monogram';
|
|
||||||
src: url('/fonts/monogramextended.woff2') format('woff2'),
|
|
||||||
url('/fonts/monogramextended.woff') format('woff'),
|
|
||||||
url('/fonts/monogramextended.ttf') format('truetype');
|
|
||||||
font-weight: 500;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas {
|
|
||||||
image-rendering: crisp-edges;
|
|
||||||
image-rendering: pixelated;
|
|
||||||
}
|
|
Loading…
Reference in New Issue