diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index aa272a4d..645ee232 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,45 +1,45 @@ -name: Rust - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - strategy: - matrix: - os: [windows-latest, ubuntu-latest, macos-latest] - - runs-on: ${{ matrix.os }} - - steps: - - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.70.0 - components: clippy, rustfmt - - uses: actions/checkout@v3 - - uses: actions/cache@v3 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target/ - key: ${{ runner.os }}-cargo-build-1.70.0-${{ hashFiles('**/Cargo.toml') }} - - name: Install alsa and udev - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev - if: runner.os == 'linux' - - name: Build - run: cargo build --verbose --workspace --features "bevy/x11" -# - name: Run tests -# run: cargo test --verbose --workspace - - name: Run fmt check - run: cargo fmt --all -- --check - - name: Run clippy - run: cargo clippy --workspace --all-targets --all-features --features "bevy/x11" -- --deny warnings +name: Rust + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + + runs-on: ${{ matrix.os }} + + steps: + - uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.75.0 + components: clippy, rustfmt + - uses: actions/checkout@v3 + - uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-build-1.75.0-${{ hashFiles('**/Cargo.toml') }} + - name: Install alsa and udev + run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev + if: runner.os == 'linux' + - name: Build + run: cargo build --verbose --workspace --features "bevy/x11" +# - name: Run tests +# run: cargo test --verbose --workspace + - name: Run fmt check + run: cargo fmt --all -- --check + - name: Run clippy + run: cargo clippy --workspace --all-targets --all-features --features "bevy/x11" -- --deny warnings diff --git a/.gitignore b/.gitignore index c8c5c7fe..7d105015 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,21 @@ -target - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb - -.vscode - -*.log - -msdfgen - -.idea - -.DS_Store - -Cargo.lock - +target + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +.vscode + +*.log + +msdfgen + +.idea + +.DS_Store + +Cargo.lock + .cargo \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index bb8d7a81..4c8cdcb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,51 +1,51 @@ -[package] -name = "kayak_ui" -description = "A UI library built using the bevy game engine!" -version = "0.4.1" -edition = "2021" -resolver = "2" -authors = ["John Mitchell"] -homepage = "https://github.com/StarArawn/kayak_ui" -repository = "https://github.com/StarArawn/kayak_ui" -license-file = "LICENSE" -exclude = ["assets/*", "screenshots/*", "book"] - -[workspace] -members = ["kayak_ui_macros", "kayak_font"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -bevy = { version = "0.11", default-features = false, features = ["bevy_render", "bevy_asset", "bevy_winit", "bevy_core_pipeline"] } -bevy_svg = { version="0.11", default-features = false } -bitflags = "1.3.2" -bytemuck = "1.12" -dashmap = "5.4" -fancy-regex = "0.11.0" -indexmap = "1.9" -instant = "0.1" -interpolation = { version = "0.2" } -kayak_font = { path = "./kayak_font", version = "0.4" } -kayak_ui_macros = { path = "./kayak_ui_macros", version = "0.4" } -log = "0.4" -morphorm = "0.3" -reorder = "2.1" -resources = "1.1" -usvg = "0.27" -uuid = { version = "1.3", features = ["v4"] } - -[dev-dependencies] -fastrand = "1.8" -bevy-inspector-egui = "0.19" -bevy = { version = "0.11", default-features = true } - -[[example]] -name = "tabs" -path = "examples/tabs/tabs.rs" - -[[example]] -name = "todo" -path = "examples/todo/todo.rs" - -[package.metadata.docs.rs] -features = ["bevy/x11"] +[package] +name = "kayak_ui" +description = "A UI library built using the bevy game engine!" +version = "0.4.1" +edition = "2021" +resolver = "2" +authors = ["John Mitchell"] +homepage = "https://github.com/StarArawn/kayak_ui" +repository = "https://github.com/StarArawn/kayak_ui" +license-file = "LICENSE" +exclude = ["assets/*", "screenshots/*", "book"] + +[workspace] +members = ["kayak_ui_macros", "kayak_font"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bevy = { version = "0.12", default-features = false, features = ["bevy_render", "bevy_asset", "bevy_winit", "bevy_core_pipeline"] } +bevy_svg = { version="0.12", default-features = false } +bitflags = "1.3.2" +bytemuck = "1.12" +dashmap = "5.4" +fancy-regex = "0.11.0" +indexmap = "1.9" +instant = "0.1" +interpolation = { version = "0.2" } +kayak_font = { path = "./kayak_font", version = "0.4" } +kayak_ui_macros = { path = "./kayak_ui_macros", version = "0.4" } +log = "0.4" +morphorm = "0.3" +reorder = "2.1" +resources = "1.1" +usvg = "0.27" +uuid = { version = "1.3", features = ["v4"] } + +[dev-dependencies] +fastrand = "1.8" +bevy-inspector-egui = "0.21" +bevy = { version = "0.12", default-features = true } + +[[example]] +name = "tabs" +path = "examples/tabs/tabs.rs" + +[[example]] +name = "todo" +path = "examples/todo/todo.rs" + +[package.metadata.docs.rs] +features = ["bevy/x11"] diff --git a/LICENSE b/LICENSE index 387b7eaf..351ccafe 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ -Kayak UI is dual-licensed under either - -* MIT License (docs/LICENSE-MIT or http://opensource.org/licenses/MIT) -* Apache License, Version 2.0 (docs/LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) - -at your option. +Kayak UI is dual-licensed under either + +* MIT License (docs/LICENSE-MIT or http://opensource.org/licenses/MIT) +* Apache License, Version 2.0 (docs/LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) + +at your option. diff --git a/README.md b/README.md index 734a56d4..0a81b0bb 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,66 @@ -

- Kayak UI -

-
- -

-

- Kayak UI -

-

- -## What is Kayak UI? -Kayak UI is a declarative UI that can be used to make user interfaces in Rust primarily targeting games. It's free and open-source! - -Check out the book! -[Kayak UI Book](./book/src/SUMMARY.md) - -## WARNING -Kayak UI is in the very early stages of development. Important features are missing and some documentation is missing. Kayak UI is designed to only work with Bevy. - -## Features -- Easy to use declarative syntax using a custom proc macro -- Basic widget and global state management -- Input events (Mouse, Keyboard, Char) -- Fast and accurate layouts using morphorm: https://github.com/geom3trik/morphorm -- A few default widgets (check out Kayak's [built-in widgets](./src/widgets)!) -- Style system built to kind of mimic CSS styles. -- Image and Nine patch rendering. -- Vec widgets see vec example! - -## Bevy Renderer Features -- Image and NinePatch renderer -- Fast MSDF Font renderer -- Quad renderer with rounded corners. -- Custom UI node to ensure UI renders on top of 3D and 2D entities. -- Fully integrated into bevy to capture input events, use bevy assets(images, etc). -- Dpi Scaling -- Batched Rendering -- Opacity Layers -- Custom Materials - -## Missing features -- More default widgets. -- More events - -## Example Screenshot -Kayak UI - -## Usage -Use bevy `0.10`! Make sure the version of Kayak you are using uses the same version of bevy. - -```rust -kayak_ui = "0.4" -bevy = "0.10" -``` - -|bevy|kayak_ui| -|---|---| -|`main`|`bevy-track`| -|0.10.x|0.4| -|0.10.x|0.3| -|0.9|0.2| -|0.9|0.1| - -## Check out the book! -[Kayak UI Book](./book/src/SUMMARY.md) +

+ Kayak UI +

+
+ +

+

+ Kayak UI +

+

+ +## What is Kayak UI? +Kayak UI is a declarative UI that can be used to make user interfaces in Rust primarily targeting games. It's free and open-source! + +Check out the book! +[Kayak UI Book](./book/src/SUMMARY.md) + +## WARNING +Kayak UI is in the very early stages of development. Important features are missing and some documentation is missing. Kayak UI is designed to only work with Bevy. + +## Features +- Easy to use declarative syntax using a custom proc macro +- Basic widget and global state management +- Input events (Mouse, Keyboard, Char) +- Fast and accurate layouts using morphorm: https://github.com/geom3trik/morphorm +- A few default widgets (check out Kayak's [built-in widgets](./src/widgets)!) +- Style system built to kind of mimic CSS styles. +- Image and Nine patch rendering. +- Vec widgets see vec example! + +## Bevy Renderer Features +- Image and NinePatch renderer +- Fast MSDF Font renderer +- Quad renderer with rounded corners. +- Custom UI node to ensure UI renders on top of 3D and 2D entities. +- Fully integrated into bevy to capture input events, use bevy assets(images, etc). +- Dpi Scaling +- Batched Rendering +- Opacity Layers +- Custom Materials + +## Missing features +- More default widgets. +- More events + +## Example Screenshot +Kayak UI + +## Usage +Use bevy `0.10`! Make sure the version of Kayak you are using uses the same version of bevy. + +```rust +kayak_ui = "0.4" +bevy = "0.10" +``` + +|bevy|kayak_ui| +|---|---| +|`main`|`bevy-track`| +|0.10.x|0.4| +|0.10.x|0.3| +|0.9|0.2| +|0.9|0.1| + +## Check out the book! +[Kayak UI Book](./book/src/SUMMARY.md) diff --git a/assets/antiquity.kayak_font b/assets/antiquity.kayak_font index 985f6ae5..42c40790 100644 --- a/assets/antiquity.kayak_font +++ b/assets/antiquity.kayak_font @@ -1,1529 +1,1529 @@ -{ - "atlas": { - "type": "msdf", - "distanceRange": 2, - "size": 32.5, - "width": 280, - "height": 280, - "yOrigin": "bottom" - }, - "metrics": { - "emSize": 1, - "lineHeight": 1.4609375, - "ascender": 1.23046875, - "descender": -0.23046875, - "underlineY": 0.07470703125, - "underlineThickness": 0.0498046875 - }, - "glyphs": [ - { - "unicode": 32, - "advance": 0.3076171875 - }, - { - "unicode": 33, - "advance": 0.38427734375, - "planeBounds": { - "left": -0.030806790865384619, - "bottom": -0.030863131009615387, - "right": 0.33842397836538463, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 175.5, - "bottom": 80.5, - "right": 187.5, - "top": 107.5 - } - }, - { - "unicode": 34, - "advance": 0.46142578125, - "planeBounds": { - "left": -0.038630558894230768, - "bottom": 0.50727914663461537, - "right": 0.42290790264423078, - "top": 0.87650991586538463 - }, - "atlasBounds": { - "left": 182.5, - "bottom": 36.5, - "right": 197.5, - "top": 48.5 - } - }, - { - "unicode": 35, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.038668118990384616, - "right": 0.64607872596153848, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 252.5, - "bottom": 168.5, - "right": 274.5, - "top": 193.5 - } - }, - { - "unicode": 36, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030863131009615387, - "right": 0.64607872596153848, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 188.5, - "bottom": 80.5, - "right": 210.5, - "top": 107.5 - } - }, - { - "unicode": 37, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 161.5, - "bottom": 0.5, - "right": 183.5, - "top": 22.5 - } - }, - { - "unicode": 38, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030863131009615387, - "right": 0.64607872596153848, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 211.5, - "bottom": 80.5, - "right": 233.5, - "top": 107.5 - } - }, - { - "unicode": 39, - "advance": 0.3076171875, - "planeBounds": { - "left": -0.038611778846153848, - "bottom": 0.42279522235576922, - "right": 0.26908052884615385, - "top": 0.88433368389423084 - }, - "atlasBounds": { - "left": 144.5, - "bottom": 33.5, - "right": 154.5, - "top": 48.5 - } - }, - { - "unicode": 40, - "advance": 0.38427734375, - "planeBounds": { - "left": -0.030806790865384619, - "bottom": -0.11534705528846154, - "right": 0.33842397836538463, - "top": 0.80772986778846156 - }, - "atlasBounds": { - "left": 187.5, - "bottom": 120.5, - "right": 199.5, - "top": 150.5 - } - }, - { - "unicode": 41, - "advance": 0.38427734375, - "planeBounds": { - "left": -0.030806790865384619, - "bottom": -0.11534705528846154, - "right": 0.33842397836538463, - "top": 0.80772986778846156 - }, - "atlasBounds": { - "left": 200.5, - "bottom": 120.5, - "right": 212.5, - "top": 150.5 - } - }, - { - "unicode": 42, - "advance": 0.46142578125, - "planeBounds": { - "left": -0.038630558894230768, - "bottom": 0.19206355168269232, - "right": 0.42290790264423078, - "top": 0.80744816706730771 - }, - "atlasBounds": { - "left": 253.5, - "bottom": 2.5, - "right": 268.5, - "top": 22.5 - } - }, - { - "unicode": 43, - "advance": 0.5380859375, - "planeBounds": { - "left": -0.030825570913461539, - "bottom": 0.045834585336538461, - "right": 0.49225135216346161, - "top": 0.56891150841346161 - }, - "atlasBounds": { - "left": 249.5, - "bottom": 239.5, - "right": 266.5, - "top": 256.5 - } - }, - { - "unicode": 44, - "advance": 0.3076171875, - "planeBounds": { - "left": -0.038611778846153848, - "bottom": -0.26909930889423078, - "right": 0.26908052884615385, - "top": 0.19243915264423078 - }, - "atlasBounds": { - "left": 155.5, - "bottom": 33.5, - "right": 165.5, - "top": 48.5 - } - }, - { - "unicode": 45, - "advance": 0.5380859375, - "planeBounds": { - "left": -0.030825570913461539, - "bottom": 0.1996807391826923, - "right": 0.49225135216346161, - "top": 0.4150653545673077 - }, - "atlasBounds": { - "left": 254.5, - "bottom": 195.5, - "right": 271.5, - "top": 202.5 - } - }, - { - "unicode": 46, - "advance": 0.23046875, - "planeBounds": { - "left": -0.030788010817307691, - "bottom": -0.030788010817307691, - "right": 0.1845966045673077, - "top": 0.1845966045673077 - }, - "atlasBounds": { - "left": 187.5, - "bottom": 112.5, - "right": 194.5, - "top": 119.5 - } - }, - { - "unicode": 47, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030863131009615387, - "right": 0.64607872596153848, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 77.5, - "bottom": 49.5, - "right": 99.5, - "top": 76.5 - } - }, - { - "unicode": 48, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.038668118990384616, - "right": 0.57673527644230771, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 191.5, - "bottom": 51.5, - "right": 211.5, - "top": 76.5 - } - }, - { - "unicode": 49, - "advance": 0.38427734375, - "planeBounds": { - "left": -0.030806790865384619, - "bottom": -0.038668118990384616, - "right": 0.33842397836538463, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 212.5, - "bottom": 51.5, - "right": 224.5, - "top": 76.5 - } - }, - { - "unicode": 50, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.038668118990384616, - "right": 0.64607872596153848, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 225.5, - "bottom": 51.5, - "right": 247.5, - "top": 76.5 - } - }, - { - "unicode": 51, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.038668118990384616, - "right": 0.57673527644230771, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 259.5, - "bottom": 51.5, - "right": 279.5, - "top": 76.5 - } - }, - { - "unicode": 52, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.038668118990384616, - "right": 0.57673527644230771, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 63.5, - "bottom": 23.5, - "right": 83.5, - "top": 48.5 - } - }, - { - "unicode": 53, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.038668118990384616, - "right": 0.57673527644230771, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 84.5, - "bottom": 23.5, - "right": 104.5, - "top": 48.5 - } - }, - { - "unicode": 54, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.038668118990384616, - "right": 0.57673527644230771, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 42.5, - "bottom": 23.5, - "right": 62.5, - "top": 48.5 - } - }, - { - "unicode": 55, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.038668118990384616, - "right": 0.57673527644230771, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 21.5, - "bottom": 23.5, - "right": 41.5, - "top": 48.5 - } - }, - { - "unicode": 56, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.038668118990384616, - "right": 0.57673527644230771, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 105.5, - "bottom": 23.5, - "right": 125.5, - "top": 48.5 - } - }, - { - "unicode": 57, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.038668118990384616, - "right": 0.57673527644230771, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 23.5, - "right": 20.5, - "top": 48.5 - } - }, - { - "unicode": 58, - "advance": 0.23046875, - "planeBounds": { - "left": -0.030788010817307691, - "bottom": 0.045834585336538461, - "right": 0.1845966045673077, - "top": 0.56891150841346161 - }, - "atlasBounds": { - "left": 267.5, - "bottom": 239.5, - "right": 274.5, - "top": 256.5 - } - }, - { - "unicode": 59, - "advance": 0.3076171875, - "planeBounds": { - "left": -0.038611778846153848, - "bottom": -0.19247671274038461, - "right": 0.26908052884615385, - "top": 0.57675405649038469 - }, - "atlasBounds": { - "left": 248.5, - "bottom": 51.5, - "right": 258.5, - "top": 76.5 - } - }, - { - "unicode": 60, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.11534705528846154, - "right": 0.57673527644230771, - "top": 0.80772986778846156 - }, - "atlasBounds": { - "left": 235.5, - "bottom": 120.5, - "right": 255.5, - "top": 150.5 - } - }, - { - "unicode": 61, - "advance": 0.5380859375, - "planeBounds": { - "left": -0.030825570913461539, - "bottom": 0.038273737980769232, - "right": 0.49225135216346161, - "top": 0.49981219951923078 - }, - "atlasBounds": { - "left": 126.5, - "bottom": 33.5, - "right": 143.5, - "top": 48.5 - } - }, - { - "unicode": 62, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.11534705528846154, - "right": 0.57673527644230771, - "top": 0.80772986778846156 - }, - "atlasBounds": { - "left": 256.5, - "bottom": 120.5, - "right": 276.5, - "top": 150.5 - } - }, - { - "unicode": 63, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.030863131009615387, - "right": 0.57673527644230771, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 147.5, - "bottom": 49.5, - "right": 167.5, - "top": 76.5 - } - }, - { - "unicode": 64, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.038668118990384616, - "right": 0.64607872596153848, - "top": 0.73056265024038469 - }, - "atlasBounds": { - "left": 168.5, - "bottom": 51.5, - "right": 190.5, - "top": 76.5 - } - }, - { - "unicode": 65, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 237.5, - "right": 35.5, - "top": 279.5 - } - }, - { - "unicode": 66, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 36.5, - "bottom": 237.5, - "right": 71.5, - "top": 279.5 - } - }, - { - "unicode": 67, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 72.5, - "bottom": 237.5, - "right": 107.5, - "top": 279.5 - } - }, - { - "unicode": 68, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 108.5, - "bottom": 237.5, - "right": 143.5, - "top": 279.5 - } - }, - { - "unicode": 69, - "advance": 1, - "planeBounds": { - "left": -0.030881911057692307, - "bottom": -0.030919471153846266, - "right": 0.95373347355769234, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 144.5, - "bottom": 237.5, - "right": 176.5, - "top": 279.5 - } - }, - { - "unicode": 70, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 177.5, - "bottom": 237.5, - "right": 212.5, - "top": 279.5 - } - }, - { - "unicode": 71, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 213.5, - "bottom": 237.5, - "right": 248.5, - "top": 279.5 - } - }, - { - "unicode": 72, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 194.5, - "right": 35.5, - "top": 236.5 - } - }, - { - "unicode": 73, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 36.5, - "bottom": 194.5, - "right": 71.5, - "top": 236.5 - } - }, - { - "unicode": 74, - "advance": 1, - "planeBounds": { - "left": -0.030881911057692307, - "bottom": -0.030919471153846266, - "right": 0.95373347355769234, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 72.5, - "bottom": 194.5, - "right": 104.5, - "top": 236.5 - } - }, - { - "unicode": 75, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 105.5, - "bottom": 194.5, - "right": 140.5, - "top": 236.5 - } - }, - { - "unicode": 76, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 141.5, - "bottom": 194.5, - "right": 176.5, - "top": 236.5 - } - }, - { - "unicode": 77, - "advance": 1.23046875, - "planeBounds": { - "left": -0.038480318509615495, - "bottom": -0.030919471153846266, - "right": 1.1922889122596152, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 177.5, - "bottom": 194.5, - "right": 217.5, - "top": 236.5 - } - }, - { - "unicode": 78, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 218.5, - "bottom": 194.5, - "right": 253.5, - "top": 236.5 - } - }, - { - "unicode": 79, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 151.5, - "right": 35.5, - "top": 193.5 - } - }, - { - "unicode": 80, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 36.5, - "bottom": 151.5, - "right": 71.5, - "top": 193.5 - } - }, - { - "unicode": 81, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 72.5, - "bottom": 151.5, - "right": 107.5, - "top": 193.5 - } - }, - { - "unicode": 82, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 108.5, - "bottom": 151.5, - "right": 143.5, - "top": 193.5 - } - }, - { - "unicode": 83, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 144.5, - "bottom": 151.5, - "right": 179.5, - "top": 193.5 - } - }, - { - "unicode": 84, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 180.5, - "bottom": 151.5, - "right": 215.5, - "top": 193.5 - } - }, - { - "unicode": 85, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 216.5, - "bottom": 151.5, - "right": 251.5, - "top": 193.5 - } - }, - { - "unicode": 86, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 108.5, - "right": 35.5, - "top": 150.5 - } - }, - { - "unicode": 87, - "advance": 1.3076171875, - "planeBounds": { - "left": -0.030919471153846266, - "bottom": -0.030919471153846266, - "right": 1.2613882211538461, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 36.5, - "bottom": 108.5, - "right": 78.5, - "top": 150.5 - } - }, - { - "unicode": 88, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 79.5, - "bottom": 108.5, - "right": 114.5, - "top": 150.5 - } - }, - { - "unicode": 89, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 115.5, - "bottom": 108.5, - "right": 150.5, - "top": 150.5 - } - }, - { - "unicode": 90, - "advance": 1.07666015625, - "planeBounds": { - "left": -0.038461538461538575, - "bottom": -0.030919471153846266, - "right": 1.0384615384615385, - "top": 1.2613882211538461 - }, - "atlasBounds": { - "left": 151.5, - "bottom": 108.5, - "right": 186.5, - "top": 150.5 - } - }, - { - "unicode": 91, - "advance": 0.3076171875, - "planeBounds": { - "left": -0.038611778846153848, - "bottom": -0.11534705528846154, - "right": 0.26908052884615385, - "top": 0.80772986778846156 - }, - "atlasBounds": { - "left": 213.5, - "bottom": 120.5, - "right": 223.5, - "top": 150.5 - } - }, - { - "unicode": 92, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030863131009615387, - "right": 0.64607872596153848, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 257.5, - "bottom": 80.5, - "right": 279.5, - "top": 107.5 - } - }, - { - "unicode": 93, - "advance": 0.3076171875, - "planeBounds": { - "left": -0.038611778846153848, - "bottom": -0.11534705528846154, - "right": 0.26908052884615385, - "top": 0.80772986778846156 - }, - "atlasBounds": { - "left": 224.5, - "bottom": 120.5, - "right": 234.5, - "top": 150.5 - } - }, - { - "unicode": 94, - "advance": 0.46142578125, - "planeBounds": { - "left": -0.038630558894230768, - "bottom": 0.43061899038461537, - "right": 0.42290790264423078, - "top": 0.79984975961538463 - }, - "atlasBounds": { - "left": 166.5, - "bottom": 36.5, - "right": 181.5, - "top": 48.5 - } - }, - { - "unicode": 95, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.18461538461538463, - "right": 0.64607872596153848, - "top": 0.18461538461538463 - }, - "atlasBounds": { - "left": 252.5, - "bottom": 155.5, - "right": 274.5, - "top": 167.5 - } - }, - { - "unicode": 96, - "advance": 0.3076171875, - "planeBounds": { - "left": -0.038611778846153848, - "bottom": 0.34589092548076922, - "right": 0.26908052884615385, - "top": 0.80742938701923084 - }, - "atlasBounds": { - "left": 269.5, - "bottom": 7.5, - "right": 279.5, - "top": 22.5 - } - }, - { - "unicode": 97, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 115.5, - "bottom": 0.5, - "right": 137.5, - "top": 22.5 - } - }, - { - "unicode": 98, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 92.5, - "bottom": 0.5, - "right": 114.5, - "top": 22.5 - } - }, - { - "unicode": 99, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 23.5, - "bottom": 0.5, - "right": 45.5, - "top": 22.5 - } - }, - { - "unicode": 100, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030863131009615387, - "right": 0.64607872596153848, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 111.5, - "bottom": 49.5, - "right": 133.5, - "top": 76.5 - } - }, - { - "unicode": 101, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 138.5, - "bottom": 0.5, - "right": 160.5, - "top": 22.5 - } - }, - { - "unicode": 102, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.26915564903846156, - "right": 0.64607872596153848, - "top": 0.65392127403846145 - }, - "atlasBounds": { - "left": 49.5, - "bottom": 77.5, - "right": 71.5, - "top": 107.5 - } - }, - { - "unicode": 103, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.26915564903846156, - "right": 0.64607872596153848, - "top": 0.65392127403846145 - }, - "atlasBounds": { - "left": 72.5, - "bottom": 77.5, - "right": 94.5, - "top": 107.5 - } - }, - { - "unicode": 104, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030863131009615387, - "right": 0.64607872596153848, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 31.5, - "bottom": 49.5, - "right": 53.5, - "top": 76.5 - } - }, - { - "unicode": 105, - "advance": 0.38427734375, - "planeBounds": { - "left": -0.030806790865384619, - "bottom": -0.030863131009615387, - "right": 0.33842397836538463, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 18.5, - "bottom": 49.5, - "right": 30.5, - "top": 76.5 - } - }, - { - "unicode": 106, - "advance": 0.38427734375, - "planeBounds": { - "left": -0.030806790865384619, - "bottom": -0.26915564903846156, - "right": 0.33842397836538463, - "top": 0.65392127403846145 - }, - "atlasBounds": { - "left": 139.5, - "bottom": 77.5, - "right": 151.5, - "top": 107.5 - } - }, - { - "unicode": 107, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030863131009615387, - "right": 0.64607872596153848, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 54.5, - "bottom": 49.5, - "right": 76.5, - "top": 76.5 - } - }, - { - "unicode": 108, - "advance": 0.38427734375, - "planeBounds": { - "left": -0.030806790865384619, - "bottom": -0.030863131009615387, - "right": 0.33842397836538463, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 134.5, - "bottom": 49.5, - "right": 146.5, - "top": 76.5 - } - }, - { - "unicode": 109, - "advance": 0.845703125, - "planeBounds": { - "left": -0.030863131009615387, - "bottom": -0.030844350961538466, - "right": 0.79990609975961546, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 249.5, - "bottom": 257.5, - "right": 276.5, - "top": 279.5 - } - }, - { - "unicode": 110, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 46.5, - "bottom": 0.5, - "right": 68.5, - "top": 22.5 - } - }, - { - "unicode": 111, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 0.5, - "right": 22.5, - "top": 22.5 - } - }, - { - "unicode": 112, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.26915564903846156, - "right": 0.64607872596153848, - "top": 0.65392127403846145 - }, - "atlasBounds": { - "left": 152.5, - "bottom": 77.5, - "right": 174.5, - "top": 107.5 - } - }, - { - "unicode": 113, - "advance": 0.615234375, - "planeBounds": { - "left": -0.038649338942307696, - "bottom": -0.26915564903846156, - "right": 0.57673527644230771, - "top": 0.65392127403846145 - }, - "atlasBounds": { - "left": 118.5, - "bottom": 77.5, - "right": 138.5, - "top": 107.5 - } - }, - { - "unicode": 114, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.18467172475961538, - "right": 0.64607872596153848, - "top": 0.64609750600961546 - }, - "atlasBounds": { - "left": 234.5, - "bottom": 80.5, - "right": 256.5, - "top": 107.5 - } - }, - { - "unicode": 115, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 207.5, - "bottom": 0.5, - "right": 229.5, - "top": 22.5 - } - }, - { - "unicode": 116, - "advance": 0.5380859375, - "planeBounds": { - "left": -0.030825570913461539, - "bottom": -0.030863131009615387, - "right": 0.49225135216346161, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 49.5, - "right": 17.5, - "top": 76.5 - } - }, - { - "unicode": 117, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 69.5, - "bottom": 0.5, - "right": 91.5, - "top": 22.5 - } - }, - { - "unicode": 118, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 184.5, - "bottom": 0.5, - "right": 206.5, - "top": 22.5 - } - }, - { - "unicode": 119, - "advance": 0.76904296875, - "planeBounds": { - "left": -0.038668118990384616, - "bottom": -0.030844350961538466, - "right": 0.73056265024038469, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 254.5, - "bottom": 214.5, - "right": 279.5, - "top": 236.5 - } - }, - { - "unicode": 120, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.26915564903846156, - "right": 0.64607872596153848, - "top": 0.65392127403846145 - }, - "atlasBounds": { - "left": 95.5, - "bottom": 77.5, - "right": 117.5, - "top": 107.5 - } - }, - { - "unicode": 121, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.26915564903846156, - "right": 0.64607872596153848, - "top": 0.65392127403846145 - }, - "atlasBounds": { - "left": 26.5, - "bottom": 77.5, - "right": 48.5, - "top": 107.5 - } - }, - { - "unicode": 122, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": -0.030844350961538466, - "right": 0.64607872596153848, - "top": 0.64607872596153848 - }, - "atlasBounds": { - "left": 230.5, - "bottom": 0.5, - "right": 252.5, - "top": 22.5 - } - }, - { - "unicode": 123, - "advance": 0.38427734375, - "planeBounds": { - "left": -0.030806790865384619, - "bottom": -0.11534705528846154, - "right": 0.33842397836538463, - "top": 0.80772986778846156 - }, - "atlasBounds": { - "left": 13.5, - "bottom": 77.5, - "right": 25.5, - "top": 107.5 - } - }, - { - "unicode": 124, - "advance": 0.3076171875, - "planeBounds": { - "left": -0.038611778846153848, - "bottom": -0.030863131009615387, - "right": 0.26908052884615385, - "top": 0.79990609975961546 - }, - "atlasBounds": { - "left": 100.5, - "bottom": 49.5, - "right": 110.5, - "top": 76.5 - } - }, - { - "unicode": 125, - "advance": 0.38427734375, - "planeBounds": { - "left": -0.030806790865384619, - "bottom": -0.11534705528846154, - "right": 0.33842397836538463, - "top": 0.80772986778846156 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 77.5, - "right": 12.5, - "top": 107.5 - } - }, - { - "unicode": 126, - "advance": 0.69189453125, - "planeBounds": { - "left": -0.030844350961538466, - "bottom": 0.26900540865384615, - "right": 0.64607872596153848, - "top": 0.57669771634615385 - }, - "atlasBounds": { - "left": 254.5, - "bottom": 203.5, - "right": 276.5, - "top": 213.5 - } - } - ], - "kerning": [] +{ + "atlas": { + "type": "msdf", + "distanceRange": 2, + "size": 32.5, + "width": 280, + "height": 280, + "yOrigin": "bottom" + }, + "metrics": { + "emSize": 1, + "lineHeight": 1.4609375, + "ascender": 1.23046875, + "descender": -0.23046875, + "underlineY": 0.07470703125, + "underlineThickness": 0.0498046875 + }, + "glyphs": [ + { + "unicode": 32, + "advance": 0.3076171875 + }, + { + "unicode": 33, + "advance": 0.38427734375, + "planeBounds": { + "left": -0.030806790865384619, + "bottom": -0.030863131009615387, + "right": 0.33842397836538463, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 175.5, + "bottom": 80.5, + "right": 187.5, + "top": 107.5 + } + }, + { + "unicode": 34, + "advance": 0.46142578125, + "planeBounds": { + "left": -0.038630558894230768, + "bottom": 0.50727914663461537, + "right": 0.42290790264423078, + "top": 0.87650991586538463 + }, + "atlasBounds": { + "left": 182.5, + "bottom": 36.5, + "right": 197.5, + "top": 48.5 + } + }, + { + "unicode": 35, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.038668118990384616, + "right": 0.64607872596153848, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 252.5, + "bottom": 168.5, + "right": 274.5, + "top": 193.5 + } + }, + { + "unicode": 36, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030863131009615387, + "right": 0.64607872596153848, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 188.5, + "bottom": 80.5, + "right": 210.5, + "top": 107.5 + } + }, + { + "unicode": 37, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 161.5, + "bottom": 0.5, + "right": 183.5, + "top": 22.5 + } + }, + { + "unicode": 38, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030863131009615387, + "right": 0.64607872596153848, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 211.5, + "bottom": 80.5, + "right": 233.5, + "top": 107.5 + } + }, + { + "unicode": 39, + "advance": 0.3076171875, + "planeBounds": { + "left": -0.038611778846153848, + "bottom": 0.42279522235576922, + "right": 0.26908052884615385, + "top": 0.88433368389423084 + }, + "atlasBounds": { + "left": 144.5, + "bottom": 33.5, + "right": 154.5, + "top": 48.5 + } + }, + { + "unicode": 40, + "advance": 0.38427734375, + "planeBounds": { + "left": -0.030806790865384619, + "bottom": -0.11534705528846154, + "right": 0.33842397836538463, + "top": 0.80772986778846156 + }, + "atlasBounds": { + "left": 187.5, + "bottom": 120.5, + "right": 199.5, + "top": 150.5 + } + }, + { + "unicode": 41, + "advance": 0.38427734375, + "planeBounds": { + "left": -0.030806790865384619, + "bottom": -0.11534705528846154, + "right": 0.33842397836538463, + "top": 0.80772986778846156 + }, + "atlasBounds": { + "left": 200.5, + "bottom": 120.5, + "right": 212.5, + "top": 150.5 + } + }, + { + "unicode": 42, + "advance": 0.46142578125, + "planeBounds": { + "left": -0.038630558894230768, + "bottom": 0.19206355168269232, + "right": 0.42290790264423078, + "top": 0.80744816706730771 + }, + "atlasBounds": { + "left": 253.5, + "bottom": 2.5, + "right": 268.5, + "top": 22.5 + } + }, + { + "unicode": 43, + "advance": 0.5380859375, + "planeBounds": { + "left": -0.030825570913461539, + "bottom": 0.045834585336538461, + "right": 0.49225135216346161, + "top": 0.56891150841346161 + }, + "atlasBounds": { + "left": 249.5, + "bottom": 239.5, + "right": 266.5, + "top": 256.5 + } + }, + { + "unicode": 44, + "advance": 0.3076171875, + "planeBounds": { + "left": -0.038611778846153848, + "bottom": -0.26909930889423078, + "right": 0.26908052884615385, + "top": 0.19243915264423078 + }, + "atlasBounds": { + "left": 155.5, + "bottom": 33.5, + "right": 165.5, + "top": 48.5 + } + }, + { + "unicode": 45, + "advance": 0.5380859375, + "planeBounds": { + "left": -0.030825570913461539, + "bottom": 0.1996807391826923, + "right": 0.49225135216346161, + "top": 0.4150653545673077 + }, + "atlasBounds": { + "left": 254.5, + "bottom": 195.5, + "right": 271.5, + "top": 202.5 + } + }, + { + "unicode": 46, + "advance": 0.23046875, + "planeBounds": { + "left": -0.030788010817307691, + "bottom": -0.030788010817307691, + "right": 0.1845966045673077, + "top": 0.1845966045673077 + }, + "atlasBounds": { + "left": 187.5, + "bottom": 112.5, + "right": 194.5, + "top": 119.5 + } + }, + { + "unicode": 47, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030863131009615387, + "right": 0.64607872596153848, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 77.5, + "bottom": 49.5, + "right": 99.5, + "top": 76.5 + } + }, + { + "unicode": 48, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.038668118990384616, + "right": 0.57673527644230771, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 191.5, + "bottom": 51.5, + "right": 211.5, + "top": 76.5 + } + }, + { + "unicode": 49, + "advance": 0.38427734375, + "planeBounds": { + "left": -0.030806790865384619, + "bottom": -0.038668118990384616, + "right": 0.33842397836538463, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 212.5, + "bottom": 51.5, + "right": 224.5, + "top": 76.5 + } + }, + { + "unicode": 50, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.038668118990384616, + "right": 0.64607872596153848, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 225.5, + "bottom": 51.5, + "right": 247.5, + "top": 76.5 + } + }, + { + "unicode": 51, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.038668118990384616, + "right": 0.57673527644230771, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 259.5, + "bottom": 51.5, + "right": 279.5, + "top": 76.5 + } + }, + { + "unicode": 52, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.038668118990384616, + "right": 0.57673527644230771, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 63.5, + "bottom": 23.5, + "right": 83.5, + "top": 48.5 + } + }, + { + "unicode": 53, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.038668118990384616, + "right": 0.57673527644230771, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 84.5, + "bottom": 23.5, + "right": 104.5, + "top": 48.5 + } + }, + { + "unicode": 54, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.038668118990384616, + "right": 0.57673527644230771, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 42.5, + "bottom": 23.5, + "right": 62.5, + "top": 48.5 + } + }, + { + "unicode": 55, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.038668118990384616, + "right": 0.57673527644230771, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 21.5, + "bottom": 23.5, + "right": 41.5, + "top": 48.5 + } + }, + { + "unicode": 56, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.038668118990384616, + "right": 0.57673527644230771, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 105.5, + "bottom": 23.5, + "right": 125.5, + "top": 48.5 + } + }, + { + "unicode": 57, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.038668118990384616, + "right": 0.57673527644230771, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 23.5, + "right": 20.5, + "top": 48.5 + } + }, + { + "unicode": 58, + "advance": 0.23046875, + "planeBounds": { + "left": -0.030788010817307691, + "bottom": 0.045834585336538461, + "right": 0.1845966045673077, + "top": 0.56891150841346161 + }, + "atlasBounds": { + "left": 267.5, + "bottom": 239.5, + "right": 274.5, + "top": 256.5 + } + }, + { + "unicode": 59, + "advance": 0.3076171875, + "planeBounds": { + "left": -0.038611778846153848, + "bottom": -0.19247671274038461, + "right": 0.26908052884615385, + "top": 0.57675405649038469 + }, + "atlasBounds": { + "left": 248.5, + "bottom": 51.5, + "right": 258.5, + "top": 76.5 + } + }, + { + "unicode": 60, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.11534705528846154, + "right": 0.57673527644230771, + "top": 0.80772986778846156 + }, + "atlasBounds": { + "left": 235.5, + "bottom": 120.5, + "right": 255.5, + "top": 150.5 + } + }, + { + "unicode": 61, + "advance": 0.5380859375, + "planeBounds": { + "left": -0.030825570913461539, + "bottom": 0.038273737980769232, + "right": 0.49225135216346161, + "top": 0.49981219951923078 + }, + "atlasBounds": { + "left": 126.5, + "bottom": 33.5, + "right": 143.5, + "top": 48.5 + } + }, + { + "unicode": 62, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.11534705528846154, + "right": 0.57673527644230771, + "top": 0.80772986778846156 + }, + "atlasBounds": { + "left": 256.5, + "bottom": 120.5, + "right": 276.5, + "top": 150.5 + } + }, + { + "unicode": 63, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.030863131009615387, + "right": 0.57673527644230771, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 147.5, + "bottom": 49.5, + "right": 167.5, + "top": 76.5 + } + }, + { + "unicode": 64, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.038668118990384616, + "right": 0.64607872596153848, + "top": 0.73056265024038469 + }, + "atlasBounds": { + "left": 168.5, + "bottom": 51.5, + "right": 190.5, + "top": 76.5 + } + }, + { + "unicode": 65, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 237.5, + "right": 35.5, + "top": 279.5 + } + }, + { + "unicode": 66, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 36.5, + "bottom": 237.5, + "right": 71.5, + "top": 279.5 + } + }, + { + "unicode": 67, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 72.5, + "bottom": 237.5, + "right": 107.5, + "top": 279.5 + } + }, + { + "unicode": 68, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 108.5, + "bottom": 237.5, + "right": 143.5, + "top": 279.5 + } + }, + { + "unicode": 69, + "advance": 1, + "planeBounds": { + "left": -0.030881911057692307, + "bottom": -0.030919471153846266, + "right": 0.95373347355769234, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 144.5, + "bottom": 237.5, + "right": 176.5, + "top": 279.5 + } + }, + { + "unicode": 70, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 177.5, + "bottom": 237.5, + "right": 212.5, + "top": 279.5 + } + }, + { + "unicode": 71, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 213.5, + "bottom": 237.5, + "right": 248.5, + "top": 279.5 + } + }, + { + "unicode": 72, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 194.5, + "right": 35.5, + "top": 236.5 + } + }, + { + "unicode": 73, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 36.5, + "bottom": 194.5, + "right": 71.5, + "top": 236.5 + } + }, + { + "unicode": 74, + "advance": 1, + "planeBounds": { + "left": -0.030881911057692307, + "bottom": -0.030919471153846266, + "right": 0.95373347355769234, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 72.5, + "bottom": 194.5, + "right": 104.5, + "top": 236.5 + } + }, + { + "unicode": 75, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 105.5, + "bottom": 194.5, + "right": 140.5, + "top": 236.5 + } + }, + { + "unicode": 76, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 141.5, + "bottom": 194.5, + "right": 176.5, + "top": 236.5 + } + }, + { + "unicode": 77, + "advance": 1.23046875, + "planeBounds": { + "left": -0.038480318509615495, + "bottom": -0.030919471153846266, + "right": 1.1922889122596152, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 177.5, + "bottom": 194.5, + "right": 217.5, + "top": 236.5 + } + }, + { + "unicode": 78, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 218.5, + "bottom": 194.5, + "right": 253.5, + "top": 236.5 + } + }, + { + "unicode": 79, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 151.5, + "right": 35.5, + "top": 193.5 + } + }, + { + "unicode": 80, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 36.5, + "bottom": 151.5, + "right": 71.5, + "top": 193.5 + } + }, + { + "unicode": 81, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 72.5, + "bottom": 151.5, + "right": 107.5, + "top": 193.5 + } + }, + { + "unicode": 82, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 108.5, + "bottom": 151.5, + "right": 143.5, + "top": 193.5 + } + }, + { + "unicode": 83, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 144.5, + "bottom": 151.5, + "right": 179.5, + "top": 193.5 + } + }, + { + "unicode": 84, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 180.5, + "bottom": 151.5, + "right": 215.5, + "top": 193.5 + } + }, + { + "unicode": 85, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 216.5, + "bottom": 151.5, + "right": 251.5, + "top": 193.5 + } + }, + { + "unicode": 86, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 108.5, + "right": 35.5, + "top": 150.5 + } + }, + { + "unicode": 87, + "advance": 1.3076171875, + "planeBounds": { + "left": -0.030919471153846266, + "bottom": -0.030919471153846266, + "right": 1.2613882211538461, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 36.5, + "bottom": 108.5, + "right": 78.5, + "top": 150.5 + } + }, + { + "unicode": 88, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 79.5, + "bottom": 108.5, + "right": 114.5, + "top": 150.5 + } + }, + { + "unicode": 89, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 115.5, + "bottom": 108.5, + "right": 150.5, + "top": 150.5 + } + }, + { + "unicode": 90, + "advance": 1.07666015625, + "planeBounds": { + "left": -0.038461538461538575, + "bottom": -0.030919471153846266, + "right": 1.0384615384615385, + "top": 1.2613882211538461 + }, + "atlasBounds": { + "left": 151.5, + "bottom": 108.5, + "right": 186.5, + "top": 150.5 + } + }, + { + "unicode": 91, + "advance": 0.3076171875, + "planeBounds": { + "left": -0.038611778846153848, + "bottom": -0.11534705528846154, + "right": 0.26908052884615385, + "top": 0.80772986778846156 + }, + "atlasBounds": { + "left": 213.5, + "bottom": 120.5, + "right": 223.5, + "top": 150.5 + } + }, + { + "unicode": 92, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030863131009615387, + "right": 0.64607872596153848, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 257.5, + "bottom": 80.5, + "right": 279.5, + "top": 107.5 + } + }, + { + "unicode": 93, + "advance": 0.3076171875, + "planeBounds": { + "left": -0.038611778846153848, + "bottom": -0.11534705528846154, + "right": 0.26908052884615385, + "top": 0.80772986778846156 + }, + "atlasBounds": { + "left": 224.5, + "bottom": 120.5, + "right": 234.5, + "top": 150.5 + } + }, + { + "unicode": 94, + "advance": 0.46142578125, + "planeBounds": { + "left": -0.038630558894230768, + "bottom": 0.43061899038461537, + "right": 0.42290790264423078, + "top": 0.79984975961538463 + }, + "atlasBounds": { + "left": 166.5, + "bottom": 36.5, + "right": 181.5, + "top": 48.5 + } + }, + { + "unicode": 95, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.18461538461538463, + "right": 0.64607872596153848, + "top": 0.18461538461538463 + }, + "atlasBounds": { + "left": 252.5, + "bottom": 155.5, + "right": 274.5, + "top": 167.5 + } + }, + { + "unicode": 96, + "advance": 0.3076171875, + "planeBounds": { + "left": -0.038611778846153848, + "bottom": 0.34589092548076922, + "right": 0.26908052884615385, + "top": 0.80742938701923084 + }, + "atlasBounds": { + "left": 269.5, + "bottom": 7.5, + "right": 279.5, + "top": 22.5 + } + }, + { + "unicode": 97, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 115.5, + "bottom": 0.5, + "right": 137.5, + "top": 22.5 + } + }, + { + "unicode": 98, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 92.5, + "bottom": 0.5, + "right": 114.5, + "top": 22.5 + } + }, + { + "unicode": 99, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 23.5, + "bottom": 0.5, + "right": 45.5, + "top": 22.5 + } + }, + { + "unicode": 100, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030863131009615387, + "right": 0.64607872596153848, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 111.5, + "bottom": 49.5, + "right": 133.5, + "top": 76.5 + } + }, + { + "unicode": 101, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 138.5, + "bottom": 0.5, + "right": 160.5, + "top": 22.5 + } + }, + { + "unicode": 102, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.26915564903846156, + "right": 0.64607872596153848, + "top": 0.65392127403846145 + }, + "atlasBounds": { + "left": 49.5, + "bottom": 77.5, + "right": 71.5, + "top": 107.5 + } + }, + { + "unicode": 103, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.26915564903846156, + "right": 0.64607872596153848, + "top": 0.65392127403846145 + }, + "atlasBounds": { + "left": 72.5, + "bottom": 77.5, + "right": 94.5, + "top": 107.5 + } + }, + { + "unicode": 104, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030863131009615387, + "right": 0.64607872596153848, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 31.5, + "bottom": 49.5, + "right": 53.5, + "top": 76.5 + } + }, + { + "unicode": 105, + "advance": 0.38427734375, + "planeBounds": { + "left": -0.030806790865384619, + "bottom": -0.030863131009615387, + "right": 0.33842397836538463, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 18.5, + "bottom": 49.5, + "right": 30.5, + "top": 76.5 + } + }, + { + "unicode": 106, + "advance": 0.38427734375, + "planeBounds": { + "left": -0.030806790865384619, + "bottom": -0.26915564903846156, + "right": 0.33842397836538463, + "top": 0.65392127403846145 + }, + "atlasBounds": { + "left": 139.5, + "bottom": 77.5, + "right": 151.5, + "top": 107.5 + } + }, + { + "unicode": 107, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030863131009615387, + "right": 0.64607872596153848, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 54.5, + "bottom": 49.5, + "right": 76.5, + "top": 76.5 + } + }, + { + "unicode": 108, + "advance": 0.38427734375, + "planeBounds": { + "left": -0.030806790865384619, + "bottom": -0.030863131009615387, + "right": 0.33842397836538463, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 134.5, + "bottom": 49.5, + "right": 146.5, + "top": 76.5 + } + }, + { + "unicode": 109, + "advance": 0.845703125, + "planeBounds": { + "left": -0.030863131009615387, + "bottom": -0.030844350961538466, + "right": 0.79990609975961546, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 249.5, + "bottom": 257.5, + "right": 276.5, + "top": 279.5 + } + }, + { + "unicode": 110, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 46.5, + "bottom": 0.5, + "right": 68.5, + "top": 22.5 + } + }, + { + "unicode": 111, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 0.5, + "right": 22.5, + "top": 22.5 + } + }, + { + "unicode": 112, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.26915564903846156, + "right": 0.64607872596153848, + "top": 0.65392127403846145 + }, + "atlasBounds": { + "left": 152.5, + "bottom": 77.5, + "right": 174.5, + "top": 107.5 + } + }, + { + "unicode": 113, + "advance": 0.615234375, + "planeBounds": { + "left": -0.038649338942307696, + "bottom": -0.26915564903846156, + "right": 0.57673527644230771, + "top": 0.65392127403846145 + }, + "atlasBounds": { + "left": 118.5, + "bottom": 77.5, + "right": 138.5, + "top": 107.5 + } + }, + { + "unicode": 114, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.18467172475961538, + "right": 0.64607872596153848, + "top": 0.64609750600961546 + }, + "atlasBounds": { + "left": 234.5, + "bottom": 80.5, + "right": 256.5, + "top": 107.5 + } + }, + { + "unicode": 115, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 207.5, + "bottom": 0.5, + "right": 229.5, + "top": 22.5 + } + }, + { + "unicode": 116, + "advance": 0.5380859375, + "planeBounds": { + "left": -0.030825570913461539, + "bottom": -0.030863131009615387, + "right": 0.49225135216346161, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 49.5, + "right": 17.5, + "top": 76.5 + } + }, + { + "unicode": 117, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 69.5, + "bottom": 0.5, + "right": 91.5, + "top": 22.5 + } + }, + { + "unicode": 118, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 184.5, + "bottom": 0.5, + "right": 206.5, + "top": 22.5 + } + }, + { + "unicode": 119, + "advance": 0.76904296875, + "planeBounds": { + "left": -0.038668118990384616, + "bottom": -0.030844350961538466, + "right": 0.73056265024038469, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 254.5, + "bottom": 214.5, + "right": 279.5, + "top": 236.5 + } + }, + { + "unicode": 120, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.26915564903846156, + "right": 0.64607872596153848, + "top": 0.65392127403846145 + }, + "atlasBounds": { + "left": 95.5, + "bottom": 77.5, + "right": 117.5, + "top": 107.5 + } + }, + { + "unicode": 121, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.26915564903846156, + "right": 0.64607872596153848, + "top": 0.65392127403846145 + }, + "atlasBounds": { + "left": 26.5, + "bottom": 77.5, + "right": 48.5, + "top": 107.5 + } + }, + { + "unicode": 122, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": -0.030844350961538466, + "right": 0.64607872596153848, + "top": 0.64607872596153848 + }, + "atlasBounds": { + "left": 230.5, + "bottom": 0.5, + "right": 252.5, + "top": 22.5 + } + }, + { + "unicode": 123, + "advance": 0.38427734375, + "planeBounds": { + "left": -0.030806790865384619, + "bottom": -0.11534705528846154, + "right": 0.33842397836538463, + "top": 0.80772986778846156 + }, + "atlasBounds": { + "left": 13.5, + "bottom": 77.5, + "right": 25.5, + "top": 107.5 + } + }, + { + "unicode": 124, + "advance": 0.3076171875, + "planeBounds": { + "left": -0.038611778846153848, + "bottom": -0.030863131009615387, + "right": 0.26908052884615385, + "top": 0.79990609975961546 + }, + "atlasBounds": { + "left": 100.5, + "bottom": 49.5, + "right": 110.5, + "top": 76.5 + } + }, + { + "unicode": 125, + "advance": 0.38427734375, + "planeBounds": { + "left": -0.030806790865384619, + "bottom": -0.11534705528846154, + "right": 0.33842397836538463, + "top": 0.80772986778846156 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 77.5, + "right": 12.5, + "top": 107.5 + } + }, + { + "unicode": 126, + "advance": 0.69189453125, + "planeBounds": { + "left": -0.030844350961538466, + "bottom": 0.26900540865384615, + "right": 0.64607872596153848, + "top": 0.57669771634615385 + }, + "atlasBounds": { + "left": 254.5, + "bottom": 203.5, + "right": 276.5, + "top": 213.5 + } + } + ], + "kerning": [] } \ No newline at end of file diff --git a/assets/fonts/roboto.kttf b/assets/fonts/roboto.kttf index d6411ede..35fffb8b 100644 --- a/assets/fonts/roboto.kttf +++ b/assets/fonts/roboto.kttf @@ -1,7 +1,7 @@ -{ - "file": "roboto.ttf", - "char_range_start": "0x20", - "char_range_end": "0x7f", - "offset_x": 0.0, - "offset_y": 25.0, +{ + "file": "roboto.ttf", + "char_range_start": "0x20", + "char_range_end": "0x7f", + "offset_x": 0.0, + "offset_y": 25.0, } \ No newline at end of file diff --git a/assets/kayak.svg b/assets/kayak.svg index ff7c4c9e..bce583f2 100644 --- a/assets/kayak.svg +++ b/assets/kayak.svg @@ -1,62 +1,62 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/assets/lato-light.kayak_font b/assets/lato-light.kayak_font index d82cd1ef..85b509c2 100644 --- a/assets/lato-light.kayak_font +++ b/assets/lato-light.kayak_font @@ -1 +1 @@ -{"atlas":{"type":"msdf","distanceRange":4,"size":64,"width":384,"height":384,"yOrigin":"bottom"},"metrics":{"emSize":1,"lineHeight":1.2,"ascender":0.98699999999999999,"descender":-0.21299999999999999,"underlineY":-0.10000000000000001,"underlineThickness":0.034000000000000002},"glyphs":[{"unicode":32,"advance":0.193},{"unicode":33,"advance":0.32250000000000001,"planeBounds":{"left":0.083125000000000004,"bottom":-0.040625000000000015,"right":0.239375,"top":0.74062499999999998},"atlasBounds":{"left":359.5,"bottom":20.5,"right":369.5,"top":70.5}},{"unicode":34,"advance":0.36699999999999999,"planeBounds":{"left":0.058250000000000003,"bottom":0.43099999999999999,"right":0.30825000000000002,"top":0.74350000000000005},"atlasBounds":{"left":51.5,"bottom":312.5,"right":67.5,"top":332.5}},{"unicode":35,"advance":0.57999999999999996,"planeBounds":{"left":0.01125,"bottom":-0.036874999999999991,"right":0.57374999999999998,"top":0.74437500000000001},"atlasBounds":{"left":158.5,"bottom":179.5,"right":194.5,"top":229.5}},{"unicode":36,"advance":0.57999999999999996,"planeBounds":{"left":0.038687500000000027,"bottom":-0.16506249999999995,"right":0.55431249999999999,"top":0.8505625},"atlasBounds":{"left":232.5,"bottom":318.5,"right":265.5,"top":383.5}},{"unicode":37,"advance":0.76700000000000002,"planeBounds":{"left":0.0082499999999999969,"bottom":-0.044937500000000012,"right":0.75824999999999998,"top":0.75193750000000004},"atlasBounds":{"left":0.5,"bottom":76.5,"right":48.5,"top":127.5}},{"unicode":38,"advance":0.6915,"planeBounds":{"left":0.015937500000000004,"bottom":-0.044687499999999984,"right":0.71906250000000005,"top":0.75218750000000001},"atlasBounds":{"left":68.5,"bottom":294.5,"right":113.5,"top":345.5}},{"unicode":39,"advance":0.2215,"planeBounds":{"left":0.056062500000000008,"bottom":0.43099999999999999,"right":0.16543750000000002,"top":0.74350000000000005},"atlasBounds":{"left":0.5,"bottom":3.5,"right":7.5,"top":23.5}},{"unicode":40,"advance":0.29999999999999999,"planeBounds":{"left":0.050562500000000003,"bottom":-0.16912499999999997,"right":0.28493750000000001,"top":0.79962500000000003},"atlasBounds":{"left":51.5,"bottom":249.5,"right":66.5,"top":311.5}},{"unicode":41,"advance":0.29999999999999999,"planeBounds":{"left":0.014562500000000004,"bottom":-0.16912499999999997,"right":0.24893750000000001,"top":0.79962500000000003},"atlasBounds":{"left":51.5,"bottom":186.5,"right":66.5,"top":248.5}},{"unicode":42,"advance":0.40000000000000002,"planeBounds":{"left":0.027375000000000014,"bottom":0.41000000000000003,"right":0.37112499999999998,"top":0.78500000000000003},"atlasBounds":{"left":115.5,"bottom":2.5,"right":137.5,"top":26.5}},{"unicode":43,"advance":0.57999999999999996,"planeBounds":{"left":0.015812500000000014,"bottom":0.05350000000000002,"right":0.56268750000000001,"top":0.61599999999999999},"atlasBounds":{"left":158.5,"bottom":91.5,"right":193.5,"top":127.5}},{"unicode":44,"advance":0.19750000000000001,"planeBounds":{"left":0.021125000000000001,"bottom":-0.16137499999999999,"right":0.177375,"top":0.11987500000000001},"atlasBounds":{"left":8.5,"bottom":5.5,"right":18.5,"top":23.5}},{"unicode":45,"advance":0.33250000000000002,"planeBounds":{"left":0.017812499999999992,"bottom":0.24206250000000001,"right":0.31468750000000001,"top":0.35143750000000001},"atlasBounds":{"left":19.5,"bottom":5.5,"right":38.5,"top":12.5}},{"unicode":46,"advance":0.19750000000000001,"planeBounds":{"left":0.020625000000000001,"bottom":-0.039375,"right":0.176875,"top":0.11687500000000001},"atlasBounds":{"left":19.5,"bottom":13.5,"right":29.5,"top":23.5}},{"unicode":47,"advance":0.35649999999999998,"planeBounds":{"left":-0.03418750000000001,"bottom":-0.079124999999999959,"right":0.38768750000000002,"top":0.764625},"atlasBounds":{"left":330.5,"bottom":204.5,"right":357.5,"top":258.5}},{"unicode":48,"advance":0.57999999999999996,"planeBounds":{"left":0.00093750000000000354,"bottom":-0.044437500000000012,"right":0.57906250000000004,"top":0.75243749999999998},"atlasBounds":{"left":158.5,"bottom":230.5,"right":195.5,"top":281.5}},{"unicode":49,"advance":0.57999999999999996,"planeBounds":{"left":0.086625000000000021,"bottom":-0.03537499999999999,"right":0.55537500000000006,"top":0.74587500000000007},"atlasBounds":{"left":299.5,"bottom":295.5,"right":329.5,"top":345.5}},{"unicode":50,"advance":0.57999999999999996,"planeBounds":{"left":0.027125000000000007,"bottom":-0.032874999999999988,"right":0.55837500000000007,"top":0.74837500000000001},"atlasBounds":{"left":197.5,"bottom":246.5,"right":231.5,"top":296.5}},{"unicode":51,"advance":0.57999999999999996,"planeBounds":{"left":0.028125000000000008,"bottom":-0.044687499999999984,"right":0.55937500000000007,"top":0.75218750000000001},"atlasBounds":{"left":197.5,"bottom":194.5,"right":231.5,"top":245.5}},{"unicode":52,"advance":0.57999999999999996,"planeBounds":{"left":-0.001625000000000016,"bottom":-0.036374999999999991,"right":0.59212500000000001,"top":0.74487500000000006},"atlasBounds":{"left":115.5,"bottom":27.5,"right":153.5,"top":77.5}},{"unicode":53,"advance":0.57999999999999996,"planeBounds":{"left":0.037999999999999999,"bottom":-0.040874999999999988,"right":0.53800000000000003,"top":0.74037500000000001},"atlasBounds":{"left":232.5,"bottom":114.5,"right":264.5,"top":164.5}},{"unicode":54,"advance":0.57999999999999996,"planeBounds":{"left":0.030125000000000009,"bottom":-0.040874999999999988,"right":0.56137499999999996,"top":0.74037500000000001},"atlasBounds":{"left":197.5,"bottom":143.5,"right":231.5,"top":193.5}},{"unicode":55,"advance":0.57999999999999996,"planeBounds":{"left":0.026812500000000013,"bottom":-0.036874999999999991,"right":0.57368750000000002,"top":0.74437500000000001},"atlasBounds":{"left":158.5,"bottom":40.5,"right":193.5,"top":90.5}},{"unicode":56,"advance":0.57999999999999996,"planeBounds":{"left":0.024374999999999983,"bottom":-0.044687499999999984,"right":0.55562500000000004,"top":0.75218750000000001},"atlasBounds":{"left":197.5,"bottom":91.5,"right":231.5,"top":142.5}},{"unicode":57,"advance":0.57999999999999996,"planeBounds":{"left":0.0474375,"bottom":-0.032874999999999988,"right":0.56306250000000002,"top":0.74837500000000001},"atlasBounds":{"left":232.5,"bottom":267.5,"right":265.5,"top":317.5}},{"unicode":58,"advance":0.23750000000000002,"planeBounds":{"left":0.040625000000000001,"bottom":-0.043250000000000004,"right":0.19687499999999999,"top":0.51924999999999999},"atlasBounds":{"left":330.5,"bottom":77.5,"right":340.5,"top":113.5}},{"unicode":59,"advance":0.23750000000000002,"planeBounds":{"left":0.040625000000000001,"bottom":-0.16525000000000001,"right":0.19687499999999999,"top":0.52224999999999999},"atlasBounds":{"left":51.5,"bottom":3.5,"right":61.5,"top":47.5}},{"unicode":60,"advance":0.57999999999999996,"planeBounds":{"left":0.048750000000000002,"bottom":0.10112500000000002,"right":0.48625000000000002,"top":0.56987500000000002},"atlasBounds":{"left":330.5,"bottom":353.5,"right":358.5,"top":383.5}},{"unicode":61,"advance":0.57999999999999996,"planeBounds":{"left":0.047562500000000014,"bottom":0.20493749999999999,"right":0.53193750000000006,"top":0.47056249999999999},"atlasBounds":{"left":197.5,"bottom":6.5,"right":228.5,"top":23.5}},{"unicode":62,"advance":0.57999999999999996,"planeBounds":{"left":0.09425,"bottom":0.10112500000000002,"right":0.53175000000000006,"top":0.56987500000000002},"atlasBounds":{"left":330.5,"bottom":259.5,"right":358.5,"top":289.5}},{"unicode":63,"advance":0.3705,"planeBounds":{"left":-0.019124999999999989,"bottom":-0.044437500000000012,"right":0.387125,"top":0.75243749999999998},"atlasBounds":{"left":330.5,"bottom":152.5,"right":356.5,"top":203.5}},{"unicode":64,"advance":0.82150000000000001,"planeBounds":{"left":0.021125000000000015,"bottom":-0.15643750000000001,"right":0.80237500000000006,"top":0.70293749999999999},"atlasBounds":{"left":0.5,"bottom":277.5,"right":50.5,"top":332.5}},{"unicode":65,"advance":0.64449999999999996,"planeBounds":{"left":-0.029062500000000002,"bottom":-0.036874999999999991,"right":0.67406250000000001,"top":0.74437500000000001},"atlasBounds":{"left":68.5,"bottom":243.5,"right":113.5,"top":293.5}},{"unicode":66,"advance":0.64100000000000001,"planeBounds":{"left":0.073374999999999982,"bottom":-0.036874999999999991,"right":0.60462499999999997,"top":0.74437500000000001},"atlasBounds":{"left":197.5,"bottom":40.5,"right":231.5,"top":90.5}},{"unicode":67,"advance":0.70350000000000001,"planeBounds":{"left":0.02662500000000001,"bottom":-0.044687499999999984,"right":0.68287500000000001,"top":0.75218750000000001},"atlasBounds":{"left":68.5,"bottom":37.5,"right":110.5,"top":88.5}},{"unicode":68,"advance":0.76000000000000001,"planeBounds":{"left":0.066812500000000011,"bottom":-0.036874999999999991,"right":0.73868750000000005,"top":0.74437500000000001},"atlasBounds":{"left":68.5,"bottom":89.5,"right":111.5,"top":139.5}},{"unicode":69,"advance":0.59099999999999997,"planeBounds":{"left":0.067000000000000004,"bottom":-0.036874999999999991,"right":0.56700000000000006,"top":0.74437500000000001},"atlasBounds":{"left":266.5,"bottom":333.5,"right":298.5,"top":383.5}},{"unicode":70,"advance":0.57200000000000006,"planeBounds":{"left":0.067000000000000004,"bottom":-0.036874999999999991,"right":0.56700000000000006,"top":0.74437500000000001},"atlasBounds":{"left":232.5,"bottom":12.5,"right":264.5,"top":62.5}},{"unicode":71,"advance":0.74850000000000005,"planeBounds":{"left":0.024000000000000021,"bottom":-0.044687499999999984,"right":0.71150000000000002,"top":0.75218750000000001},"atlasBounds":{"left":68.5,"bottom":140.5,"right":112.5,"top":191.5}},{"unicode":72,"advance":0.75600000000000001,"planeBounds":{"left":0.07331250000000003,"bottom":-0.036874999999999991,"right":0.6826875,"top":0.74437500000000001},"atlasBounds":{"left":115.5,"bottom":180.5,"right":154.5,"top":230.5}},{"unicode":73,"advance":0.29899999999999999,"planeBounds":{"left":0.086750000000000008,"bottom":-0.036874999999999991,"right":0.21174999999999999,"top":0.74437500000000001},"atlasBounds":{"left":341.5,"bottom":63.5,"right":349.5,"top":113.5}},{"unicode":74,"advance":0.45400000000000001,"planeBounds":{"left":0.0092499999999999961,"bottom":-0.040874999999999988,"right":0.38424999999999998,"top":0.74037500000000001},"atlasBounds":{"left":359.5,"bottom":284.5,"right":383.5,"top":334.5}},{"unicode":75,"advance":0.66000000000000003,"planeBounds":{"left":0.083874999999999991,"bottom":-0.036374999999999991,"right":0.67762500000000003,"top":0.74487500000000006},"atlasBounds":{"left":158.5,"bottom":333.5,"right":196.5,"top":383.5}},{"unicode":76,"advance":0.51150000000000007,"planeBounds":{"left":0.071687500000000001,"bottom":-0.036874999999999991,"right":0.52481250000000002,"top":0.74437500000000001},"atlasBounds":{"left":299.5,"bottom":102.5,"right":328.5,"top":152.5}},{"unicode":77,"advance":0.90900000000000003,"planeBounds":{"left":0.071687500000000029,"bottom":-0.036874999999999991,"right":0.83731250000000002,"top":0.74437500000000001},"atlasBounds":{"left":0.5,"bottom":128.5,"right":49.5,"top":178.5}},{"unicode":78,"advance":0.75600000000000001,"planeBounds":{"left":0.07331250000000003,"bottom":-0.036874999999999991,"right":0.6826875,"top":0.74437500000000001},"atlasBounds":{"left":115.5,"bottom":129.5,"right":154.5,"top":179.5}},{"unicode":79,"advance":0.79749999999999999,"planeBounds":{"left":0.023749999999999993,"bottom":-0.044437500000000012,"right":0.77375000000000005,"top":0.75243749999999998},"atlasBounds":{"left":0.5,"bottom":24.5,"right":48.5,"top":75.5}},{"unicode":80,"advance":0.59350000000000003,"planeBounds":{"left":0.086750000000000008,"bottom":-0.036874999999999991,"right":0.58674999999999999,"top":0.74437500000000001},"atlasBounds":{"left":232.5,"bottom":63.5,"right":264.5,"top":113.5}},{"unicode":81,"advance":0.79749999999999999,"planeBounds":{"left":0.022625000000000006,"bottom":-0.18899999999999997,"right":0.80387500000000001,"top":0.74850000000000005},"atlasBounds":{"left":0.5,"bottom":216.5,"right":50.5,"top":276.5}},{"unicode":82,"advance":0.63100000000000001,"planeBounds":{"left":0.082750000000000004,"bottom":-0.036874999999999991,"right":0.64524999999999999,"top":0.74437500000000001},"atlasBounds":{"left":158.5,"bottom":128.5,"right":194.5,"top":178.5}},{"unicode":83,"advance":0.52249999999999996,"planeBounds":{"left":0.01125,"bottom":-0.044687499999999984,"right":0.51124999999999998,"top":0.75218750000000001},"atlasBounds":{"left":232.5,"bottom":165.5,"right":264.5,"top":216.5}},{"unicode":84,"advance":0.58450000000000002,"planeBounds":{"left":-0.020250000000000008,"bottom":-0.036874999999999991,"right":0.60475000000000001,"top":0.74437500000000001},"atlasBounds":{"left":115.5,"bottom":231.5,"right":155.5,"top":281.5}},{"unicode":85,"advance":0.73350000000000004,"planeBounds":{"left":0.061812500000000013,"bottom":-0.041125000000000016,"right":0.67118750000000005,"top":0.74012500000000003},"atlasBounds":{"left":115.5,"bottom":78.5,"right":154.5,"top":128.5}},{"unicode":86,"advance":0.64449999999999996,"planeBounds":{"left":-0.029312499999999971,"bottom":-0.036874999999999991,"right":0.67381250000000004,"top":0.74437500000000001},"atlasBounds":{"left":68.5,"bottom":192.5,"right":113.5,"top":242.5}},{"unicode":87,"advance":0.98699999999999999,"planeBounds":{"left":-0.030187499999999985,"bottom":-0.036874999999999991,"right":1.0166875,"top":0.74437500000000001},"atlasBounds":{"left":0.5,"bottom":333.5,"right":67.5,"top":383.5}},{"unicode":88,"advance":0.59950000000000003,"planeBounds":{"left":-0.028625000000000022,"bottom":-0.036874999999999991,"right":0.62762499999999999,"top":0.74437500000000001},"atlasBounds":{"left":115.5,"bottom":333.5,"right":157.5,"top":383.5}},{"unicode":89,"advance":0.59950000000000003,"planeBounds":{"left":-0.020562499999999994,"bottom":-0.036874999999999991,"right":0.62006249999999996,"top":0.74437500000000001},"atlasBounds":{"left":115.5,"bottom":282.5,"right":156.5,"top":332.5}},{"unicode":90,"advance":0.63300000000000001,"planeBounds":{"left":0.02262500000000001,"bottom":-0.036874999999999991,"right":0.61637500000000001,"top":0.74437500000000001},"atlasBounds":{"left":158.5,"bottom":282.5,"right":196.5,"top":332.5}},{"unicode":91,"advance":0.29999999999999999,"planeBounds":{"left":0.049812500000000003,"bottom":-0.16331249999999997,"right":0.28418749999999998,"top":0.78981250000000003},"atlasBounds":{"left":51.5,"bottom":124.5,"right":66.5,"top":185.5}},{"unicode":92,"advance":0.35749999999999998,"planeBounds":{"left":-0.035687500000000011,"bottom":-0.079124999999999959,"right":0.38618750000000002,"top":0.764625},"atlasBounds":{"left":266.5,"bottom":0.5,"right":293.5,"top":54.5}},{"unicode":93,"advance":0.29999999999999999,"planeBounds":{"left":0.015562500000000002,"bottom":-0.16331249999999997,"right":0.24993750000000001,"top":0.78981250000000003},"atlasBounds":{"left":51.5,"bottom":62.5,"right":66.5,"top":123.5}},{"unicode":94,"advance":0.57999999999999996,"planeBounds":{"left":0.068250000000000005,"bottom":0.36625000000000002,"right":0.50575000000000003,"top":0.74124999999999996},"atlasBounds":{"left":330.5,"bottom":328.5,"right":358.5,"top":352.5}},{"unicode":95,"advance":0.39400000000000002,"planeBounds":{"left":-0.037374999999999992,"bottom":-0.1741875,"right":0.43137500000000001,"top":-0.064812499999999995},"atlasBounds":{"left":232.5,"bottom":4.5,"right":262.5,"top":11.5}},{"unicode":96,"advance":0.29249999999999998,"planeBounds":{"left":0.010625000000000001,"bottom":0.54643750000000002,"right":0.229375,"top":0.74956250000000002},"atlasBounds":{"left":51.5,"bottom":48.5,"right":65.5,"top":61.5}},{"unicode":97,"advance":0.48649999999999999,"planeBounds":{"left":0.016749999999999994,"bottom":-0.040062499999999994,"right":0.45424999999999999,"top":0.5380625},"atlasBounds":{"left":330.5,"bottom":290.5,"right":358.5,"top":327.5}},{"unicode":98,"advance":0.54600000000000004,"planeBounds":{"left":0.052062500000000018,"bottom":-0.037937500000000006,"right":0.53643750000000001,"top":0.75893750000000004},"atlasBounds":{"left":266.5,"bottom":232.5,"right":297.5,"top":283.5}},{"unicode":99,"advance":0.45500000000000002,"planeBounds":{"left":0.0094375000000000032,"bottom":-0.039562499999999994,"right":0.46256249999999999,"top":0.53856250000000006},"atlasBounds":{"left":299.5,"bottom":205.5,"right":328.5,"top":242.5}},{"unicode":100,"advance":0.54600000000000004,"planeBounds":{"left":0.0095625000000000172,"bottom":-0.037937500000000006,"right":0.49393750000000003,"top":0.75893750000000004},"atlasBounds":{"left":266.5,"bottom":142.5,"right":297.5,"top":193.5}},{"unicode":101,"advance":0.51100000000000001,"planeBounds":{"left":0.011812499999999993,"bottom":-0.039562499999999994,"right":0.4961875,"top":0.53856250000000006},"atlasBounds":{"left":266.5,"bottom":194.5,"right":297.5,"top":231.5}},{"unicode":102,"advance":0.32200000000000001,"planeBounds":{"left":-0.016687500000000008,"bottom":-0.032374999999999987,"right":0.34268750000000003,"top":0.74887500000000007},"atlasBounds":{"left":359.5,"bottom":195.5,"right":382.5,"top":245.5}},{"unicode":103,"advance":0.50450000000000006,"planeBounds":{"left":0.0021875000000000319,"bottom":-0.2225625,"right":0.51781250000000001,"top":0.5430625},"atlasBounds":{"left":232.5,"bottom":217.5,"right":265.5,"top":266.5}},{"unicode":104,"advance":0.54100000000000004,"planeBounds":{"left":0.04212500000000001,"bottom":-0.034687499999999989,"right":0.51087499999999997,"top":0.76218750000000002},"atlasBounds":{"left":299.5,"bottom":243.5,"right":329.5,"top":294.5}},{"unicode":105,"advance":0.23750000000000002,"planeBounds":{"left":0.041125000000000002,"bottom":-0.033874999999999988,"right":0.19737499999999999,"top":0.74737500000000001},"atlasBounds":{"left":330.5,"bottom":26.5,"right":340.5,"top":76.5}},{"unicode":106,"advance":0.23550000000000001,"planeBounds":{"left":-0.063562500000000008,"bottom":-0.21987500000000001,"right":0.20206250000000001,"top":0.74887500000000007},"atlasBounds":{"left":307.5,"bottom":2.5,"right":324.5,"top":64.5}},{"unicode":107,"advance":0.49199999999999999,"planeBounds":{"left":0.050437500000000003,"bottom":-0.034687499999999989,"right":0.50356250000000002,"top":0.76218750000000002},"atlasBounds":{"left":299.5,"bottom":153.5,"right":328.5,"top":204.5}},{"unicode":108,"advance":0.23750000000000002,"planeBounds":{"left":0.056250000000000001,"bottom":-0.034687499999999989,"right":0.18124999999999999,"top":0.76218750000000002},"atlasBounds":{"left":341.5,"bottom":11.5,"right":349.5,"top":62.5}},{"unicode":109,"advance":0.79549999999999998,"planeBounds":{"left":0.044625000000000005,"bottom":-0.03631249999999997,"right":0.76337500000000003,"top":0.54181250000000003},"atlasBounds":{"left":68.5,"bottom":346.5,"right":114.5,"top":383.5}},{"unicode":110,"advance":0.54100000000000004,"planeBounds":{"left":0.04212500000000001,"bottom":-0.03631249999999997,"right":0.51087499999999997,"top":0.54181250000000003},"atlasBounds":{"left":299.5,"bottom":346.5,"right":329.5,"top":383.5}},{"unicode":111,"advance":0.54100000000000004,"planeBounds":{"left":0.0046250000000000076,"bottom":-0.039562499999999994,"right":0.53587499999999999,"top":0.53856250000000006},"atlasBounds":{"left":197.5,"bottom":297.5,"right":231.5,"top":334.5}},{"unicode":112,"advance":0.53500000000000003,"planeBounds":{"left":0.046812500000000014,"bottom":-0.20999999999999996,"right":0.53118750000000003,"top":0.54000000000000004},"atlasBounds":{"left":266.5,"bottom":284.5,"right":297.5,"top":332.5}},{"unicode":113,"advance":0.54600000000000004,"planeBounds":{"left":0.0095625000000000172,"bottom":-0.20999999999999996,"right":0.49393750000000003,"top":0.54000000000000004},"atlasBounds":{"left":266.5,"bottom":93.5,"right":297.5,"top":141.5}},{"unicode":114,"advance":0.39700000000000002,"planeBounds":{"left":0.044062500000000018,"bottom":-0.036062499999999997,"right":0.4034375,"top":0.5420625},"atlasBounds":{"left":359.5,"bottom":246.5,"right":382.5,"top":283.5}},{"unicode":115,"advance":0.42999999999999999,"planeBounds":{"left":0.0078750000000000087,"bottom":-0.040312499999999966,"right":0.41412500000000002,"top":0.53781250000000003},"atlasBounds":{"left":330.5,"bottom":114.5,"right":356.5,"top":151.5}},{"unicode":116,"advance":0.35649999999999998,"planeBounds":{"left":-0.011500000000000007,"bottom":-0.042999999999999976,"right":0.36349999999999999,"top":0.70699999999999996},"atlasBounds":{"left":359.5,"bottom":335.5,"right":383.5,"top":383.5}},{"unicode":117,"advance":0.54100000000000004,"planeBounds":{"left":0.029875000000000009,"bottom":-0.04431249999999997,"right":0.49862499999999998,"top":0.53381250000000002},"atlasBounds":{"left":266.5,"bottom":55.5,"right":296.5,"top":92.5}},{"unicode":118,"advance":0.48699999999999999,"planeBounds":{"left":-0.022125000000000016,"bottom":-0.032499999999999973,"right":0.50912500000000005,"top":0.53000000000000003},"atlasBounds":{"left":158.5,"bottom":3.5,"right":192.5,"top":39.5}},{"unicode":119,"advance":0.73699999999999999,"planeBounds":{"left":-0.022125000000000016,"bottom":-0.03125,"right":0.75912500000000005,"top":0.53125},"atlasBounds":{"left":0.5,"bottom":179.5,"right":50.5,"top":215.5}},{"unicode":120,"advance":0.46050000000000002,"planeBounds":{"left":-0.019750000000000007,"bottom":-0.032499999999999973,"right":0.48025000000000001,"top":0.53000000000000003},"atlasBounds":{"left":68.5,"bottom":0.5,"right":100.5,"top":36.5}},{"unicode":121,"advance":0.48699999999999999,"planeBounds":{"left":-0.022374999999999985,"bottom":-0.21425,"right":0.50887499999999997,"top":0.53575000000000006},"atlasBounds":{"left":197.5,"bottom":335.5,"right":231.5,"top":383.5}},{"unicode":122,"advance":0.45200000000000001,"planeBounds":{"left":-0.0015625000000000001,"bottom":-0.032499999999999973,"right":0.45156250000000003,"top":0.53000000000000003},"atlasBounds":{"left":299.5,"bottom":65.5,"right":328.5,"top":101.5}},{"unicode":123,"advance":0.29999999999999999,"planeBounds":{"left":-0.0011249999999999876,"bottom":-0.16331249999999997,"right":0.28012500000000001,"top":0.78981250000000003},"atlasBounds":{"left":359.5,"bottom":133.5,"right":377.5,"top":194.5}},{"unicode":124,"advance":0.29999999999999999,"planeBounds":{"left":0.095062500000000008,"bottom":-0.20874999999999999,"right":0.20443749999999999,"top":0.79125000000000001},"atlasBounds":{"left":299.5,"bottom":0.5,"right":306.5,"top":64.5}},{"unicode":125,"advance":0.29999999999999999,"planeBounds":{"left":0.019625000000000014,"bottom":-0.16331249999999997,"right":0.300875,"top":0.78981250000000003},"atlasBounds":{"left":359.5,"bottom":71.5,"right":377.5,"top":132.5}},{"unicode":126,"advance":0.57999999999999996,"planeBounds":{"left":0.032187500000000029,"bottom":0.17806250000000001,"right":0.54781250000000004,"top":0.41243750000000001},"atlasBounds":{"left":197.5,"bottom":24.5,"right":230.5,"top":39.5}}],"kerning":[]} +{"atlas":{"type":"msdf","distanceRange":4,"size":64,"width":384,"height":384,"yOrigin":"bottom"},"metrics":{"emSize":1,"lineHeight":1.2,"ascender":0.98699999999999999,"descender":-0.21299999999999999,"underlineY":-0.10000000000000001,"underlineThickness":0.034000000000000002},"glyphs":[{"unicode":32,"advance":0.193},{"unicode":33,"advance":0.32250000000000001,"planeBounds":{"left":0.083125000000000004,"bottom":-0.040625000000000015,"right":0.239375,"top":0.74062499999999998},"atlasBounds":{"left":359.5,"bottom":20.5,"right":369.5,"top":70.5}},{"unicode":34,"advance":0.36699999999999999,"planeBounds":{"left":0.058250000000000003,"bottom":0.43099999999999999,"right":0.30825000000000002,"top":0.74350000000000005},"atlasBounds":{"left":51.5,"bottom":312.5,"right":67.5,"top":332.5}},{"unicode":35,"advance":0.57999999999999996,"planeBounds":{"left":0.01125,"bottom":-0.036874999999999991,"right":0.57374999999999998,"top":0.74437500000000001},"atlasBounds":{"left":158.5,"bottom":179.5,"right":194.5,"top":229.5}},{"unicode":36,"advance":0.57999999999999996,"planeBounds":{"left":0.038687500000000027,"bottom":-0.16506249999999995,"right":0.55431249999999999,"top":0.8505625},"atlasBounds":{"left":232.5,"bottom":318.5,"right":265.5,"top":383.5}},{"unicode":37,"advance":0.76700000000000002,"planeBounds":{"left":0.0082499999999999969,"bottom":-0.044937500000000012,"right":0.75824999999999998,"top":0.75193750000000004},"atlasBounds":{"left":0.5,"bottom":76.5,"right":48.5,"top":127.5}},{"unicode":38,"advance":0.6915,"planeBounds":{"left":0.015937500000000004,"bottom":-0.044687499999999984,"right":0.71906250000000005,"top":0.75218750000000001},"atlasBounds":{"left":68.5,"bottom":294.5,"right":113.5,"top":345.5}},{"unicode":39,"advance":0.2215,"planeBounds":{"left":0.056062500000000008,"bottom":0.43099999999999999,"right":0.16543750000000002,"top":0.74350000000000005},"atlasBounds":{"left":0.5,"bottom":3.5,"right":7.5,"top":23.5}},{"unicode":40,"advance":0.29999999999999999,"planeBounds":{"left":0.050562500000000003,"bottom":-0.16912499999999997,"right":0.28493750000000001,"top":0.79962500000000003},"atlasBounds":{"left":51.5,"bottom":249.5,"right":66.5,"top":311.5}},{"unicode":41,"advance":0.29999999999999999,"planeBounds":{"left":0.014562500000000004,"bottom":-0.16912499999999997,"right":0.24893750000000001,"top":0.79962500000000003},"atlasBounds":{"left":51.5,"bottom":186.5,"right":66.5,"top":248.5}},{"unicode":42,"advance":0.40000000000000002,"planeBounds":{"left":0.027375000000000014,"bottom":0.41000000000000003,"right":0.37112499999999998,"top":0.78500000000000003},"atlasBounds":{"left":115.5,"bottom":2.5,"right":137.5,"top":26.5}},{"unicode":43,"advance":0.57999999999999996,"planeBounds":{"left":0.015812500000000014,"bottom":0.05350000000000002,"right":0.56268750000000001,"top":0.61599999999999999},"atlasBounds":{"left":158.5,"bottom":91.5,"right":193.5,"top":127.5}},{"unicode":44,"advance":0.19750000000000001,"planeBounds":{"left":0.021125000000000001,"bottom":-0.16137499999999999,"right":0.177375,"top":0.11987500000000001},"atlasBounds":{"left":8.5,"bottom":5.5,"right":18.5,"top":23.5}},{"unicode":45,"advance":0.33250000000000002,"planeBounds":{"left":0.017812499999999992,"bottom":0.24206250000000001,"right":0.31468750000000001,"top":0.35143750000000001},"atlasBounds":{"left":19.5,"bottom":5.5,"right":38.5,"top":12.5}},{"unicode":46,"advance":0.19750000000000001,"planeBounds":{"left":0.020625000000000001,"bottom":-0.039375,"right":0.176875,"top":0.11687500000000001},"atlasBounds":{"left":19.5,"bottom":13.5,"right":29.5,"top":23.5}},{"unicode":47,"advance":0.35649999999999998,"planeBounds":{"left":-0.03418750000000001,"bottom":-0.079124999999999959,"right":0.38768750000000002,"top":0.764625},"atlasBounds":{"left":330.5,"bottom":204.5,"right":357.5,"top":258.5}},{"unicode":48,"advance":0.57999999999999996,"planeBounds":{"left":0.00093750000000000354,"bottom":-0.044437500000000012,"right":0.57906250000000004,"top":0.75243749999999998},"atlasBounds":{"left":158.5,"bottom":230.5,"right":195.5,"top":281.5}},{"unicode":49,"advance":0.57999999999999996,"planeBounds":{"left":0.086625000000000021,"bottom":-0.03537499999999999,"right":0.55537500000000006,"top":0.74587500000000007},"atlasBounds":{"left":299.5,"bottom":295.5,"right":329.5,"top":345.5}},{"unicode":50,"advance":0.57999999999999996,"planeBounds":{"left":0.027125000000000007,"bottom":-0.032874999999999988,"right":0.55837500000000007,"top":0.74837500000000001},"atlasBounds":{"left":197.5,"bottom":246.5,"right":231.5,"top":296.5}},{"unicode":51,"advance":0.57999999999999996,"planeBounds":{"left":0.028125000000000008,"bottom":-0.044687499999999984,"right":0.55937500000000007,"top":0.75218750000000001},"atlasBounds":{"left":197.5,"bottom":194.5,"right":231.5,"top":245.5}},{"unicode":52,"advance":0.57999999999999996,"planeBounds":{"left":-0.001625000000000016,"bottom":-0.036374999999999991,"right":0.59212500000000001,"top":0.74487500000000006},"atlasBounds":{"left":115.5,"bottom":27.5,"right":153.5,"top":77.5}},{"unicode":53,"advance":0.57999999999999996,"planeBounds":{"left":0.037999999999999999,"bottom":-0.040874999999999988,"right":0.53800000000000003,"top":0.74037500000000001},"atlasBounds":{"left":232.5,"bottom":114.5,"right":264.5,"top":164.5}},{"unicode":54,"advance":0.57999999999999996,"planeBounds":{"left":0.030125000000000009,"bottom":-0.040874999999999988,"right":0.56137499999999996,"top":0.74037500000000001},"atlasBounds":{"left":197.5,"bottom":143.5,"right":231.5,"top":193.5}},{"unicode":55,"advance":0.57999999999999996,"planeBounds":{"left":0.026812500000000013,"bottom":-0.036874999999999991,"right":0.57368750000000002,"top":0.74437500000000001},"atlasBounds":{"left":158.5,"bottom":40.5,"right":193.5,"top":90.5}},{"unicode":56,"advance":0.57999999999999996,"planeBounds":{"left":0.024374999999999983,"bottom":-0.044687499999999984,"right":0.55562500000000004,"top":0.75218750000000001},"atlasBounds":{"left":197.5,"bottom":91.5,"right":231.5,"top":142.5}},{"unicode":57,"advance":0.57999999999999996,"planeBounds":{"left":0.0474375,"bottom":-0.032874999999999988,"right":0.56306250000000002,"top":0.74837500000000001},"atlasBounds":{"left":232.5,"bottom":267.5,"right":265.5,"top":317.5}},{"unicode":58,"advance":0.23750000000000002,"planeBounds":{"left":0.040625000000000001,"bottom":-0.043250000000000004,"right":0.19687499999999999,"top":0.51924999999999999},"atlasBounds":{"left":330.5,"bottom":77.5,"right":340.5,"top":113.5}},{"unicode":59,"advance":0.23750000000000002,"planeBounds":{"left":0.040625000000000001,"bottom":-0.16525000000000001,"right":0.19687499999999999,"top":0.52224999999999999},"atlasBounds":{"left":51.5,"bottom":3.5,"right":61.5,"top":47.5}},{"unicode":60,"advance":0.57999999999999996,"planeBounds":{"left":0.048750000000000002,"bottom":0.10112500000000002,"right":0.48625000000000002,"top":0.56987500000000002},"atlasBounds":{"left":330.5,"bottom":353.5,"right":358.5,"top":383.5}},{"unicode":61,"advance":0.57999999999999996,"planeBounds":{"left":0.047562500000000014,"bottom":0.20493749999999999,"right":0.53193750000000006,"top":0.47056249999999999},"atlasBounds":{"left":197.5,"bottom":6.5,"right":228.5,"top":23.5}},{"unicode":62,"advance":0.57999999999999996,"planeBounds":{"left":0.09425,"bottom":0.10112500000000002,"right":0.53175000000000006,"top":0.56987500000000002},"atlasBounds":{"left":330.5,"bottom":259.5,"right":358.5,"top":289.5}},{"unicode":63,"advance":0.3705,"planeBounds":{"left":-0.019124999999999989,"bottom":-0.044437500000000012,"right":0.387125,"top":0.75243749999999998},"atlasBounds":{"left":330.5,"bottom":152.5,"right":356.5,"top":203.5}},{"unicode":64,"advance":0.82150000000000001,"planeBounds":{"left":0.021125000000000015,"bottom":-0.15643750000000001,"right":0.80237500000000006,"top":0.70293749999999999},"atlasBounds":{"left":0.5,"bottom":277.5,"right":50.5,"top":332.5}},{"unicode":65,"advance":0.64449999999999996,"planeBounds":{"left":-0.029062500000000002,"bottom":-0.036874999999999991,"right":0.67406250000000001,"top":0.74437500000000001},"atlasBounds":{"left":68.5,"bottom":243.5,"right":113.5,"top":293.5}},{"unicode":66,"advance":0.64100000000000001,"planeBounds":{"left":0.073374999999999982,"bottom":-0.036874999999999991,"right":0.60462499999999997,"top":0.74437500000000001},"atlasBounds":{"left":197.5,"bottom":40.5,"right":231.5,"top":90.5}},{"unicode":67,"advance":0.70350000000000001,"planeBounds":{"left":0.02662500000000001,"bottom":-0.044687499999999984,"right":0.68287500000000001,"top":0.75218750000000001},"atlasBounds":{"left":68.5,"bottom":37.5,"right":110.5,"top":88.5}},{"unicode":68,"advance":0.76000000000000001,"planeBounds":{"left":0.066812500000000011,"bottom":-0.036874999999999991,"right":0.73868750000000005,"top":0.74437500000000001},"atlasBounds":{"left":68.5,"bottom":89.5,"right":111.5,"top":139.5}},{"unicode":69,"advance":0.59099999999999997,"planeBounds":{"left":0.067000000000000004,"bottom":-0.036874999999999991,"right":0.56700000000000006,"top":0.74437500000000001},"atlasBounds":{"left":266.5,"bottom":333.5,"right":298.5,"top":383.5}},{"unicode":70,"advance":0.57200000000000006,"planeBounds":{"left":0.067000000000000004,"bottom":-0.036874999999999991,"right":0.56700000000000006,"top":0.74437500000000001},"atlasBounds":{"left":232.5,"bottom":12.5,"right":264.5,"top":62.5}},{"unicode":71,"advance":0.74850000000000005,"planeBounds":{"left":0.024000000000000021,"bottom":-0.044687499999999984,"right":0.71150000000000002,"top":0.75218750000000001},"atlasBounds":{"left":68.5,"bottom":140.5,"right":112.5,"top":191.5}},{"unicode":72,"advance":0.75600000000000001,"planeBounds":{"left":0.07331250000000003,"bottom":-0.036874999999999991,"right":0.6826875,"top":0.74437500000000001},"atlasBounds":{"left":115.5,"bottom":180.5,"right":154.5,"top":230.5}},{"unicode":73,"advance":0.29899999999999999,"planeBounds":{"left":0.086750000000000008,"bottom":-0.036874999999999991,"right":0.21174999999999999,"top":0.74437500000000001},"atlasBounds":{"left":341.5,"bottom":63.5,"right":349.5,"top":113.5}},{"unicode":74,"advance":0.45400000000000001,"planeBounds":{"left":0.0092499999999999961,"bottom":-0.040874999999999988,"right":0.38424999999999998,"top":0.74037500000000001},"atlasBounds":{"left":359.5,"bottom":284.5,"right":383.5,"top":334.5}},{"unicode":75,"advance":0.66000000000000003,"planeBounds":{"left":0.083874999999999991,"bottom":-0.036374999999999991,"right":0.67762500000000003,"top":0.74487500000000006},"atlasBounds":{"left":158.5,"bottom":333.5,"right":196.5,"top":383.5}},{"unicode":76,"advance":0.51150000000000007,"planeBounds":{"left":0.071687500000000001,"bottom":-0.036874999999999991,"right":0.52481250000000002,"top":0.74437500000000001},"atlasBounds":{"left":299.5,"bottom":102.5,"right":328.5,"top":152.5}},{"unicode":77,"advance":0.90900000000000003,"planeBounds":{"left":0.071687500000000029,"bottom":-0.036874999999999991,"right":0.83731250000000002,"top":0.74437500000000001},"atlasBounds":{"left":0.5,"bottom":128.5,"right":49.5,"top":178.5}},{"unicode":78,"advance":0.75600000000000001,"planeBounds":{"left":0.07331250000000003,"bottom":-0.036874999999999991,"right":0.6826875,"top":0.74437500000000001},"atlasBounds":{"left":115.5,"bottom":129.5,"right":154.5,"top":179.5}},{"unicode":79,"advance":0.79749999999999999,"planeBounds":{"left":0.023749999999999993,"bottom":-0.044437500000000012,"right":0.77375000000000005,"top":0.75243749999999998},"atlasBounds":{"left":0.5,"bottom":24.5,"right":48.5,"top":75.5}},{"unicode":80,"advance":0.59350000000000003,"planeBounds":{"left":0.086750000000000008,"bottom":-0.036874999999999991,"right":0.58674999999999999,"top":0.74437500000000001},"atlasBounds":{"left":232.5,"bottom":63.5,"right":264.5,"top":113.5}},{"unicode":81,"advance":0.79749999999999999,"planeBounds":{"left":0.022625000000000006,"bottom":-0.18899999999999997,"right":0.80387500000000001,"top":0.74850000000000005},"atlasBounds":{"left":0.5,"bottom":216.5,"right":50.5,"top":276.5}},{"unicode":82,"advance":0.63100000000000001,"planeBounds":{"left":0.082750000000000004,"bottom":-0.036874999999999991,"right":0.64524999999999999,"top":0.74437500000000001},"atlasBounds":{"left":158.5,"bottom":128.5,"right":194.5,"top":178.5}},{"unicode":83,"advance":0.52249999999999996,"planeBounds":{"left":0.01125,"bottom":-0.044687499999999984,"right":0.51124999999999998,"top":0.75218750000000001},"atlasBounds":{"left":232.5,"bottom":165.5,"right":264.5,"top":216.5}},{"unicode":84,"advance":0.58450000000000002,"planeBounds":{"left":-0.020250000000000008,"bottom":-0.036874999999999991,"right":0.60475000000000001,"top":0.74437500000000001},"atlasBounds":{"left":115.5,"bottom":231.5,"right":155.5,"top":281.5}},{"unicode":85,"advance":0.73350000000000004,"planeBounds":{"left":0.061812500000000013,"bottom":-0.041125000000000016,"right":0.67118750000000005,"top":0.74012500000000003},"atlasBounds":{"left":115.5,"bottom":78.5,"right":154.5,"top":128.5}},{"unicode":86,"advance":0.64449999999999996,"planeBounds":{"left":-0.029312499999999971,"bottom":-0.036874999999999991,"right":0.67381250000000004,"top":0.74437500000000001},"atlasBounds":{"left":68.5,"bottom":192.5,"right":113.5,"top":242.5}},{"unicode":87,"advance":0.98699999999999999,"planeBounds":{"left":-0.030187499999999985,"bottom":-0.036874999999999991,"right":1.0166875,"top":0.74437500000000001},"atlasBounds":{"left":0.5,"bottom":333.5,"right":67.5,"top":383.5}},{"unicode":88,"advance":0.59950000000000003,"planeBounds":{"left":-0.028625000000000022,"bottom":-0.036874999999999991,"right":0.62762499999999999,"top":0.74437500000000001},"atlasBounds":{"left":115.5,"bottom":333.5,"right":157.5,"top":383.5}},{"unicode":89,"advance":0.59950000000000003,"planeBounds":{"left":-0.020562499999999994,"bottom":-0.036874999999999991,"right":0.62006249999999996,"top":0.74437500000000001},"atlasBounds":{"left":115.5,"bottom":282.5,"right":156.5,"top":332.5}},{"unicode":90,"advance":0.63300000000000001,"planeBounds":{"left":0.02262500000000001,"bottom":-0.036874999999999991,"right":0.61637500000000001,"top":0.74437500000000001},"atlasBounds":{"left":158.5,"bottom":282.5,"right":196.5,"top":332.5}},{"unicode":91,"advance":0.29999999999999999,"planeBounds":{"left":0.049812500000000003,"bottom":-0.16331249999999997,"right":0.28418749999999998,"top":0.78981250000000003},"atlasBounds":{"left":51.5,"bottom":124.5,"right":66.5,"top":185.5}},{"unicode":92,"advance":0.35749999999999998,"planeBounds":{"left":-0.035687500000000011,"bottom":-0.079124999999999959,"right":0.38618750000000002,"top":0.764625},"atlasBounds":{"left":266.5,"bottom":0.5,"right":293.5,"top":54.5}},{"unicode":93,"advance":0.29999999999999999,"planeBounds":{"left":0.015562500000000002,"bottom":-0.16331249999999997,"right":0.24993750000000001,"top":0.78981250000000003},"atlasBounds":{"left":51.5,"bottom":62.5,"right":66.5,"top":123.5}},{"unicode":94,"advance":0.57999999999999996,"planeBounds":{"left":0.068250000000000005,"bottom":0.36625000000000002,"right":0.50575000000000003,"top":0.74124999999999996},"atlasBounds":{"left":330.5,"bottom":328.5,"right":358.5,"top":352.5}},{"unicode":95,"advance":0.39400000000000002,"planeBounds":{"left":-0.037374999999999992,"bottom":-0.1741875,"right":0.43137500000000001,"top":-0.064812499999999995},"atlasBounds":{"left":232.5,"bottom":4.5,"right":262.5,"top":11.5}},{"unicode":96,"advance":0.29249999999999998,"planeBounds":{"left":0.010625000000000001,"bottom":0.54643750000000002,"right":0.229375,"top":0.74956250000000002},"atlasBounds":{"left":51.5,"bottom":48.5,"right":65.5,"top":61.5}},{"unicode":97,"advance":0.48649999999999999,"planeBounds":{"left":0.016749999999999994,"bottom":-0.040062499999999994,"right":0.45424999999999999,"top":0.5380625},"atlasBounds":{"left":330.5,"bottom":290.5,"right":358.5,"top":327.5}},{"unicode":98,"advance":0.54600000000000004,"planeBounds":{"left":0.052062500000000018,"bottom":-0.037937500000000006,"right":0.53643750000000001,"top":0.75893750000000004},"atlasBounds":{"left":266.5,"bottom":232.5,"right":297.5,"top":283.5}},{"unicode":99,"advance":0.45500000000000002,"planeBounds":{"left":0.0094375000000000032,"bottom":-0.039562499999999994,"right":0.46256249999999999,"top":0.53856250000000006},"atlasBounds":{"left":299.5,"bottom":205.5,"right":328.5,"top":242.5}},{"unicode":100,"advance":0.54600000000000004,"planeBounds":{"left":0.0095625000000000172,"bottom":-0.037937500000000006,"right":0.49393750000000003,"top":0.75893750000000004},"atlasBounds":{"left":266.5,"bottom":142.5,"right":297.5,"top":193.5}},{"unicode":101,"advance":0.51100000000000001,"planeBounds":{"left":0.011812499999999993,"bottom":-0.039562499999999994,"right":0.4961875,"top":0.53856250000000006},"atlasBounds":{"left":266.5,"bottom":194.5,"right":297.5,"top":231.5}},{"unicode":102,"advance":0.32200000000000001,"planeBounds":{"left":-0.016687500000000008,"bottom":-0.032374999999999987,"right":0.34268750000000003,"top":0.74887500000000007},"atlasBounds":{"left":359.5,"bottom":195.5,"right":382.5,"top":245.5}},{"unicode":103,"advance":0.50450000000000006,"planeBounds":{"left":0.0021875000000000319,"bottom":-0.2225625,"right":0.51781250000000001,"top":0.5430625},"atlasBounds":{"left":232.5,"bottom":217.5,"right":265.5,"top":266.5}},{"unicode":104,"advance":0.54100000000000004,"planeBounds":{"left":0.04212500000000001,"bottom":-0.034687499999999989,"right":0.51087499999999997,"top":0.76218750000000002},"atlasBounds":{"left":299.5,"bottom":243.5,"right":329.5,"top":294.5}},{"unicode":105,"advance":0.23750000000000002,"planeBounds":{"left":0.041125000000000002,"bottom":-0.033874999999999988,"right":0.19737499999999999,"top":0.74737500000000001},"atlasBounds":{"left":330.5,"bottom":26.5,"right":340.5,"top":76.5}},{"unicode":106,"advance":0.23550000000000001,"planeBounds":{"left":-0.063562500000000008,"bottom":-0.21987500000000001,"right":0.20206250000000001,"top":0.74887500000000007},"atlasBounds":{"left":307.5,"bottom":2.5,"right":324.5,"top":64.5}},{"unicode":107,"advance":0.49199999999999999,"planeBounds":{"left":0.050437500000000003,"bottom":-0.034687499999999989,"right":0.50356250000000002,"top":0.76218750000000002},"atlasBounds":{"left":299.5,"bottom":153.5,"right":328.5,"top":204.5}},{"unicode":108,"advance":0.23750000000000002,"planeBounds":{"left":0.056250000000000001,"bottom":-0.034687499999999989,"right":0.18124999999999999,"top":0.76218750000000002},"atlasBounds":{"left":341.5,"bottom":11.5,"right":349.5,"top":62.5}},{"unicode":109,"advance":0.79549999999999998,"planeBounds":{"left":0.044625000000000005,"bottom":-0.03631249999999997,"right":0.76337500000000003,"top":0.54181250000000003},"atlasBounds":{"left":68.5,"bottom":346.5,"right":114.5,"top":383.5}},{"unicode":110,"advance":0.54100000000000004,"planeBounds":{"left":0.04212500000000001,"bottom":-0.03631249999999997,"right":0.51087499999999997,"top":0.54181250000000003},"atlasBounds":{"left":299.5,"bottom":346.5,"right":329.5,"top":383.5}},{"unicode":111,"advance":0.54100000000000004,"planeBounds":{"left":0.0046250000000000076,"bottom":-0.039562499999999994,"right":0.53587499999999999,"top":0.53856250000000006},"atlasBounds":{"left":197.5,"bottom":297.5,"right":231.5,"top":334.5}},{"unicode":112,"advance":0.53500000000000003,"planeBounds":{"left":0.046812500000000014,"bottom":-0.20999999999999996,"right":0.53118750000000003,"top":0.54000000000000004},"atlasBounds":{"left":266.5,"bottom":284.5,"right":297.5,"top":332.5}},{"unicode":113,"advance":0.54600000000000004,"planeBounds":{"left":0.0095625000000000172,"bottom":-0.20999999999999996,"right":0.49393750000000003,"top":0.54000000000000004},"atlasBounds":{"left":266.5,"bottom":93.5,"right":297.5,"top":141.5}},{"unicode":114,"advance":0.39700000000000002,"planeBounds":{"left":0.044062500000000018,"bottom":-0.036062499999999997,"right":0.4034375,"top":0.5420625},"atlasBounds":{"left":359.5,"bottom":246.5,"right":382.5,"top":283.5}},{"unicode":115,"advance":0.42999999999999999,"planeBounds":{"left":0.0078750000000000087,"bottom":-0.040312499999999966,"right":0.41412500000000002,"top":0.53781250000000003},"atlasBounds":{"left":330.5,"bottom":114.5,"right":356.5,"top":151.5}},{"unicode":116,"advance":0.35649999999999998,"planeBounds":{"left":-0.011500000000000007,"bottom":-0.042999999999999976,"right":0.36349999999999999,"top":0.70699999999999996},"atlasBounds":{"left":359.5,"bottom":335.5,"right":383.5,"top":383.5}},{"unicode":117,"advance":0.54100000000000004,"planeBounds":{"left":0.029875000000000009,"bottom":-0.04431249999999997,"right":0.49862499999999998,"top":0.53381250000000002},"atlasBounds":{"left":266.5,"bottom":55.5,"right":296.5,"top":92.5}},{"unicode":118,"advance":0.48699999999999999,"planeBounds":{"left":-0.022125000000000016,"bottom":-0.032499999999999973,"right":0.50912500000000005,"top":0.53000000000000003},"atlasBounds":{"left":158.5,"bottom":3.5,"right":192.5,"top":39.5}},{"unicode":119,"advance":0.73699999999999999,"planeBounds":{"left":-0.022125000000000016,"bottom":-0.03125,"right":0.75912500000000005,"top":0.53125},"atlasBounds":{"left":0.5,"bottom":179.5,"right":50.5,"top":215.5}},{"unicode":120,"advance":0.46050000000000002,"planeBounds":{"left":-0.019750000000000007,"bottom":-0.032499999999999973,"right":0.48025000000000001,"top":0.53000000000000003},"atlasBounds":{"left":68.5,"bottom":0.5,"right":100.5,"top":36.5}},{"unicode":121,"advance":0.48699999999999999,"planeBounds":{"left":-0.022374999999999985,"bottom":-0.21425,"right":0.50887499999999997,"top":0.53575000000000006},"atlasBounds":{"left":197.5,"bottom":335.5,"right":231.5,"top":383.5}},{"unicode":122,"advance":0.45200000000000001,"planeBounds":{"left":-0.0015625000000000001,"bottom":-0.032499999999999973,"right":0.45156250000000003,"top":0.53000000000000003},"atlasBounds":{"left":299.5,"bottom":65.5,"right":328.5,"top":101.5}},{"unicode":123,"advance":0.29999999999999999,"planeBounds":{"left":-0.0011249999999999876,"bottom":-0.16331249999999997,"right":0.28012500000000001,"top":0.78981250000000003},"atlasBounds":{"left":359.5,"bottom":133.5,"right":377.5,"top":194.5}},{"unicode":124,"advance":0.29999999999999999,"planeBounds":{"left":0.095062500000000008,"bottom":-0.20874999999999999,"right":0.20443749999999999,"top":0.79125000000000001},"atlasBounds":{"left":299.5,"bottom":0.5,"right":306.5,"top":64.5}},{"unicode":125,"advance":0.29999999999999999,"planeBounds":{"left":0.019625000000000014,"bottom":-0.16331249999999997,"right":0.300875,"top":0.78981250000000003},"atlasBounds":{"left":359.5,"bottom":71.5,"right":377.5,"top":132.5}},{"unicode":126,"advance":0.57999999999999996,"planeBounds":{"left":0.032187500000000029,"bottom":0.17806250000000001,"right":0.54781250000000004,"top":0.41243750000000001},"atlasBounds":{"left":197.5,"bottom":24.5,"right":230.5,"top":39.5}}],"kerning":[]} diff --git a/assets/lato-light.kttf b/assets/lato-light.kttf index a4088c10..6e899fde 100644 --- a/assets/lato-light.kttf +++ b/assets/lato-light.kttf @@ -1,7 +1,7 @@ -{ - "file": "lato-light.ttf", - "char_range_start": "0x20", - "char_range_end": "0x7f", - "offset_x": 0.0, - "offset_y": 25.0, +{ + "file": "lato-light.ttf", + "char_range_start": "0x20", + "char_range_end": "0x7f", + "offset_x": 0.0, + "offset_y": 25.0, } \ No newline at end of file diff --git a/assets/rainbow_shader.wgsl b/assets/rainbow_shader.wgsl index fc10bb19..bd978fa3 100644 --- a/assets/rainbow_shader.wgsl +++ b/assets/rainbow_shader.wgsl @@ -1,17 +1,17 @@ -#import kayak_ui::bindings globals -#import kayak_ui::sample_quad sample_quad -#import kayak_ui::vertex_output VertexOutput - -fn hsv2rgb(c: vec3) -> vec3 -{ - let K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, vec3(0.0), vec3(1.0)), c.y); -} - -@fragment -fn fragment(in: VertexOutput) -> @location(0) vec4 { - var output_color = sample_quad(in); - let hsv = vec3(abs(sin(globals.time)), 1.0, 1.0); - return vec4(hsv2rgb(hsv), output_color.a); -} +#import kayak_ui::bindings::globals +#import kayak_ui::sample_quad::sample_quad +#import kayak_ui::vertex_output::VertexOutput + +fn hsv2rgb(c: vec3) -> vec3 +{ + let K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, vec3(0.0), vec3(1.0)), c.y); +} + +@fragment +fn fragment(in: VertexOutput) -> @location(0) vec4 { + var output_color = sample_quad(in); + let hsv = vec3(abs(sin(globals.time)), 1.0, 1.0); + return vec4(hsv2rgb(hsv), output_color.a); +} diff --git a/assets/roboto.kayak_font b/assets/roboto.kayak_font index d61382b0..cb843676 100644 --- a/assets/roboto.kayak_font +++ b/assets/roboto.kayak_font @@ -1,3069 +1,3069 @@ -{ - "atlas": { - "type": "msdf", - "distanceRange": 2, - "size": 32.375, - "width": 312, - "height": 312, - "yOrigin": "bottom" - }, - "metrics": { - "emSize": 1, - "lineHeight": 1.171875, - "ascender": 0.927734375, - "descender": -0.244140625, - "underlineY": -0.09765625, - "underlineThickness": 0.048828125 - }, - "glyphs": [ - { - "unicode": 32, - "advance": 0.24755859375 - }, - { - "unicode": 33, - "advance": 0.25732421875, - "planeBounds": { - "left": 0.038927704210907341, - "bottom": -0.048761198419401491, - "right": 0.22425588953909267, - "top": 0.75432760466940163 - }, - "atlasBounds": { - "left": 133.5, - "bottom": 146.5, - "right": 139.5, - "top": 172.5 - } - }, - { - "unicode": 34, - "advance": 0.31982421875, - "planeBounds": { - "left": 0.027751907878861004, - "bottom": 0.47495437680984559, - "right": 0.305744185871139, - "top": 0.78383468569015446 - }, - "atlasBounds": { - "left": 298.5, - "bottom": 146.5, - "right": 307.5, - "top": 156.5 - } - }, - { - "unicode": 35, - "advance": 0.61572265625, - "planeBounds": { - "left": 0.021686097369691175, - "bottom": -0.046075651544401491, - "right": 0.63944671513030904, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 180.5, - "bottom": 146.5, - "right": 200.5, - "top": 172.5 - } - }, - { - "unicode": 36, - "advance": 0.5615234375, - "planeBounds": { - "left": 0.018457596826737505, - "bottom": -0.14734782215250966, - "right": 0.54355412192326258, - "top": 0.87195719715250952 - }, - "atlasBounds": { - "left": 140.5, - "bottom": 278.5, - "right": 157.5, - "top": 311.5 - } - }, - { - "unicode": 37, - "advance": 0.732421875, - "planeBounds": { - "left": 0.014904832287644842, - "bottom": -0.046075651544401491, - "right": 0.72532954271235528, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 274.5, - "bottom": 146.5, - "right": 297.5, - "top": 172.5 - } - }, - { - "unicode": 38, - "advance": 0.62158203125, - "planeBounds": { - "left": 0.0096600506756757305, - "bottom": -0.046075651544401491, - "right": 0.65830869932432434, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 290.5, - "bottom": 174.5, - "right": 311.5, - "top": 200.5 - } - }, - { - "unicode": 39, - "advance": 0.17431640625, - "planeBounds": { - "left": 0.0096939852799227781, - "bottom": 0.47861648618484559, - "right": 0.1641341397200772, - "top": 0.78749679506515446 - }, - "atlasBounds": { - "left": 115.5, - "bottom": 5.5, - "right": 120.5, - "top": 15.5 - } - }, - { - "unicode": 40, - "advance": 0.341796875, - "planeBounds": { - "left": 0.023963486365830115, - "bottom": -0.26960760285955593, - "right": 0.36373182613416988, - "top": 0.84236150910955598 - }, - "atlasBounds": { - "left": 34.5, - "bottom": 275.5, - "right": 45.5, - "top": 311.5 - } - }, - { - "unicode": 41, - "advance": 0.34765625, - "planeBounds": { - "left": -0.022179091759169888, - "bottom": -0.26960760285955593, - "right": 0.31758924800916988, - "top": 0.84236150910955598 - }, - "atlasBounds": { - "left": 46.5, - "bottom": 275.5, - "right": 57.5, - "top": 311.5 - } - }, - { - "unicode": 42, - "advance": 0.4306640625, - "planeBounds": { - "left": -0.03201635647924711, - "bottom": 0.25704614352075295, - "right": 0.46219213772924705, - "top": 0.75125463772924705 - }, - "atlasBounds": { - "left": 295.5, - "bottom": 249.5, - "right": 311.5, - "top": 265.5 - } - }, - { - "unicode": 43, - "advance": 0.56689453125, - "planeBounds": { - "left": 0.0037460032577220637, - "bottom": 0.036641831563706623, - "right": 0.55973055924227799, - "top": 0.62351441843629352 - }, - "atlasBounds": { - "left": 171.5, - "bottom": 17.5, - "right": 189.5, - "top": 36.5 - } - }, - { - "unicode": 44, - "advance": 0.1962890625, - "planeBounds": { - "left": -0.025832717483108111, - "bottom": -0.18721815425916988, - "right": 0.19038349873310811, - "top": 0.15255018550916991 - }, - "atlasBounds": { - "left": 107.5, - "bottom": 4.5, - "right": 114.5, - "top": 15.5 - } - }, - { - "unicode": 45, - "advance": 0.27587890625, - "planeBounds": { - "left": -0.01723312319015444, - "bottom": 0.2247818759049228, - "right": 0.29164718569015446, - "top": 0.37922203034507723 - }, - "atlasBounds": { - "left": 82.5, - "bottom": 269.5, - "right": 92.5, - "top": 274.5 - } - }, - { - "unicode": 46, - "advance": 0.26318359375, - "planeBounds": { - "left": 0.033800751085907341, - "bottom": -0.044324248914092659, - "right": 0.21912893641409267, - "top": 0.14100393641409267 - }, - "atlasBounds": { - "left": 54.5, - "bottom": 268.5, - "right": 60.5, - "top": 274.5 - } - }, - { - "unicode": 47, - "advance": 0.412109375, - "planeBounds": { - "left": -0.035859450410231669, - "bottom": -0.092037245113416932, - "right": 0.42746101291023164, - "top": 0.74193958886341704 - }, - "atlasBounds": { - "left": 63.5, - "bottom": 173.5, - "right": 78.5, - "top": 200.5 - } - }, - { - "unicode": 48, - "advance": 0.5615234375, - "planeBounds": { - "left": 0.017969315576737505, - "bottom": -0.046075651544401491, - "right": 0.54306584067326258, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 145.5, - "bottom": 118.5, - "right": 162.5, - "top": 144.5 - } - }, - { - "unicode": 49, - "advance": 0.5615234375, - "planeBounds": { - "left": 0.049598251990830108, - "bottom": -0.044366667169401491, - "right": 0.38936659175916988, - "top": 0.75872213591940163 - }, - "atlasBounds": { - "left": 163.5, - "bottom": 118.5, - "right": 174.5, - "top": 144.5 - } - }, - { - "unicode": 50, - "advance": 0.5615234375, - "planeBounds": { - "left": 0.0071639720077220637, - "bottom": -0.041192839044401491, - "right": 0.56314852799227799, - "top": 0.76189596404440163 - }, - "atlasBounds": { - "left": 175.5, - "bottom": 118.5, - "right": 193.5, - "top": 144.5 - } - }, - { - "unicode": 51, - "advance": 0.5615234375, - "planeBounds": { - "left": 0.0086919718267375046, - "bottom": -0.046075651544401491, - "right": 0.53378849692326258, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 194.5, - "bottom": 118.5, - "right": 211.5, - "top": 144.5 - } - }, - { - "unicode": 52, - "advance": 0.5615234375, - "planeBounds": { - "left": -0.010965590311293381, - "bottom": -0.046075651544401491, - "right": 0.57590699656129352, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 248.5, - "bottom": 118.5, - "right": 267.5, - "top": 144.5 - } - }, - { - "unicode": 53, - "advance": 0.5615234375, - "planeBounds": { - "left": 0.036035721826737505, - "bottom": -0.050958464044401491, - "right": 0.56113224692326258, - "top": 0.75213033904440163 - }, - "atlasBounds": { - "left": 268.5, - "bottom": 118.5, - "right": 285.5, - "top": 144.5 - } - }, - { - "unicode": 54, - "advance": 0.5615234375, - "planeBounds": { - "left": 0.026514237451737505, - "bottom": -0.050714323419401491, - "right": 0.55161076254826258, - "top": 0.75237447966940163 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 91.5, - "right": 17.5, - "top": 117.5 - } - }, - { - "unicode": 55, - "advance": 0.5615234375, - "planeBounds": { - "left": -0.00016024674227793634, - "bottom": -0.046075651544401491, - "right": 0.55582430924227799, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 18.5, - "bottom": 91.5, - "right": 36.5, - "top": 117.5 - } - }, - { - "unicode": 56, - "advance": 0.5615234375, - "planeBounds": { - "left": 0.018213456201737505, - "bottom": -0.046075651544401491, - "right": 0.54330998129826258, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 62.5, - "bottom": 91.5, - "right": 79.5, - "top": 117.5 - } - }, - { - "unicode": 57, - "advance": 0.5615234375, - "planeBounds": { - "left": 0.0099126749517375046, - "bottom": -0.041436979669401491, - "right": 0.53500920004826258, - "top": 0.76165182341940163 - }, - "atlasBounds": { - "left": 80.5, - "bottom": 91.5, - "right": 97.5, - "top": 117.5 - } - }, - { - "unicode": 58, - "advance": 0.2421875, - "planeBounds": { - "left": 0.029162079210907337, - "bottom": -0.044964293255308832, - "right": 0.21449026453909267, - "top": 0.57279632450530904 - }, - "atlasBounds": { - "left": 18.5, - "bottom": 16.5, - "right": 24.5, - "top": 36.5 - } - }, - { - "unicode": 59, - "advance": 0.21142578125, - "planeBounds": { - "left": -0.014846389358108107, - "bottom": -0.17485558940637061, - "right": 0.20136982685810811, - "top": 0.5664571519063708 - }, - "atlasBounds": { - "left": 165.5, - "bottom": 39.5, - "right": 172.5, - "top": 63.5 - } - }, - { - "unicode": 60, - "advance": 0.50830078125, - "planeBounds": { - "left": 0.0032030495897683378, - "bottom": 0.053125565576737505, - "right": 0.46652351291023164, - "top": 0.57822209067326269 - }, - "atlasBounds": { - "left": 190.5, - "bottom": 19.5, - "right": 205.5, - "top": 36.5 - } - }, - { - "unicode": 61, - "advance": 0.548828125, - "planeBounds": { - "left": 0.030727784145752921, - "bottom": 0.15012103342181471, - "right": 0.52493627835424705, - "top": 0.5207774040781854 - }, - "atlasBounds": { - "left": 295.5, - "bottom": 236.5, - "right": 311.5, - "top": 248.5 - } - }, - { - "unicode": 62, - "advance": 0.5224609375, - "planeBounds": { - "left": 0.026821534145752921, - "bottom": 0.053613846826737505, - "right": 0.52103002835424705, - "top": 0.57871037192326269 - }, - "atlasBounds": { - "left": 224.5, - "bottom": 19.5, - "right": 240.5, - "top": 36.5 - } - }, - { - "unicode": 63, - "advance": 0.47216796875, - "planeBounds": { - "left": 0.0029589089647683378, - "bottom": -0.043878385919401491, - "right": 0.46627937228523164, - "top": 0.75921041716940163 - }, - "atlasBounds": { - "left": 115.5, - "bottom": 91.5, - "right": 130.5, - "top": 117.5 - } - }, - { - "unicode": 64, - "advance": 0.89794921875, - "planeBounds": { - "left": 0.020699599520762921, - "bottom": -0.25543896295849411, - "right": 0.88556446438562775, - "top": 0.73297802545849433 - }, - "atlasBounds": { - "left": 249.5, - "bottom": 279.5, - "right": 277.5, - "top": 311.5 - } - }, - { - "unicode": 65, - "advance": 0.65234375, - "planeBounds": { - "left": -0.028796339587355158, - "bottom": -0.046075651544401491, - "right": 0.68162837083735528, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 148.5, - "bottom": 91.5, - "right": 171.5, - "top": 117.5 - } - }, - { - "unicode": 66, - "advance": 0.62255859375, - "planeBounds": { - "left": 0.046470612632722064, - "bottom": -0.046075651544401491, - "right": 0.60245516861727799, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 188.5, - "bottom": 91.5, - "right": 206.5, - "top": 117.5 - } - }, - { - "unicode": 67, - "advance": 0.65087890625, - "planeBounds": { - "left": 0.022906800494691175, - "bottom": -0.046075651544401491, - "right": 0.64066741825530904, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 207.5, - "bottom": 91.5, - "right": 227.5, - "top": 117.5 - } - }, - { - "unicode": 68, - "advance": 0.65576171875, - "planeBounds": { - "left": 0.046163315938706623, - "bottom": -0.046075651544401491, - "right": 0.63303590281129352, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 228.5, - "bottom": 91.5, - "right": 247.5, - "top": 117.5 - } - }, - { - "unicode": 69, - "advance": 0.568359375, - "planeBounds": { - "left": 0.045801346826737505, - "bottom": -0.046075651544401491, - "right": 0.57089787192326258, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 248.5, - "bottom": 91.5, - "right": 265.5, - "top": 117.5 - } - }, - { - "unicode": 70, - "advance": 0.552734375, - "planeBounds": { - "left": 0.040186112451737505, - "bottom": -0.046075651544401491, - "right": 0.56528263754826258, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 266.5, - "bottom": 91.5, - "right": 283.5, - "top": 117.5 - } - }, - { - "unicode": 71, - "advance": 0.68115234375, - "planeBounds": { - "left": 0.024615784869691175, - "bottom": -0.046075651544401491, - "right": 0.64237640263030904, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 284.5, - "bottom": 91.5, - "right": 304.5, - "top": 117.5 - } - }, - { - "unicode": 72, - "advance": 0.712890625, - "planeBounds": { - "left": 0.046832581744691168, - "bottom": -0.046075651544401491, - "right": 0.66459319950530904, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 64.5, - "right": 20.5, - "top": 90.5 - } - }, - { - "unicode": 73, - "advance": 0.27197265625, - "planeBounds": { - "left": 0.043566376085907341, - "bottom": -0.046075651544401491, - "right": 0.22889456141409267, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 305.5, - "bottom": 91.5, - "right": 311.5, - "top": 117.5 - } - }, - { - "unicode": 74, - "advance": 0.5517578125, - "planeBounds": { - "left": -0.012304121923262495, - "bottom": -0.050958464044401491, - "right": 0.51279240317326258, - "top": 0.75213033904440163 - }, - "atlasBounds": { - "left": 38.5, - "bottom": 37.5, - "right": 55.5, - "top": 63.5 - } - }, - { - "unicode": 75, - "advance": 0.626953125, - "planeBounds": { - "left": 0.046100159869691175, - "bottom": -0.046075651544401491, - "right": 0.66386077763030904, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 17.5, - "bottom": 37.5, - "right": 37.5, - "top": 63.5 - } - }, - { - "unicode": 76, - "advance": 0.5380859375, - "planeBounds": { - "left": 0.050991456020752918, - "bottom": -0.046075651544401491, - "right": 0.54519995022924705, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 37.5, - "right": 16.5, - "top": 63.5 - } - }, - { - "unicode": 77, - "advance": 0.873046875, - "planeBounds": { - "left": 0.05017891077461395, - "bottom": -0.046075651544401491, - "right": 0.82237968297538611, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 286.5, - "bottom": 118.5, - "right": 311.5, - "top": 144.5 - } - }, - { - "unicode": 78, - "advance": 0.712890625, - "planeBounds": { - "left": 0.046832581744691168, - "bottom": -0.046075651544401491, - "right": 0.66459319950530904, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 262.5, - "bottom": 64.5, - "right": 282.5, - "top": 90.5 - } - }, - { - "unicode": 79, - "advance": 0.6875, - "planeBounds": { - "left": 0.019181535050675731, - "bottom": -0.046075651544401491, - "right": 0.66783018369932434, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 240.5, - "bottom": 64.5, - "right": 261.5, - "top": 90.5 - } - }, - { - "unicode": 80, - "advance": 0.630859375, - "planeBounds": { - "left": 0.044698472188706623, - "bottom": -0.046075651544401491, - "right": 0.63157105906129352, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 220.5, - "bottom": 64.5, - "right": 239.5, - "top": 90.5 - } - }, - { - "unicode": 81, - "advance": 0.6875, - "planeBounds": { - "left": 0.016251847550675731, - "bottom": -0.16302749457046325, - "right": 0.66490049619932434, - "top": 0.76361343207046339 - }, - "atlasBounds": { - "left": 143.5, - "bottom": 202.5, - "right": 164.5, - "top": 232.5 - } - }, - { - "unicode": 82, - "advance": 0.61572265625, - "planeBounds": { - "left": 0.046651597188706623, - "bottom": -0.046075651544401491, - "right": 0.63352418406129352, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 180.5, - "bottom": 64.5, - "right": 199.5, - "top": 90.5 - } - }, - { - "unicode": 83, - "advance": 0.59326171875, - "planeBounds": { - "left": 0.0039269878137066193, - "bottom": -0.046075651544401491, - "right": 0.59079957468629352, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 160.5, - "bottom": 64.5, - "right": 179.5, - "top": 90.5 - } - }, - { - "unicode": 84, - "advance": 0.5966796875, - "planeBounds": { - "left": -0.010052183880308825, - "bottom": -0.046075651544401491, - "right": 0.60770843388030904, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 139.5, - "bottom": 64.5, - "right": 159.5, - "top": 90.5 - } - }, - { - "unicode": 85, - "advance": 0.6484375, - "planeBounds": { - "left": 0.032247300313706623, - "bottom": -0.050958464044401491, - "right": 0.61911988718629352, - "top": 0.75213033904440163 - }, - "atlasBounds": { - "left": 119.5, - "bottom": 64.5, - "right": 138.5, - "top": 90.5 - } - }, - { - "unicode": 86, - "advance": 0.63623046875, - "planeBounds": { - "left": -0.02116482414333971, - "bottom": -0.046075651544401491, - "right": 0.65837185539333987, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 96.5, - "bottom": 64.5, - "right": 118.5, - "top": 90.5 - } - }, - { - "unicode": 87, - "advance": 0.88720703125, - "planeBounds": { - "left": -0.015566557070463265, - "bottom": -0.046075651544401491, - "right": 0.91107436957046339, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 65.5, - "bottom": 64.5, - "right": 95.5, - "top": 90.5 - } - }, - { - "unicode": 88, - "advance": 0.626953125, - "planeBounds": { - "left": -0.010115339949324269, - "bottom": -0.046075651544401491, - "right": 0.63853330869932434, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 43.5, - "bottom": 64.5, - "right": 64.5, - "top": 90.5 - } - }, - { - "unicode": 89, - "advance": 0.6005859375, - "planeBounds": { - "left": -0.025007918074324269, - "bottom": -0.046075651544401491, - "right": 0.62364073057432434, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 21.5, - "bottom": 64.5, - "right": 42.5, - "top": 90.5 - } - }, - { - "unicode": 90, - "advance": 0.5986328125, - "planeBounds": { - "left": 0.0073449565637066193, - "bottom": -0.046075651544401491, - "right": 0.59421754343629352, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 200.5, - "bottom": 64.5, - "right": 219.5, - "top": 90.5 - } - }, - { - "unicode": 91, - "advance": 0.26513671875, - "planeBounds": { - "left": 0.039777954572876445, - "bottom": -0.1950184000965251, - "right": 0.28688220167712358, - "top": 0.85517465009652516 - }, - "atlasBounds": { - "left": 58.5, - "bottom": 277.5, - "right": 66.5, - "top": 311.5 - } - }, - { - "unicode": 92, - "advance": 0.41015625, - "planeBounds": { - "left": -0.020722731660231666, - "bottom": -0.092037245113416932, - "right": 0.44259773166023164, - "top": 0.74193958886341704 - }, - "atlasBounds": { - "left": 134.5, - "bottom": 173.5, - "right": 149.5, - "top": 200.5 - } - }, - { - "unicode": 93, - "advance": 0.26513671875, - "planeBounds": { - "left": -0.026872436052123552, - "bottom": -0.1950184000965251, - "right": 0.22023181105212358, - "top": 0.85517465009652516 - }, - "atlasBounds": { - "left": 67.5, - "bottom": 277.5, - "right": 75.5, - "top": 311.5 - } - }, - { - "unicode": 94, - "advance": 0.41796875, - "planeBounds": { - "left": -0.0082084037162162178, - "bottom": 0.31723104940878383, - "right": 0.42422402871621623, - "top": 0.74966348184121623 - }, - "atlasBounds": { - "left": 81.5, - "bottom": 1.5, - "right": 95.5, - "top": 15.5 - } - }, - { - "unicode": 95, - "advance": 0.451171875, - "planeBounds": { - "left": -0.036962325048262551, - "bottom": -0.1140853115950772, - "right": 0.48813420004826258, - "top": 0.040354842845077232 - }, - "atlasBounds": { - "left": 93.5, - "bottom": 269.5, - "right": 110.5, - "top": 274.5 - } - }, - { - "unicode": 96, - "advance": 0.30908203125, - "planeBounds": { - "left": -0.0093574671211389959, - "bottom": 0.57011454814189189, - "right": 0.268634810871139, - "top": 0.78633076435810811 - }, - "atlasBounds": { - "left": 34.5, - "bottom": 267.5, - "right": 43.5, - "top": 274.5 - } - }, - { - "unicode": 97, - "advance": 0.5439453125, - "planeBounds": { - "left": 0.0086919718267374525, - "bottom": -0.044720152630308832, - "right": 0.53378849692326258, - "top": 0.57304046513030904 - }, - "atlasBounds": { - "left": 215.5, - "bottom": 43.5, - "right": 232.5, - "top": 63.5 - } - }, - { - "unicode": 98, - "advance": 0.56103515625, - "planeBounds": { - "left": 0.029443924951737505, - "bottom": -0.046871229488416932, - "right": 0.55454045004826258, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 188.5, - "bottom": 173.5, - "right": 205.5, - "top": 200.5 - } - }, - { - "unicode": 99, - "advance": 0.5234375, - "planeBounds": { - "left": 0.0050298624517375046, - "bottom": -0.044720152630308832, - "right": 0.53012638754826258, - "top": 0.57304046513030904 - }, - "atlasBounds": { - "left": 250.5, - "bottom": 43.5, - "right": 267.5, - "top": 63.5 - } - }, - { - "unicode": 100, - "advance": 0.56396484375, - "planeBounds": { - "left": 0.0067388468267375046, - "bottom": -0.046871229488416932, - "right": 0.53183537192326258, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 223.5, - "bottom": 173.5, - "right": 240.5, - "top": 200.5 - } - }, - { - "unicode": 101, - "advance": 0.52978515625, - "planeBounds": { - "left": 0.0069829874517375046, - "bottom": -0.044720152630308832, - "right": 0.53207951254826258, - "top": 0.57304046513030904 - }, - "atlasBounds": { - "left": 25.5, - "bottom": 16.5, - "right": 42.5, - "top": 36.5 - } - }, - { - "unicode": 102, - "advance": 0.34716796875, - "planeBounds": { - "left": -0.011807357022200773, - "bottom": -0.036861463863416932, - "right": 0.38973704452220076, - "top": 0.79711537011341704 - }, - "atlasBounds": { - "left": 241.5, - "bottom": 173.5, - "right": 254.5, - "top": 200.5 - } - }, - { - "unicode": 103, - "advance": 0.56103515625, - "planeBounds": { - "left": 0.0074712687017375046, - "bottom": -0.25194935448841688, - "right": 0.53256779379826258, - "top": 0.58202747948841704 - }, - "atlasBounds": { - "left": 255.5, - "bottom": 173.5, - "right": 272.5, - "top": 200.5 - } - }, - { - "unicode": 104, - "advance": 0.55078125, - "planeBounds": { - "left": 0.029018799770752921, - "bottom": -0.041988416988416932, - "right": 0.52322729397924705, - "top": 0.79198841698841704 - }, - "atlasBounds": { - "left": 273.5, - "bottom": 173.5, - "right": 289.5, - "top": 200.5 - } - }, - { - "unicode": 105, - "advance": 0.24267578125, - "planeBounds": { - "left": 0.029650360460907337, - "bottom": -0.041192839044401491, - "right": 0.21497854578909267, - "top": 0.76189596404440163 - }, - "atlasBounds": { - "left": 55.5, - "bottom": 91.5, - "right": 61.5, - "top": 117.5 - } - }, - { - "unicode": 106, - "advance": 0.23876953125, - "planeBounds": { - "left": -0.070636763996138996, - "bottom": -0.25599040027750963, - "right": 0.20735551399613902, - "top": 0.76331461902750952 - }, - "atlasBounds": { - "left": 194.5, - "bottom": 278.5, - "right": 203.5, - "top": 311.5 - } - }, - { - "unicode": 107, - "advance": 0.5068359375, - "planeBounds": { - "left": 0.024805253076737453, - "bottom": -0.041988416988416932, - "right": 0.54990177817326258, - "top": 0.79198841698841704 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 145.5, - "right": 17.5, - "top": 172.5 - } - }, - { - "unicode": 108, - "advance": 0.24267578125, - "planeBounds": { - "left": 0.044117813404922782, - "bottom": -0.041988416988416932, - "right": 0.1985579678450772, - "top": 0.79198841698841704 - }, - "atlasBounds": { - "left": 18.5, - "bottom": 145.5, - "right": 23.5, - "top": 172.5 - } - }, - { - "unicode": 109, - "advance": 0.87646484375, - "planeBounds": { - "left": 0.036688020330598509, - "bottom": -0.039837340130308832, - "right": 0.83977682341940163, - "top": 0.57792327763030904 - }, - "atlasBounds": { - "left": 113.5, - "bottom": 16.5, - "right": 139.5, - "top": 36.5 - } - }, - { - "unicode": 110, - "advance": 0.5517578125, - "planeBounds": { - "left": 0.029018799770752921, - "bottom": -0.039837340130308832, - "right": 0.52322729397924705, - "top": 0.57792327763030904 - }, - "atlasBounds": { - "left": 60.5, - "bottom": 16.5, - "right": 76.5, - "top": 36.5 - } - }, - { - "unicode": 111, - "advance": 0.5703125, - "planeBounds": { - "left": 0.0069198313827220637, - "bottom": -0.044720152630308832, - "right": 0.56290438736727799, - "top": 0.57304046513030904 - }, - "atlasBounds": { - "left": 77.5, - "bottom": 16.5, - "right": 95.5, - "top": 36.5 - } - }, - { - "unicode": 112, - "advance": 0.56103515625, - "planeBounds": { - "left": 0.028955643701737505, - "bottom": -0.23406393279440149, - "right": 0.55405216879826258, - "top": 0.56902487029440163 - }, - "atlasBounds": { - "left": 230.5, - "bottom": 118.5, - "right": 247.5, - "top": 144.5 - } - }, - { - "unicode": 113, - "advance": 0.568359375, - "planeBounds": { - "left": 0.0064947062017375046, - "bottom": -0.23406393279440149, - "right": 0.53159123129826258, - "top": 0.56902487029440163 - }, - "atlasBounds": { - "left": 212.5, - "bottom": 118.5, - "right": 229.5, - "top": 144.5 - } - }, - { - "unicode": 114, - "advance": 0.33837890625, - "planeBounds": { - "left": 0.026160751990830115, - "bottom": -0.039837340130308832, - "right": 0.36592909175916988, - "top": 0.57792327763030904 - }, - "atlasBounds": { - "left": 140.5, - "bottom": 16.5, - "right": 151.5, - "top": 36.5 - } - }, - { - "unicode": 115, - "advance": 0.515625, - "planeBounds": { - "left": 0.0092434091457528969, - "bottom": -0.044720152630308832, - "right": 0.50345190335424705, - "top": 0.57304046513030904 - }, - "atlasBounds": { - "left": 96.5, - "bottom": 16.5, - "right": 112.5, - "top": 36.5 - } - }, - { - "unicode": 116, - "advance": 0.32666015625, - "planeBounds": { - "left": -0.037134825953185333, - "bottom": -0.04741418315637061, - "right": 0.33352154470318535, - "top": 0.6938985581563708 - }, - "atlasBounds": { - "left": 152.5, - "bottom": 39.5, - "right": 164.5, - "top": 63.5 - } - }, - { - "unicode": 117, - "advance": 0.55126953125, - "planeBounds": { - "left": 0.027309815395752921, - "bottom": -0.049602965130308832, - "right": 0.52151830960424705, - "top": 0.56815765263030904 - }, - "atlasBounds": { - "left": 43.5, - "bottom": 16.5, - "right": 59.5, - "top": 36.5 - } - }, - { - "unicode": 118, - "advance": 0.484375, - "planeBounds": { - "left": -0.021581465673262547, - "bottom": -0.044720152630308832, - "right": 0.50351505942326258, - "top": 0.57304046513030904 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 16.5, - "right": 17.5, - "top": 36.5 - } - }, - { - "unicode": 119, - "advance": 0.75146484375, - "planeBounds": { - "left": -0.011588667350386047, - "bottom": -0.044720152630308832, - "right": 0.76061210485038611, - "top": 0.57304046513030904 - }, - "atlasBounds": { - "left": 286.5, - "bottom": 43.5, - "right": 311.5, - "top": 63.5 - } - }, - { - "unicode": 120, - "advance": 0.49560546875, - "planeBounds": { - "left": -0.015722090673262495, - "bottom": -0.044720152630308832, - "right": 0.50937443442326258, - "top": 0.57304046513030904 - }, - "atlasBounds": { - "left": 268.5, - "bottom": 43.5, - "right": 285.5, - "top": 63.5 - } - }, - { - "unicode": 121, - "advance": 0.47314453125, - "planeBounds": { - "left": -0.026708418798262547, - "bottom": -0.25951771386341688, - "right": 0.49838810629826258, - "top": 0.57445912011341704 - }, - "atlasBounds": { - "left": 43.5, - "bottom": 145.5, - "right": 60.5, - "top": 172.5 - } - }, - { - "unicode": 122, - "advance": 0.49560546875, - "planeBounds": { - "left": 0.0055812997707528969, - "bottom": -0.044720152630308832, - "right": 0.49978979397924711, - "top": 0.57304046513030904 - }, - "atlasBounds": { - "left": 233.5, - "bottom": 43.5, - "right": 249.5, - "top": 63.5 - } - }, - { - "unicode": 123, - "advance": 0.33837890625, - "planeBounds": { - "left": -0.0061289665781853291, - "bottom": -0.2245594157215251, - "right": 0.36452740407818535, - "top": 0.82563363447152516 - }, - "atlasBounds": { - "left": 94.5, - "bottom": 277.5, - "right": 106.5, - "top": 311.5 - } - }, - { - "unicode": 124, - "advance": 0.24365234375, - "planeBounds": { - "left": 0.044606094654922782, - "bottom": -0.17376968207046325, - "right": 0.1990462490950772, - "top": 0.75287124457046339 - }, - "atlasBounds": { - "left": 165.5, - "bottom": 202.5, - "right": 170.5, - "top": 232.5 - } - }, - { - "unicode": 125, - "advance": 0.33837890625, - "planeBounds": { - "left": -0.027857482203185329, - "bottom": -0.2245594157215251, - "right": 0.34279888845318535, - "top": 0.82563363447152516 - }, - "atlasBounds": { - "left": 107.5, - "bottom": 277.5, - "right": 119.5, - "top": 311.5 - } - }, - { - "unicode": 126, - "advance": 0.68017578125, - "planeBounds": { - "left": 0.031451722369691175, - "bottom": 0.154949173503861, - "right": 0.64921234013030904, - "top": 0.43294145149613905 - }, - "atlasBounds": { - "left": 121.5, - "bottom": 6.5, - "right": 141.5, - "top": 15.5 - } - }, - { - "unicode": 160, - "advance": 0.24755859375 - }, - { - "unicode": 161, - "advance": 0.24365234375, - "planeBounds": { - "left": 0.028673797960907337, - "bottom": -0.22063619841940149, - "right": 0.21400198328909267, - "top": 0.58245260466940163 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 118.5, - "right": 6.5, - "top": 144.5 - } - }, - { - "unicode": 162, - "advance": 0.546875, - "planeBounds": { - "left": 0.011377518701737505, - "bottom": -0.15502552636341693, - "right": 0.53647404379826258, - "top": 0.67895130761341704 - }, - "atlasBounds": { - "left": 79.5, - "bottom": 145.5, - "right": 96.5, - "top": 172.5 - } - }, - { - "unicode": 163, - "advance": 0.5810546875, - "planeBounds": { - "left": 0.0041711284387066193, - "bottom": -0.041192839044401491, - "right": 0.59104371531129352, - "top": 0.76189596404440163 - }, - "atlasBounds": { - "left": 254.5, - "bottom": 146.5, - "right": 273.5, - "top": 172.5 - } - }, - { - "unicode": 164, - "advance": 0.712890625, - "planeBounds": { - "left": 0.0051392072876448418, - "bottom": -0.052966261462355169, - "right": 0.71556391771235528, - "top": 0.65745844896235528 - }, - "atlasBounds": { - "left": 173.5, - "bottom": 40.5, - "right": 196.5, - "top": 63.5 - } - }, - { - "unicode": 165, - "advance": 0.52490234375, - "planeBounds": { - "left": -0.030985121561293381, - "bottom": -0.046075651544401491, - "right": 0.55588746531129352, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 201.5, - "bottom": 146.5, - "right": 220.5, - "top": 172.5 - } - }, - { - "unicode": 166, - "advance": 0.23974609375, - "planeBounds": { - "left": 0.039967422779922782, - "bottom": -0.17376968207046325, - "right": 0.1944075772200772, - "top": 0.75287124457046339 - }, - "atlasBounds": { - "left": 171.5, - "bottom": 202.5, - "right": 176.5, - "top": 232.5 - } - }, - { - "unicode": 167, - "advance": 0.61328125, - "planeBounds": { - "left": 0.0080773784387066193, - "bottom": -0.28559457197152505, - "right": 0.59494996531129352, - "top": 0.76459847822152516 - }, - "atlasBounds": { - "left": 120.5, - "bottom": 277.5, - "right": 139.5, - "top": 311.5 - } - }, - { - "unicode": 168, - "advance": 0.41796875, - "planeBounds": { - "left": 0.0069914711027992266, - "bottom": 0.5765253604609073, - "right": 0.40853587264720076, - "top": 0.7618535457890927 - }, - "atlasBounds": { - "left": 61.5, - "bottom": 268.5, - "right": 74.5, - "top": 274.5 - } - }, - { - "unicode": 169, - "advance": 0.78564453125, - "planeBounds": { - "left": 0.004768754524613953, - "bottom": -0.046319792169401491, - "right": 0.77696952672538611, - "top": 0.75676901091940163 - }, - "atlasBounds": { - "left": 140.5, - "bottom": 146.5, - "right": 165.5, - "top": 172.5 - } - }, - { - "unicode": 170, - "advance": 0.44677734375, - "planeBounds": { - "left": 0.026278580477799227, - "bottom": 0.29739250271476841, - "right": 0.42782298202220076, - "top": 0.76071296603523164 - }, - "atlasBounds": { - "left": 298.5, - "bottom": 157.5, - "right": 311.5, - "top": 172.5 - } - }, - { - "unicode": 171, - "advance": 0.46923828125, - "planeBounds": { - "left": 0.0051561745897683378, - "bottom": 0.036406174589768338, - "right": 0.46847663791023164, - "top": 0.49972663791023164 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 0.5, - "right": 15.5, - "top": 15.5 - } - }, - { - "unicode": 172, - "advance": 0.5537109375, - "planeBounds": { - "left": 0.017788331020752897, - "bottom": 0.147869095378861, - "right": 0.51199682522924705, - "top": 0.42586137337113905 - }, - "atlasBounds": { - "left": 150.5, - "bottom": 6.5, - "right": 166.5, - "top": 15.5 - } - }, - { - "unicode": 173, - "advance": 0.27587890625, - "planeBounds": { - "left": -0.01723312319015444, - "bottom": 0.2247818759049228, - "right": 0.29164718569015446, - "top": 0.37922203034507723 - }, - "atlasBounds": { - "left": 111.5, - "bottom": 269.5, - "right": 121.5, - "top": 274.5 - } - }, - { - "unicode": 174, - "advance": 0.7861328125, - "planeBounds": { - "left": 0.004280473274613953, - "bottom": -0.046319792169401491, - "right": 0.77648124547538611, - "top": 0.75676901091940163 - }, - "atlasBounds": { - "left": 56.5, - "bottom": 37.5, - "right": 81.5, - "top": 63.5 - } - }, - { - "unicode": 175, - "advance": 0.4580078125, - "planeBounds": { - "left": 0.032626236727799227, - "bottom": 0.59343421965492271, - "right": 0.43417063827220076, - "top": 0.74787437409507718 - }, - "atlasBounds": { - "left": 122.5, - "bottom": 269.5, - "right": 135.5, - "top": 274.5 - } - }, - { - "unicode": 176, - "advance": 0.37353515625, - "planeBounds": { - "left": 0.032571564309845563, - "bottom": 0.42484239261583018, - "right": 0.34145187319015446, - "top": 0.76461073238416999 - }, - "atlasBounds": { - "left": 96.5, - "bottom": 4.5, - "right": 106.5, - "top": 15.5 - } - }, - { - "unicode": 177, - "advance": 0.5341796875, - "planeBounds": { - "left": 0.0084478312017375046, - "bottom": -0.045886183337355155, - "right": 0.53354435629826258, - "top": 0.66453852708735528 - }, - "atlasBounds": { - "left": 197.5, - "bottom": 40.5, - "right": 214.5, - "top": 63.5 - } - }, - { - "unicode": 178, - "advance": 0.36669921875, - "planeBounds": { - "left": -0.0024668572031853291, - "bottom": 0.28933586208976841, - "right": 0.36818951345318535, - "top": 0.75265632541023164 - }, - "atlasBounds": { - "left": 32.5, - "bottom": 0.5, - "right": 44.5, - "top": 15.5 - } - }, - { - "unicode": 179, - "advance": 0.36669921875, - "planeBounds": { - "left": -0.0075938103281853291, - "bottom": 0.28665031521476841, - "right": 0.36306256032818535, - "top": 0.74997077853523164 - }, - "atlasBounds": { - "left": 45.5, - "bottom": 0.5, - "right": 57.5, - "top": 15.5 - } - }, - { - "unicode": 180, - "advance": 0.3134765625, - "planeBounds": { - "left": 0.022869095378861004, - "bottom": 0.57011454814189189, - "right": 0.300861373371139, - "top": 0.78633076435810811 - }, - "atlasBounds": { - "left": 44.5, - "bottom": 267.5, - "right": 53.5, - "top": 274.5 - } - }, - { - "unicode": 181, - "advance": 0.56640625, - "planeBounds": { - "left": 0.036098877895752918, - "bottom": -0.23894674529440149, - "right": 0.53030737210424705, - "top": 0.56414205779440163 - }, - "atlasBounds": { - "left": 131.5, - "bottom": 91.5, - "right": 147.5, - "top": 117.5 - } - }, - { - "unicode": 182, - "advance": 0.48876953125, - "planeBounds": { - "left": -0.012177809785231662, - "bottom": -0.046075651544401491, - "right": 0.45114265353523164, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 172.5, - "bottom": 91.5, - "right": 187.5, - "top": 117.5 - } - }, - { - "unicode": 183, - "advance": 0.2607421875, - "planeBounds": { - "left": 0.035265594835907341, - "bottom": 0.26378121983590735, - "right": 0.22059378016409267, - "top": 0.4491094051640927 - }, - "atlasBounds": { - "left": 75.5, - "bottom": 268.5, - "right": 81.5, - "top": 274.5 - } - }, - { - "unicode": 184, - "advance": 0.24755859375, - "planeBounds": { - "left": 0.024216110641891893, - "bottom": -0.24519731087113897, - "right": 0.24043232685810811, - "top": 0.032794967121139051 - }, - "atlasBounds": { - "left": 142.5, - "bottom": 6.5, - "right": 149.5, - "top": 15.5 - } - }, - { - "unicode": 185, - "advance": 0.36669921875, - "planeBounds": { - "left": 0.027082642072876448, - "bottom": 0.28665031521476841, - "right": 0.27418688917712358, - "top": 0.74997077853523164 - }, - "atlasBounds": { - "left": 72.5, - "bottom": 0.5, - "right": 80.5, - "top": 15.5 - } - }, - { - "unicode": 186, - "advance": 0.45458984375, - "planeBounds": { - "left": 0.026034439852799227, - "bottom": 0.29714836208976841, - "right": 0.42757884139720076, - "top": 0.76046882541023164 - }, - "atlasBounds": { - "left": 58.5, - "bottom": 0.5, - "right": 71.5, - "top": 15.5 - } - }, - { - "unicode": 187, - "advance": 0.46875, - "planeBounds": { - "left": 0.010038987089768338, - "bottom": 0.037138596464768338, - "right": 0.47335945041023164, - "top": 0.50045905978523164 - }, - "atlasBounds": { - "left": 16.5, - "bottom": 0.5, - "right": 31.5, - "top": 15.5 - } - }, - { - "unicode": 188, - "advance": 0.732421875, - "planeBounds": { - "left": -0.0020040269063706026, - "bottom": -0.03136405797538605, - "right": 0.7393087144063708, - "top": 0.74083671422538611 - }, - "atlasBounds": { - "left": 82.5, - "bottom": 38.5, - "right": 106.5, - "top": 63.5 - } - }, - { - "unicode": 189, - "advance": 0.77587890625, - "planeBounds": { - "left": -0.004996870475386047, - "bottom": -0.03136405797538605, - "right": 0.76720390172538611, - "top": 0.74083671422538611 - }, - "atlasBounds": { - "left": 107.5, - "bottom": 38.5, - "right": 132.5, - "top": 63.5 - } - }, - { - "unicode": 190, - "advance": 0.77783203125, - "planeBounds": { - "left": 0.011360551399613953, - "bottom": -0.043390104669401491, - "right": 0.78356132360038611, - "top": 0.75969869841940163 - }, - "atlasBounds": { - "left": 119.5, - "bottom": 118.5, - "right": 144.5, - "top": 144.5 - } - }, - { - "unicode": 191, - "advance": 0.47314453125, - "planeBounds": { - "left": 0.0017382058397683378, - "bottom": -0.22673971404440149, - "right": 0.46505866916023164, - "top": 0.57634908904440163 - }, - "atlasBounds": { - "left": 103.5, - "bottom": 118.5, - "right": 118.5, - "top": 144.5 - } - }, - { - "unicode": 192, - "advance": 0.65234375, - "planeBounds": { - "left": -0.028796339587355158, - "bottom": -0.043524900458494151, - "right": 0.68162837083735528, - "top": 0.94489208795849422 - }, - "atlasBounds": { - "left": 278.5, - "bottom": 279.5, - "right": 301.5, - "top": 311.5 - } - }, - { - "unicode": 193, - "advance": 0.65234375, - "planeBounds": { - "left": -0.028796339587355158, - "bottom": -0.043524900458494151, - "right": 0.68162837083735528, - "top": 0.94489208795849422 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 233.5, - "right": 23.5, - "top": 265.5 - } - }, - { - "unicode": 194, - "advance": 0.65234375, - "planeBounds": { - "left": -0.028796339587355158, - "bottom": -0.043524900458494151, - "right": 0.68162837083735528, - "top": 0.94489208795849422 - }, - "atlasBounds": { - "left": 24.5, - "bottom": 233.5, - "right": 47.5, - "top": 265.5 - } - }, - { - "unicode": 195, - "advance": 0.65234375, - "planeBounds": { - "left": -0.028796339587355158, - "bottom": -0.03296369751447871, - "right": 0.68162837083735528, - "top": 0.92456526001447892 - }, - "atlasBounds": { - "left": 22.5, - "bottom": 201.5, - "right": 45.5, - "top": 232.5 - } - }, - { - "unicode": 196, - "advance": 0.65234375, - "planeBounds": { - "left": -0.028796339587355158, - "bottom": -0.04248518188947871, - "right": 0.68162837083735528, - "top": 0.91504377563947892 - }, - "atlasBounds": { - "left": 66.5, - "bottom": 201.5, - "right": 89.5, - "top": 232.5 - } - }, - { - "unicode": 197, - "advance": 0.65234375, - "planeBounds": { - "left": -0.028796339587355158, - "bottom": -0.036752119027509661, - "right": 0.68162837083735528, - "top": 0.98255290027750952 - }, - "atlasBounds": { - "left": 204.5, - "bottom": 278.5, - "right": 227.5, - "top": 311.5 - } - }, - { - "unicode": 198, - "advance": 0.9345703125, - "planeBounds": { - "left": -0.038886228583494151, - "bottom": -0.046075651544401491, - "right": 0.94953075983349422, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 221.5, - "bottom": 146.5, - "right": 253.5, - "top": 172.5 - } - }, - { - "unicode": 199, - "advance": 0.65087890625, - "planeBounds": { - "left": 0.022906800494691175, - "bottom": -0.25769938465250963, - "right": 0.64066741825530904, - "top": 0.76160563465250952 - }, - "atlasBounds": { - "left": 228.5, - "bottom": 278.5, - "right": 248.5, - "top": 311.5 - } - }, - { - "unicode": 200, - "advance": 0.568359375, - "planeBounds": { - "left": 0.045801346826737505, - "bottom": -0.040595212958494151, - "right": 0.57089787192326258, - "top": 0.94782177545849422 - }, - "atlasBounds": { - "left": 48.5, - "bottom": 233.5, - "right": 65.5, - "top": 265.5 - } - }, - { - "unicode": 201, - "advance": 0.568359375, - "planeBounds": { - "left": 0.045801346826737505, - "bottom": -0.040595212958494151, - "right": 0.57089787192326258, - "top": 0.94782177545849422 - }, - "atlasBounds": { - "left": 66.5, - "bottom": 233.5, - "right": 83.5, - "top": 265.5 - } - }, - { - "unicode": 202, - "advance": 0.568359375, - "planeBounds": { - "left": 0.045801346826737505, - "bottom": -0.040595212958494151, - "right": 0.57089787192326258, - "top": 0.94782177545849422 - }, - "atlasBounds": { - "left": 84.5, - "bottom": 233.5, - "right": 101.5, - "top": 265.5 - } - }, - { - "unicode": 203, - "advance": 0.568359375, - "planeBounds": { - "left": 0.045801346826737505, - "bottom": -0.03955549438947871, - "right": 0.57089787192326258, - "top": 0.91797346313947892 - }, - "atlasBounds": { - "left": 111.5, - "bottom": 201.5, - "right": 128.5, - "top": 232.5 - } - }, - { - "unicode": 204, - "advance": 0.27197265625, - "planeBounds": { - "left": -0.052814498371138996, - "bottom": -0.040595212958494151, - "right": 0.22517777962113902, - "top": 0.94782177545849422 - }, - "atlasBounds": { - "left": 302.5, - "bottom": 279.5, - "right": 311.5, - "top": 311.5 - } - }, - { - "unicode": 205, - "advance": 0.27197265625, - "planeBounds": { - "left": 0.048748001628861004, - "bottom": -0.040595212958494151, - "right": 0.32674027962113905, - "top": 0.94782177545849422 - }, - "atlasBounds": { - "left": 102.5, - "bottom": 233.5, - "right": 111.5, - "top": 265.5 - } - }, - { - "unicode": 206, - "advance": 0.27197265625, - "planeBounds": { - "left": -0.048853575953185333, - "bottom": -0.040595212958494151, - "right": 0.32180279470318535, - "top": 0.94782177545849422 - }, - "atlasBounds": { - "left": 112.5, - "bottom": 233.5, - "right": 124.5, - "top": 265.5 - } - }, - { - "unicode": 207, - "advance": 0.27197265625, - "planeBounds": { - "left": -0.063321028897200773, - "bottom": -0.03955549438947871, - "right": 0.33822337264720076, - "top": 0.91797346313947892 - }, - "atlasBounds": { - "left": 129.5, - "bottom": 201.5, - "right": 142.5, - "top": 232.5 - } - }, - { - "unicode": 208, - "advance": 0.67041015625, - "planeBounds": { - "left": -0.032395292893339714, - "bottom": -0.046075651544401491, - "right": 0.64714138664333987, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 7.5, - "bottom": 118.5, - "right": 29.5, - "top": 144.5 - } - }, - { - "unicode": 209, - "advance": 0.712890625, - "planeBounds": { - "left": 0.046832581744691168, - "bottom": -0.03296369751447871, - "right": 0.66459319950530904, - "top": 0.92456526001447892 - }, - "atlasBounds": { - "left": 90.5, - "bottom": 201.5, - "right": 110.5, - "top": 232.5 - } - }, - { - "unicode": 210, - "advance": 0.6875, - "planeBounds": { - "left": 0.019181535050675731, - "bottom": -0.047919431708494165, - "right": 0.66783018369932434, - "top": 0.94049755670849422 - }, - "atlasBounds": { - "left": 125.5, - "bottom": 233.5, - "right": 146.5, - "top": 265.5 - } - }, - { - "unicode": 211, - "advance": 0.6875, - "planeBounds": { - "left": 0.019181535050675731, - "bottom": -0.047919431708494165, - "right": 0.66783018369932434, - "top": 0.94049755670849422 - }, - "atlasBounds": { - "left": 147.5, - "bottom": 233.5, - "right": 168.5, - "top": 265.5 - } - }, - { - "unicode": 212, - "advance": 0.6875, - "planeBounds": { - "left": 0.019181535050675731, - "bottom": -0.047919431708494165, - "right": 0.66783018369932434, - "top": 0.94049755670849422 - }, - "atlasBounds": { - "left": 191.5, - "bottom": 233.5, - "right": 212.5, - "top": 265.5 - } - }, - { - "unicode": 213, - "advance": 0.6875, - "planeBounds": { - "left": 0.019181535050675731, - "bottom": -0.052802244208494165, - "right": 0.66783018369932434, - "top": 0.93561474420849422 - }, - "atlasBounds": { - "left": 273.5, - "bottom": 233.5, - "right": 294.5, - "top": 265.5 - } - }, - { - "unicode": 214, - "advance": 0.6875, - "planeBounds": { - "left": 0.019181535050675731, - "bottom": -0.04687971313947871, - "right": 0.66783018369932434, - "top": 0.91064924438947892 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 201.5, - "right": 21.5, - "top": 232.5 - } - }, - { - "unicode": 215, - "advance": 0.533203125, - "planeBounds": { - "left": 0.00063533120173750457, - "bottom": 0.061914628076737505, - "right": 0.52573185629826258, - "top": 0.58701115317326269 - }, - "atlasBounds": { - "left": 206.5, - "bottom": 19.5, - "right": 223.5, - "top": 36.5 - } - }, - { - "unicode": 216, - "advance": 0.6875, - "planeBounds": { - "left": 0.024064347550675731, - "bottom": -0.085020323057432373, - "right": 0.67271299619932434, - "top": 0.77984454180743246 - }, - "atlasBounds": { - "left": 195.5, - "bottom": 204.5, - "right": 216.5, - "top": 232.5 - } - }, - { - "unicode": 217, - "advance": 0.6484375, - "planeBounds": { - "left": 0.032247300313706623, - "bottom": -0.048407712958494165, - "right": 0.61911988718629352, - "top": 0.94000927545849422 - }, - "atlasBounds": { - "left": 253.5, - "bottom": 233.5, - "right": 272.5, - "top": 265.5 - } - }, - { - "unicode": 218, - "advance": 0.6484375, - "planeBounds": { - "left": 0.032247300313706623, - "bottom": -0.048407712958494165, - "right": 0.61911988718629352, - "top": 0.94000927545849422 - }, - "atlasBounds": { - "left": 233.5, - "bottom": 233.5, - "right": 252.5, - "top": 265.5 - } - }, - { - "unicode": 219, - "advance": 0.6484375, - "planeBounds": { - "left": 0.032247300313706623, - "bottom": -0.048407712958494165, - "right": 0.61911988718629352, - "top": 0.94000927545849422 - }, - "atlasBounds": { - "left": 213.5, - "bottom": 233.5, - "right": 232.5, - "top": 265.5 - } - }, - { - "unicode": 220, - "advance": 0.6484375, - "planeBounds": { - "left": 0.032247300313706623, - "bottom": -0.04736799438947871, - "right": 0.61911988718629352, - "top": 0.91016096313947892 - }, - "atlasBounds": { - "left": 46.5, - "bottom": 201.5, - "right": 65.5, - "top": 232.5 - } - }, - { - "unicode": 221, - "advance": 0.6005859375, - "planeBounds": { - "left": -0.025007918074324269, - "bottom": -0.043524900458494151, - "right": 0.62364073057432434, - "top": 0.94489208795849422 - }, - "atlasBounds": { - "left": 169.5, - "bottom": 233.5, - "right": 190.5, - "top": 265.5 - } - }, - { - "unicode": 222, - "advance": 0.5908203125, - "planeBounds": { - "left": 0.035240143882722064, - "bottom": -0.046075651544401491, - "right": 0.59122469986727799, - "top": 0.75701315154440163 - }, - "atlasBounds": { - "left": 84.5, - "bottom": 118.5, - "right": 102.5, - "top": 144.5 - } - }, - { - "unicode": 223, - "advance": 0.5947265625, - "planeBounds": { - "left": 0.031822175132722064, - "bottom": -0.042476698238416932, - "right": 0.58780673111727799, - "top": 0.79150013573841704 - }, - "atlasBounds": { - "left": 97.5, - "bottom": 145.5, - "right": 115.5, - "top": 172.5 - } - }, - { - "unicode": 224, - "advance": 0.5439453125, - "planeBounds": { - "left": 0.0086919718267374525, - "bottom": -0.046871229488416932, - "right": 0.53378849692326258, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 97.5, - "bottom": 173.5, - "right": 114.5, - "top": 200.5 - } - }, - { - "unicode": 225, - "advance": 0.5439453125, - "planeBounds": { - "left": 0.0086919718267374525, - "bottom": -0.046871229488416932, - "right": 0.53378849692326258, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 27.5, - "bottom": 173.5, - "right": 44.5, - "top": 200.5 - } - }, - { - "unicode": 226, - "advance": 0.5439453125, - "planeBounds": { - "left": 0.0086919718267374525, - "bottom": -0.046871229488416932, - "right": 0.53378849692326258, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 294.5, - "bottom": 205.5, - "right": 311.5, - "top": 232.5 - } - }, - { - "unicode": 227, - "advance": 0.5439453125, - "planeBounds": { - "left": 0.0086919718267374525, - "bottom": -0.051754041988416932, - "right": 0.53378849692326258, - "top": 0.78222279198841704 - }, - "atlasBounds": { - "left": 61.5, - "bottom": 145.5, - "right": 78.5, - "top": 172.5 - } - }, - { - "unicode": 228, - "advance": 0.5439453125, - "planeBounds": { - "left": 0.0086919718267374525, - "bottom": -0.045831510919401491, - "right": 0.53378849692326258, - "top": 0.75725729216940163 - }, - "atlasBounds": { - "left": 47.5, - "bottom": 118.5, - "right": 64.5, - "top": 144.5 - } - }, - { - "unicode": 229, - "advance": 0.5439453125, - "planeBounds": { - "left": 0.0086919718267374525, - "bottom": -0.055542463501447828, - "right": 0.53378849692326258, - "top": 0.84021043225144798 - }, - "atlasBounds": { - "left": 177.5, - "bottom": 203.5, - "right": 194.5, - "top": 232.5 - } - }, - { - "unicode": 230, - "advance": 0.84423828125, - "planeBounds": { - "left": -0.0081160261824323766, - "bottom": -0.044720152630308832, - "right": 0.85674883868243246, - "top": 0.57304046513030904 - }, - "atlasBounds": { - "left": 283.5, - "bottom": 70.5, - "right": 311.5, - "top": 90.5 - } - }, - { - "unicode": 231, - "advance": 0.5234375, - "planeBounds": { - "left": 0.0050298624517375046, - "bottom": -0.25634388573841688, - "right": 0.53012638754826258, - "top": 0.57763294823841704 - }, - "atlasBounds": { - "left": 45.5, - "bottom": 173.5, - "right": 62.5, - "top": 200.5 - } - }, - { - "unicode": 232, - "advance": 0.52978515625, - "planeBounds": { - "left": 0.0069829874517375046, - "bottom": -0.046871229488416932, - "right": 0.53207951254826258, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 79.5, - "bottom": 173.5, - "right": 96.5, - "top": 200.5 - } - }, - { - "unicode": 233, - "advance": 0.52978515625, - "planeBounds": { - "left": 0.0069829874517375046, - "bottom": -0.046871229488416932, - "right": 0.53207951254826258, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 248.5, - "bottom": 205.5, - "right": 265.5, - "top": 232.5 - } - }, - { - "unicode": 234, - "advance": 0.52978515625, - "planeBounds": { - "left": 0.0069829874517375046, - "bottom": -0.046871229488416932, - "right": 0.53207951254826258, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 276.5, - "bottom": 205.5, - "right": 293.5, - "top": 232.5 - } - }, - { - "unicode": 235, - "advance": 0.52978515625, - "planeBounds": { - "left": 0.0069829874517375046, - "bottom": -0.045831510919401491, - "right": 0.53207951254826258, - "top": 0.75725729216940163 - }, - "atlasBounds": { - "left": 37.5, - "bottom": 91.5, - "right": 54.5, - "top": 117.5 - } - }, - { - "unicode": 236, - "advance": 0.2470703125, - "planeBounds": { - "left": -0.065509810871138996, - "bottom": -0.042232557613416932, - "right": 0.21248246712113902, - "top": 0.79174427636341704 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 173.5, - "right": 9.5, - "top": 200.5 - } - }, - { - "unicode": 237, - "advance": 0.2470703125, - "planeBounds": { - "left": 0.036052689128861004, - "bottom": -0.042232557613416932, - "right": 0.314044967121139, - "top": 0.79174427636341704 - }, - "atlasBounds": { - "left": 266.5, - "bottom": 205.5, - "right": 275.5, - "top": 232.5 - } - }, - { - "unicode": 238, - "advance": 0.2470703125, - "planeBounds": { - "left": -0.061548888453185333, - "bottom": -0.042232557613416932, - "right": 0.30910748220318535, - "top": 0.79174427636341704 - }, - "atlasBounds": { - "left": 235.5, - "bottom": 205.5, - "right": 247.5, - "top": 232.5 - } - }, - { - "unicode": 239, - "advance": 0.2470703125, - "planeBounds": { - "left": -0.076016341397200773, - "bottom": -0.041192839044401491, - "right": 0.32552806014720076, - "top": 0.76189596404440163 - }, - "atlasBounds": { - "left": 166.5, - "bottom": 146.5, - "right": 179.5, - "top": 172.5 - } - }, - { - "unicode": 240, - "advance": 0.5859375, - "planeBounds": { - "left": 0.029199784326737505, - "bottom": -0.051573057432432373, - "right": 0.55429630942326258, - "top": 0.81329180743243246 - }, - "atlasBounds": { - "left": 217.5, - "bottom": 204.5, - "right": 234.5, - "top": 232.5 - } - }, - { - "unicode": 241, - "advance": 0.5517578125, - "planeBounds": { - "left": 0.029018799770752921, - "bottom": -0.031427214044401491, - "right": 0.52322729397924705, - "top": 0.77166158904440163 - }, - "atlasBounds": { - "left": 30.5, - "bottom": 118.5, - "right": 46.5, - "top": 144.5 - } - }, - { - "unicode": 242, - "advance": 0.5703125, - "planeBounds": { - "left": 0.0069198313827220637, - "bottom": -0.046871229488416932, - "right": 0.56290438736727799, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 169.5, - "bottom": 173.5, - "right": 187.5, - "top": 200.5 - } - }, - { - "unicode": 243, - "advance": 0.5703125, - "planeBounds": { - "left": 0.0069198313827220637, - "bottom": -0.046871229488416932, - "right": 0.56290438736727799, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 150.5, - "bottom": 173.5, - "right": 168.5, - "top": 200.5 - } - }, - { - "unicode": 244, - "advance": 0.5703125, - "planeBounds": { - "left": 0.0069198313827220637, - "bottom": -0.046871229488416932, - "right": 0.56290438736727799, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 115.5, - "bottom": 173.5, - "right": 133.5, - "top": 200.5 - } - }, - { - "unicode": 245, - "advance": 0.5703125, - "planeBounds": { - "left": 0.0069198313827220637, - "bottom": -0.051754041988416932, - "right": 0.56290438736727799, - "top": 0.78222279198841704 - }, - "atlasBounds": { - "left": 24.5, - "bottom": 145.5, - "right": 42.5, - "top": 172.5 - } - }, - { - "unicode": 246, - "advance": 0.5703125, - "planeBounds": { - "left": 0.0069198313827220637, - "bottom": -0.045831510919401491, - "right": 0.56290438736727799, - "top": 0.75725729216940163 - }, - "atlasBounds": { - "left": 65.5, - "bottom": 118.5, - "right": 83.5, - "top": 144.5 - } - }, - { - "unicode": 247, - "advance": 0.57080078125, - "planeBounds": { - "left": 0.00032803450772206366, - "bottom": 0.043966050313706623, - "right": 0.55631259049227799, - "top": 0.63083863718629352 - }, - "atlasBounds": { - "left": 152.5, - "bottom": 17.5, - "right": 170.5, - "top": 36.5 - } - }, - { - "unicode": 248, - "advance": 0.56640625, - "planeBounds": { - "left": 0.0069198313827220637, - "bottom": -0.1084493394063706, - "right": 0.56290438736727799, - "top": 0.6328634019063708 - }, - "atlasBounds": { - "left": 133.5, - "bottom": 39.5, - "right": 151.5, - "top": 63.5 - } - }, - { - "unicode": 249, - "advance": 0.55126953125, - "planeBounds": { - "left": 0.027309815395752921, - "bottom": -0.046871229488416932, - "right": 0.52151830960424705, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 206.5, - "bottom": 173.5, - "right": 222.5, - "top": 200.5 - } - }, - { - "unicode": 250, - "advance": 0.55126953125, - "planeBounds": { - "left": 0.027309815395752921, - "bottom": -0.046871229488416932, - "right": 0.52151830960424705, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 116.5, - "bottom": 145.5, - "right": 132.5, - "top": 172.5 - } - }, - { - "unicode": 251, - "advance": 0.55126953125, - "planeBounds": { - "left": 0.027309815395752921, - "bottom": -0.046871229488416932, - "right": 0.52151830960424705, - "top": 0.78710560448841704 - }, - "atlasBounds": { - "left": 10.5, - "bottom": 173.5, - "right": 26.5, - "top": 200.5 - } - }, - { - "unicode": 252, - "advance": 0.55126953125, - "planeBounds": { - "left": 0.027309815395752921, - "bottom": -0.045831510919401491, - "right": 0.52151830960424705, - "top": 0.75725729216940163 - }, - "atlasBounds": { - "left": 98.5, - "bottom": 91.5, - "right": 114.5, - "top": 117.5 - } - }, - { - "unicode": 253, - "advance": 0.47314453125, - "planeBounds": { - "left": -0.026708418798262547, - "bottom": -0.25678597822152505, - "right": 0.49838810629826258, - "top": 0.79340707197152516 - }, - "atlasBounds": { - "left": 76.5, - "bottom": 277.5, - "right": 93.5, - "top": 311.5 - } - }, - { - "unicode": 254, - "advance": 0.576171875, - "planeBounds": { - "left": 0.033350174951737505, - "bottom": -0.23621500965250966, - "right": 0.55844670004826258, - "top": 0.78309000965250952 - }, - "atlasBounds": { - "left": 176.5, - "bottom": 278.5, - "right": 193.5, - "top": 311.5 - } - }, - { - "unicode": 255, - "advance": 0.47314453125, - "planeBounds": { - "left": -0.026708418798262547, - "bottom": -0.25574625965250963, - "right": 0.49838810629826258, - "top": 0.76355875965250952 - }, - "atlasBounds": { - "left": 158.5, - "bottom": 278.5, - "right": 175.5, - "top": 311.5 - } - }, - { - "unicode": 65533, - "advance": 1.02587890625, - "planeBounds": { - "left": 0.002798662222490346, - "bottom": -0.30240256998069504, - "right": 1.0221036815275095, - "top": 1.0875588199806949 - }, - "atlasBounds": { - "left": 0.5, - "bottom": 266.5, - "right": 33.5, - "top": 311.5 - } - } - ], - "kerning": [] -} +{ + "atlas": { + "type": "msdf", + "distanceRange": 2, + "size": 32.375, + "width": 312, + "height": 312, + "yOrigin": "bottom" + }, + "metrics": { + "emSize": 1, + "lineHeight": 1.171875, + "ascender": 0.927734375, + "descender": -0.244140625, + "underlineY": -0.09765625, + "underlineThickness": 0.048828125 + }, + "glyphs": [ + { + "unicode": 32, + "advance": 0.24755859375 + }, + { + "unicode": 33, + "advance": 0.25732421875, + "planeBounds": { + "left": 0.038927704210907341, + "bottom": -0.048761198419401491, + "right": 0.22425588953909267, + "top": 0.75432760466940163 + }, + "atlasBounds": { + "left": 133.5, + "bottom": 146.5, + "right": 139.5, + "top": 172.5 + } + }, + { + "unicode": 34, + "advance": 0.31982421875, + "planeBounds": { + "left": 0.027751907878861004, + "bottom": 0.47495437680984559, + "right": 0.305744185871139, + "top": 0.78383468569015446 + }, + "atlasBounds": { + "left": 298.5, + "bottom": 146.5, + "right": 307.5, + "top": 156.5 + } + }, + { + "unicode": 35, + "advance": 0.61572265625, + "planeBounds": { + "left": 0.021686097369691175, + "bottom": -0.046075651544401491, + "right": 0.63944671513030904, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 180.5, + "bottom": 146.5, + "right": 200.5, + "top": 172.5 + } + }, + { + "unicode": 36, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.018457596826737505, + "bottom": -0.14734782215250966, + "right": 0.54355412192326258, + "top": 0.87195719715250952 + }, + "atlasBounds": { + "left": 140.5, + "bottom": 278.5, + "right": 157.5, + "top": 311.5 + } + }, + { + "unicode": 37, + "advance": 0.732421875, + "planeBounds": { + "left": 0.014904832287644842, + "bottom": -0.046075651544401491, + "right": 0.72532954271235528, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 274.5, + "bottom": 146.5, + "right": 297.5, + "top": 172.5 + } + }, + { + "unicode": 38, + "advance": 0.62158203125, + "planeBounds": { + "left": 0.0096600506756757305, + "bottom": -0.046075651544401491, + "right": 0.65830869932432434, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 290.5, + "bottom": 174.5, + "right": 311.5, + "top": 200.5 + } + }, + { + "unicode": 39, + "advance": 0.17431640625, + "planeBounds": { + "left": 0.0096939852799227781, + "bottom": 0.47861648618484559, + "right": 0.1641341397200772, + "top": 0.78749679506515446 + }, + "atlasBounds": { + "left": 115.5, + "bottom": 5.5, + "right": 120.5, + "top": 15.5 + } + }, + { + "unicode": 40, + "advance": 0.341796875, + "planeBounds": { + "left": 0.023963486365830115, + "bottom": -0.26960760285955593, + "right": 0.36373182613416988, + "top": 0.84236150910955598 + }, + "atlasBounds": { + "left": 34.5, + "bottom": 275.5, + "right": 45.5, + "top": 311.5 + } + }, + { + "unicode": 41, + "advance": 0.34765625, + "planeBounds": { + "left": -0.022179091759169888, + "bottom": -0.26960760285955593, + "right": 0.31758924800916988, + "top": 0.84236150910955598 + }, + "atlasBounds": { + "left": 46.5, + "bottom": 275.5, + "right": 57.5, + "top": 311.5 + } + }, + { + "unicode": 42, + "advance": 0.4306640625, + "planeBounds": { + "left": -0.03201635647924711, + "bottom": 0.25704614352075295, + "right": 0.46219213772924705, + "top": 0.75125463772924705 + }, + "atlasBounds": { + "left": 295.5, + "bottom": 249.5, + "right": 311.5, + "top": 265.5 + } + }, + { + "unicode": 43, + "advance": 0.56689453125, + "planeBounds": { + "left": 0.0037460032577220637, + "bottom": 0.036641831563706623, + "right": 0.55973055924227799, + "top": 0.62351441843629352 + }, + "atlasBounds": { + "left": 171.5, + "bottom": 17.5, + "right": 189.5, + "top": 36.5 + } + }, + { + "unicode": 44, + "advance": 0.1962890625, + "planeBounds": { + "left": -0.025832717483108111, + "bottom": -0.18721815425916988, + "right": 0.19038349873310811, + "top": 0.15255018550916991 + }, + "atlasBounds": { + "left": 107.5, + "bottom": 4.5, + "right": 114.5, + "top": 15.5 + } + }, + { + "unicode": 45, + "advance": 0.27587890625, + "planeBounds": { + "left": -0.01723312319015444, + "bottom": 0.2247818759049228, + "right": 0.29164718569015446, + "top": 0.37922203034507723 + }, + "atlasBounds": { + "left": 82.5, + "bottom": 269.5, + "right": 92.5, + "top": 274.5 + } + }, + { + "unicode": 46, + "advance": 0.26318359375, + "planeBounds": { + "left": 0.033800751085907341, + "bottom": -0.044324248914092659, + "right": 0.21912893641409267, + "top": 0.14100393641409267 + }, + "atlasBounds": { + "left": 54.5, + "bottom": 268.5, + "right": 60.5, + "top": 274.5 + } + }, + { + "unicode": 47, + "advance": 0.412109375, + "planeBounds": { + "left": -0.035859450410231669, + "bottom": -0.092037245113416932, + "right": 0.42746101291023164, + "top": 0.74193958886341704 + }, + "atlasBounds": { + "left": 63.5, + "bottom": 173.5, + "right": 78.5, + "top": 200.5 + } + }, + { + "unicode": 48, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.017969315576737505, + "bottom": -0.046075651544401491, + "right": 0.54306584067326258, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 145.5, + "bottom": 118.5, + "right": 162.5, + "top": 144.5 + } + }, + { + "unicode": 49, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.049598251990830108, + "bottom": -0.044366667169401491, + "right": 0.38936659175916988, + "top": 0.75872213591940163 + }, + "atlasBounds": { + "left": 163.5, + "bottom": 118.5, + "right": 174.5, + "top": 144.5 + } + }, + { + "unicode": 50, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.0071639720077220637, + "bottom": -0.041192839044401491, + "right": 0.56314852799227799, + "top": 0.76189596404440163 + }, + "atlasBounds": { + "left": 175.5, + "bottom": 118.5, + "right": 193.5, + "top": 144.5 + } + }, + { + "unicode": 51, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.0086919718267375046, + "bottom": -0.046075651544401491, + "right": 0.53378849692326258, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 194.5, + "bottom": 118.5, + "right": 211.5, + "top": 144.5 + } + }, + { + "unicode": 52, + "advance": 0.5615234375, + "planeBounds": { + "left": -0.010965590311293381, + "bottom": -0.046075651544401491, + "right": 0.57590699656129352, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 248.5, + "bottom": 118.5, + "right": 267.5, + "top": 144.5 + } + }, + { + "unicode": 53, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.036035721826737505, + "bottom": -0.050958464044401491, + "right": 0.56113224692326258, + "top": 0.75213033904440163 + }, + "atlasBounds": { + "left": 268.5, + "bottom": 118.5, + "right": 285.5, + "top": 144.5 + } + }, + { + "unicode": 54, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.026514237451737505, + "bottom": -0.050714323419401491, + "right": 0.55161076254826258, + "top": 0.75237447966940163 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 91.5, + "right": 17.5, + "top": 117.5 + } + }, + { + "unicode": 55, + "advance": 0.5615234375, + "planeBounds": { + "left": -0.00016024674227793634, + "bottom": -0.046075651544401491, + "right": 0.55582430924227799, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 18.5, + "bottom": 91.5, + "right": 36.5, + "top": 117.5 + } + }, + { + "unicode": 56, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.018213456201737505, + "bottom": -0.046075651544401491, + "right": 0.54330998129826258, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 62.5, + "bottom": 91.5, + "right": 79.5, + "top": 117.5 + } + }, + { + "unicode": 57, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.0099126749517375046, + "bottom": -0.041436979669401491, + "right": 0.53500920004826258, + "top": 0.76165182341940163 + }, + "atlasBounds": { + "left": 80.5, + "bottom": 91.5, + "right": 97.5, + "top": 117.5 + } + }, + { + "unicode": 58, + "advance": 0.2421875, + "planeBounds": { + "left": 0.029162079210907337, + "bottom": -0.044964293255308832, + "right": 0.21449026453909267, + "top": 0.57279632450530904 + }, + "atlasBounds": { + "left": 18.5, + "bottom": 16.5, + "right": 24.5, + "top": 36.5 + } + }, + { + "unicode": 59, + "advance": 0.21142578125, + "planeBounds": { + "left": -0.014846389358108107, + "bottom": -0.17485558940637061, + "right": 0.20136982685810811, + "top": 0.5664571519063708 + }, + "atlasBounds": { + "left": 165.5, + "bottom": 39.5, + "right": 172.5, + "top": 63.5 + } + }, + { + "unicode": 60, + "advance": 0.50830078125, + "planeBounds": { + "left": 0.0032030495897683378, + "bottom": 0.053125565576737505, + "right": 0.46652351291023164, + "top": 0.57822209067326269 + }, + "atlasBounds": { + "left": 190.5, + "bottom": 19.5, + "right": 205.5, + "top": 36.5 + } + }, + { + "unicode": 61, + "advance": 0.548828125, + "planeBounds": { + "left": 0.030727784145752921, + "bottom": 0.15012103342181471, + "right": 0.52493627835424705, + "top": 0.5207774040781854 + }, + "atlasBounds": { + "left": 295.5, + "bottom": 236.5, + "right": 311.5, + "top": 248.5 + } + }, + { + "unicode": 62, + "advance": 0.5224609375, + "planeBounds": { + "left": 0.026821534145752921, + "bottom": 0.053613846826737505, + "right": 0.52103002835424705, + "top": 0.57871037192326269 + }, + "atlasBounds": { + "left": 224.5, + "bottom": 19.5, + "right": 240.5, + "top": 36.5 + } + }, + { + "unicode": 63, + "advance": 0.47216796875, + "planeBounds": { + "left": 0.0029589089647683378, + "bottom": -0.043878385919401491, + "right": 0.46627937228523164, + "top": 0.75921041716940163 + }, + "atlasBounds": { + "left": 115.5, + "bottom": 91.5, + "right": 130.5, + "top": 117.5 + } + }, + { + "unicode": 64, + "advance": 0.89794921875, + "planeBounds": { + "left": 0.020699599520762921, + "bottom": -0.25543896295849411, + "right": 0.88556446438562775, + "top": 0.73297802545849433 + }, + "atlasBounds": { + "left": 249.5, + "bottom": 279.5, + "right": 277.5, + "top": 311.5 + } + }, + { + "unicode": 65, + "advance": 0.65234375, + "planeBounds": { + "left": -0.028796339587355158, + "bottom": -0.046075651544401491, + "right": 0.68162837083735528, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 148.5, + "bottom": 91.5, + "right": 171.5, + "top": 117.5 + } + }, + { + "unicode": 66, + "advance": 0.62255859375, + "planeBounds": { + "left": 0.046470612632722064, + "bottom": -0.046075651544401491, + "right": 0.60245516861727799, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 188.5, + "bottom": 91.5, + "right": 206.5, + "top": 117.5 + } + }, + { + "unicode": 67, + "advance": 0.65087890625, + "planeBounds": { + "left": 0.022906800494691175, + "bottom": -0.046075651544401491, + "right": 0.64066741825530904, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 207.5, + "bottom": 91.5, + "right": 227.5, + "top": 117.5 + } + }, + { + "unicode": 68, + "advance": 0.65576171875, + "planeBounds": { + "left": 0.046163315938706623, + "bottom": -0.046075651544401491, + "right": 0.63303590281129352, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 228.5, + "bottom": 91.5, + "right": 247.5, + "top": 117.5 + } + }, + { + "unicode": 69, + "advance": 0.568359375, + "planeBounds": { + "left": 0.045801346826737505, + "bottom": -0.046075651544401491, + "right": 0.57089787192326258, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 248.5, + "bottom": 91.5, + "right": 265.5, + "top": 117.5 + } + }, + { + "unicode": 70, + "advance": 0.552734375, + "planeBounds": { + "left": 0.040186112451737505, + "bottom": -0.046075651544401491, + "right": 0.56528263754826258, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 266.5, + "bottom": 91.5, + "right": 283.5, + "top": 117.5 + } + }, + { + "unicode": 71, + "advance": 0.68115234375, + "planeBounds": { + "left": 0.024615784869691175, + "bottom": -0.046075651544401491, + "right": 0.64237640263030904, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 284.5, + "bottom": 91.5, + "right": 304.5, + "top": 117.5 + } + }, + { + "unicode": 72, + "advance": 0.712890625, + "planeBounds": { + "left": 0.046832581744691168, + "bottom": -0.046075651544401491, + "right": 0.66459319950530904, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 64.5, + "right": 20.5, + "top": 90.5 + } + }, + { + "unicode": 73, + "advance": 0.27197265625, + "planeBounds": { + "left": 0.043566376085907341, + "bottom": -0.046075651544401491, + "right": 0.22889456141409267, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 305.5, + "bottom": 91.5, + "right": 311.5, + "top": 117.5 + } + }, + { + "unicode": 74, + "advance": 0.5517578125, + "planeBounds": { + "left": -0.012304121923262495, + "bottom": -0.050958464044401491, + "right": 0.51279240317326258, + "top": 0.75213033904440163 + }, + "atlasBounds": { + "left": 38.5, + "bottom": 37.5, + "right": 55.5, + "top": 63.5 + } + }, + { + "unicode": 75, + "advance": 0.626953125, + "planeBounds": { + "left": 0.046100159869691175, + "bottom": -0.046075651544401491, + "right": 0.66386077763030904, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 17.5, + "bottom": 37.5, + "right": 37.5, + "top": 63.5 + } + }, + { + "unicode": 76, + "advance": 0.5380859375, + "planeBounds": { + "left": 0.050991456020752918, + "bottom": -0.046075651544401491, + "right": 0.54519995022924705, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 37.5, + "right": 16.5, + "top": 63.5 + } + }, + { + "unicode": 77, + "advance": 0.873046875, + "planeBounds": { + "left": 0.05017891077461395, + "bottom": -0.046075651544401491, + "right": 0.82237968297538611, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 286.5, + "bottom": 118.5, + "right": 311.5, + "top": 144.5 + } + }, + { + "unicode": 78, + "advance": 0.712890625, + "planeBounds": { + "left": 0.046832581744691168, + "bottom": -0.046075651544401491, + "right": 0.66459319950530904, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 262.5, + "bottom": 64.5, + "right": 282.5, + "top": 90.5 + } + }, + { + "unicode": 79, + "advance": 0.6875, + "planeBounds": { + "left": 0.019181535050675731, + "bottom": -0.046075651544401491, + "right": 0.66783018369932434, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 240.5, + "bottom": 64.5, + "right": 261.5, + "top": 90.5 + } + }, + { + "unicode": 80, + "advance": 0.630859375, + "planeBounds": { + "left": 0.044698472188706623, + "bottom": -0.046075651544401491, + "right": 0.63157105906129352, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 220.5, + "bottom": 64.5, + "right": 239.5, + "top": 90.5 + } + }, + { + "unicode": 81, + "advance": 0.6875, + "planeBounds": { + "left": 0.016251847550675731, + "bottom": -0.16302749457046325, + "right": 0.66490049619932434, + "top": 0.76361343207046339 + }, + "atlasBounds": { + "left": 143.5, + "bottom": 202.5, + "right": 164.5, + "top": 232.5 + } + }, + { + "unicode": 82, + "advance": 0.61572265625, + "planeBounds": { + "left": 0.046651597188706623, + "bottom": -0.046075651544401491, + "right": 0.63352418406129352, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 180.5, + "bottom": 64.5, + "right": 199.5, + "top": 90.5 + } + }, + { + "unicode": 83, + "advance": 0.59326171875, + "planeBounds": { + "left": 0.0039269878137066193, + "bottom": -0.046075651544401491, + "right": 0.59079957468629352, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 160.5, + "bottom": 64.5, + "right": 179.5, + "top": 90.5 + } + }, + { + "unicode": 84, + "advance": 0.5966796875, + "planeBounds": { + "left": -0.010052183880308825, + "bottom": -0.046075651544401491, + "right": 0.60770843388030904, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 139.5, + "bottom": 64.5, + "right": 159.5, + "top": 90.5 + } + }, + { + "unicode": 85, + "advance": 0.6484375, + "planeBounds": { + "left": 0.032247300313706623, + "bottom": -0.050958464044401491, + "right": 0.61911988718629352, + "top": 0.75213033904440163 + }, + "atlasBounds": { + "left": 119.5, + "bottom": 64.5, + "right": 138.5, + "top": 90.5 + } + }, + { + "unicode": 86, + "advance": 0.63623046875, + "planeBounds": { + "left": -0.02116482414333971, + "bottom": -0.046075651544401491, + "right": 0.65837185539333987, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 96.5, + "bottom": 64.5, + "right": 118.5, + "top": 90.5 + } + }, + { + "unicode": 87, + "advance": 0.88720703125, + "planeBounds": { + "left": -0.015566557070463265, + "bottom": -0.046075651544401491, + "right": 0.91107436957046339, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 65.5, + "bottom": 64.5, + "right": 95.5, + "top": 90.5 + } + }, + { + "unicode": 88, + "advance": 0.626953125, + "planeBounds": { + "left": -0.010115339949324269, + "bottom": -0.046075651544401491, + "right": 0.63853330869932434, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 43.5, + "bottom": 64.5, + "right": 64.5, + "top": 90.5 + } + }, + { + "unicode": 89, + "advance": 0.6005859375, + "planeBounds": { + "left": -0.025007918074324269, + "bottom": -0.046075651544401491, + "right": 0.62364073057432434, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 21.5, + "bottom": 64.5, + "right": 42.5, + "top": 90.5 + } + }, + { + "unicode": 90, + "advance": 0.5986328125, + "planeBounds": { + "left": 0.0073449565637066193, + "bottom": -0.046075651544401491, + "right": 0.59421754343629352, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 200.5, + "bottom": 64.5, + "right": 219.5, + "top": 90.5 + } + }, + { + "unicode": 91, + "advance": 0.26513671875, + "planeBounds": { + "left": 0.039777954572876445, + "bottom": -0.1950184000965251, + "right": 0.28688220167712358, + "top": 0.85517465009652516 + }, + "atlasBounds": { + "left": 58.5, + "bottom": 277.5, + "right": 66.5, + "top": 311.5 + } + }, + { + "unicode": 92, + "advance": 0.41015625, + "planeBounds": { + "left": -0.020722731660231666, + "bottom": -0.092037245113416932, + "right": 0.44259773166023164, + "top": 0.74193958886341704 + }, + "atlasBounds": { + "left": 134.5, + "bottom": 173.5, + "right": 149.5, + "top": 200.5 + } + }, + { + "unicode": 93, + "advance": 0.26513671875, + "planeBounds": { + "left": -0.026872436052123552, + "bottom": -0.1950184000965251, + "right": 0.22023181105212358, + "top": 0.85517465009652516 + }, + "atlasBounds": { + "left": 67.5, + "bottom": 277.5, + "right": 75.5, + "top": 311.5 + } + }, + { + "unicode": 94, + "advance": 0.41796875, + "planeBounds": { + "left": -0.0082084037162162178, + "bottom": 0.31723104940878383, + "right": 0.42422402871621623, + "top": 0.74966348184121623 + }, + "atlasBounds": { + "left": 81.5, + "bottom": 1.5, + "right": 95.5, + "top": 15.5 + } + }, + { + "unicode": 95, + "advance": 0.451171875, + "planeBounds": { + "left": -0.036962325048262551, + "bottom": -0.1140853115950772, + "right": 0.48813420004826258, + "top": 0.040354842845077232 + }, + "atlasBounds": { + "left": 93.5, + "bottom": 269.5, + "right": 110.5, + "top": 274.5 + } + }, + { + "unicode": 96, + "advance": 0.30908203125, + "planeBounds": { + "left": -0.0093574671211389959, + "bottom": 0.57011454814189189, + "right": 0.268634810871139, + "top": 0.78633076435810811 + }, + "atlasBounds": { + "left": 34.5, + "bottom": 267.5, + "right": 43.5, + "top": 274.5 + } + }, + { + "unicode": 97, + "advance": 0.5439453125, + "planeBounds": { + "left": 0.0086919718267374525, + "bottom": -0.044720152630308832, + "right": 0.53378849692326258, + "top": 0.57304046513030904 + }, + "atlasBounds": { + "left": 215.5, + "bottom": 43.5, + "right": 232.5, + "top": 63.5 + } + }, + { + "unicode": 98, + "advance": 0.56103515625, + "planeBounds": { + "left": 0.029443924951737505, + "bottom": -0.046871229488416932, + "right": 0.55454045004826258, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 188.5, + "bottom": 173.5, + "right": 205.5, + "top": 200.5 + } + }, + { + "unicode": 99, + "advance": 0.5234375, + "planeBounds": { + "left": 0.0050298624517375046, + "bottom": -0.044720152630308832, + "right": 0.53012638754826258, + "top": 0.57304046513030904 + }, + "atlasBounds": { + "left": 250.5, + "bottom": 43.5, + "right": 267.5, + "top": 63.5 + } + }, + { + "unicode": 100, + "advance": 0.56396484375, + "planeBounds": { + "left": 0.0067388468267375046, + "bottom": -0.046871229488416932, + "right": 0.53183537192326258, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 223.5, + "bottom": 173.5, + "right": 240.5, + "top": 200.5 + } + }, + { + "unicode": 101, + "advance": 0.52978515625, + "planeBounds": { + "left": 0.0069829874517375046, + "bottom": -0.044720152630308832, + "right": 0.53207951254826258, + "top": 0.57304046513030904 + }, + "atlasBounds": { + "left": 25.5, + "bottom": 16.5, + "right": 42.5, + "top": 36.5 + } + }, + { + "unicode": 102, + "advance": 0.34716796875, + "planeBounds": { + "left": -0.011807357022200773, + "bottom": -0.036861463863416932, + "right": 0.38973704452220076, + "top": 0.79711537011341704 + }, + "atlasBounds": { + "left": 241.5, + "bottom": 173.5, + "right": 254.5, + "top": 200.5 + } + }, + { + "unicode": 103, + "advance": 0.56103515625, + "planeBounds": { + "left": 0.0074712687017375046, + "bottom": -0.25194935448841688, + "right": 0.53256779379826258, + "top": 0.58202747948841704 + }, + "atlasBounds": { + "left": 255.5, + "bottom": 173.5, + "right": 272.5, + "top": 200.5 + } + }, + { + "unicode": 104, + "advance": 0.55078125, + "planeBounds": { + "left": 0.029018799770752921, + "bottom": -0.041988416988416932, + "right": 0.52322729397924705, + "top": 0.79198841698841704 + }, + "atlasBounds": { + "left": 273.5, + "bottom": 173.5, + "right": 289.5, + "top": 200.5 + } + }, + { + "unicode": 105, + "advance": 0.24267578125, + "planeBounds": { + "left": 0.029650360460907337, + "bottom": -0.041192839044401491, + "right": 0.21497854578909267, + "top": 0.76189596404440163 + }, + "atlasBounds": { + "left": 55.5, + "bottom": 91.5, + "right": 61.5, + "top": 117.5 + } + }, + { + "unicode": 106, + "advance": 0.23876953125, + "planeBounds": { + "left": -0.070636763996138996, + "bottom": -0.25599040027750963, + "right": 0.20735551399613902, + "top": 0.76331461902750952 + }, + "atlasBounds": { + "left": 194.5, + "bottom": 278.5, + "right": 203.5, + "top": 311.5 + } + }, + { + "unicode": 107, + "advance": 0.5068359375, + "planeBounds": { + "left": 0.024805253076737453, + "bottom": -0.041988416988416932, + "right": 0.54990177817326258, + "top": 0.79198841698841704 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 145.5, + "right": 17.5, + "top": 172.5 + } + }, + { + "unicode": 108, + "advance": 0.24267578125, + "planeBounds": { + "left": 0.044117813404922782, + "bottom": -0.041988416988416932, + "right": 0.1985579678450772, + "top": 0.79198841698841704 + }, + "atlasBounds": { + "left": 18.5, + "bottom": 145.5, + "right": 23.5, + "top": 172.5 + } + }, + { + "unicode": 109, + "advance": 0.87646484375, + "planeBounds": { + "left": 0.036688020330598509, + "bottom": -0.039837340130308832, + "right": 0.83977682341940163, + "top": 0.57792327763030904 + }, + "atlasBounds": { + "left": 113.5, + "bottom": 16.5, + "right": 139.5, + "top": 36.5 + } + }, + { + "unicode": 110, + "advance": 0.5517578125, + "planeBounds": { + "left": 0.029018799770752921, + "bottom": -0.039837340130308832, + "right": 0.52322729397924705, + "top": 0.57792327763030904 + }, + "atlasBounds": { + "left": 60.5, + "bottom": 16.5, + "right": 76.5, + "top": 36.5 + } + }, + { + "unicode": 111, + "advance": 0.5703125, + "planeBounds": { + "left": 0.0069198313827220637, + "bottom": -0.044720152630308832, + "right": 0.56290438736727799, + "top": 0.57304046513030904 + }, + "atlasBounds": { + "left": 77.5, + "bottom": 16.5, + "right": 95.5, + "top": 36.5 + } + }, + { + "unicode": 112, + "advance": 0.56103515625, + "planeBounds": { + "left": 0.028955643701737505, + "bottom": -0.23406393279440149, + "right": 0.55405216879826258, + "top": 0.56902487029440163 + }, + "atlasBounds": { + "left": 230.5, + "bottom": 118.5, + "right": 247.5, + "top": 144.5 + } + }, + { + "unicode": 113, + "advance": 0.568359375, + "planeBounds": { + "left": 0.0064947062017375046, + "bottom": -0.23406393279440149, + "right": 0.53159123129826258, + "top": 0.56902487029440163 + }, + "atlasBounds": { + "left": 212.5, + "bottom": 118.5, + "right": 229.5, + "top": 144.5 + } + }, + { + "unicode": 114, + "advance": 0.33837890625, + "planeBounds": { + "left": 0.026160751990830115, + "bottom": -0.039837340130308832, + "right": 0.36592909175916988, + "top": 0.57792327763030904 + }, + "atlasBounds": { + "left": 140.5, + "bottom": 16.5, + "right": 151.5, + "top": 36.5 + } + }, + { + "unicode": 115, + "advance": 0.515625, + "planeBounds": { + "left": 0.0092434091457528969, + "bottom": -0.044720152630308832, + "right": 0.50345190335424705, + "top": 0.57304046513030904 + }, + "atlasBounds": { + "left": 96.5, + "bottom": 16.5, + "right": 112.5, + "top": 36.5 + } + }, + { + "unicode": 116, + "advance": 0.32666015625, + "planeBounds": { + "left": -0.037134825953185333, + "bottom": -0.04741418315637061, + "right": 0.33352154470318535, + "top": 0.6938985581563708 + }, + "atlasBounds": { + "left": 152.5, + "bottom": 39.5, + "right": 164.5, + "top": 63.5 + } + }, + { + "unicode": 117, + "advance": 0.55126953125, + "planeBounds": { + "left": 0.027309815395752921, + "bottom": -0.049602965130308832, + "right": 0.52151830960424705, + "top": 0.56815765263030904 + }, + "atlasBounds": { + "left": 43.5, + "bottom": 16.5, + "right": 59.5, + "top": 36.5 + } + }, + { + "unicode": 118, + "advance": 0.484375, + "planeBounds": { + "left": -0.021581465673262547, + "bottom": -0.044720152630308832, + "right": 0.50351505942326258, + "top": 0.57304046513030904 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 16.5, + "right": 17.5, + "top": 36.5 + } + }, + { + "unicode": 119, + "advance": 0.75146484375, + "planeBounds": { + "left": -0.011588667350386047, + "bottom": -0.044720152630308832, + "right": 0.76061210485038611, + "top": 0.57304046513030904 + }, + "atlasBounds": { + "left": 286.5, + "bottom": 43.5, + "right": 311.5, + "top": 63.5 + } + }, + { + "unicode": 120, + "advance": 0.49560546875, + "planeBounds": { + "left": -0.015722090673262495, + "bottom": -0.044720152630308832, + "right": 0.50937443442326258, + "top": 0.57304046513030904 + }, + "atlasBounds": { + "left": 268.5, + "bottom": 43.5, + "right": 285.5, + "top": 63.5 + } + }, + { + "unicode": 121, + "advance": 0.47314453125, + "planeBounds": { + "left": -0.026708418798262547, + "bottom": -0.25951771386341688, + "right": 0.49838810629826258, + "top": 0.57445912011341704 + }, + "atlasBounds": { + "left": 43.5, + "bottom": 145.5, + "right": 60.5, + "top": 172.5 + } + }, + { + "unicode": 122, + "advance": 0.49560546875, + "planeBounds": { + "left": 0.0055812997707528969, + "bottom": -0.044720152630308832, + "right": 0.49978979397924711, + "top": 0.57304046513030904 + }, + "atlasBounds": { + "left": 233.5, + "bottom": 43.5, + "right": 249.5, + "top": 63.5 + } + }, + { + "unicode": 123, + "advance": 0.33837890625, + "planeBounds": { + "left": -0.0061289665781853291, + "bottom": -0.2245594157215251, + "right": 0.36452740407818535, + "top": 0.82563363447152516 + }, + "atlasBounds": { + "left": 94.5, + "bottom": 277.5, + "right": 106.5, + "top": 311.5 + } + }, + { + "unicode": 124, + "advance": 0.24365234375, + "planeBounds": { + "left": 0.044606094654922782, + "bottom": -0.17376968207046325, + "right": 0.1990462490950772, + "top": 0.75287124457046339 + }, + "atlasBounds": { + "left": 165.5, + "bottom": 202.5, + "right": 170.5, + "top": 232.5 + } + }, + { + "unicode": 125, + "advance": 0.33837890625, + "planeBounds": { + "left": -0.027857482203185329, + "bottom": -0.2245594157215251, + "right": 0.34279888845318535, + "top": 0.82563363447152516 + }, + "atlasBounds": { + "left": 107.5, + "bottom": 277.5, + "right": 119.5, + "top": 311.5 + } + }, + { + "unicode": 126, + "advance": 0.68017578125, + "planeBounds": { + "left": 0.031451722369691175, + "bottom": 0.154949173503861, + "right": 0.64921234013030904, + "top": 0.43294145149613905 + }, + "atlasBounds": { + "left": 121.5, + "bottom": 6.5, + "right": 141.5, + "top": 15.5 + } + }, + { + "unicode": 160, + "advance": 0.24755859375 + }, + { + "unicode": 161, + "advance": 0.24365234375, + "planeBounds": { + "left": 0.028673797960907337, + "bottom": -0.22063619841940149, + "right": 0.21400198328909267, + "top": 0.58245260466940163 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 118.5, + "right": 6.5, + "top": 144.5 + } + }, + { + "unicode": 162, + "advance": 0.546875, + "planeBounds": { + "left": 0.011377518701737505, + "bottom": -0.15502552636341693, + "right": 0.53647404379826258, + "top": 0.67895130761341704 + }, + "atlasBounds": { + "left": 79.5, + "bottom": 145.5, + "right": 96.5, + "top": 172.5 + } + }, + { + "unicode": 163, + "advance": 0.5810546875, + "planeBounds": { + "left": 0.0041711284387066193, + "bottom": -0.041192839044401491, + "right": 0.59104371531129352, + "top": 0.76189596404440163 + }, + "atlasBounds": { + "left": 254.5, + "bottom": 146.5, + "right": 273.5, + "top": 172.5 + } + }, + { + "unicode": 164, + "advance": 0.712890625, + "planeBounds": { + "left": 0.0051392072876448418, + "bottom": -0.052966261462355169, + "right": 0.71556391771235528, + "top": 0.65745844896235528 + }, + "atlasBounds": { + "left": 173.5, + "bottom": 40.5, + "right": 196.5, + "top": 63.5 + } + }, + { + "unicode": 165, + "advance": 0.52490234375, + "planeBounds": { + "left": -0.030985121561293381, + "bottom": -0.046075651544401491, + "right": 0.55588746531129352, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 201.5, + "bottom": 146.5, + "right": 220.5, + "top": 172.5 + } + }, + { + "unicode": 166, + "advance": 0.23974609375, + "planeBounds": { + "left": 0.039967422779922782, + "bottom": -0.17376968207046325, + "right": 0.1944075772200772, + "top": 0.75287124457046339 + }, + "atlasBounds": { + "left": 171.5, + "bottom": 202.5, + "right": 176.5, + "top": 232.5 + } + }, + { + "unicode": 167, + "advance": 0.61328125, + "planeBounds": { + "left": 0.0080773784387066193, + "bottom": -0.28559457197152505, + "right": 0.59494996531129352, + "top": 0.76459847822152516 + }, + "atlasBounds": { + "left": 120.5, + "bottom": 277.5, + "right": 139.5, + "top": 311.5 + } + }, + { + "unicode": 168, + "advance": 0.41796875, + "planeBounds": { + "left": 0.0069914711027992266, + "bottom": 0.5765253604609073, + "right": 0.40853587264720076, + "top": 0.7618535457890927 + }, + "atlasBounds": { + "left": 61.5, + "bottom": 268.5, + "right": 74.5, + "top": 274.5 + } + }, + { + "unicode": 169, + "advance": 0.78564453125, + "planeBounds": { + "left": 0.004768754524613953, + "bottom": -0.046319792169401491, + "right": 0.77696952672538611, + "top": 0.75676901091940163 + }, + "atlasBounds": { + "left": 140.5, + "bottom": 146.5, + "right": 165.5, + "top": 172.5 + } + }, + { + "unicode": 170, + "advance": 0.44677734375, + "planeBounds": { + "left": 0.026278580477799227, + "bottom": 0.29739250271476841, + "right": 0.42782298202220076, + "top": 0.76071296603523164 + }, + "atlasBounds": { + "left": 298.5, + "bottom": 157.5, + "right": 311.5, + "top": 172.5 + } + }, + { + "unicode": 171, + "advance": 0.46923828125, + "planeBounds": { + "left": 0.0051561745897683378, + "bottom": 0.036406174589768338, + "right": 0.46847663791023164, + "top": 0.49972663791023164 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 0.5, + "right": 15.5, + "top": 15.5 + } + }, + { + "unicode": 172, + "advance": 0.5537109375, + "planeBounds": { + "left": 0.017788331020752897, + "bottom": 0.147869095378861, + "right": 0.51199682522924705, + "top": 0.42586137337113905 + }, + "atlasBounds": { + "left": 150.5, + "bottom": 6.5, + "right": 166.5, + "top": 15.5 + } + }, + { + "unicode": 173, + "advance": 0.27587890625, + "planeBounds": { + "left": -0.01723312319015444, + "bottom": 0.2247818759049228, + "right": 0.29164718569015446, + "top": 0.37922203034507723 + }, + "atlasBounds": { + "left": 111.5, + "bottom": 269.5, + "right": 121.5, + "top": 274.5 + } + }, + { + "unicode": 174, + "advance": 0.7861328125, + "planeBounds": { + "left": 0.004280473274613953, + "bottom": -0.046319792169401491, + "right": 0.77648124547538611, + "top": 0.75676901091940163 + }, + "atlasBounds": { + "left": 56.5, + "bottom": 37.5, + "right": 81.5, + "top": 63.5 + } + }, + { + "unicode": 175, + "advance": 0.4580078125, + "planeBounds": { + "left": 0.032626236727799227, + "bottom": 0.59343421965492271, + "right": 0.43417063827220076, + "top": 0.74787437409507718 + }, + "atlasBounds": { + "left": 122.5, + "bottom": 269.5, + "right": 135.5, + "top": 274.5 + } + }, + { + "unicode": 176, + "advance": 0.37353515625, + "planeBounds": { + "left": 0.032571564309845563, + "bottom": 0.42484239261583018, + "right": 0.34145187319015446, + "top": 0.76461073238416999 + }, + "atlasBounds": { + "left": 96.5, + "bottom": 4.5, + "right": 106.5, + "top": 15.5 + } + }, + { + "unicode": 177, + "advance": 0.5341796875, + "planeBounds": { + "left": 0.0084478312017375046, + "bottom": -0.045886183337355155, + "right": 0.53354435629826258, + "top": 0.66453852708735528 + }, + "atlasBounds": { + "left": 197.5, + "bottom": 40.5, + "right": 214.5, + "top": 63.5 + } + }, + { + "unicode": 178, + "advance": 0.36669921875, + "planeBounds": { + "left": -0.0024668572031853291, + "bottom": 0.28933586208976841, + "right": 0.36818951345318535, + "top": 0.75265632541023164 + }, + "atlasBounds": { + "left": 32.5, + "bottom": 0.5, + "right": 44.5, + "top": 15.5 + } + }, + { + "unicode": 179, + "advance": 0.36669921875, + "planeBounds": { + "left": -0.0075938103281853291, + "bottom": 0.28665031521476841, + "right": 0.36306256032818535, + "top": 0.74997077853523164 + }, + "atlasBounds": { + "left": 45.5, + "bottom": 0.5, + "right": 57.5, + "top": 15.5 + } + }, + { + "unicode": 180, + "advance": 0.3134765625, + "planeBounds": { + "left": 0.022869095378861004, + "bottom": 0.57011454814189189, + "right": 0.300861373371139, + "top": 0.78633076435810811 + }, + "atlasBounds": { + "left": 44.5, + "bottom": 267.5, + "right": 53.5, + "top": 274.5 + } + }, + { + "unicode": 181, + "advance": 0.56640625, + "planeBounds": { + "left": 0.036098877895752918, + "bottom": -0.23894674529440149, + "right": 0.53030737210424705, + "top": 0.56414205779440163 + }, + "atlasBounds": { + "left": 131.5, + "bottom": 91.5, + "right": 147.5, + "top": 117.5 + } + }, + { + "unicode": 182, + "advance": 0.48876953125, + "planeBounds": { + "left": -0.012177809785231662, + "bottom": -0.046075651544401491, + "right": 0.45114265353523164, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 172.5, + "bottom": 91.5, + "right": 187.5, + "top": 117.5 + } + }, + { + "unicode": 183, + "advance": 0.2607421875, + "planeBounds": { + "left": 0.035265594835907341, + "bottom": 0.26378121983590735, + "right": 0.22059378016409267, + "top": 0.4491094051640927 + }, + "atlasBounds": { + "left": 75.5, + "bottom": 268.5, + "right": 81.5, + "top": 274.5 + } + }, + { + "unicode": 184, + "advance": 0.24755859375, + "planeBounds": { + "left": 0.024216110641891893, + "bottom": -0.24519731087113897, + "right": 0.24043232685810811, + "top": 0.032794967121139051 + }, + "atlasBounds": { + "left": 142.5, + "bottom": 6.5, + "right": 149.5, + "top": 15.5 + } + }, + { + "unicode": 185, + "advance": 0.36669921875, + "planeBounds": { + "left": 0.027082642072876448, + "bottom": 0.28665031521476841, + "right": 0.27418688917712358, + "top": 0.74997077853523164 + }, + "atlasBounds": { + "left": 72.5, + "bottom": 0.5, + "right": 80.5, + "top": 15.5 + } + }, + { + "unicode": 186, + "advance": 0.45458984375, + "planeBounds": { + "left": 0.026034439852799227, + "bottom": 0.29714836208976841, + "right": 0.42757884139720076, + "top": 0.76046882541023164 + }, + "atlasBounds": { + "left": 58.5, + "bottom": 0.5, + "right": 71.5, + "top": 15.5 + } + }, + { + "unicode": 187, + "advance": 0.46875, + "planeBounds": { + "left": 0.010038987089768338, + "bottom": 0.037138596464768338, + "right": 0.47335945041023164, + "top": 0.50045905978523164 + }, + "atlasBounds": { + "left": 16.5, + "bottom": 0.5, + "right": 31.5, + "top": 15.5 + } + }, + { + "unicode": 188, + "advance": 0.732421875, + "planeBounds": { + "left": -0.0020040269063706026, + "bottom": -0.03136405797538605, + "right": 0.7393087144063708, + "top": 0.74083671422538611 + }, + "atlasBounds": { + "left": 82.5, + "bottom": 38.5, + "right": 106.5, + "top": 63.5 + } + }, + { + "unicode": 189, + "advance": 0.77587890625, + "planeBounds": { + "left": -0.004996870475386047, + "bottom": -0.03136405797538605, + "right": 0.76720390172538611, + "top": 0.74083671422538611 + }, + "atlasBounds": { + "left": 107.5, + "bottom": 38.5, + "right": 132.5, + "top": 63.5 + } + }, + { + "unicode": 190, + "advance": 0.77783203125, + "planeBounds": { + "left": 0.011360551399613953, + "bottom": -0.043390104669401491, + "right": 0.78356132360038611, + "top": 0.75969869841940163 + }, + "atlasBounds": { + "left": 119.5, + "bottom": 118.5, + "right": 144.5, + "top": 144.5 + } + }, + { + "unicode": 191, + "advance": 0.47314453125, + "planeBounds": { + "left": 0.0017382058397683378, + "bottom": -0.22673971404440149, + "right": 0.46505866916023164, + "top": 0.57634908904440163 + }, + "atlasBounds": { + "left": 103.5, + "bottom": 118.5, + "right": 118.5, + "top": 144.5 + } + }, + { + "unicode": 192, + "advance": 0.65234375, + "planeBounds": { + "left": -0.028796339587355158, + "bottom": -0.043524900458494151, + "right": 0.68162837083735528, + "top": 0.94489208795849422 + }, + "atlasBounds": { + "left": 278.5, + "bottom": 279.5, + "right": 301.5, + "top": 311.5 + } + }, + { + "unicode": 193, + "advance": 0.65234375, + "planeBounds": { + "left": -0.028796339587355158, + "bottom": -0.043524900458494151, + "right": 0.68162837083735528, + "top": 0.94489208795849422 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 233.5, + "right": 23.5, + "top": 265.5 + } + }, + { + "unicode": 194, + "advance": 0.65234375, + "planeBounds": { + "left": -0.028796339587355158, + "bottom": -0.043524900458494151, + "right": 0.68162837083735528, + "top": 0.94489208795849422 + }, + "atlasBounds": { + "left": 24.5, + "bottom": 233.5, + "right": 47.5, + "top": 265.5 + } + }, + { + "unicode": 195, + "advance": 0.65234375, + "planeBounds": { + "left": -0.028796339587355158, + "bottom": -0.03296369751447871, + "right": 0.68162837083735528, + "top": 0.92456526001447892 + }, + "atlasBounds": { + "left": 22.5, + "bottom": 201.5, + "right": 45.5, + "top": 232.5 + } + }, + { + "unicode": 196, + "advance": 0.65234375, + "planeBounds": { + "left": -0.028796339587355158, + "bottom": -0.04248518188947871, + "right": 0.68162837083735528, + "top": 0.91504377563947892 + }, + "atlasBounds": { + "left": 66.5, + "bottom": 201.5, + "right": 89.5, + "top": 232.5 + } + }, + { + "unicode": 197, + "advance": 0.65234375, + "planeBounds": { + "left": -0.028796339587355158, + "bottom": -0.036752119027509661, + "right": 0.68162837083735528, + "top": 0.98255290027750952 + }, + "atlasBounds": { + "left": 204.5, + "bottom": 278.5, + "right": 227.5, + "top": 311.5 + } + }, + { + "unicode": 198, + "advance": 0.9345703125, + "planeBounds": { + "left": -0.038886228583494151, + "bottom": -0.046075651544401491, + "right": 0.94953075983349422, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 221.5, + "bottom": 146.5, + "right": 253.5, + "top": 172.5 + } + }, + { + "unicode": 199, + "advance": 0.65087890625, + "planeBounds": { + "left": 0.022906800494691175, + "bottom": -0.25769938465250963, + "right": 0.64066741825530904, + "top": 0.76160563465250952 + }, + "atlasBounds": { + "left": 228.5, + "bottom": 278.5, + "right": 248.5, + "top": 311.5 + } + }, + { + "unicode": 200, + "advance": 0.568359375, + "planeBounds": { + "left": 0.045801346826737505, + "bottom": -0.040595212958494151, + "right": 0.57089787192326258, + "top": 0.94782177545849422 + }, + "atlasBounds": { + "left": 48.5, + "bottom": 233.5, + "right": 65.5, + "top": 265.5 + } + }, + { + "unicode": 201, + "advance": 0.568359375, + "planeBounds": { + "left": 0.045801346826737505, + "bottom": -0.040595212958494151, + "right": 0.57089787192326258, + "top": 0.94782177545849422 + }, + "atlasBounds": { + "left": 66.5, + "bottom": 233.5, + "right": 83.5, + "top": 265.5 + } + }, + { + "unicode": 202, + "advance": 0.568359375, + "planeBounds": { + "left": 0.045801346826737505, + "bottom": -0.040595212958494151, + "right": 0.57089787192326258, + "top": 0.94782177545849422 + }, + "atlasBounds": { + "left": 84.5, + "bottom": 233.5, + "right": 101.5, + "top": 265.5 + } + }, + { + "unicode": 203, + "advance": 0.568359375, + "planeBounds": { + "left": 0.045801346826737505, + "bottom": -0.03955549438947871, + "right": 0.57089787192326258, + "top": 0.91797346313947892 + }, + "atlasBounds": { + "left": 111.5, + "bottom": 201.5, + "right": 128.5, + "top": 232.5 + } + }, + { + "unicode": 204, + "advance": 0.27197265625, + "planeBounds": { + "left": -0.052814498371138996, + "bottom": -0.040595212958494151, + "right": 0.22517777962113902, + "top": 0.94782177545849422 + }, + "atlasBounds": { + "left": 302.5, + "bottom": 279.5, + "right": 311.5, + "top": 311.5 + } + }, + { + "unicode": 205, + "advance": 0.27197265625, + "planeBounds": { + "left": 0.048748001628861004, + "bottom": -0.040595212958494151, + "right": 0.32674027962113905, + "top": 0.94782177545849422 + }, + "atlasBounds": { + "left": 102.5, + "bottom": 233.5, + "right": 111.5, + "top": 265.5 + } + }, + { + "unicode": 206, + "advance": 0.27197265625, + "planeBounds": { + "left": -0.048853575953185333, + "bottom": -0.040595212958494151, + "right": 0.32180279470318535, + "top": 0.94782177545849422 + }, + "atlasBounds": { + "left": 112.5, + "bottom": 233.5, + "right": 124.5, + "top": 265.5 + } + }, + { + "unicode": 207, + "advance": 0.27197265625, + "planeBounds": { + "left": -0.063321028897200773, + "bottom": -0.03955549438947871, + "right": 0.33822337264720076, + "top": 0.91797346313947892 + }, + "atlasBounds": { + "left": 129.5, + "bottom": 201.5, + "right": 142.5, + "top": 232.5 + } + }, + { + "unicode": 208, + "advance": 0.67041015625, + "planeBounds": { + "left": -0.032395292893339714, + "bottom": -0.046075651544401491, + "right": 0.64714138664333987, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 7.5, + "bottom": 118.5, + "right": 29.5, + "top": 144.5 + } + }, + { + "unicode": 209, + "advance": 0.712890625, + "planeBounds": { + "left": 0.046832581744691168, + "bottom": -0.03296369751447871, + "right": 0.66459319950530904, + "top": 0.92456526001447892 + }, + "atlasBounds": { + "left": 90.5, + "bottom": 201.5, + "right": 110.5, + "top": 232.5 + } + }, + { + "unicode": 210, + "advance": 0.6875, + "planeBounds": { + "left": 0.019181535050675731, + "bottom": -0.047919431708494165, + "right": 0.66783018369932434, + "top": 0.94049755670849422 + }, + "atlasBounds": { + "left": 125.5, + "bottom": 233.5, + "right": 146.5, + "top": 265.5 + } + }, + { + "unicode": 211, + "advance": 0.6875, + "planeBounds": { + "left": 0.019181535050675731, + "bottom": -0.047919431708494165, + "right": 0.66783018369932434, + "top": 0.94049755670849422 + }, + "atlasBounds": { + "left": 147.5, + "bottom": 233.5, + "right": 168.5, + "top": 265.5 + } + }, + { + "unicode": 212, + "advance": 0.6875, + "planeBounds": { + "left": 0.019181535050675731, + "bottom": -0.047919431708494165, + "right": 0.66783018369932434, + "top": 0.94049755670849422 + }, + "atlasBounds": { + "left": 191.5, + "bottom": 233.5, + "right": 212.5, + "top": 265.5 + } + }, + { + "unicode": 213, + "advance": 0.6875, + "planeBounds": { + "left": 0.019181535050675731, + "bottom": -0.052802244208494165, + "right": 0.66783018369932434, + "top": 0.93561474420849422 + }, + "atlasBounds": { + "left": 273.5, + "bottom": 233.5, + "right": 294.5, + "top": 265.5 + } + }, + { + "unicode": 214, + "advance": 0.6875, + "planeBounds": { + "left": 0.019181535050675731, + "bottom": -0.04687971313947871, + "right": 0.66783018369932434, + "top": 0.91064924438947892 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 201.5, + "right": 21.5, + "top": 232.5 + } + }, + { + "unicode": 215, + "advance": 0.533203125, + "planeBounds": { + "left": 0.00063533120173750457, + "bottom": 0.061914628076737505, + "right": 0.52573185629826258, + "top": 0.58701115317326269 + }, + "atlasBounds": { + "left": 206.5, + "bottom": 19.5, + "right": 223.5, + "top": 36.5 + } + }, + { + "unicode": 216, + "advance": 0.6875, + "planeBounds": { + "left": 0.024064347550675731, + "bottom": -0.085020323057432373, + "right": 0.67271299619932434, + "top": 0.77984454180743246 + }, + "atlasBounds": { + "left": 195.5, + "bottom": 204.5, + "right": 216.5, + "top": 232.5 + } + }, + { + "unicode": 217, + "advance": 0.6484375, + "planeBounds": { + "left": 0.032247300313706623, + "bottom": -0.048407712958494165, + "right": 0.61911988718629352, + "top": 0.94000927545849422 + }, + "atlasBounds": { + "left": 253.5, + "bottom": 233.5, + "right": 272.5, + "top": 265.5 + } + }, + { + "unicode": 218, + "advance": 0.6484375, + "planeBounds": { + "left": 0.032247300313706623, + "bottom": -0.048407712958494165, + "right": 0.61911988718629352, + "top": 0.94000927545849422 + }, + "atlasBounds": { + "left": 233.5, + "bottom": 233.5, + "right": 252.5, + "top": 265.5 + } + }, + { + "unicode": 219, + "advance": 0.6484375, + "planeBounds": { + "left": 0.032247300313706623, + "bottom": -0.048407712958494165, + "right": 0.61911988718629352, + "top": 0.94000927545849422 + }, + "atlasBounds": { + "left": 213.5, + "bottom": 233.5, + "right": 232.5, + "top": 265.5 + } + }, + { + "unicode": 220, + "advance": 0.6484375, + "planeBounds": { + "left": 0.032247300313706623, + "bottom": -0.04736799438947871, + "right": 0.61911988718629352, + "top": 0.91016096313947892 + }, + "atlasBounds": { + "left": 46.5, + "bottom": 201.5, + "right": 65.5, + "top": 232.5 + } + }, + { + "unicode": 221, + "advance": 0.6005859375, + "planeBounds": { + "left": -0.025007918074324269, + "bottom": -0.043524900458494151, + "right": 0.62364073057432434, + "top": 0.94489208795849422 + }, + "atlasBounds": { + "left": 169.5, + "bottom": 233.5, + "right": 190.5, + "top": 265.5 + } + }, + { + "unicode": 222, + "advance": 0.5908203125, + "planeBounds": { + "left": 0.035240143882722064, + "bottom": -0.046075651544401491, + "right": 0.59122469986727799, + "top": 0.75701315154440163 + }, + "atlasBounds": { + "left": 84.5, + "bottom": 118.5, + "right": 102.5, + "top": 144.5 + } + }, + { + "unicode": 223, + "advance": 0.5947265625, + "planeBounds": { + "left": 0.031822175132722064, + "bottom": -0.042476698238416932, + "right": 0.58780673111727799, + "top": 0.79150013573841704 + }, + "atlasBounds": { + "left": 97.5, + "bottom": 145.5, + "right": 115.5, + "top": 172.5 + } + }, + { + "unicode": 224, + "advance": 0.5439453125, + "planeBounds": { + "left": 0.0086919718267374525, + "bottom": -0.046871229488416932, + "right": 0.53378849692326258, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 97.5, + "bottom": 173.5, + "right": 114.5, + "top": 200.5 + } + }, + { + "unicode": 225, + "advance": 0.5439453125, + "planeBounds": { + "left": 0.0086919718267374525, + "bottom": -0.046871229488416932, + "right": 0.53378849692326258, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 27.5, + "bottom": 173.5, + "right": 44.5, + "top": 200.5 + } + }, + { + "unicode": 226, + "advance": 0.5439453125, + "planeBounds": { + "left": 0.0086919718267374525, + "bottom": -0.046871229488416932, + "right": 0.53378849692326258, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 294.5, + "bottom": 205.5, + "right": 311.5, + "top": 232.5 + } + }, + { + "unicode": 227, + "advance": 0.5439453125, + "planeBounds": { + "left": 0.0086919718267374525, + "bottom": -0.051754041988416932, + "right": 0.53378849692326258, + "top": 0.78222279198841704 + }, + "atlasBounds": { + "left": 61.5, + "bottom": 145.5, + "right": 78.5, + "top": 172.5 + } + }, + { + "unicode": 228, + "advance": 0.5439453125, + "planeBounds": { + "left": 0.0086919718267374525, + "bottom": -0.045831510919401491, + "right": 0.53378849692326258, + "top": 0.75725729216940163 + }, + "atlasBounds": { + "left": 47.5, + "bottom": 118.5, + "right": 64.5, + "top": 144.5 + } + }, + { + "unicode": 229, + "advance": 0.5439453125, + "planeBounds": { + "left": 0.0086919718267374525, + "bottom": -0.055542463501447828, + "right": 0.53378849692326258, + "top": 0.84021043225144798 + }, + "atlasBounds": { + "left": 177.5, + "bottom": 203.5, + "right": 194.5, + "top": 232.5 + } + }, + { + "unicode": 230, + "advance": 0.84423828125, + "planeBounds": { + "left": -0.0081160261824323766, + "bottom": -0.044720152630308832, + "right": 0.85674883868243246, + "top": 0.57304046513030904 + }, + "atlasBounds": { + "left": 283.5, + "bottom": 70.5, + "right": 311.5, + "top": 90.5 + } + }, + { + "unicode": 231, + "advance": 0.5234375, + "planeBounds": { + "left": 0.0050298624517375046, + "bottom": -0.25634388573841688, + "right": 0.53012638754826258, + "top": 0.57763294823841704 + }, + "atlasBounds": { + "left": 45.5, + "bottom": 173.5, + "right": 62.5, + "top": 200.5 + } + }, + { + "unicode": 232, + "advance": 0.52978515625, + "planeBounds": { + "left": 0.0069829874517375046, + "bottom": -0.046871229488416932, + "right": 0.53207951254826258, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 79.5, + "bottom": 173.5, + "right": 96.5, + "top": 200.5 + } + }, + { + "unicode": 233, + "advance": 0.52978515625, + "planeBounds": { + "left": 0.0069829874517375046, + "bottom": -0.046871229488416932, + "right": 0.53207951254826258, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 248.5, + "bottom": 205.5, + "right": 265.5, + "top": 232.5 + } + }, + { + "unicode": 234, + "advance": 0.52978515625, + "planeBounds": { + "left": 0.0069829874517375046, + "bottom": -0.046871229488416932, + "right": 0.53207951254826258, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 276.5, + "bottom": 205.5, + "right": 293.5, + "top": 232.5 + } + }, + { + "unicode": 235, + "advance": 0.52978515625, + "planeBounds": { + "left": 0.0069829874517375046, + "bottom": -0.045831510919401491, + "right": 0.53207951254826258, + "top": 0.75725729216940163 + }, + "atlasBounds": { + "left": 37.5, + "bottom": 91.5, + "right": 54.5, + "top": 117.5 + } + }, + { + "unicode": 236, + "advance": 0.2470703125, + "planeBounds": { + "left": -0.065509810871138996, + "bottom": -0.042232557613416932, + "right": 0.21248246712113902, + "top": 0.79174427636341704 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 173.5, + "right": 9.5, + "top": 200.5 + } + }, + { + "unicode": 237, + "advance": 0.2470703125, + "planeBounds": { + "left": 0.036052689128861004, + "bottom": -0.042232557613416932, + "right": 0.314044967121139, + "top": 0.79174427636341704 + }, + "atlasBounds": { + "left": 266.5, + "bottom": 205.5, + "right": 275.5, + "top": 232.5 + } + }, + { + "unicode": 238, + "advance": 0.2470703125, + "planeBounds": { + "left": -0.061548888453185333, + "bottom": -0.042232557613416932, + "right": 0.30910748220318535, + "top": 0.79174427636341704 + }, + "atlasBounds": { + "left": 235.5, + "bottom": 205.5, + "right": 247.5, + "top": 232.5 + } + }, + { + "unicode": 239, + "advance": 0.2470703125, + "planeBounds": { + "left": -0.076016341397200773, + "bottom": -0.041192839044401491, + "right": 0.32552806014720076, + "top": 0.76189596404440163 + }, + "atlasBounds": { + "left": 166.5, + "bottom": 146.5, + "right": 179.5, + "top": 172.5 + } + }, + { + "unicode": 240, + "advance": 0.5859375, + "planeBounds": { + "left": 0.029199784326737505, + "bottom": -0.051573057432432373, + "right": 0.55429630942326258, + "top": 0.81329180743243246 + }, + "atlasBounds": { + "left": 217.5, + "bottom": 204.5, + "right": 234.5, + "top": 232.5 + } + }, + { + "unicode": 241, + "advance": 0.5517578125, + "planeBounds": { + "left": 0.029018799770752921, + "bottom": -0.031427214044401491, + "right": 0.52322729397924705, + "top": 0.77166158904440163 + }, + "atlasBounds": { + "left": 30.5, + "bottom": 118.5, + "right": 46.5, + "top": 144.5 + } + }, + { + "unicode": 242, + "advance": 0.5703125, + "planeBounds": { + "left": 0.0069198313827220637, + "bottom": -0.046871229488416932, + "right": 0.56290438736727799, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 169.5, + "bottom": 173.5, + "right": 187.5, + "top": 200.5 + } + }, + { + "unicode": 243, + "advance": 0.5703125, + "planeBounds": { + "left": 0.0069198313827220637, + "bottom": -0.046871229488416932, + "right": 0.56290438736727799, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 150.5, + "bottom": 173.5, + "right": 168.5, + "top": 200.5 + } + }, + { + "unicode": 244, + "advance": 0.5703125, + "planeBounds": { + "left": 0.0069198313827220637, + "bottom": -0.046871229488416932, + "right": 0.56290438736727799, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 115.5, + "bottom": 173.5, + "right": 133.5, + "top": 200.5 + } + }, + { + "unicode": 245, + "advance": 0.5703125, + "planeBounds": { + "left": 0.0069198313827220637, + "bottom": -0.051754041988416932, + "right": 0.56290438736727799, + "top": 0.78222279198841704 + }, + "atlasBounds": { + "left": 24.5, + "bottom": 145.5, + "right": 42.5, + "top": 172.5 + } + }, + { + "unicode": 246, + "advance": 0.5703125, + "planeBounds": { + "left": 0.0069198313827220637, + "bottom": -0.045831510919401491, + "right": 0.56290438736727799, + "top": 0.75725729216940163 + }, + "atlasBounds": { + "left": 65.5, + "bottom": 118.5, + "right": 83.5, + "top": 144.5 + } + }, + { + "unicode": 247, + "advance": 0.57080078125, + "planeBounds": { + "left": 0.00032803450772206366, + "bottom": 0.043966050313706623, + "right": 0.55631259049227799, + "top": 0.63083863718629352 + }, + "atlasBounds": { + "left": 152.5, + "bottom": 17.5, + "right": 170.5, + "top": 36.5 + } + }, + { + "unicode": 248, + "advance": 0.56640625, + "planeBounds": { + "left": 0.0069198313827220637, + "bottom": -0.1084493394063706, + "right": 0.56290438736727799, + "top": 0.6328634019063708 + }, + "atlasBounds": { + "left": 133.5, + "bottom": 39.5, + "right": 151.5, + "top": 63.5 + } + }, + { + "unicode": 249, + "advance": 0.55126953125, + "planeBounds": { + "left": 0.027309815395752921, + "bottom": -0.046871229488416932, + "right": 0.52151830960424705, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 206.5, + "bottom": 173.5, + "right": 222.5, + "top": 200.5 + } + }, + { + "unicode": 250, + "advance": 0.55126953125, + "planeBounds": { + "left": 0.027309815395752921, + "bottom": -0.046871229488416932, + "right": 0.52151830960424705, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 116.5, + "bottom": 145.5, + "right": 132.5, + "top": 172.5 + } + }, + { + "unicode": 251, + "advance": 0.55126953125, + "planeBounds": { + "left": 0.027309815395752921, + "bottom": -0.046871229488416932, + "right": 0.52151830960424705, + "top": 0.78710560448841704 + }, + "atlasBounds": { + "left": 10.5, + "bottom": 173.5, + "right": 26.5, + "top": 200.5 + } + }, + { + "unicode": 252, + "advance": 0.55126953125, + "planeBounds": { + "left": 0.027309815395752921, + "bottom": -0.045831510919401491, + "right": 0.52151830960424705, + "top": 0.75725729216940163 + }, + "atlasBounds": { + "left": 98.5, + "bottom": 91.5, + "right": 114.5, + "top": 117.5 + } + }, + { + "unicode": 253, + "advance": 0.47314453125, + "planeBounds": { + "left": -0.026708418798262547, + "bottom": -0.25678597822152505, + "right": 0.49838810629826258, + "top": 0.79340707197152516 + }, + "atlasBounds": { + "left": 76.5, + "bottom": 277.5, + "right": 93.5, + "top": 311.5 + } + }, + { + "unicode": 254, + "advance": 0.576171875, + "planeBounds": { + "left": 0.033350174951737505, + "bottom": -0.23621500965250966, + "right": 0.55844670004826258, + "top": 0.78309000965250952 + }, + "atlasBounds": { + "left": 176.5, + "bottom": 278.5, + "right": 193.5, + "top": 311.5 + } + }, + { + "unicode": 255, + "advance": 0.47314453125, + "planeBounds": { + "left": -0.026708418798262547, + "bottom": -0.25574625965250963, + "right": 0.49838810629826258, + "top": 0.76355875965250952 + }, + "atlasBounds": { + "left": 158.5, + "bottom": 278.5, + "right": 175.5, + "top": 311.5 + } + }, + { + "unicode": 65533, + "advance": 1.02587890625, + "planeBounds": { + "left": 0.002798662222490346, + "bottom": -0.30240256998069504, + "right": 1.0221036815275095, + "top": 1.0875588199806949 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 266.5, + "right": 33.5, + "top": 311.5 + } + } + ], + "kerning": [] +} diff --git a/assets/roboto.kttf b/assets/roboto.kttf new file mode 100644 index 00000000..35fffb8b --- /dev/null +++ b/assets/roboto.kttf @@ -0,0 +1,7 @@ +{ + "file": "roboto.ttf", + "char_range_start": "0x20", + "char_range_end": "0x7f", + "offset_x": 0.0, + "offset_y": 25.0, +} \ No newline at end of file diff --git a/assets/roboto.kttf-cached.png b/assets/roboto.kttf-cached.png new file mode 100644 index 00000000..ddba48f2 Binary files /dev/null and b/assets/roboto.kttf-cached.png differ diff --git a/book/.gitignore b/book/.gitignore index 7585238e..52a6b805 100644 --- a/book/.gitignore +++ b/book/.gitignore @@ -1 +1 @@ -book +book diff --git a/book/book.toml b/book/book.toml index e646d36a..df574ebc 100644 --- a/book/book.toml +++ b/book/book.toml @@ -1,6 +1,6 @@ -[book] -authors = ["StarToaster"] -language = "en" -multilingual = false -src = "src" -title = "Kayak UI" +[book] +authors = ["StarToaster"] +language = "en" +multilingual = false +src = "src" +title = "Kayak UI" diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 04025871..69cc1597 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -1,12 +1,12 @@ -# Kayak UI - -- [Introduction](./introduction.md) -- [Chapter 1 - Installing and hello world!](./chapter_1.md) -- [Chapter 2 - Understanding flow](./chapter_2.md) -- [Chapter 3 - Creating custom widgets!](./chapter_3.md) -- [Chapter 4 - State](./chapter_4.md) -- [Chapter 5 - Context](./chapter_5.md) -- [Chapter 6 - Fonts](./chapter_6.md) -- [Chapter 7 - Widget Update Systems(Diffing)](./chapter_7.md) -- [Chapter 8 - Prebuilt Widgets](./chapter_8.md) +# Kayak UI + +- [Introduction](./introduction.md) +- [Chapter 1 - Installing and hello world!](./chapter_1.md) +- [Chapter 2 - Understanding flow](./chapter_2.md) +- [Chapter 3 - Creating custom widgets!](./chapter_3.md) +- [Chapter 4 - State](./chapter_4.md) +- [Chapter 5 - Context](./chapter_5.md) +- [Chapter 6 - Fonts](./chapter_6.md) +- [Chapter 7 - Widget Update Systems(Diffing)](./chapter_7.md) +- [Chapter 8 - Prebuilt Widgets](./chapter_8.md) - [Chapter 9 - Practical Usage](./chapter_9.md) \ No newline at end of file diff --git a/book/src/chapter_1.md b/book/src/chapter_1.md index ab3ea638..9f833c42 100644 --- a/book/src/chapter_1.md +++ b/book/src/chapter_1.md @@ -1,121 +1,121 @@ -# Chapter 1 - Installing and hello world! -Kayak UI is quite easy to setup! First make sure you add it to your cargo.toml file in your project. - -```toml -kayak_ui = "0.4" -``` - -Once you've added Kayak UI to your bevy project you can now start to use it! In order for you to copy and run this in your own project don't forget to move the `roboto.kayak_font` and the `roboto.png` files to your asset folder. Optionally you can also generate your own font! See: [Chapter 5 - Fonts](./chapter_6.md) - -Hello World Example: -```rust -use bevy::prelude::*; -use kayak_ui::{ - prelude::{widgets::*, *}, - CameraUIKayak, -}; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn(Camera2dBundle::default()) - .insert(CameraUIKayak) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kttf")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - rsx! { - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugin(KayakContextPlugin) - .add_plugin(KayakWidgets) - .add_startup_system(startup) - .run() -} - -``` - -## Wait where is the ECS? -Kayak UI encourages the use of our proc macro called `rsx!`. This proc macro simulates XML like syntax and turns it into bevy commands. This proc macro is completely optional though! - -Here is the same hello world example but this time we'll use bevy's ECS directly. - -```rust -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, *}; -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn(Camera2dBundle::default()) - .insert(CameraUIKayak) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kttf")); - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - - let app_entity = widget_context.spawn_widget(&mut commands, None, None); - // Create default app bundle - let mut app_bundle = KayakAppBundle { - ..Default::default() - }; - - // Create app's children - let mut children = KChildren::new(); - - // Create the text child - let text_entity = widget_context.spawn_widget(&mut commands, None, None); - commands.entity(text_entity).insert(TextWidgetBundle { - text: TextProps { - content: "Hello World".into(), - ..Default::default() - }, - ..Default::default() - }); - // Add the text as a child of the App Widget. - children.add(text_entity); - - // Finalize app bundle and add to entity. - app_bundle.children = children; - commands.entity(app_entity).insert(app_bundle); - - // Add app widget to context. - widget_context.add_widget(None, app_entity); - - // Add widget context as resource. - - commands.spawn((widget_context, EventDispatcher::default())); -} -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugin(KayakContextPlugin) - .add_plugin(KayakWidgets) - .add_startup_system(startup) - .run() -} -``` +# Chapter 1 - Installing and hello world! +Kayak UI is quite easy to setup! First make sure you add it to your cargo.toml file in your project. + +```toml +kayak_ui = "0.4" +``` + +Once you've added Kayak UI to your bevy project you can now start to use it! In order for you to copy and run this in your own project don't forget to move the `roboto.kayak_font` and the `roboto.png` files to your asset folder. Optionally you can also generate your own font! See: [Chapter 5 - Fonts](./chapter_6.md) + +Hello World Example: +```rust +use bevy::prelude::*; +use kayak_ui::{ + prelude::{widgets::*, *}, + CameraUIKayak, +}; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn(Camera2dBundle::default()) + .insert(CameraUIKayak) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kttf")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + rsx! { + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_plugin(KayakContextPlugin) + .add_plugin(KayakWidgets) + .add_startup_system(startup) + .run() +} + +``` + +## Wait where is the ECS? +Kayak UI encourages the use of our proc macro called `rsx!`. This proc macro simulates XML like syntax and turns it into bevy commands. This proc macro is completely optional though! + +Here is the same hello world example but this time we'll use bevy's ECS directly. + +```rust +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, *}; +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn(Camera2dBundle::default()) + .insert(CameraUIKayak) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kttf")); + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + + let app_entity = widget_context.spawn_widget(&mut commands, None, None); + // Create default app bundle + let mut app_bundle = KayakAppBundle { + ..Default::default() + }; + + // Create app's children + let mut children = KChildren::new(); + + // Create the text child + let text_entity = widget_context.spawn_widget(&mut commands, None, None); + commands.entity(text_entity).insert(TextWidgetBundle { + text: TextProps { + content: "Hello World".into(), + ..Default::default() + }, + ..Default::default() + }); + // Add the text as a child of the App Widget. + children.add(text_entity); + + // Finalize app bundle and add to entity. + app_bundle.children = children; + commands.entity(app_entity).insert(app_bundle); + + // Add app widget to context. + widget_context.add_widget(None, app_entity); + + // Add widget context as resource. + + commands.spawn((widget_context, EventDispatcher::default())); +} +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_plugin(KayakContextPlugin) + .add_plugin(KayakWidgets) + .add_startup_system(startup) + .run() +} +``` diff --git a/book/src/chapter_2.md b/book/src/chapter_2.md index 24d26d3f..be2cb9da 100644 --- a/book/src/chapter_2.md +++ b/book/src/chapter_2.md @@ -1,108 +1,108 @@ -# Chapter 2 - Understanding flow -In Kayak widget structure and flow are important concepts. In this section we'll be discussion high level concepts on how Kayak UI works. - -Kayak UI builds out UI using a tree structure. A widget can be defined as any object that lives in the UI tree. Typically a widget will have some sort of visual appearance, however that doesn't necessarily have to be the case. You might have widgets that manage state or just wrap other widgets. - -## Core Concepts - -### Widgets are entities -Kayak UI uses Bevy ECS. Each widget is considered an entity with a collection of data. Typically an widget and it's entity can contain whatever data desired, but some common components are: -- Mount - A component tag used to know that a widget was spawned and added to the tree. -- KStyle - Used to pass in styles from outside of a widget. -- ComputedStyles - The actual styles of a widget. Styles define the look and layout of the widget. Kayak uses this component to dictate UI rendering. -- KChildren - A collection of entities that are added to the tree in a deferred way. These entities are coming from higher up the hierarchy. -- OnEvent - A mini/micro bevy system that lets you respond to UI input events. -- OnChange - A mini/micro system which allows changes to state based on value changes to state. -- OnLayout - A mini/micro system which allows reaction to layout change events. I.E. the width, height, or position has changed. -- Focusable - Lets the event dispatcher know that this widget can be focused. -- WidgetName - All widgets require this component for internal purposes. This is essentially used to determine the "type" of a widget. - -### Widgets and bundles? -It's advised to have bundles that correspond to a group of components on a widget. Example: -```rust -#[derive(Bundle)] -pub struct BackgroundBundle { - pub background: Background, - pub styles: KStyle, - pub computed_styles: ComputedStyles, - pub children: KChildren, - pub on_event: OnEvent, - pub widget_name: WidgetName, -} -``` -Bundles are also required when using the RSX syntax: -```rust -rsx! { - -} -``` -In the example above the RSX macro automatically adds missing fields in the bundle using rust default and the spread operator: `..Default::default()`. Because of this requirement users who want to use RSX need to also implement default on their bundles. - -### Spawning Widgets -Widgets can be spawned using bevy's default spawning method. Example: -```rust -commands.spawn(MyWidgetBundle { .. }); -``` - -However, it is advised that you use the `WidgetContext`'s `spawn_widget` function. This function caches entities at a specific spot in the tree. Take this tree for example: -``` -widget1 - entity 2 - - widget2 entity 3 - - widget3 entity 4 -``` -When widget 1 renders, its children will have random entity id's if you use bevy's default spawning commands, but by using `spawn_widget` you can guarantee somewhat consistent entities. There are a couple of a caveats to this though. If a widget is despawned due to being removed from the tree, its entity id is no longer guaranteed. This means that entities that are removed from the tree will lose access to their context and state. It's important to remember that! - -### Relationships - -Widgets, by the nature of them being stored as a tree, contain certain relationships. The most common one is the *parent-child* relationship. A widget may contain zero or more children. - -

- Diagram showing the parent-child relationship -

- -When a parent re-renders, it also causes its children to be re-rendered as well (more on this later). - -Another implicit relationship is that of siblings. These aren't currently very useful in Kayak UI currently, but know that any time two widgets share a parent, they are considered siblings. - -### Props - -What good is a widget if it can't hold or process data? This is where the concept of *props* comes in (short for " -properties"). Props allow data to flow from parent to child. - -

- Diagram showing the flow of props -

- -For example, a widget might have access to a game's player info. It could then take the current value of the player's -health points and pass that to a widget that is specifically configured to display health points. Which brings up -another important topic when talking about widgets: modularity. - -### Modularity - -Widgets are meant to be modular. It's rarely a good idea to have a widget with hundreds and hundreds of lines of code. -Kayak UI instead suggests breaking parts of your UI down into individual components. This could be as simple as breaking up logical parts of a single UI into multiple files in order to make things easier to read/maintain. - -This modularity allows for widgets to be abstracted to cover more generic use-cases. Rather than having two different -widgets for a player's health points and a teammates, you could just create one reusable `Health` widget. Want to keep -the same functionality but modify the style for enemies? Wrap the `Health` widget in another widget that configures it -enough to fit your needs. - -### State - -To make widgets even more modular, provide greater functionality, and be reactive, widgets may contain their own state. While props can be used to pass data to widgets, state allows data to be retained. This is important because non-state data, such as props, are lost between renders. Without state, what goes in is all the widget has at its disposal. - -This book has a [section](./chapter_4.md) dedicated to widget state so check that out for more on state! - -### Lifecycle -The last core concept is that of *widget lifecycle*. Widgets have a lifecycle as entities which looks something like this: - -1. Mount - This occurs when a widget is added to the tree for the first time. A component is added called `Mount` and is removed after the first render. -2. Update or Diff - During each update loop the widgets are diffed with previous values from the last update to see if they have changed. If a widget has changed it is re-rendered. -3. Render - Render occurs when a widget has changed and allows users to change behavior according to entity changes. -4. Layout - Occurs after the entire tree has been updated. Widget entities marked as "dirty" will have their rendering and layout recalculated. -5. Removal/Despawning - Entities that are removed from the tree are despawned additionally any children they had are also despawned and removed from the tree. It's important to avoid removing a widget from the tree if you need to preserve that widgets state. +# Chapter 2 - Understanding flow +In Kayak widget structure and flow are important concepts. In this section we'll be discussion high level concepts on how Kayak UI works. + +Kayak UI builds out UI using a tree structure. A widget can be defined as any object that lives in the UI tree. Typically a widget will have some sort of visual appearance, however that doesn't necessarily have to be the case. You might have widgets that manage state or just wrap other widgets. + +## Core Concepts + +### Widgets are entities +Kayak UI uses Bevy ECS. Each widget is considered an entity with a collection of data. Typically an widget and it's entity can contain whatever data desired, but some common components are: +- Mount - A component tag used to know that a widget was spawned and added to the tree. +- KStyle - Used to pass in styles from outside of a widget. +- ComputedStyles - The actual styles of a widget. Styles define the look and layout of the widget. Kayak uses this component to dictate UI rendering. +- KChildren - A collection of entities that are added to the tree in a deferred way. These entities are coming from higher up the hierarchy. +- OnEvent - A mini/micro bevy system that lets you respond to UI input events. +- OnChange - A mini/micro system which allows changes to state based on value changes to state. +- OnLayout - A mini/micro system which allows reaction to layout change events. I.E. the width, height, or position has changed. +- Focusable - Lets the event dispatcher know that this widget can be focused. +- WidgetName - All widgets require this component for internal purposes. This is essentially used to determine the "type" of a widget. + +### Widgets and bundles? +It's advised to have bundles that correspond to a group of components on a widget. Example: +```rust +#[derive(Bundle)] +pub struct BackgroundBundle { + pub background: Background, + pub styles: KStyle, + pub computed_styles: ComputedStyles, + pub children: KChildren, + pub on_event: OnEvent, + pub widget_name: WidgetName, +} +``` +Bundles are also required when using the RSX syntax: +```rust +rsx! { + +} +``` +In the example above the RSX macro automatically adds missing fields in the bundle using rust default and the spread operator: `..Default::default()`. Because of this requirement users who want to use RSX need to also implement default on their bundles. + +### Spawning Widgets +Widgets can be spawned using bevy's default spawning method. Example: +```rust +commands.spawn(MyWidgetBundle { .. }); +``` + +However, it is advised that you use the `WidgetContext`'s `spawn_widget` function. This function caches entities at a specific spot in the tree. Take this tree for example: +``` +widget1 - entity 2 + - widget2 entity 3 + - widget3 entity 4 +``` +When widget 1 renders, its children will have random entity id's if you use bevy's default spawning commands, but by using `spawn_widget` you can guarantee somewhat consistent entities. There are a couple of a caveats to this though. If a widget is despawned due to being removed from the tree, its entity id is no longer guaranteed. This means that entities that are removed from the tree will lose access to their context and state. It's important to remember that! + +### Relationships + +Widgets, by the nature of them being stored as a tree, contain certain relationships. The most common one is the *parent-child* relationship. A widget may contain zero or more children. + +

+ Diagram showing the parent-child relationship +

+ +When a parent re-renders, it also causes its children to be re-rendered as well (more on this later). + +Another implicit relationship is that of siblings. These aren't currently very useful in Kayak UI currently, but know that any time two widgets share a parent, they are considered siblings. + +### Props + +What good is a widget if it can't hold or process data? This is where the concept of *props* comes in (short for " +properties"). Props allow data to flow from parent to child. + +

+ Diagram showing the flow of props +

+ +For example, a widget might have access to a game's player info. It could then take the current value of the player's +health points and pass that to a widget that is specifically configured to display health points. Which brings up +another important topic when talking about widgets: modularity. + +### Modularity + +Widgets are meant to be modular. It's rarely a good idea to have a widget with hundreds and hundreds of lines of code. +Kayak UI instead suggests breaking parts of your UI down into individual components. This could be as simple as breaking up logical parts of a single UI into multiple files in order to make things easier to read/maintain. + +This modularity allows for widgets to be abstracted to cover more generic use-cases. Rather than having two different +widgets for a player's health points and a teammates, you could just create one reusable `Health` widget. Want to keep +the same functionality but modify the style for enemies? Wrap the `Health` widget in another widget that configures it +enough to fit your needs. + +### State + +To make widgets even more modular, provide greater functionality, and be reactive, widgets may contain their own state. While props can be used to pass data to widgets, state allows data to be retained. This is important because non-state data, such as props, are lost between renders. Without state, what goes in is all the widget has at its disposal. + +This book has a [section](./chapter_4.md) dedicated to widget state so check that out for more on state! + +### Lifecycle +The last core concept is that of *widget lifecycle*. Widgets have a lifecycle as entities which looks something like this: + +1. Mount - This occurs when a widget is added to the tree for the first time. A component is added called `Mount` and is removed after the first render. +2. Update or Diff - During each update loop the widgets are diffed with previous values from the last update to see if they have changed. If a widget has changed it is re-rendered. +3. Render - Render occurs when a widget has changed and allows users to change behavior according to entity changes. +4. Layout - Occurs after the entire tree has been updated. Widget entities marked as "dirty" will have their rendering and layout recalculated. +5. Removal/Despawning - Entities that are removed from the tree are despawned additionally any children they had are also despawned and removed from the tree. It's important to avoid removing a widget from the tree if you need to preserve that widgets state. diff --git a/book/src/chapter_3.md b/book/src/chapter_3.md index 3b1ba156..0e14cc71 100644 --- a/book/src/chapter_3.md +++ b/book/src/chapter_3.md @@ -1,134 +1,134 @@ -# Chapter 3 - Creating custom widgets! -Kayak UI allows users to create custom widgets. - -Widgets are structured in a few different ways: -1. Widgets at a bare minimum must include a Props component, Widget Bundle, and the update and render systems. -2. Widgets can include custom components and data but the default `widget_update` system only supports diffing of props and state. -3. Widgets have some base components which are auto checked these are: KStyles and KChildren. - -I think it's best if we showcase a simple example: -```rust -// At a bare minimum the widget props component must include these derives. -// This is because we need to diff the previous values of these. -// Default is used to make creating widgets a little easier. -// And component is required since this is a bevy component! -#[derive(Component, Clone, PartialEq, Default)] -pub struct MyButtonProps { - -} - -// In the future this will tell Kayak that these Props belongs to a widget. -// For now it's use to get the `WidgetName` component. -impl Widget for MyButtonProps { } - -// Now we need a widget bundle this can represent a collection of components our widget might have -// Note: You can include custom data here. Just don't expect it to get diffed during update! -#[derive(Bundle)] -pub struct MyButtonBundle { - pub props: MyButtonProps, - pub styles: KStyle, - pub computed_styles: ComputedStyles, - pub children: KChildren, - // This allows us to hook into on click events! - pub on_event: OnEvent, - // Widget name is required by Kayak UI! - pub widget_name: WidgetName, -} - -impl Default for MyButtonBundle { - fn default() -> Self { - Self { - props: MyButtonProps::default(), - styles: KStyle::default(), - computed_styles: ComputedStyles::default(), - children: KChildren::default(), - on_event: OnEvent::default(), - // Kayak uses this component to find out more information about your widget. - // This is done because bevy does not have the ability to query traits. - widget_name: MyButtonProps::default().get_name(), - } - } -} - -// Now we need to create our systems. -// Since our button doesn't have any custom data we can diff using the default widget_update system. -// We do need to create a render system! - -pub fn my_button_render( - // This is a bevy feature which allows custom parameters to be passed into a system. - // In this case Kayak UI gives the system an `Entity`. - In(entity): In, - // This struct allows us to make changes to the widget tree. - mut widget_context: ResMut, - // The rest of the parameters are just like those found in a bevy system! - // In fact you can add whatever you would like here including more queries or lookups - // to resources within bevy's ECS. - mut commands: Commands, - // In this case we really only care about our buttons children! Let's query for them. - mut query: Query<&KChildren>, -) -> bool { - // Grab our children for our button widget: - if let Ok(children) = query.get(entity) { - - let background_styles = KStyle { - // Lets use red for our button background! - background_color: StyleProp::Value(Color::RED), - // 50 pixel border radius. - border_radius: Corner::all(50.0).into(), - ..Default::default() - }; - - let parent_id = Some(entity); - - rsx! { - - }; - } - - // The boolean returned here tells kayak UI to update the tree. You can avoid tree updates by - // returning false, but in practice this should be done rarely. As kayak diff's the tree and - // will avoid tree updates if nothing has changed! - true -} - -// Finally we need to let the core widget context know about our new widget! -fn startup(...) { - - // Default kayak startup stuff. - ... - - // We need to register the prop and state types. - // State is empty so you can use the `EmptyState` component! - widget_context.add_widget_data::(); - - // Next we need to add the systems - widget_context.add_widget_system( - // We are registering these systems with a specific WidgetName. - MyButtonProps::default().get_name(), - // widget_update auto diffs props and state. - // Optionally if you have context you can use: widget_update_with_context - // otherwise you will need to create your own widget update system! - widget_update::, - // Add our render system! - my_button_render, - ); - - // We can now create our widget like: - rsx! { - - - - - - } -} -``` +# Chapter 3 - Creating custom widgets! +Kayak UI allows users to create custom widgets. + +Widgets are structured in a few different ways: +1. Widgets at a bare minimum must include a Props component, Widget Bundle, and the update and render systems. +2. Widgets can include custom components and data but the default `widget_update` system only supports diffing of props and state. +3. Widgets have some base components which are auto checked these are: KStyles and KChildren. + +I think it's best if we showcase a simple example: +```rust +// At a bare minimum the widget props component must include these derives. +// This is because we need to diff the previous values of these. +// Default is used to make creating widgets a little easier. +// And component is required since this is a bevy component! +#[derive(Component, Clone, PartialEq, Default)] +pub struct MyButtonProps { + +} + +// In the future this will tell Kayak that these Props belongs to a widget. +// For now it's use to get the `WidgetName` component. +impl Widget for MyButtonProps { } + +// Now we need a widget bundle this can represent a collection of components our widget might have +// Note: You can include custom data here. Just don't expect it to get diffed during update! +#[derive(Bundle)] +pub struct MyButtonBundle { + pub props: MyButtonProps, + pub styles: KStyle, + pub computed_styles: ComputedStyles, + pub children: KChildren, + // This allows us to hook into on click events! + pub on_event: OnEvent, + // Widget name is required by Kayak UI! + pub widget_name: WidgetName, +} + +impl Default for MyButtonBundle { + fn default() -> Self { + Self { + props: MyButtonProps::default(), + styles: KStyle::default(), + computed_styles: ComputedStyles::default(), + children: KChildren::default(), + on_event: OnEvent::default(), + // Kayak uses this component to find out more information about your widget. + // This is done because bevy does not have the ability to query traits. + widget_name: MyButtonProps::default().get_name(), + } + } +} + +// Now we need to create our systems. +// Since our button doesn't have any custom data we can diff using the default widget_update system. +// We do need to create a render system! + +pub fn my_button_render( + // This is a bevy feature which allows custom parameters to be passed into a system. + // In this case Kayak UI gives the system an `Entity`. + In(entity): In, + // This struct allows us to make changes to the widget tree. + mut widget_context: ResMut, + // The rest of the parameters are just like those found in a bevy system! + // In fact you can add whatever you would like here including more queries or lookups + // to resources within bevy's ECS. + mut commands: Commands, + // In this case we really only care about our buttons children! Let's query for them. + mut query: Query<&KChildren>, +) -> bool { + // Grab our children for our button widget: + if let Ok(children) = query.get(entity) { + + let background_styles = KStyle { + // Lets use red for our button background! + background_color: StyleProp::Value(Color::RED), + // 50 pixel border radius. + border_radius: Corner::all(50.0).into(), + ..Default::default() + }; + + let parent_id = Some(entity); + + rsx! { + + }; + } + + // The boolean returned here tells kayak UI to update the tree. You can avoid tree updates by + // returning false, but in practice this should be done rarely. As kayak diff's the tree and + // will avoid tree updates if nothing has changed! + true +} + +// Finally we need to let the core widget context know about our new widget! +fn startup(...) { + + // Default kayak startup stuff. + ... + + // We need to register the prop and state types. + // State is empty so you can use the `EmptyState` component! + widget_context.add_widget_data::(); + + // Next we need to add the systems + widget_context.add_widget_system( + // We are registering these systems with a specific WidgetName. + MyButtonProps::default().get_name(), + // widget_update auto diffs props and state. + // Optionally if you have context you can use: widget_update_with_context + // otherwise you will need to create your own widget update system! + widget_update::, + // Add our render system! + my_button_render, + ); + + // We can now create our widget like: + rsx! { + + + + + + } +} +``` diff --git a/book/src/chapter_4.md b/book/src/chapter_4.md index ca37a215..b06801a9 100644 --- a/book/src/chapter_4.md +++ b/book/src/chapter_4.md @@ -1,40 +1,40 @@ -# Chapter 4 - State -State is data that is directly associated with a particular widget. State persists during re-renders, but will be destroyed when an widget is despawned. - -State can be created in Kayak easily, here is an example: -```rust -#[derive(Component, Default, PartialEq, Clone)] -struct CurrentCountState { - foo: u32, -} - -// During a widget's render function -let state_entity = widget_context.use_state( - // Bevy commands - &mut commands, - // The widget entity. - entity, - // The default starting values for the state. - CurrentCountState::default() -); - -// State can be queried like any entity. -// This can be done via bevy query iteration or via lookup using the state_entity -if let Ok(state) = state_query.get(state_entity) { - dbg!(state.foo); -} - -fn my_bevy_system(state_query: Query<&CurrentCountState>) { - for state in state_query.iter() { - dbg!(state.foo); - } -} -``` - -When an entity is despawned the state associated with that entity is also despawned. - -## Update/Diffing system -By default Kayak provides a system for diffing widgets. This system is called: `widget_update` and can be attached to any widget via the root kayak context. - -`widget_update` takes two generic parameters called: `Props` and `State`. Both of these types expect to derive: `Component`, `PartialEq`, and `Clone`. Currently only one state type can be defined which can be an issue as widgets might have more than one piece of state. For now it's advised to group state by component type, however if a user desires they can implement a custom widget update system which manually checks more pieces of state. This is however considered to be more advanced usage and may not be as well documented. - +# Chapter 4 - State +State is data that is directly associated with a particular widget. State persists during re-renders, but will be destroyed when an widget is despawned. + +State can be created in Kayak easily, here is an example: +```rust +#[derive(Component, Default, PartialEq, Clone)] +struct CurrentCountState { + foo: u32, +} + +// During a widget's render function +let state_entity = widget_context.use_state( + // Bevy commands + &mut commands, + // The widget entity. + entity, + // The default starting values for the state. + CurrentCountState::default() +); + +// State can be queried like any entity. +// This can be done via bevy query iteration or via lookup using the state_entity +if let Ok(state) = state_query.get(state_entity) { + dbg!(state.foo); +} + +fn my_bevy_system(state_query: Query<&CurrentCountState>) { + for state in state_query.iter() { + dbg!(state.foo); + } +} +``` + +When an entity is despawned the state associated with that entity is also despawned. + +## Update/Diffing system +By default Kayak provides a system for diffing widgets. This system is called: `widget_update` and can be attached to any widget via the root kayak context. + +`widget_update` takes two generic parameters called: `Props` and `State`. Both of these types expect to derive: `Component`, `PartialEq`, and `Clone`. Currently only one state type can be defined which can be an issue as widgets might have more than one piece of state. For now it's advised to group state by component type, however if a user desires they can implement a custom widget update system which manually checks more pieces of state. This is however considered to be more advanced usage and may not be as well documented. + diff --git a/book/src/chapter_5.md b/book/src/chapter_5.md index 5245a295..2fdf365b 100644 --- a/book/src/chapter_5.md +++ b/book/src/chapter_5.md @@ -1,48 +1,48 @@ -# Chapter 5 - Context -Context in Kayak UI allows users to pass data through the widget tree without having to pass data between each widget at every level in the tree. - -Typically in Kayak the data is passed top-down or parent to child via "props", but this can be cumbersome when dealing with complex widget trees. Context provides a way to share values from a parent widget down to children without the need to explicitly pass that data through every level of the tree. - -## When to use context? -Context can be great for sharing "global" data. This might be something as simple as a user or potentially even more complex data. In the [tabs example](../../examples/tabs/tabs.rs) we can see how context is used to pass shared tab state to the buttons and the button content. - - -## How to use context? -Context starts by creating a context entity that is associated with a piece of data and it's parent widget. This looks like: -```rust -// Check if the context entity already exists -if widget_context - .get_context_entity::(entity) - .is_none() -{ - // Spawn the context entity with initial state - let context_entity = commands - .spawn(MyContext { - foo: 0, - }) - .id(); - - // Let the widget context know about our custom context data. - widget_context.set_context_entity::(Some(entity), context_entity); -} -``` - -Once the context has been created users can query the context in widget render systems like so: -```rust -fn my_child_widget_render( - ... - context_query: Query<&MyContext>, -) { - // get_context_entity will jump up the tree until it finds a matching data type and entity. - if let Some(context_entity) = widget_context.get_context_entity::(entity) { - let context_data = context_query.get(context_entity); - dbg!(context_data.foo); - } -} -``` - -## Handling diff and widget updating -When a widget is associated with context it's important that the widget update system is aware of this. By default the `widget_update` diff system is used. This accepts types for props and state but not for context. A separate system called `widget_update_with_context` can be used which takes an optional third type for context. - -### Important! -`widget_update_with_context` is only designed to work with one type of context. If you need multiple context diffing for a single widget it's advised that you use a custom widget update system. +# Chapter 5 - Context +Context in Kayak UI allows users to pass data through the widget tree without having to pass data between each widget at every level in the tree. + +Typically in Kayak the data is passed top-down or parent to child via "props", but this can be cumbersome when dealing with complex widget trees. Context provides a way to share values from a parent widget down to children without the need to explicitly pass that data through every level of the tree. + +## When to use context? +Context can be great for sharing "global" data. This might be something as simple as a user or potentially even more complex data. In the [tabs example](../../examples/tabs/tabs.rs) we can see how context is used to pass shared tab state to the buttons and the button content. + + +## How to use context? +Context starts by creating a context entity that is associated with a piece of data and it's parent widget. This looks like: +```rust +// Check if the context entity already exists +if widget_context + .get_context_entity::(entity) + .is_none() +{ + // Spawn the context entity with initial state + let context_entity = commands + .spawn(MyContext { + foo: 0, + }) + .id(); + + // Let the widget context know about our custom context data. + widget_context.set_context_entity::(Some(entity), context_entity); +} +``` + +Once the context has been created users can query the context in widget render systems like so: +```rust +fn my_child_widget_render( + ... + context_query: Query<&MyContext>, +) { + // get_context_entity will jump up the tree until it finds a matching data type and entity. + if let Some(context_entity) = widget_context.get_context_entity::(entity) { + let context_data = context_query.get(context_entity); + dbg!(context_data.foo); + } +} +``` + +## Handling diff and widget updating +When a widget is associated with context it's important that the widget update system is aware of this. By default the `widget_update` diff system is used. This accepts types for props and state but not for context. A separate system called `widget_update_with_context` can be used which takes an optional third type for context. + +### Important! +`widget_update_with_context` is only designed to work with one type of context. If you need multiple context diffing for a single widget it's advised that you use a custom widget update system. diff --git a/book/src/chapter_6.md b/book/src/chapter_6.md index fbff8342..98514c51 100644 --- a/book/src/chapter_6.md +++ b/book/src/chapter_6.md @@ -1,28 +1,28 @@ -# Chapter 6 - Fonts -Kayak UI uses SDF(signed distance fields) for rendering fonts. More specifically it uses multi-channel signed distance fields. Reasons for why we use MSDF: -- High Quality font rendering. -- Fast rendering! -- No need for a new asset for each font size. MSDF's can size to any font size! - -Fonts are stored in two different ways. First a font can be defined as a Kayak TTF(kttf) file. -These font files are relatively simple and simply link to a ttf font: -```json -{ - "file": "roboto.ttf", - "char_range_start": "0x20", - "char_range_end": "0x7f" -} -``` -The char range is a defined as u32 char values. 0x20 through 0x7f represents most of the standard English language characters. Font's using this method are processed in native rust into MSDF's. The output is cached as the generation can take a while. - -Fonts are also stored as an atlased image and a json file which tells Kayak about the font glyphs. These fonts are generated using `msdf-atlas-gen`. Check out `roboto.kayak_font` and `roboto.png` in the `assets` folder. The cached file name will be located next to the kttf file and have the file format of: `{font_name}.kttf-cached.png`. - -### Generating Legacy `*.kayak_font`. WARNING! Does not work in wasm. -In order to create a new font you need to use the `msdf-atlas-gen` tool. This can be found at: -[https://github.com/Chlumsky/msdf-atlas-gen](https://github.com/Chlumsky/msdf-atlas-gen) - -Please refer to the documentation found in the link about for generating fonts. However a simple way is to use the following command line: - -``` -.\msdf-atlas-gen.exe -font .\my_font.ttf -type msdf -minsize 32 -format png -imageout my_font.png -json my_font.kayak_font -``` +# Chapter 6 - Fonts +Kayak UI uses SDF(signed distance fields) for rendering fonts. More specifically it uses multi-channel signed distance fields. Reasons for why we use MSDF: +- High Quality font rendering. +- Fast rendering! +- No need for a new asset for each font size. MSDF's can size to any font size! + +Fonts are stored in two different ways. First a font can be defined as a Kayak TTF(kttf) file. +These font files are relatively simple and simply link to a ttf font: +```json +{ + "file": "roboto.ttf", + "char_range_start": "0x20", + "char_range_end": "0x7f" +} +``` +The char range is a defined as u32 char values. 0x20 through 0x7f represents most of the standard English language characters. Font's using this method are processed in native rust into MSDF's. The output is cached as the generation can take a while. + +Fonts are also stored as an atlased image and a json file which tells Kayak about the font glyphs. These fonts are generated using `msdf-atlas-gen`. Check out `roboto.kayak_font` and `roboto.png` in the `assets` folder. The cached file name will be located next to the kttf file and have the file format of: `{font_name}.kttf-cached.png`. + +### Generating Legacy `*.kayak_font`. WARNING! Does not work in wasm. +In order to create a new font you need to use the `msdf-atlas-gen` tool. This can be found at: +[https://github.com/Chlumsky/msdf-atlas-gen](https://github.com/Chlumsky/msdf-atlas-gen) + +Please refer to the documentation found in the link about for generating fonts. However a simple way is to use the following command line: + +``` +.\msdf-atlas-gen.exe -font .\my_font.ttf -type msdf -minsize 32 -format png -imageout my_font.png -json my_font.kayak_font +``` diff --git a/book/src/chapter_7.md b/book/src/chapter_7.md index 794420f1..e837636d 100644 --- a/book/src/chapter_7.md +++ b/book/src/chapter_7.md @@ -1,17 +1,17 @@ -# Chapter 7 - Widget Update Systems(Diffing) -By default Kayak offers two widget update systems. These systems look at components on widgets and automatically diff(compare) them to the same components from the last render. If the widgets have changed it causes the internal systems to call that widget's render function. - -The default widget update systems are: -- `widget_update` - This system diffs the props and state components. It also diffs some commonly provided components like: `KStyle` and `KChildren` automatically. Note: Only one type of state is allowed. In the future it might be possible to pass in a tuple of state types instead. If you require multiple state "types" please create a custom widget update function. -- `widget_update_with_context` - Like `widget_update` but also provides functionality for auto diffing context as well. Again like with state this will only auto check one singular context type. - -## How does it work? -Behind the scenes Kayak UI keeps track of the types that are associated with props and state for a given widget. After each successful render of a widget kayak will clone the entire widget onto a new entity. This is considered the "last" render state of the entity and is expect to not change. These special entities can be avoided by using the `PreviousWidget` tag component and bevy query filters. They are also not added to the tree and are only loosely attached to the widget entity that lives in the tree. - -## Custom widget update systems -Since the widget update is a system users can define very fine grained and custom diffing by writing their own system. - -Kayak UI provides a bevy `SystemParam` called `WidgetParam` which aids in achieving this. The `SystemParam` takes two generics like the default widget update system for props and state. It has a special function which compares the components from entity A with entity B called `has_changed`. - -## **WARNING!** - There is currently little documentation for how this works, and this is considered a rather delicate and highly advanced operation. +# Chapter 7 - Widget Update Systems(Diffing) +By default Kayak offers two widget update systems. These systems look at components on widgets and automatically diff(compare) them to the same components from the last render. If the widgets have changed it causes the internal systems to call that widget's render function. + +The default widget update systems are: +- `widget_update` - This system diffs the props and state components. It also diffs some commonly provided components like: `KStyle` and `KChildren` automatically. Note: Only one type of state is allowed. In the future it might be possible to pass in a tuple of state types instead. If you require multiple state "types" please create a custom widget update function. +- `widget_update_with_context` - Like `widget_update` but also provides functionality for auto diffing context as well. Again like with state this will only auto check one singular context type. + +## How does it work? +Behind the scenes Kayak UI keeps track of the types that are associated with props and state for a given widget. After each successful render of a widget kayak will clone the entire widget onto a new entity. This is considered the "last" render state of the entity and is expect to not change. These special entities can be avoided by using the `PreviousWidget` tag component and bevy query filters. They are also not added to the tree and are only loosely attached to the widget entity that lives in the tree. + +## Custom widget update systems +Since the widget update is a system users can define very fine grained and custom diffing by writing their own system. + +Kayak UI provides a bevy `SystemParam` called `WidgetParam` which aids in achieving this. The `SystemParam` takes two generics like the default widget update system for props and state. It has a special function which compares the components from entity A with entity B called `has_changed`. + +## **WARNING!** - There is currently little documentation for how this works, and this is considered a rather delicate and highly advanced operation. Feel free to reach out if you feel like you would like to help improve this API! \ No newline at end of file diff --git a/book/src/chapter_8.md b/book/src/chapter_8.md index b45eb382..be742db8 100644 --- a/book/src/chapter_8.md +++ b/book/src/chapter_8.md @@ -1,63 +1,63 @@ -# Chapter 8 - Prebuilt Widget -Kayak UI comes with a few pre-built widgets. Some of these widgets are highly customizable and others might be more rigidly defined. - -## 1. Core Visual Widgets -Core visual widgets are widgets that provide specific rendering commands to the rendering backend. These drive the look and feel of Kayak UI! - -### Background -A background is a widget that renders a quad. It's style render command is hard coded to always be `RenderCommand::Quad`. In addition to rendering a quad the background widget can be customized to render a border, border radius, and other similar affects. - -#### Props: -- KStyle -- KChildren -- OnEvent - -### Clip -Clips are special widgets that cause areas of the renderer to not draw pixels outside of their bounds. These can essentially be considered an inverse "mask" although they are always only rectangular in shape. A clip can be useful to keep content from spilling out of an existing area, in that regard they almost behave like the CSS overflow property. - -#### Props: -- KStyle -- KChildren - -### Image -Like the name implies this widget renders an image. The image that is rendered is an image loaded in by bevy. The size is controlled by styles. The widget also responds to border radius via an SDF mask. - -#### Props: -- KImage(Handle) - This component accepts a bevy handle to an image asset. -- KStyle - -### Nine Patch -The nine patch widget is a special widget designed to render a sliced UI image. Also know as 9-slicing. This 2D technique allows users to render UI images at multiple resolutions while maintaining a level of quality. The image in the middle is repeated. - -#### Props: -- NinePatch - - `handle`: A bevy handle to a nine patch image asset which. - - `border`: This represents the area that is sliced into eight pieces along the edge of the image. The ninth piece is the middle which is repeated. -- KStyle -- OnEvent -- KChildren - -### Text -This widget renders text directly to the screen. - -#### Props: -- TextProps - - `content`: The string to display - - `font`: The name of the font to use - - `line_height`: The height of a line of text (currently in pixels). Defaults to font size * 1.2 which is the firefox default method of calculating line height. - - `show_cursor`: If true, displays the default text cursor when hovered. - - `size`: The font size (in pixels) - - `alignement`: Text alignment. - - `user_styles`: Specific styles applied directly to the text itself. - - `word_wrap`: Wraps the words if said text would overflow it's parent. -- KStyle - -### Texture Atlas -The texture atlas widget will render a bevy texture atlas inside of the UI. This can be useful for users who have UI that lives inside of an atlas texture. Although currently there are not any performance benefits of using this compared to just a regular single image. - -#### Props -- TextureAtlasProps - - `handle`: The handle to bevy texture atlas image - - `position`: The position of the tile (in pixels) - - `tile_size`: The size of the tile (in pixels) -- KStyle +# Chapter 8 - Prebuilt Widget +Kayak UI comes with a few pre-built widgets. Some of these widgets are highly customizable and others might be more rigidly defined. + +## 1. Core Visual Widgets +Core visual widgets are widgets that provide specific rendering commands to the rendering backend. These drive the look and feel of Kayak UI! + +### Background +A background is a widget that renders a quad. It's style render command is hard coded to always be `RenderCommand::Quad`. In addition to rendering a quad the background widget can be customized to render a border, border radius, and other similar affects. + +#### Props: +- KStyle +- KChildren +- OnEvent + +### Clip +Clips are special widgets that cause areas of the renderer to not draw pixels outside of their bounds. These can essentially be considered an inverse "mask" although they are always only rectangular in shape. A clip can be useful to keep content from spilling out of an existing area, in that regard they almost behave like the CSS overflow property. + +#### Props: +- KStyle +- KChildren + +### Image +Like the name implies this widget renders an image. The image that is rendered is an image loaded in by bevy. The size is controlled by styles. The widget also responds to border radius via an SDF mask. + +#### Props: +- KImage(Handle) - This component accepts a bevy handle to an image asset. +- KStyle + +### Nine Patch +The nine patch widget is a special widget designed to render a sliced UI image. Also know as 9-slicing. This 2D technique allows users to render UI images at multiple resolutions while maintaining a level of quality. The image in the middle is repeated. + +#### Props: +- NinePatch + - `handle`: A bevy handle to a nine patch image asset which. + - `border`: This represents the area that is sliced into eight pieces along the edge of the image. The ninth piece is the middle which is repeated. +- KStyle +- OnEvent +- KChildren + +### Text +This widget renders text directly to the screen. + +#### Props: +- TextProps + - `content`: The string to display + - `font`: The name of the font to use + - `line_height`: The height of a line of text (currently in pixels). Defaults to font size * 1.2 which is the firefox default method of calculating line height. + - `show_cursor`: If true, displays the default text cursor when hovered. + - `size`: The font size (in pixels) + - `alignement`: Text alignment. + - `user_styles`: Specific styles applied directly to the text itself. + - `word_wrap`: Wraps the words if said text would overflow it's parent. +- KStyle + +### Texture Atlas +The texture atlas widget will render a bevy texture atlas inside of the UI. This can be useful for users who have UI that lives inside of an atlas texture. Although currently there are not any performance benefits of using this compared to just a regular single image. + +#### Props +- TextureAtlasProps + - `handle`: The handle to bevy texture atlas image + - `position`: The position of the tile (in pixels) + - `tile_size`: The size of the tile (in pixels) +- KStyle diff --git a/book/src/chapter_9.md b/book/src/chapter_9.md index d88803da..7301149a 100644 --- a/book/src/chapter_9.md +++ b/book/src/chapter_9.md @@ -1,2 +1,2 @@ -# Chapter 9 - Practical Usage +# Chapter 9 - Practical Usage Coming soon! \ No newline at end of file diff --git a/book/src/img/kayak.svg b/book/src/img/kayak.svg index 9231eef9..a2dcf533 100644 --- a/book/src/img/kayak.svg +++ b/book/src/img/kayak.svg @@ -1,62 +1,62 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/book/src/introduction.md b/book/src/introduction.md index b73e0fc3..27ef8dd1 100644 --- a/book/src/introduction.md +++ b/book/src/introduction.md @@ -1,42 +1,42 @@ -

- Kayak UI -

-
- -# Introduction - -Kayak UI is a declarative UI that can be used to make user interfaces in Rust primarily targeting games. It's free and open-source! - -## Features -- Full integration into Bevy ECS. -- Easy to use declarative syntax using a custom proc macro -- Basic widget, global, and context state management -- Input events (Mouse, Keyboard, Char) -- Fast and accurate layouts using morphorm: https://github.com/geom3trik/morphorm -- A few default widgets (check out Kayak's [built-in widgets](https://github.com/StarArawn/kayak_ui/tree/main/src/widgets)!) -- Style system built to kind of mimic CSS styles. -- Image and Nine patch rendering. -- Widget and Tree diff based updating - - -## This book -In this book you'll be learning: -- How to use widgets. -- How to create custom widgets. -- Accessing bevy data from a widget. -- Handling widget updates. - -And more! - -## License -Copyright © 2021-2022 John Mitchell. - -All code in the book is provided under the MIT-0 License. At your option, you may also use it under the regular MIT License. - -The text of the book is provided under the CC BY-NC-SA 4.0. - -## Contributions -Development of this book is hosted on GitHub. - -Please file GitHub Issues for any wrong/confusing/misleading information, as well as suggestions for new content you'd like to be added to the book. - +

+ Kayak UI +

+
+ +# Introduction + +Kayak UI is a declarative UI that can be used to make user interfaces in Rust primarily targeting games. It's free and open-source! + +## Features +- Full integration into Bevy ECS. +- Easy to use declarative syntax using a custom proc macro +- Basic widget, global, and context state management +- Input events (Mouse, Keyboard, Char) +- Fast and accurate layouts using morphorm: https://github.com/geom3trik/morphorm +- A few default widgets (check out Kayak's [built-in widgets](https://github.com/StarArawn/kayak_ui/tree/main/src/widgets)!) +- Style system built to kind of mimic CSS styles. +- Image and Nine patch rendering. +- Widget and Tree diff based updating + + +## This book +In this book you'll be learning: +- How to use widgets. +- How to create custom widgets. +- Accessing bevy data from a widget. +- Handling widget updates. + +And more! + +## License +Copyright © 2021-2022 John Mitchell. + +All code in the book is provided under the MIT-0 License. At your option, you may also use it under the regular MIT License. + +The text of the book is provided under the CC BY-NC-SA 4.0. + +## Contributions +Development of this book is hosted on GitHub. + +Please file GitHub Issues for any wrong/confusing/misleading information, as well as suggestions for new content you'd like to be added to the book. + diff --git a/clippy.toml b/clippy.toml index da8a02c4..73f59c8d 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,3 +1,3 @@ -# BLOCKED: https://github.com/rust-lang/cargo/issues/5034 for properly disabling lints -type-complexity-threshold = 9000 +# BLOCKED: https://github.com/rust-lang/cargo/issues/5034 for properly disabling lints +type-complexity-threshold = 9000 too-many-arguments-threshold = 30 \ No newline at end of file diff --git a/docs/LICENSE-APACHE b/docs/LICENSE-APACHE index b9b9d2a6..7ef1c23e 100644 --- a/docs/LICENSE-APACHE +++ b/docs/LICENSE-APACHE @@ -1,176 +1,176 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/docs/LICENSE-MIT b/docs/LICENSE-MIT index 6802bc4b..4174b30f 100644 --- a/docs/LICENSE-MIT +++ b/docs/LICENSE-MIT @@ -1,19 +1,19 @@ -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/docs/kayak_children.md b/docs/kayak_children.md index a7afecbc..16716842 100644 --- a/docs/kayak_children.md +++ b/docs/kayak_children.md @@ -1,83 +1,83 @@ -## Intro -1. We have a simple tree that stores entities. -2. Nodes in the tree need to have consistent identifiers(I.E. entity id's). - -## Problems -1. Children passing - Children are entities that are passed from higher up in the tree to some place lower in the tree. Normally children are directly attached to their parent, but because of our tree structure we often need to spawn entities ahead of time because the parent has not yet spawned. Example xml tree: - -Root: -```xml - - - - - -``` -B: -```xml - - {children} - -``` - -Here the widget B is wrapped around C but the actual children are a child of D. - -How can we handle children? - -### 1. Closures - A function that can be passed down the tree. -Pros: -- Essentially differed adding and spawning of widgets until later. -- No need to worry about if the entity ID is correct in the tree just pull it out. - -Cons: -- Closures require ownership to move data into them. This might seem small but remember we have a tree again so quite quickly it becomes challenging: -```rust -// Imagine some data that has clone only. -let some_data = SomeData { foo }; -parent.children = Children::new(move || - let some_data = some_data.clone(); - let child_1 = create_widget(); - child_1.children = Children::new(move || { - // We might need to clone again if child_2 has children that need this data? - // let some_data = some_data.clone(); - // let child_2 = create_widget(some_data.foo); // OOPS error. - let child_2 = create_widget(some_data.foo); - }) -); -``` -This is a pretty massive con in my opinion and one we should try to avoid. - -## Alternatives - -### 2. Ordered tree -Another solution is to keep track of where the entity id's are spawned and make them consistent at their spawn point. Then we don't need to pass data down the tree only entity id's. - -Process: -1. For each widget spawned add it to a new tree with it's parent set to the widget that spawned it. -2. Make sure this ordered tree stays in sync with additions of entities. -3. Pass children down as just id's that get added to the tree in their actual parent widget. - -So for our same example above with(a, b, c, d). Our tree looks like: - -``` -├── A -| └── B -| └── D -| └── C -``` - -Our ordered tree looks like: -``` -├── A -| ├── B -| └── D -| └── C -``` - -Now with a lack of closures we only need to clone, copy, or move data when we specifically need to. When we re-render the tree a second time we look at our ordered tree first to see if we have a matching entity in the slot we are trying to render to. - -This sounds easy in practice but there are also some big cons: - -Cons: -- Complexity increased. -- Can cause issues if your tree and ordered tree get out of sync.s \ No newline at end of file +## Intro +1. We have a simple tree that stores entities. +2. Nodes in the tree need to have consistent identifiers(I.E. entity id's). + +## Problems +1. Children passing - Children are entities that are passed from higher up in the tree to some place lower in the tree. Normally children are directly attached to their parent, but because of our tree structure we often need to spawn entities ahead of time because the parent has not yet spawned. Example xml tree: + +Root: +```xml + + + + + +``` +B: +```xml + + {children} + +``` + +Here the widget B is wrapped around C but the actual children are a child of D. + +How can we handle children? + +### 1. Closures - A function that can be passed down the tree. +Pros: +- Essentially differed adding and spawning of widgets until later. +- No need to worry about if the entity ID is correct in the tree just pull it out. + +Cons: +- Closures require ownership to move data into them. This might seem small but remember we have a tree again so quite quickly it becomes challenging: +```rust +// Imagine some data that has clone only. +let some_data = SomeData { foo }; +parent.children = Children::new(move || + let some_data = some_data.clone(); + let child_1 = create_widget(); + child_1.children = Children::new(move || { + // We might need to clone again if child_2 has children that need this data? + // let some_data = some_data.clone(); + // let child_2 = create_widget(some_data.foo); // OOPS error. + let child_2 = create_widget(some_data.foo); + }) +); +``` +This is a pretty massive con in my opinion and one we should try to avoid. + +## Alternatives + +### 2. Ordered tree +Another solution is to keep track of where the entity id's are spawned and make them consistent at their spawn point. Then we don't need to pass data down the tree only entity id's. + +Process: +1. For each widget spawned add it to a new tree with it's parent set to the widget that spawned it. +2. Make sure this ordered tree stays in sync with additions of entities. +3. Pass children down as just id's that get added to the tree in their actual parent widget. + +So for our same example above with(a, b, c, d). Our tree looks like: + +``` +├── A 1 +| └── B 2 +| └── D 4 +| └── C 3 +``` + +Our ordered tree looks like: +``` +├── A 1 +| ├── B 2 +| └── D 4 +| └── C 3 +``` + +Now with a lack of closures we only need to clone, copy, or move data when we specifically need to. When we re-render the tree a second time we look at our ordered tree first to see if we have a matching entity in the slot we are trying to render to. + +This sounds easy in practice but there are also some big cons: + +Cons: +- Complexity increased. +- Can cause issues if your tree and ordered tree get out of sync. diff --git a/examples/accordion.rs b/examples/accordion.rs index 1c8cc755..4f025735 100644 --- a/examples/accordion.rs +++ b/examples/accordion.rs @@ -1,125 +1,125 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, *}; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("fonts/roboto.kttf")); - - let image = asset_server.load("generic-rpg-vendor.png"); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - rsx! { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) - .add_plugins((KayakContextPlugin, KayakWidgets)) - // .add_plugin(bevy_inspector_egui::quick::WorldInspectorPlugin::default()) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, *}; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("fonts/roboto.kttf")); + + let image = asset_server.load("generic-rpg-vendor.png"); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + rsx! { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) + .add_plugins((KayakContextPlugin, KayakWidgets)) + // .add_plugin(bevy_inspector_egui::quick::WorldInspectorPlugin::default()) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/avsb.rs b/examples/avsb.rs index 46bcb9d5..836f846f 100644 --- a/examples/avsb.rs +++ b/examples/avsb.rs @@ -1,224 +1,224 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, *}; - -#[derive(Component, Default, PartialEq, Clone)] -struct CurrentCount; - -impl Widget for CurrentCount {} - -#[derive(Component, Default, PartialEq, Clone)] -struct CurrentCountState { - foo: u32, -} - -#[derive(Bundle)] -struct CurrentCountBundle { - count: CurrentCount, - styles: KStyle, - computed_styles: ComputedStyles, - widget_name: WidgetName, -} - -impl Default for CurrentCountBundle { - fn default() -> Self { - Self { - count: CurrentCount::default(), - styles: KStyle::default(), - computed_styles: ComputedStyles::default(), - widget_name: CurrentCount::default().get_name(), - } - } -} - -fn current_count_render( - In(entity): In, - widget_context: Res, - mut commands: Commands, - query: Query<&CurrentCountState>, -) -> bool { - let state_entity = - widget_context.use_state(&mut commands, entity, CurrentCountState::default()); - if let Ok(current_count) = query.get(state_entity) { - let parent_id = Some(entity); - rsx! { - - - , - mut event: ResMut, - mut query: Query<&mut CurrentCountState>| { - if let EventType::Click(..) = event.event_type { - event.prevent_default(); - event.stop_propagation(); - if let Ok(mut current_count) = query.get_mut(state_entity) { - current_count.foo += 1; - } - } - }, - )} - /> - - }; - } - - true -} - -/// A test for switching from component A to component B. -/// Q: Why does adding a key cause the state of the widget to "reset"? -/// A: When you use a unique identifier the entity id will be unique to the identifier. -/// if you do not use a key the widget is considered the "same" as before with updated props. -#[derive(Component, Default, Clone, PartialEq)] -pub struct AvsB {} - -impl Widget for AvsB {} - -#[derive(Component, Default, Clone, PartialEq)] -pub struct AvsBState { - is_a: bool, -} - -#[derive(Bundle)] -pub struct AvsBBundle { - pub avsb: AvsB, - pub widget_name: WidgetName, -} - -impl Default for AvsBBundle { - fn default() -> Self { - Self { - avsb: Default::default(), - widget_name: AvsB::default().get_name(), - } - } -} - -fn render( - In(entity): In, - widget_context: Res, - mut commands: Commands, - query: Query<&AvsBState>, -) -> bool { - let state_entity = widget_context.use_state(&mut commands, entity, AvsBState::default()); - if let Ok(state) = query.get(state_entity) { - let parent_id = Some(entity); - - rsx! { - - - { - if state.is_a { - constructor! { - - - - } - } else { - constructor! { - - - - } - } - } - - - }; - } - - true -} - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("fonts/roboto.kttf")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - - widget_context.add_widget_data::(); - widget_context.add_widget_system( - AvsB::default().get_name(), - widget_update::, - render, - ); - - widget_context.add_widget_data::(); - widget_context.add_widget_system( - CurrentCount::default().get_name(), - widget_update::, - current_count_render, - ); - - let parent_id = None; - rsx! { - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn swap(input: Res>, mut query: Query<&mut AvsBState, Without>) { - if input.just_pressed(KeyCode::Space) { - for mut avsb in query.iter_mut() { - avsb.is_a = !avsb.is_a; - } - } -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) - .add_plugins(( - bevy_inspector_egui::quick::WorldInspectorPlugin::new(), - KayakContextPlugin, - KayakWidgets, - )) - .add_systems(Startup, startup) - .add_systems(Update, swap) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, *}; + +#[derive(Component, Default, PartialEq, Clone)] +struct CurrentCount; + +impl Widget for CurrentCount {} + +#[derive(Component, Default, PartialEq, Clone)] +struct CurrentCountState { + foo: u32, +} + +#[derive(Bundle)] +struct CurrentCountBundle { + count: CurrentCount, + styles: KStyle, + computed_styles: ComputedStyles, + widget_name: WidgetName, +} + +impl Default for CurrentCountBundle { + fn default() -> Self { + Self { + count: CurrentCount, + styles: KStyle::default(), + computed_styles: ComputedStyles::default(), + widget_name: CurrentCount.get_name(), + } + } +} + +fn current_count_render( + In(entity): In, + widget_context: Res, + mut commands: Commands, + query: Query<&CurrentCountState>, +) -> bool { + let state_entity = + widget_context.use_state(&mut commands, entity, CurrentCountState::default()); + if let Ok(current_count) = query.get(state_entity) { + let parent_id = Some(entity); + rsx! { + + + , + mut event: ResMut, + mut query: Query<&mut CurrentCountState>| { + if let EventType::Click(..) = event.event_type { + event.prevent_default(); + event.stop_propagation(); + if let Ok(mut current_count) = query.get_mut(state_entity) { + current_count.foo += 1; + } + } + }, + )} + /> + + }; + } + + true +} + +/// A test for switching from component A to component B. +/// Q: Why does adding a key cause the state of the widget to "reset"? +/// A: When you use a unique identifier the entity id will be unique to the identifier. +/// if you do not use a key the widget is considered the "same" as before with updated props. +#[derive(Component, Default, Clone, PartialEq)] +pub struct AvsB {} + +impl Widget for AvsB {} + +#[derive(Component, Default, Clone, PartialEq)] +pub struct AvsBState { + is_a: bool, +} + +#[derive(Bundle)] +pub struct AvsBBundle { + pub avsb: AvsB, + pub widget_name: WidgetName, +} + +impl Default for AvsBBundle { + fn default() -> Self { + Self { + avsb: Default::default(), + widget_name: AvsB::default().get_name(), + } + } +} + +fn render( + In(entity): In, + widget_context: Res, + mut commands: Commands, + query: Query<&AvsBState>, +) -> bool { + let state_entity = widget_context.use_state(&mut commands, entity, AvsBState::default()); + if let Ok(state) = query.get(state_entity) { + let parent_id = Some(entity); + + rsx! { + + + { + if state.is_a { + constructor! { + + + + } + } else { + constructor! { + + + + } + } + } + + + }; + } + + true +} + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("fonts/roboto.kttf")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + + widget_context.add_widget_data::(); + widget_context.add_widget_system( + AvsB::default().get_name(), + widget_update::, + render, + ); + + widget_context.add_widget_data::(); + widget_context.add_widget_system( + CurrentCount.get_name(), + widget_update::, + current_count_render, + ); + + let parent_id = None; + rsx! { + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn swap(input: Res>, mut query: Query<&mut AvsBState, Without>) { + if input.just_pressed(KeyCode::Space) { + for mut avsb in query.iter_mut() { + avsb.is_a = !avsb.is_a; + } + } +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) + .add_plugins(( + bevy_inspector_egui::quick::WorldInspectorPlugin::new(), + KayakContextPlugin, + KayakWidgets, + )) + .add_systems(Startup, startup) + .add_systems(Update, swap) + .run() +} diff --git a/examples/bevy_scene.rs b/examples/bevy_scene.rs index 46286067..a33793f8 100644 --- a/examples/bevy_scene.rs +++ b/examples/bevy_scene.rs @@ -1,274 +1,275 @@ -use bevy::{ - math::{Vec3Swizzles, Vec4Swizzles}, - prelude::*, - window::PrimaryWindow, -}; -use kayak_ui::prelude::{widgets::*, *}; - -const TILE_SIZE: Vec2 = Vec2::from_array([50.0, 50.0]); -const COLORS: &[Color] = &[Color::TEAL, Color::MAROON, Color::INDIGO]; - -// ! === Unnecessary Details Below === ! // -// Below this point are mainly implementation details. The main purpose of this example is to show how to know -// when to allow or disallow world interaction through `BevyContext` (see the `set_active_tile_target` function) - -/// A resource used to control the color of the tiles -#[derive(Resource)] -struct ActiveColor { - index: usize, -} - -/// A component used to control the "Active Tile" that moves to the clicked positions -#[derive(Default, Component)] -struct ActiveTile { - target: Vec2, -} - -/// A component used to control the "Ghost Tile" that follows the user's cursor -#[derive(Component)] -struct GhostTile; - -/// A component used to mark the "world camera" (differentiating it from other cameras possibly in the scene) -#[derive(Component)] -struct WorldCamera; - -/// This is the system that sets the active tile's target position -/// -/// To prevent the tile from being moved to a position under our UI, we can use the `BevyContext` resource -/// to filter out clicks that occur over the UI -fn set_active_tile_target( - mut tile: Query<&mut ActiveTile>, - cursor: Res>, - event_context: Query<&EventDispatcher, With>, - camera_transform: Query<&GlobalTransform, With>, - window: Query<&Window, With>, -) { - if !cursor.just_pressed(MouseButton::Left) { - // Only run this system when the mouse button is clicked - return; - } - - if event_context.single().contains_cursor() { - // This is the important bit: - // If the cursor is over a part of the UI, then we should not allow clicks to pass through to the world - return; - } - - // If you wanted to allow clicks through the UI as long as the cursor is not on a focusable widget (such as Buttons), - // you could use `context.wants_cursor()` instead: - // - // ``` - // if context.wants_cursor() { - // return; - // } - // ``` - - let world_pos = cursor_to_world(window.single(), camera_transform.single()); - let tile_pos = world_to_tile(world_pos); - let mut tile = tile.single_mut(); - tile.target = tile_pos; -} - -/// A system that moves the active tile to its target position -fn move_active_tile(mut tile: Query<(&mut Transform, &ActiveTile)>) { - let (mut transform, tile) = tile.single_mut(); - let curr_pos = transform.translation.xy(); - let next_pos = curr_pos.lerp(tile.target, 0.1); - transform.translation.x = next_pos.x; - transform.translation.y = next_pos.y; -} - -/// A system that moves the ghost tile to the cursor's position -fn move_ghost_tile( - event_context: Query<&EventDispatcher, With>, - mut tile: Query<&mut Transform, With>, - mut cursor_moved: EventReader, - camera_transform: Query<&GlobalTransform, With>, - window: Query<&Window, With>, -) { - for _ in cursor_moved.iter() { - if !event_context.single().contains_cursor() { - let world_pos = cursor_to_world(window.single(), camera_transform.single()); - let tile_pos = world_to_tile(world_pos); - let mut ghost = tile.single_mut(); - ghost.translation.x = tile_pos.x; - ghost.translation.y = tile_pos.y; - } - } -} - -/// A system that updates the tiles' color -fn on_color_change( - mut active_tile: Query<&mut Sprite, (With, Without)>, - mut ghost_tile: Query<&mut Sprite, (With, Without)>, - active_color: Res, -) { - if !active_color.is_changed() { - return; - } - - let mut active_tile = active_tile.single_mut(); - active_tile.color = COLORS[active_color.index]; - - let mut ghost_tile = ghost_tile.single_mut(); - ghost_tile.color = ghost_color(COLORS[active_color.index]); -} - -/// A system that sets up the world -fn world_setup(mut commands: Commands, active_color: Res) { - commands - .spawn(SpriteBundle { - sprite: Sprite { - color: COLORS[active_color.index], - custom_size: Some(TILE_SIZE), - ..Default::default() - }, - ..Default::default() - }) - .insert(ActiveTile::default()); - commands - .spawn(SpriteBundle { - sprite: Sprite { - color: ghost_color(COLORS[active_color.index]), - custom_size: Some(TILE_SIZE), - ..Default::default() - }, - ..Default::default() - }) - .insert(GhostTile); -} - -/// Get the world position of the cursor in 2D space -fn cursor_to_world(window: &Window, camera_transform: &GlobalTransform) -> Vec2 { - let size = Vec2::new(window.width(), window.height()); - - let mut pos = window.cursor_position().unwrap_or_default(); - pos -= size / 2.0; - - let point = camera_transform.compute_matrix() * pos.extend(0.0).extend(1.0); - point.xy() -} - -/// Converts a world coordinate to a rounded tile coordinate -fn world_to_tile(world_pos: Vec2) -> Vec2 { - let extents = TILE_SIZE / 2.0; - let world_pos = world_pos - extents; - (world_pos / TILE_SIZE).ceil() * TILE_SIZE -} - -/// Get the ghost tile color for a given color -fn ghost_color(color: Color) -> Color { - let mut c = color; - c.set_a(0.35); - c -} - -#[derive(Component)] -pub struct GameUI; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - // The UI Camera and the world camera are the same. - // CameraUIKayak is used to tell kayak which camera should render UI. - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak, WorldCamera)) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kayak_font")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - - let handle_change_color = OnEvent::new( - move |In(_entity): In, - event: Res, - mut active_color: ResMut| { - if let EventType::Click(..) = event.event_type { - active_color.index = (active_color.index + 1) % COLORS.len(); - } - }, - ); - - let text_styles = KStyle { - left: StyleProp::Value(Units::Stretch(1.0)), - right: StyleProp::Value(Units::Stretch(1.0)), - ..Default::default() - }; - let button_styles = KStyle { - min_width: StyleProp::Value(Units::Pixels(150.0)), - width: StyleProp::Value(Units::Auto), - height: StyleProp::Value(Units::Auto), - left: StyleProp::Value(Units::Stretch(1.0)), - right: StyleProp::Value(Units::Stretch(1.0)), - top: StyleProp::Value(Units::Pixels(16.0)), - bottom: StyleProp::Value(Units::Pixels(8.0)), - padding: StyleProp::Value(Edge::axis(Units::Pixels(8.0), Units::Pixels(48.0))), - ..Default::default() - }; - - let parent_id = None; - rsx! { - - - - - - - - }; - - commands.spawn((widget_context, EventDispatcher::default(), GameUI)); -} - -fn main() { - App::new() - .insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0))) - .insert_resource(ActiveColor { index: 0 }) - .add_plugins(DefaultPlugins) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, (startup, world_setup)) - .add_systems( - Update, - ( - move_ghost_tile, - set_active_tile_target, - move_active_tile, - on_color_change, - ), - ) - .run() -} +use bevy::{ + math::{Vec3Swizzles, Vec4Swizzles}, + prelude::*, + window::PrimaryWindow, +}; +use kayak_ui::prelude::{widgets::*, *}; + +const TILE_SIZE: Vec2 = Vec2::from_array([50.0, 50.0]); +const COLORS: &[Color] = &[Color::TEAL, Color::MAROON, Color::INDIGO]; + +// ! === Unnecessary Details Below === ! // +// Below this point are mainly implementation details. The main purpose of this example is to show how to know +// when to allow or disallow world interaction through `BevyContext` (see the `set_active_tile_target` function) + +/// A resource used to control the color of the tiles +#[derive(Resource)] +struct ActiveColor { + index: usize, +} + +/// A component used to control the "Active Tile" that moves to the clicked positions +#[derive(Default, Component)] +struct ActiveTile { + target: Vec2, +} + +/// A component used to control the "Ghost Tile" that follows the user's cursor +#[derive(Component)] +struct GhostTile; + +/// A component used to mark the "world camera" (differentiating it from other cameras possibly in the scene) +#[derive(Component)] +struct WorldCamera; + +/// This is the system that sets the active tile's target position +/// +/// To prevent the tile from being moved to a position under our UI, we can use the `BevyContext` resource +/// to filter out clicks that occur over the UI +fn set_active_tile_target( + mut tile: Query<&mut ActiveTile>, + cursor: Res>, + event_context: Query<&EventDispatcher, With>, + camera_transform: Query<&GlobalTransform, With>, + window: Query<&Window, With>, +) { + if !cursor.just_pressed(MouseButton::Left) { + // Only run this system when the mouse button is clicked + return; + } + + if event_context.single().contains_cursor() { + // This is the important bit: + // If the cursor is over a part of the UI, then we should not allow clicks to pass through to the world + return; + } + + // If you wanted to allow clicks through the UI as long as the cursor is not on a focusable widget (such as Buttons), + // you could use `context.wants_cursor()` instead: + // + // ``` + // if context.wants_cursor() { + // return; + // } + // ``` + + let world_pos = cursor_to_world(window.single(), camera_transform.single()); + let tile_pos = world_to_tile(world_pos); + let mut tile = tile.single_mut(); + tile.target = tile_pos; +} + +/// A system that moves the active tile to its target position +fn move_active_tile(mut tile: Query<(&mut Transform, &ActiveTile)>) { + let (mut transform, tile) = tile.single_mut(); + let curr_pos = transform.translation.xy(); + let next_pos = curr_pos.lerp(tile.target, 0.1); + transform.translation.x = next_pos.x; + transform.translation.y = next_pos.y; +} + +/// A system that moves the ghost tile to the cursor's position +fn move_ghost_tile( + event_context: Query<&EventDispatcher, With>, + mut tile: Query<&mut Transform, With>, + mut cursor_moved: EventReader, + camera_transform: Query<&GlobalTransform, With>, + window: Query<&Window, With>, +) { + for _ in cursor_moved.read() { + if !event_context.single().contains_cursor() { + let world_pos = cursor_to_world(window.single(), camera_transform.single()); + let tile_pos = world_to_tile(world_pos); + let mut ghost = tile.single_mut(); + ghost.translation.x = tile_pos.x; + ghost.translation.y = tile_pos.y; + } + } +} + +/// A system that updates the tiles' color +fn on_color_change( + mut active_tile: Query<&mut Sprite, (With, Without)>, + mut ghost_tile: Query<&mut Sprite, (With, Without)>, + active_color: Res, +) { + if !active_color.is_changed() { + return; + } + + let mut active_tile = active_tile.single_mut(); + active_tile.color = COLORS[active_color.index]; + + let mut ghost_tile = ghost_tile.single_mut(); + ghost_tile.color = ghost_color(COLORS[active_color.index]); +} + +/// A system that sets up the world +fn world_setup(mut commands: Commands, active_color: Res) { + commands + .spawn(SpriteBundle { + sprite: Sprite { + color: COLORS[active_color.index], + custom_size: Some(TILE_SIZE), + ..Default::default() + }, + ..Default::default() + }) + .insert(ActiveTile::default()); + commands + .spawn(SpriteBundle { + sprite: Sprite { + color: ghost_color(COLORS[active_color.index]), + custom_size: Some(TILE_SIZE), + ..Default::default() + }, + ..Default::default() + }) + .insert(GhostTile); +} + +/// Get the world position of the cursor in 2D space +fn cursor_to_world(window: &Window, camera_transform: &GlobalTransform) -> Vec2 { + let size = Vec2::new(window.width(), window.height()); + + let mut pos = window.cursor_position().unwrap_or_default(); + pos -= size / 2.0; + pos.y = -pos.y; + + let point = camera_transform.compute_matrix() * pos.extend(0.0).extend(1.0); + point.xy() +} + +/// Converts a world coordinate to a rounded tile coordinate +fn world_to_tile(world_pos: Vec2) -> Vec2 { + let extents = TILE_SIZE / 2.0; + let world_pos = world_pos - extents; + (world_pos / TILE_SIZE).ceil() * TILE_SIZE +} + +/// Get the ghost tile color for a given color +fn ghost_color(color: Color) -> Color { + let mut c = color; + c.set_a(0.35); + c +} + +#[derive(Component)] +pub struct GameUI; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + // The UI Camera and the world camera are the same. + // CameraUIKayak is used to tell kayak which camera should render UI. + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak, WorldCamera)) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kayak_font")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + + let handle_change_color = OnEvent::new( + move |In(_entity): In, + event: Res, + mut active_color: ResMut| { + if let EventType::Click(..) = event.event_type { + active_color.index = (active_color.index + 1) % COLORS.len(); + } + }, + ); + + let text_styles = KStyle { + left: StyleProp::Value(Units::Stretch(1.0)), + right: StyleProp::Value(Units::Stretch(1.0)), + ..Default::default() + }; + let button_styles = KStyle { + min_width: StyleProp::Value(Units::Pixels(150.0)), + width: StyleProp::Value(Units::Auto), + height: StyleProp::Value(Units::Auto), + left: StyleProp::Value(Units::Stretch(1.0)), + right: StyleProp::Value(Units::Stretch(1.0)), + top: StyleProp::Value(Units::Pixels(16.0)), + bottom: StyleProp::Value(Units::Pixels(8.0)), + padding: StyleProp::Value(Edge::axis(Units::Pixels(8.0), Units::Pixels(48.0))), + ..Default::default() + }; + + let parent_id = None; + rsx! { + + + + + + + + }; + + commands.spawn((widget_context, EventDispatcher::default(), GameUI)); +} + +fn main() { + App::new() + .insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0))) + .insert_resource(ActiveColor { index: 0 }) + .add_plugins(DefaultPlugins) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, (startup, world_setup)) + .add_systems( + Update, + ( + move_ghost_tile, + set_active_tile_target, + move_active_tile, + on_color_change, + ), + ) + .run() +} diff --git a/examples/box_shadows.rs b/examples/box_shadows.rs index 400c83e8..d1c656e9 100644 --- a/examples/box_shadows.rs +++ b/examples/box_shadows.rs @@ -1,183 +1,183 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, KStyle, *}; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kayak_font")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - rsx! { - - - - - - - - - - - - - - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .insert_resource(ClearColor(Color::rgb(1.0, 1.0, 1.0))) - .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, KStyle, *}; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kayak_font")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + rsx! { + + + + + + + + + + + + + + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .insert_resource(ClearColor(Color::rgb(1.0, 1.0, 1.0))) + .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/clipping.rs b/examples/clipping.rs index 9c6c7acc..e36b22a6 100644 --- a/examples/clipping.rs +++ b/examples/clipping.rs @@ -1,73 +1,73 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, KStyle, *}; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("fonts/roboto.kttf")); - - let image = asset_server.load("panel.png"); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - - let nine_patch_styles = KStyle { - width: StyleProp::Value(Units::Pixels(512.0)), - height: StyleProp::Value(Units::Pixels(512.0)), - offset: StyleProp::Value(Edge::all(Units::Stretch(1.0))), - padding: StyleProp::Value(Edge::all(Units::Pixels(25.0))), - ..KStyle::default() - }; - - let lorem_ipsum = r#" -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sed tellus neque. Proin tempus ligula a mi molestie aliquam. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam venenatis consequat ultricies. Sed ac orci purus. Nullam velit nisl, dapibus vel mauris id, dignissim elementum sapien. Vestibulum faucibus sapien ut erat bibendum, id lobortis nisi luctus. Mauris feugiat at lectus at pretium. Pellentesque vitae finibus ante. Nulla non ex neque. Cras varius, lorem facilisis consequat blandit, lorem mauris mollis massa, eget consectetur magna sem vel enim. Nam aliquam risus pulvinar, volutpat leo eget, eleifend urna. Suspendisse in magna sed ligula vehicula volutpat non vitae augue. Phasellus aliquam viverra consequat. Nam rhoncus molestie purus, sed laoreet neque imperdiet eget. Sed egestas metus eget sodales congue. - - Sed vel ante placerat, posuere lacus sit amet, tempus enim. Cras ullamcorper ex vitae metus consequat, a blandit leo semper. Nunc lacinia porta massa, a tempus leo laoreet nec. Sed vel metus tincidunt, scelerisque ex sit amet, lacinia dui. In sollicitudin pulvinar odio vitae hendrerit. Maecenas mollis tempor egestas. Nulla facilisi. Praesent nisi turpis, accumsan eu lobortis vestibulum, ultrices id nibh. Suspendisse sed dui porta, mollis elit sed, ornare sem. Cras molestie est libero, quis faucibus leo semper at. - - Nulla vel nisl rutrum, fringilla elit non, mollis odio. Donec convallis arcu neque, eget venenatis sem mattis nec. Nulla facilisi. Phasellus risus elit, vehicula sit amet risus et, sodales ultrices est. Quisque vulputate felis orci, non tristique leo faucibus in. Duis quis velit urna. Sed rhoncus dolor vel commodo aliquet. In sed tempor quam. Nunc non tempus ipsum. Praesent mi lacus, vehicula eu dolor eu, condimentum venenatis diam. In tristique ligula a ligula dictum, eu dictum lacus consectetur. Proin elementum egestas pharetra. Nunc suscipit dui ac nisl maximus, id congue velit volutpat. Etiam condimentum, mauris ac sodales tristique, est augue accumsan elit, ut luctus est mi ut urna. Mauris commodo, tortor eget gravida lacinia, leo est imperdiet arcu, a ullamcorper dui sapien eget erat. - - Vivamus pulvinar dui et elit volutpat hendrerit. Praesent luctus dolor ut rutrum finibus. Fusce ut odio ultrices, laoreet est at, condimentum turpis. Morbi at ultricies nibh. Mauris tempus imperdiet porta. Proin sit amet tincidunt eros. Quisque rutrum lacus ac est vehicula dictum. Pellentesque nec augue mi. - - Vestibulum rutrum imperdiet nisl, et consequat massa porttitor vel. Ut velit justo, vehicula a nulla eu, auctor eleifend metus. Ut egestas malesuada metus, sit amet pretium nunc commodo ac. Pellentesque gravida, nisl in faucibus volutpat, libero turpis mattis orci, vitae tincidunt ligula ligula ut tortor. Maecenas vehicula lobortis odio in molestie. Curabitur dictum elit sed arcu dictum, ut semper nunc cursus. Donec semper felis non nisl tincidunt elementum. - "#.to_string(); - - rsx! { - - - - - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0))) - .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, KStyle, *}; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("fonts/roboto.kttf")); + + let image = asset_server.load("panel.png"); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + + let nine_patch_styles = KStyle { + width: StyleProp::Value(Units::Pixels(512.0)), + height: StyleProp::Value(Units::Pixels(512.0)), + offset: StyleProp::Value(Edge::all(Units::Stretch(1.0))), + padding: StyleProp::Value(Edge::all(Units::Pixels(25.0))), + ..KStyle::default() + }; + + let lorem_ipsum = r#" +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sed tellus neque. Proin tempus ligula a mi molestie aliquam. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam venenatis consequat ultricies. Sed ac orci purus. Nullam velit nisl, dapibus vel mauris id, dignissim elementum sapien. Vestibulum faucibus sapien ut erat bibendum, id lobortis nisi luctus. Mauris feugiat at lectus at pretium. Pellentesque vitae finibus ante. Nulla non ex neque. Cras varius, lorem facilisis consequat blandit, lorem mauris mollis massa, eget consectetur magna sem vel enim. Nam aliquam risus pulvinar, volutpat leo eget, eleifend urna. Suspendisse in magna sed ligula vehicula volutpat non vitae augue. Phasellus aliquam viverra consequat. Nam rhoncus molestie purus, sed laoreet neque imperdiet eget. Sed egestas metus eget sodales congue. + + Sed vel ante placerat, posuere lacus sit amet, tempus enim. Cras ullamcorper ex vitae metus consequat, a blandit leo semper. Nunc lacinia porta massa, a tempus leo laoreet nec. Sed vel metus tincidunt, scelerisque ex sit amet, lacinia dui. In sollicitudin pulvinar odio vitae hendrerit. Maecenas mollis tempor egestas. Nulla facilisi. Praesent nisi turpis, accumsan eu lobortis vestibulum, ultrices id nibh. Suspendisse sed dui porta, mollis elit sed, ornare sem. Cras molestie est libero, quis faucibus leo semper at. + + Nulla vel nisl rutrum, fringilla elit non, mollis odio. Donec convallis arcu neque, eget venenatis sem mattis nec. Nulla facilisi. Phasellus risus elit, vehicula sit amet risus et, sodales ultrices est. Quisque vulputate felis orci, non tristique leo faucibus in. Duis quis velit urna. Sed rhoncus dolor vel commodo aliquet. In sed tempor quam. Nunc non tempus ipsum. Praesent mi lacus, vehicula eu dolor eu, condimentum venenatis diam. In tristique ligula a ligula dictum, eu dictum lacus consectetur. Proin elementum egestas pharetra. Nunc suscipit dui ac nisl maximus, id congue velit volutpat. Etiam condimentum, mauris ac sodales tristique, est augue accumsan elit, ut luctus est mi ut urna. Mauris commodo, tortor eget gravida lacinia, leo est imperdiet arcu, a ullamcorper dui sapien eget erat. + + Vivamus pulvinar dui et elit volutpat hendrerit. Praesent luctus dolor ut rutrum finibus. Fusce ut odio ultrices, laoreet est at, condimentum turpis. Morbi at ultricies nibh. Mauris tempus imperdiet porta. Proin sit amet tincidunt eros. Quisque rutrum lacus ac est vehicula dictum. Pellentesque nec augue mi. + + Vestibulum rutrum imperdiet nisl, et consequat massa porttitor vel. Ut velit justo, vehicula a nulla eu, auctor eleifend metus. Ut egestas malesuada metus, sit amet pretium nunc commodo ac. Pellentesque gravida, nisl in faucibus volutpat, libero turpis mattis orci, vitae tincidunt ligula ligula ut tortor. Maecenas vehicula lobortis odio in molestie. Curabitur dictum elit sed arcu dictum, ut semper nunc cursus. Donec semper felis non nisl tincidunt elementum. + "#.to_string(); + + rsx! { + + + + + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0))) + .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/conditional_widget.rs b/examples/conditional_widget.rs index 04b8b5b5..54f1451a 100644 --- a/examples/conditional_widget.rs +++ b/examples/conditional_widget.rs @@ -1,138 +1,138 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, *}; - -#[derive(Component, Default, PartialEq, Clone)] -struct MyWidget; - -impl Widget for MyWidget {} - -#[derive(Component, Default, PartialEq, Clone)] -struct MyWidgetState { - pub show_window: bool, -} - -#[derive(Bundle)] -struct MyWidgetBundle { - count: MyWidget, - styles: KStyle, - widget_name: WidgetName, -} - -impl Default for MyWidgetBundle { - fn default() -> Self { - Self { - count: MyWidget::default(), - styles: KStyle::default(), - widget_name: MyWidget::default().get_name(), - } - } -} - -fn my_widget_render( - In(entity): In, - widget_context: Res, - mut commands: Commands, - query: Query<&MyWidgetState>, -) -> bool { - let state_entity = widget_context.use_state(&mut commands, entity, MyWidgetState::default()); - if let Ok(state) = query.get(state_entity) { - let parent_id = Some(entity); - rsx! { - - , - mut event: ResMut, - mut query: Query<&mut MyWidgetState>| { - event.prevent_default(); - event.stop_propagation(); - if let EventType::Click(..) = event.event_type { - if let Ok(mut state) = query.get_mut(state_entity) { - state.show_window = true; - } - } - }, - )} - /> - {if state.show_window { - constructor! { - - , - mut event: ResMut, - mut query: Query<&mut MyWidgetState>| { - if let EventType::Click(..) = event.event_type { - event.prevent_default(); - event.stop_propagation(); - if let Ok(mut state) = query.get_mut(state_entity) { - state.show_window = false; - } - } - }, - )} - /> - - } - }} - - }; - } - - true -} - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("lato-light.kttf")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - widget_context.add_widget_data::(); - widget_context.add_widget_system( - MyWidget::default().get_name(), - widget_update::, - my_widget_render, - ); - rsx! { - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0))) - .add_plugins(DefaultPlugins) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, *}; + +#[derive(Component, Default, PartialEq, Clone)] +struct MyWidget; + +impl Widget for MyWidget {} + +#[derive(Component, Default, PartialEq, Clone)] +struct MyWidgetState { + pub show_window: bool, +} + +#[derive(Bundle)] +struct MyWidgetBundle { + count: MyWidget, + styles: KStyle, + widget_name: WidgetName, +} + +impl Default for MyWidgetBundle { + fn default() -> Self { + Self { + count: MyWidget, + styles: KStyle::default(), + widget_name: MyWidget.get_name(), + } + } +} + +fn my_widget_render( + In(entity): In, + widget_context: Res, + mut commands: Commands, + query: Query<&MyWidgetState>, +) -> bool { + let state_entity = widget_context.use_state(&mut commands, entity, MyWidgetState::default()); + if let Ok(state) = query.get(state_entity) { + let parent_id = Some(entity); + rsx! { + + , + mut event: ResMut, + mut query: Query<&mut MyWidgetState>| { + event.prevent_default(); + event.stop_propagation(); + if let EventType::Click(..) = event.event_type { + if let Ok(mut state) = query.get_mut(state_entity) { + state.show_window = true; + } + } + }, + )} + /> + {if state.show_window { + constructor! { + + , + mut event: ResMut, + mut query: Query<&mut MyWidgetState>| { + if let EventType::Click(..) = event.event_type { + event.prevent_default(); + event.stop_propagation(); + if let Ok(mut state) = query.get_mut(state_entity) { + state.show_window = false; + } + } + }, + )} + /> + + } + }} + + }; + } + + true +} + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("lato-light.kttf")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + widget_context.add_widget_data::(); + widget_context.add_widget_system( + MyWidget.get_name(), + widget_update::, + my_widget_render, + ); + rsx! { + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0))) + .add_plugins(DefaultPlugins) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/context.rs b/examples/context.rs index 28c4f0e8..8ba6720b 100644 --- a/examples/context.rs +++ b/examples/context.rs @@ -1,384 +1,384 @@ -//! This example demonstrates how to use the provider/consumer pattern for passing props down -//! to multiple descendants. -//! -//! The problem we'll be solving here is adding support for theming. -//! -//! One reason the provider/consumer pattern might be favored over a global state is that it allows -//! for better specificity and makes local contexts much easier to manage. In the case of theming, -//! this allows us to have multiple active themes, even if they are nested within each other! - -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, KStyle, *}; - -/// The color theme struct we will be using across our demo widgets -#[derive(Component, Debug, Default, Clone, PartialEq)] -struct Theme { - name: String, - primary: Color, - secondary: Color, - background: Color, -} - -impl Theme { - fn vampire() -> Self { - Self { - name: "Vampire".to_string(), - primary: Color::rgba(1.0, 0.475, 0.776, 1.0), - secondary: Color::rgba(0.641, 0.476, 0.876, 1.0), - background: Color::rgba(0.157, 0.165, 0.212, 1.0), - } - } - fn solar() -> Self { - Self { - name: "Solar".to_string(), - primary: Color::rgba(0.514, 0.580, 0.588, 1.0), - secondary: Color::rgba(0.149, 0.545, 0.824, 1.0), - background: Color::rgba(0.026, 0.212, 0.259, 1.0), - } - } - fn vector() -> Self { - Self { - name: "Vector".to_string(), - primary: Color::rgba(0.533, 1.0, 0.533, 1.0), - secondary: Color::rgba(0.098, 0.451, 0.098, 1.0), - background: Color::rgba(0.004, 0.059, 0.004, 1.0), - } - } -} - -#[derive(Component, Debug, Default, Clone, PartialEq)] -struct ThemeButton { - pub theme: Theme, -} -impl Widget for ThemeButton {} - -#[derive(Bundle)] -pub struct ThemeButtonBundle { - theme_button: ThemeButton, - styles: KStyle, - widget_name: WidgetName, -} - -impl Default for ThemeButtonBundle { - fn default() -> Self { - Self { - theme_button: Default::default(), - styles: KStyle::default(), - widget_name: ThemeButton::default().get_name(), - } - } -} - -fn update_theme_button( - In(theme_button_entity): In, - widget_context: Res, - mut commands: Commands, - query: Query<&ThemeButton>, - mut context_query: Query<&mut Theme>, -) -> bool { - if let Ok(theme_button) = query.get(theme_button_entity) { - if let Some(theme_context_entity) = - widget_context.get_context_entity::(theme_button_entity) - { - if let Ok(theme) = context_query.get_mut(theme_context_entity) { - let mut box_style = KStyle { - width: StyleProp::Value(Units::Pixels(30.0)), - height: StyleProp::Value(Units::Pixels(30.0)), - background_color: StyleProp::Value(theme_button.theme.primary), - ..Default::default() - }; - - if theme_button.theme.name == theme.name { - box_style.top = StyleProp::Value(Units::Pixels(3.0)); - box_style.left = StyleProp::Value(Units::Pixels(3.0)); - box_style.bottom = StyleProp::Value(Units::Pixels(3.0)); - box_style.right = StyleProp::Value(Units::Pixels(3.0)); - box_style.width = StyleProp::Value(Units::Pixels(24.0)); - box_style.height = StyleProp::Value(Units::Pixels(24.0)); - } - - let parent_id = Some(theme_button_entity); - rsx! { - , - event: ResMut, - query: Query<&ThemeButton>, - mut context_query: Query<&mut Theme>, - | { - if let EventType::Click(..) = event.event_type { - if let Ok(button) = query.get(theme_button_entity) { - if let Ok(mut context_theme) = context_query.get_mut(theme_context_entity) { - *context_theme = button.theme.clone(); - } - } - } - }, - )} - /> - }; - } - } - } - - true -} - -#[derive(Component, Debug, Default, Clone, PartialEq)] -struct ThemeSelector; -impl Widget for ThemeSelector {} - -#[derive(Bundle)] -pub struct ThemeSelectorBundle { - theme_selector: ThemeSelector, - styles: KStyle, - widget_name: WidgetName, -} - -impl Default for ThemeSelectorBundle { - fn default() -> Self { - Self { - theme_selector: Default::default(), - styles: KStyle { - height: StyleProp::Value(Units::Auto), - padding_bottom: Units::Pixels(40.0).into(), - ..Default::default() - }, - widget_name: ThemeSelector::default().get_name(), - } - } -} - -fn update_theme_selector( - In(entity): In, - widget_context: Res, - mut commands: Commands, - query: Query<&ThemeSelector>, -) -> bool { - if query.get(entity).is_ok() { - let button_container_style = KStyle { - layout_type: StyleProp::Value(LayoutType::Row), - width: StyleProp::Value(Units::Stretch(1.0)), - height: StyleProp::Value(Units::Auto), - top: StyleProp::Value(Units::Pixels(5.0)), - ..Default::default() - }; - - let vampire_theme = Theme::vampire(); - let solar_theme = Theme::solar(); - let vector_theme = Theme::vector(); - - let parent_id = Some(entity); - rsx! { - - - - - - }; - } - - true -} - -#[derive(Component, Debug, Default, Clone, PartialEq, Eq)] -pub struct ThemeDemo { - is_root: bool, - context_entity: Option, -} -impl Widget for ThemeDemo {} - -#[derive(Bundle)] -pub struct ThemeDemoBundle { - theme_demo: ThemeDemo, - styles: KStyle, - widget_name: WidgetName, -} - -impl Default for ThemeDemoBundle { - fn default() -> Self { - Self { - theme_demo: Default::default(), - styles: KStyle::default(), - widget_name: ThemeDemo::default().get_name(), - } - } -} - -fn update_theme_demo( - In(entity): In, - widget_context: Res, - mut commands: Commands, - mut query_set: Query<&mut ThemeDemo>, - theme_context: Query<&Theme>, -) -> bool { - if let Ok(mut theme_demo) = query_set.get_mut(entity) { - if let Some(theme_context_entity) = widget_context.get_context_entity::(entity) { - if let Ok(theme) = theme_context.get(theme_context_entity) { - let select_lbl = if theme_demo.is_root { - format!("Select Theme (Current: {})", theme.name) - } else { - format!("Select A Different Theme (Current: {})", theme.name) - }; - - if theme_demo.is_root && theme_demo.context_entity.is_none() { - let theme_entity = commands.spawn(Theme::vector()).id(); - theme_demo.context_entity = Some(theme_entity); - } - - let context_entity = if let Some(entity) = theme_demo.context_entity { - entity - } else { - Entity::from_raw(1000000) - }; - let text_styles = KStyle { - color: StyleProp::Value(theme.primary), - height: StyleProp::Value(Units::Pixels(28.0)), - ..Default::default() - }; - let btn_style = KStyle { - background_color: StyleProp::Value(theme.secondary), - width: StyleProp::Value(Units::Stretch(0.75)), - height: StyleProp::Value(Units::Pixels(32.0)), - top: StyleProp::Value(Units::Pixels(5.0)), - left: StyleProp::Value(Units::Stretch(1.0)), - right: StyleProp::Value(Units::Stretch(1.0)), - ..Default::default() - }; - - let parent_id = Some(entity); - rsx! { - - - - - - - { - if theme_demo.is_root { - widget_context.set_context_entity::( - parent_id, - context_entity, - ); - constructor! { - - - - } - } - } - - - }; - } - } - } - - true -} - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kayak_font")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - widget_context.add_widget_data::(); - widget_context.add_widget_data::(); - widget_context.add_widget_data::(); - widget_context.add_widget_system( - ThemeDemo::default().get_name(), - widget_update_with_context::, - update_theme_demo, - ); - widget_context.add_widget_system( - ThemeButton::default().get_name(), - widget_update_with_context::, - update_theme_button, - ); - widget_context.add_widget_system( - ThemeSelector::default().get_name(), - widget_update_with_context::, - update_theme_selector, - ); - let parent_id = None; - rsx! { - - { - let theme_entity = commands.spawn(Theme::vampire()).id(); - widget_context.set_context_entity::(parent_id, theme_entity); - } - - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +//! This example demonstrates how to use the provider/consumer pattern for passing props down +//! to multiple descendants. +//! +//! The problem we'll be solving here is adding support for theming. +//! +//! One reason the provider/consumer pattern might be favored over a global state is that it allows +//! for better specificity and makes local contexts much easier to manage. In the case of theming, +//! this allows us to have multiple active themes, even if they are nested within each other! + +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, KStyle, *}; + +/// The color theme struct we will be using across our demo widgets +#[derive(Component, Debug, Default, Clone, PartialEq)] +struct Theme { + name: String, + primary: Color, + secondary: Color, + background: Color, +} + +impl Theme { + fn vampire() -> Self { + Self { + name: "Vampire".to_string(), + primary: Color::rgba(1.0, 0.475, 0.776, 1.0), + secondary: Color::rgba(0.641, 0.476, 0.876, 1.0), + background: Color::rgba(0.157, 0.165, 0.212, 1.0), + } + } + fn solar() -> Self { + Self { + name: "Solar".to_string(), + primary: Color::rgba(0.514, 0.580, 0.588, 1.0), + secondary: Color::rgba(0.149, 0.545, 0.824, 1.0), + background: Color::rgba(0.026, 0.212, 0.259, 1.0), + } + } + fn vector() -> Self { + Self { + name: "Vector".to_string(), + primary: Color::rgba(0.533, 1.0, 0.533, 1.0), + secondary: Color::rgba(0.098, 0.451, 0.098, 1.0), + background: Color::rgba(0.004, 0.059, 0.004, 1.0), + } + } +} + +#[derive(Component, Debug, Default, Clone, PartialEq)] +struct ThemeButton { + pub theme: Theme, +} +impl Widget for ThemeButton {} + +#[derive(Bundle)] +pub struct ThemeButtonBundle { + theme_button: ThemeButton, + styles: KStyle, + widget_name: WidgetName, +} + +impl Default for ThemeButtonBundle { + fn default() -> Self { + Self { + theme_button: Default::default(), + styles: KStyle::default(), + widget_name: ThemeButton::default().get_name(), + } + } +} + +fn update_theme_button( + In(theme_button_entity): In, + widget_context: Res, + mut commands: Commands, + query: Query<&ThemeButton>, + mut context_query: Query<&mut Theme>, +) -> bool { + if let Ok(theme_button) = query.get(theme_button_entity) { + if let Some(theme_context_entity) = + widget_context.get_context_entity::(theme_button_entity) + { + if let Ok(theme) = context_query.get_mut(theme_context_entity) { + let mut box_style = KStyle { + width: StyleProp::Value(Units::Pixels(30.0)), + height: StyleProp::Value(Units::Pixels(30.0)), + background_color: StyleProp::Value(theme_button.theme.primary), + ..Default::default() + }; + + if theme_button.theme.name == theme.name { + box_style.top = StyleProp::Value(Units::Pixels(3.0)); + box_style.left = StyleProp::Value(Units::Pixels(3.0)); + box_style.bottom = StyleProp::Value(Units::Pixels(3.0)); + box_style.right = StyleProp::Value(Units::Pixels(3.0)); + box_style.width = StyleProp::Value(Units::Pixels(24.0)); + box_style.height = StyleProp::Value(Units::Pixels(24.0)); + } + + let parent_id = Some(theme_button_entity); + rsx! { + , + event: ResMut, + query: Query<&ThemeButton>, + mut context_query: Query<&mut Theme>, + | { + if let EventType::Click(..) = event.event_type { + if let Ok(button) = query.get(theme_button_entity) { + if let Ok(mut context_theme) = context_query.get_mut(theme_context_entity) { + *context_theme = button.theme.clone(); + } + } + } + }, + )} + /> + }; + } + } + } + + true +} + +#[derive(Component, Debug, Default, Clone, PartialEq)] +struct ThemeSelector; +impl Widget for ThemeSelector {} + +#[derive(Bundle)] +pub struct ThemeSelectorBundle { + theme_selector: ThemeSelector, + styles: KStyle, + widget_name: WidgetName, +} + +impl Default for ThemeSelectorBundle { + fn default() -> Self { + Self { + theme_selector: Default::default(), + styles: KStyle { + height: StyleProp::Value(Units::Auto), + padding_bottom: Units::Pixels(40.0).into(), + ..Default::default() + }, + widget_name: ThemeSelector.get_name(), + } + } +} + +fn update_theme_selector( + In(entity): In, + widget_context: Res, + mut commands: Commands, + query: Query<&ThemeSelector>, +) -> bool { + if query.get(entity).is_ok() { + let button_container_style = KStyle { + layout_type: StyleProp::Value(LayoutType::Row), + width: StyleProp::Value(Units::Stretch(1.0)), + height: StyleProp::Value(Units::Auto), + top: StyleProp::Value(Units::Pixels(5.0)), + ..Default::default() + }; + + let vampire_theme = Theme::vampire(); + let solar_theme = Theme::solar(); + let vector_theme = Theme::vector(); + + let parent_id = Some(entity); + rsx! { + + + + + + }; + } + + true +} + +#[derive(Component, Debug, Default, Clone, PartialEq, Eq)] +pub struct ThemeDemo { + is_root: bool, + context_entity: Option, +} +impl Widget for ThemeDemo {} + +#[derive(Bundle)] +pub struct ThemeDemoBundle { + theme_demo: ThemeDemo, + styles: KStyle, + widget_name: WidgetName, +} + +impl Default for ThemeDemoBundle { + fn default() -> Self { + Self { + theme_demo: Default::default(), + styles: KStyle::default(), + widget_name: ThemeDemo::default().get_name(), + } + } +} + +fn update_theme_demo( + In(entity): In, + widget_context: Res, + mut commands: Commands, + mut query_set: Query<&mut ThemeDemo>, + theme_context: Query<&Theme>, +) -> bool { + if let Ok(mut theme_demo) = query_set.get_mut(entity) { + if let Some(theme_context_entity) = widget_context.get_context_entity::(entity) { + if let Ok(theme) = theme_context.get(theme_context_entity) { + let select_lbl = if theme_demo.is_root { + format!("Select Theme (Current: {})", theme.name) + } else { + format!("Select A Different Theme (Current: {})", theme.name) + }; + + if theme_demo.is_root && theme_demo.context_entity.is_none() { + let theme_entity = commands.spawn(Theme::vector()).id(); + theme_demo.context_entity = Some(theme_entity); + } + + let context_entity = if let Some(entity) = theme_demo.context_entity { + entity + } else { + Entity::from_raw(1000000) + }; + let text_styles = KStyle { + color: StyleProp::Value(theme.primary), + height: StyleProp::Value(Units::Pixels(28.0)), + ..Default::default() + }; + let btn_style = KStyle { + background_color: StyleProp::Value(theme.secondary), + width: StyleProp::Value(Units::Stretch(0.75)), + height: StyleProp::Value(Units::Pixels(32.0)), + top: StyleProp::Value(Units::Pixels(5.0)), + left: StyleProp::Value(Units::Stretch(1.0)), + right: StyleProp::Value(Units::Stretch(1.0)), + ..Default::default() + }; + + let parent_id = Some(entity); + rsx! { + + + + + + + { + if theme_demo.is_root { + widget_context.set_context_entity::( + parent_id, + context_entity, + ); + constructor! { + + + + } + } + } + + + }; + } + } + } + + true +} + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kayak_font")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + widget_context.add_widget_data::(); + widget_context.add_widget_data::(); + widget_context.add_widget_data::(); + widget_context.add_widget_system( + ThemeDemo::default().get_name(), + widget_update_with_context::, + update_theme_demo, + ); + widget_context.add_widget_system( + ThemeButton::default().get_name(), + widget_update_with_context::, + update_theme_button, + ); + widget_context.add_widget_system( + ThemeSelector.get_name(), + widget_update_with_context::, + update_theme_selector, + ); + let parent_id = None; + rsx! { + + { + let theme_entity = commands.spawn(Theme::vampire()).id(); + widget_context.set_context_entity::(parent_id, theme_entity); + } + + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/custom_shader.rs b/examples/custom_shader.rs index 9ddd4631..99a2403b 100644 --- a/examples/custom_shader.rs +++ b/examples/custom_shader.rs @@ -1,15 +1,10 @@ -use bevy::{ - prelude::*, - reflect::{TypePath, TypeUuid}, - render::render_resource::AsBindGroup, -}; +use bevy::{prelude::*, reflect::TypePath, render::render_resource::AsBindGroup}; use kayak_ui::{ prelude::{widgets::*, *}, CameraUIKayak, }; -#[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)] -#[uuid = "94c4e6f9-6f10-422c-85ec-6d582d471afc"] +#[derive(AsBindGroup, Asset, TypePath, Debug, Clone)] pub struct MyUIMaterial {} impl MaterialUI for MyUIMaterial { fn fragment_shader() -> bevy::render::render_resource::ShaderRef { diff --git a/examples/demo.rs b/examples/demo.rs index eecc2dfa..d4f15421 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -1,77 +1,77 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, *}; - -#[derive(Debug, Component, Default, Clone, PartialEq, Eq)] -pub struct MyWidget { - pub foo: u32, -} - -fn my_widget_1_render( - In(entity): In, - mut _commands: Commands, - query: Query<&MyWidget>, -) -> bool { - if let Ok(my_widget) = query.get(entity) { - dbg!(my_widget.foo); - } - - true -} - -impl Widget for MyWidget {} - -fn startup(mut commands: Commands) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - let mut context = KayakRootContext::new(camera_entity); - context.add_plugin(KayakWidgetsContextPlugin); - context.add_widget_system( - MyWidget::default().get_name(), - widget_update::, - my_widget_1_render, - ); - context.add_widget_data::(); - - let app_entity = commands.spawn_empty().id(); - let mut children = KChildren::default(); - let entity = commands - .spawn(( - MyWidget { foo: 0 }, - kayak_ui::prelude::KStyle::default(), - MyWidget::default().get_name(), - )) - .id(); - children.add(entity); - - commands.entity(app_entity).insert(KayakAppBundle { - children, - ..KayakAppBundle::default() - }); - context.add_widget(None, app_entity); - - commands.spawn((context, EventDispatcher::default())); -} - -// Note this example shows prop changing not state changing which is quite different. -// For state changes please see simple_state example. -fn update_resource( - keyboard_input: Res>, - mut query: Query<&mut MyWidget, Without>, -) { - if keyboard_input.just_pressed(KeyCode::Space) { - for mut my_widget in query.iter_mut() { - my_widget.foo += 1; - } - } -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .add_systems(Update, update_resource) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, *}; + +#[derive(Debug, Component, Default, Clone, PartialEq, Eq)] +pub struct MyWidget { + pub foo: u32, +} + +fn my_widget_1_render( + In(entity): In, + mut _commands: Commands, + query: Query<&MyWidget>, +) -> bool { + if let Ok(my_widget) = query.get(entity) { + dbg!(my_widget.foo); + } + + true +} + +impl Widget for MyWidget {} + +fn startup(mut commands: Commands) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + let mut context = KayakRootContext::new(camera_entity); + context.add_plugin(KayakWidgetsContextPlugin); + context.add_widget_system( + MyWidget::default().get_name(), + widget_update::, + my_widget_1_render, + ); + context.add_widget_data::(); + + let app_entity = commands.spawn_empty().id(); + let mut children = KChildren::default(); + let entity = commands + .spawn(( + MyWidget { foo: 0 }, + kayak_ui::prelude::KStyle::default(), + MyWidget::default().get_name(), + )) + .id(); + children.add(entity); + + commands.entity(app_entity).insert(KayakAppBundle { + children, + ..KayakAppBundle::default() + }); + context.add_widget(None, app_entity); + + commands.spawn((context, EventDispatcher::default())); +} + +// Note this example shows prop changing not state changing which is quite different. +// For state changes please see simple_state example. +fn update_resource( + keyboard_input: Res>, + mut query: Query<&mut MyWidget, Without>, +) { + if keyboard_input.just_pressed(KeyCode::Space) { + for mut my_widget in query.iter_mut() { + my_widget.foo += 1; + } + } +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .add_systems(Update, update_resource) + .run() +} diff --git a/examples/font_size_test.rs b/examples/font_size_test.rs index 39626c7c..9e7a57b8 100644 --- a/examples/font_size_test.rs +++ b/examples/font_size_test.rs @@ -1,60 +1,60 @@ -use bevy::prelude::*; -use kayak_ui::{ - prelude::{widgets::*, *}, - CameraUIKayak, -}; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn(Camera2dBundle::default()) - .insert(CameraUIKayak) - .id(); - - font_mapping.set_default(asset_server.load("fonts/roboto.kttf")); - font_mapping.force_subpixel(&asset_server.load("fonts/roboto.kttf")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - rsx! { - - - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::{ + prelude::{widgets::*, *}, + CameraUIKayak, +}; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn(Camera2dBundle::default()) + .insert(CameraUIKayak) + .id(); + + font_mapping.set_default(asset_server.load("fonts/roboto.kttf")); + font_mapping.force_subpixel(&asset_server.load("fonts/roboto.kttf")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + rsx! { + + + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 741a22e8..79915cab 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -1,44 +1,44 @@ -use bevy::prelude::*; -use kayak_ui::{ - prelude::{widgets::*, *}, - CameraUIKayak, -}; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn(Camera2dBundle::default()) - .insert(CameraUIKayak) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kayak_font")); - // font_mapping.force_subpixel(&asset_server.load("roboto.kayak_font")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - rsx! { - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::{ + prelude::{widgets::*, *}, + CameraUIKayak, +}; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn(Camera2dBundle::default()) + .insert(CameraUIKayak) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kayak_font")); + // font_mapping.force_subpixel(&asset_server.load("roboto.kayak_font")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + rsx! { + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/hello_world_no_macro.rs b/examples/hello_world_no_macro.rs index 46a55aa1..91825efb 100644 --- a/examples/hello_world_no_macro.rs +++ b/examples/hello_world_no_macro.rs @@ -1,55 +1,55 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, *}; -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn(Camera2dBundle::default()) - .insert(CameraUIKayak) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kayak_font")); - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - - let app_entity = widget_context.spawn_widget(&mut commands, None, None); - // Create default app bundle - let mut app_bundle = KayakAppBundle { - ..Default::default() - }; - - // Create app's children - let mut children = KChildren::new(); - - // Create the text child - let text_entity = widget_context.spawn_widget(&mut commands, None, None); - commands.entity(text_entity).insert(TextWidgetBundle { - text: TextProps { - content: "Hello World".into(), - ..Default::default() - }, - ..Default::default() - }); - // Add the text as a child of the App Widget. - children.add(text_entity); - - // Finalize app bundle and add to entity. - app_bundle.children = children; - commands.entity(app_entity).insert(app_bundle); - - // Add app widget to context. - widget_context.add_widget(None, app_entity); - - // Add widget context as resource. - - commands.spawn((widget_context, EventDispatcher::default())); -} -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, *}; +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn(Camera2dBundle::default()) + .insert(CameraUIKayak) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kayak_font")); + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + + let app_entity = widget_context.spawn_widget(&mut commands, None, None); + // Create default app bundle + let mut app_bundle = KayakAppBundle { + ..Default::default() + }; + + // Create app's children + let mut children = KChildren::new(); + + // Create the text child + let text_entity = widget_context.spawn_widget(&mut commands, None, None); + commands.entity(text_entity).insert(TextWidgetBundle { + text: TextProps { + content: "Hello World".into(), + ..Default::default() + }, + ..Default::default() + }); + // Add the text as a child of the App Widget. + children.add(text_entity); + + // Finalize app bundle and add to entity. + app_bundle.children = children; + commands.entity(app_entity).insert(app_bundle); + + // Add app widget to context. + widget_context.add_widget(None, app_entity); + + // Add widget context as resource. + + commands.spawn((widget_context, EventDispatcher::default())); +} +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/image.rs b/examples/image.rs index 089cab70..86c5c7e7 100644 --- a/examples/image.rs +++ b/examples/image.rs @@ -1,46 +1,46 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, KStyle, *}; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kayak_font")); - - let image = asset_server.load("generic-rpg-vendor.png"); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - rsx! { - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, KStyle, *}; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kayak_font")); + + let image = asset_server.load("generic-rpg-vendor.png"); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + rsx! { + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/layout.rs b/examples/layout.rs index ee0950cb..85e331b6 100644 --- a/examples/layout.rs +++ b/examples/layout.rs @@ -1,142 +1,142 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, *}; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kayak_font")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - - rsx! { - - - - - - - - - - - - - - - - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, *}; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kayak_font")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + + rsx! { + + + + + + + + + + + + + + + + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/main_menu.rs b/examples/main_menu.rs index 7b33cef6..3e2625db 100644 --- a/examples/main_menu.rs +++ b/examples/main_menu.rs @@ -1,221 +1,221 @@ -use bevy::{app::AppExit, prelude::*}; -use kayak_ui::prelude::{widgets::*, *}; - -#[derive(Default, Clone, PartialEq, Component)] -pub struct MenuButton { - text: String, -} - -impl Widget for MenuButton {} - -#[derive(Bundle)] -pub struct MenuButtonBundle { - button: MenuButton, - styles: KStyle, - on_event: OnEvent, - widget_name: WidgetName, -} - -impl Default for MenuButtonBundle { - fn default() -> Self { - Self { - button: Default::default(), - styles: KStyle { - bottom: Units::Pixels(20.0).into(), - cursor: KCursorIcon(CursorIcon::Hand).into(), - ..Default::default() - }, - on_event: OnEvent::default(), - widget_name: MenuButton::default().get_name(), - } - } -} - -fn menu_button_render( - In(entity): In, - widget_context: Res, - mut commands: Commands, - asset_server: Res, - menu_button_query: Query<&MenuButton>, - state_query: Query<&ButtonState>, -) -> bool { - let state_entity = - widget_context.use_state(&mut commands, entity, ButtonState { hovering: false }); - - let button_text = menu_button_query.get(entity).unwrap().text.clone(); - let button_image = asset_server.load("main_menu/button.png"); - let button_image_hover = asset_server.load("main_menu/button-hover.png"); - - let on_event = OnEvent::new( - move |In(_entity): In, - mut event: ResMut, - mut query: Query<&mut ButtonState>| { - if let Ok(mut button) = query.get_mut(state_entity) { - match event.event_type { - EventType::MouseIn(..) => { - event.stop_propagation(); - button.hovering = true; - } - EventType::MouseOut(..) => { - button.hovering = false; - } - _ => {} - } - } - }, - ); - - if let Ok(button_state) = state_query.get(state_entity) { - let button_image_handle = if button_state.hovering { - button_image_hover - } else { - button_image - }; - - let parent_id = Some(entity); - rsx! { - - - - }; - } - true -} - -#[derive(Default, Resource)] -pub struct PreloadResource { - images: Vec>, -} - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, - mut preload_resource: ResMut, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("lato-light.kttf")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - widget_context.add_widget_data::(); - widget_context.add_widget_system( - MenuButton::default().get_name(), - widget_update::, - menu_button_render, - ); - - let panel1_image = asset_server.load("main_menu/panel1.png"); - let logo_image = asset_server.load("main_menu/logo.png"); - let kayak_image = asset_server.load("main_menu/kayak.png"); - let button_image = asset_server.load("main_menu/button.png"); - let button_image_hover = asset_server.load("main_menu/button-hover.png"); - - preload_resource.images.extend(vec![ - panel1_image.clone(), - logo_image.clone(), - button_image, - button_image_hover, - ]); - - let handle_click_close = OnEvent::new( - move |In(_entity): In, event: ResMut, mut exit: EventWriter| { - if let EventType::Click(..) = event.event_type { - exit.send(AppExit); - } - }, - ); - - let parent_id = None; - rsx! { - - - - - - - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .init_resource::() - .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::{app::AppExit, prelude::*}; +use kayak_ui::prelude::{widgets::*, *}; + +#[derive(Default, Clone, PartialEq, Component)] +pub struct MenuButton { + text: String, +} + +impl Widget for MenuButton {} + +#[derive(Bundle)] +pub struct MenuButtonBundle { + button: MenuButton, + styles: KStyle, + on_event: OnEvent, + widget_name: WidgetName, +} + +impl Default for MenuButtonBundle { + fn default() -> Self { + Self { + button: Default::default(), + styles: KStyle { + bottom: Units::Pixels(20.0).into(), + cursor: KCursorIcon(CursorIcon::Hand).into(), + ..Default::default() + }, + on_event: OnEvent::default(), + widget_name: MenuButton::default().get_name(), + } + } +} + +fn menu_button_render( + In(entity): In, + widget_context: Res, + mut commands: Commands, + asset_server: Res, + menu_button_query: Query<&MenuButton>, + state_query: Query<&ButtonState>, +) -> bool { + let state_entity = + widget_context.use_state(&mut commands, entity, ButtonState { hovering: false }); + + let button_text = menu_button_query.get(entity).unwrap().text.clone(); + let button_image = asset_server.load("main_menu/button.png"); + let button_image_hover = asset_server.load("main_menu/button-hover.png"); + + let on_event = OnEvent::new( + move |In(_entity): In, + mut event: ResMut, + mut query: Query<&mut ButtonState>| { + if let Ok(mut button) = query.get_mut(state_entity) { + match event.event_type { + EventType::MouseIn(..) => { + event.stop_propagation(); + button.hovering = true; + } + EventType::MouseOut(..) => { + button.hovering = false; + } + _ => {} + } + } + }, + ); + + if let Ok(button_state) = state_query.get(state_entity) { + let button_image_handle = if button_state.hovering { + button_image_hover + } else { + button_image + }; + + let parent_id = Some(entity); + rsx! { + + + + }; + } + true +} + +#[derive(Default, Resource)] +pub struct PreloadResource { + images: Vec>, +} + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, + mut preload_resource: ResMut, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("lato-light.kttf")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + widget_context.add_widget_data::(); + widget_context.add_widget_system( + MenuButton::default().get_name(), + widget_update::, + menu_button_render, + ); + + let panel1_image = asset_server.load("main_menu/panel1.png"); + let logo_image = asset_server.load("main_menu/logo.png"); + let kayak_image = asset_server.load("main_menu/kayak.png"); + let button_image = asset_server.load("main_menu/button.png"); + let button_image_hover = asset_server.load("main_menu/button-hover.png"); + + preload_resource.images.extend(vec![ + panel1_image.clone(), + logo_image.clone(), + button_image, + button_image_hover, + ]); + + let handle_click_close = OnEvent::new( + move |In(_entity): In, event: ResMut, mut exit: EventWriter| { + if let EventType::Click(..) = event.event_type { + exit.send(AppExit); + } + }, + ); + + let parent_id = None; + rsx! { + + + + + + + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .init_resource::() + .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/modal.rs b/examples/modal.rs index a3907ca9..789a23f2 100644 --- a/examples/modal.rs +++ b/examples/modal.rs @@ -1,12 +1,7 @@ -use bevy::{ - prelude::*, - reflect::{TypePath, TypeUuid}, - render::render_resource::AsBindGroup, -}; +use bevy::{prelude::*, reflect::TypePath, render::render_resource::AsBindGroup}; use kayak_ui::prelude::{widgets::*, *}; -#[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)] -#[uuid = "94c4e6f9-6f10-422c-85ec-6d582d471afc"] +#[derive(AsBindGroup, Asset, TypePath, Debug, Clone)] pub struct MyUIMaterial {} impl MaterialUI for MyUIMaterial { fn fragment_shader() -> bevy::render::render_resource::ShaderRef { @@ -34,9 +29,9 @@ struct MyWidgetBundle { impl Default for MyWidgetBundle { fn default() -> Self { Self { - count: MyWidget::default(), + count: MyWidget, styles: KStyle::default(), - widget_name: MyWidget::default().get_name(), + widget_name: MyWidget.get_name(), } } } @@ -145,7 +140,7 @@ fn startup( let parent_id = None; widget_context.add_widget_data::(); widget_context.add_widget_system( - MyWidget::default().get_name(), + MyWidget.get_name(), widget_update::, my_widget_render, ); diff --git a/examples/nine_patch.rs b/examples/nine_patch.rs index 5c5b7930..405d59b3 100644 --- a/examples/nine_patch.rs +++ b/examples/nine_patch.rs @@ -1,67 +1,67 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, KStyle, *}; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kayak_font")); - - let image = asset_server.load("panel.png"); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - - // The border prop splits up the image into 9 quadrants like so: - // 1----2----3 - // | | - // 4 9 5 - // | | - // 6----7----8 - // The sizes of sprites for a 15 pixel border are as follows: - // TopLeft = (15, 15) - // TopRight = (15, 15) - // LeftCenter = (15, image_height) - // RightCenter = (15, image_height) - // TopCenter = (image_width, 15) - // BottomCenter = (image_width, 15) - // BottomRight = (15, 15) - // BottomLeft = (15, 15) - // Middle = ( - // 30 being left border + right border - // image_width - 30 - // 30 being top border + bottom border - // image_height - 30 - // ) - rsx! { - - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, KStyle, *}; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kayak_font")); + + let image = asset_server.load("panel.png"); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + + // The border prop splits up the image into 9 quadrants like so: + // 1----2----3 + // | | + // 4 9 5 + // | | + // 6----7----8 + // The sizes of sprites for a 15 pixel border are as follows: + // TopLeft = (15, 15) + // TopRight = (15, 15) + // LeftCenter = (15, image_height) + // RightCenter = (15, image_height) + // TopCenter = (image_width, 15) + // BottomCenter = (image_width, 15) + // BottomRight = (15, 15) + // BottomLeft = (15, 15) + // Middle = ( + // 30 being left border + right border + // image_width - 30 + // 30 being top border + bottom border + // image_height - 30 + // ) + rsx! { + + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/opacity_layers.rs b/examples/opacity_layers.rs index 0ed151db..32afe69d 100644 --- a/examples/opacity_layers.rs +++ b/examples/opacity_layers.rs @@ -1,62 +1,62 @@ -use bevy::prelude::*; -use kayak_ui::prelude::{widgets::*, *}; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("lato-light.kttf")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - let spacing = Vec2::new(50.0, 50.0); - rsx! { - - - { - // Opacity layers are limited to 5 maximum at a time for a given camera. - let max_windows = 5; - let mut alpha = 0.1; - for i in 1..(max_windows + 1) { - constructor! { - - } - alpha = i as f32 / (max_windows - 1) as f32; - } - } - - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0))) - .add_plugins(DefaultPlugins) - .add_plugins((KayakContextPlugin, KayakWidgets)) - .add_systems(Startup, startup) - .run() -} +use bevy::prelude::*; +use kayak_ui::prelude::{widgets::*, *}; + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("lato-light.kttf")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + let spacing = Vec2::new(50.0, 50.0); + rsx! { + + + { + // Opacity layers are limited to 5 maximum at a time for a given camera. + let max_windows = 5; + let mut alpha = 0.1; + for i in 1..(max_windows + 1) { + constructor! { + + } + alpha = i as f32 / (max_windows - 1) as f32; + } + } + + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0))) + .add_plugins(DefaultPlugins) + .add_plugins((KayakContextPlugin, KayakWidgets)) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/quads.rs b/examples/quads.rs index 44ec9b72..ac3a910f 100644 --- a/examples/quads.rs +++ b/examples/quads.rs @@ -1,146 +1,146 @@ -use bevy::{ - diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, - prelude::*, -}; -use kayak_ui::prelude::{widgets::*, KStyle, *}; - -#[derive(Component, Default, Clone, PartialEq)] -pub struct MyQuad { - pos: Vec2, - pub size: Vec2, - pub color: Color, - pub z_index: i32, -} - -fn my_quad_update( - In(entity): In, - mut query: Query<(&MyQuad, &KStyle, &mut ComputedStyles, &mut OnEvent)>, -) -> bool { - if let Ok((quad, style, mut computed_styles, mut on_event)) = query.get_mut(entity) { - *computed_styles = KStyle::default() - .with_style(KStyle { - render_command: StyleProp::Value(RenderCommand::Quad), - position_type: StyleProp::Value(KPositionType::SelfDirected), - left: StyleProp::Value(Units::Pixels(quad.pos.x)), - top: StyleProp::Value(Units::Pixels(quad.pos.y)), - width: StyleProp::Value(Units::Pixels(quad.size.x)), - height: StyleProp::Value(Units::Pixels(quad.size.y)), - z_index: StyleProp::Value(quad.z_index), - ..Default::default() - }) - .with_style(style) - .with_style(KStyle { - background_color: StyleProp::Value(quad.color), - ..Default::default() - }) - .into(); - - *on_event = OnEvent::new( - move |In(_entity): In, - mut event: ResMut, - mut query: Query<(&mut KStyle, &MyQuad)>| { - event.prevent_default(); - event.stop_propagation(); - match event.event_type { - EventType::MouseIn(..) => { - if let Ok((mut styles, _)) = query.get_mut(entity) { - styles.background_color = StyleProp::Value(Color::WHITE); - } - } - EventType::MouseOut(..) => { - if let Ok((mut styles, my_quad)) = query.get_mut(entity) { - styles.background_color = StyleProp::Value(my_quad.color); - } - } - _ => {} - } - }, - ); - } - - true -} - -impl Widget for MyQuad {} - -#[derive(Bundle)] -pub struct MyQuadBundle { - my_quad: MyQuad, - styles: KStyle, - computed_styles: ComputedStyles, - on_event: OnEvent, - widget_name: WidgetName, -} - -impl Default for MyQuadBundle { - fn default() -> Self { - Self { - my_quad: Default::default(), - styles: KStyle::default(), - on_event: OnEvent::default(), - computed_styles: ComputedStyles::default(), - widget_name: MyQuad::default().get_name(), - } - } -} - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, -) { - let camera_entity = commands - .spawn((Camera2dBundle::default(), CameraUIKayak)) - .id(); - - font_mapping.set_default(asset_server.load("roboto.kayak_font")); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - widget_context.add_widget_system( - MyQuad::default().get_name(), - widget_update::, - my_quad_update, - ); - let parent_id = None; - - rsx! { - - { - (0..1000i32).for_each(|i| { - let pos = Vec2::new(fastrand::i32(0..1280) as f32, fastrand::i32(0..720) as f32); - let size = Vec2::new( - fastrand::i32(32..64) as f32, - fastrand::i32(32..64) as f32, - ); - let color = Color::rgba( - fastrand::f32(), - fastrand::f32(), - fastrand::f32(), - fastrand::f32(), - ); - constructor! { - - } - }); - } - - }; - - commands.spawn((widget_context, EventDispatcher::default())); -} - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugins(( - LogDiagnosticsPlugin::default(), - FrameTimeDiagnosticsPlugin::default(), - KayakContextPlugin, - KayakWidgets, - )) - .add_systems(Startup, startup) - .run() -} +use bevy::{ + diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, + prelude::*, +}; +use kayak_ui::prelude::{widgets::*, KStyle, *}; + +#[derive(Component, Default, Clone, PartialEq)] +pub struct MyQuad { + pos: Vec2, + pub size: Vec2, + pub color: Color, + pub z_index: i32, +} + +fn my_quad_update( + In(entity): In, + mut query: Query<(&MyQuad, &KStyle, &mut ComputedStyles, &mut OnEvent)>, +) -> bool { + if let Ok((quad, style, mut computed_styles, mut on_event)) = query.get_mut(entity) { + *computed_styles = KStyle::default() + .with_style(KStyle { + render_command: StyleProp::Value(RenderCommand::Quad), + position_type: StyleProp::Value(KPositionType::SelfDirected), + left: StyleProp::Value(Units::Pixels(quad.pos.x)), + top: StyleProp::Value(Units::Pixels(quad.pos.y)), + width: StyleProp::Value(Units::Pixels(quad.size.x)), + height: StyleProp::Value(Units::Pixels(quad.size.y)), + z_index: StyleProp::Value(quad.z_index), + ..Default::default() + }) + .with_style(style) + .with_style(KStyle { + background_color: StyleProp::Value(quad.color), + ..Default::default() + }) + .into(); + + *on_event = OnEvent::new( + move |In(_entity): In, + mut event: ResMut, + mut query: Query<(&mut KStyle, &MyQuad)>| { + event.prevent_default(); + event.stop_propagation(); + match event.event_type { + EventType::MouseIn(..) => { + if let Ok((mut styles, _)) = query.get_mut(entity) { + styles.background_color = StyleProp::Value(Color::WHITE); + } + } + EventType::MouseOut(..) => { + if let Ok((mut styles, my_quad)) = query.get_mut(entity) { + styles.background_color = StyleProp::Value(my_quad.color); + } + } + _ => {} + } + }, + ); + } + + true +} + +impl Widget for MyQuad {} + +#[derive(Bundle)] +pub struct MyQuadBundle { + my_quad: MyQuad, + styles: KStyle, + computed_styles: ComputedStyles, + on_event: OnEvent, + widget_name: WidgetName, +} + +impl Default for MyQuadBundle { + fn default() -> Self { + Self { + my_quad: Default::default(), + styles: KStyle::default(), + on_event: OnEvent::default(), + computed_styles: ComputedStyles::default(), + widget_name: MyQuad::default().get_name(), + } + } +} + +fn startup( + mut commands: Commands, + mut font_mapping: ResMut, + asset_server: Res, +) { + let camera_entity = commands + .spawn((Camera2dBundle::default(), CameraUIKayak)) + .id(); + + font_mapping.set_default(asset_server.load("roboto.kayak_font")); + + let mut widget_context = KayakRootContext::new(camera_entity); + widget_context.add_plugin(KayakWidgetsContextPlugin); + widget_context.add_widget_system( + MyQuad::default().get_name(), + widget_update::, + my_quad_update, + ); + let parent_id = None; + + rsx! { + + { + (0..1000i32).for_each(|i| { + let pos = Vec2::new(fastrand::i32(0..1280) as f32, fastrand::i32(0..720) as f32); + let size = Vec2::new( + fastrand::i32(32..64) as f32, + fastrand::i32(32..64) as f32, + ); + let color = Color::rgba( + fastrand::f32(), + fastrand::f32(), + fastrand::f32(), + fastrand::f32(), + ); + constructor! { + + } + }); + } + + }; + + commands.spawn((widget_context, EventDispatcher::default())); +} + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_plugins(( + LogDiagnosticsPlugin::default(), + FrameTimeDiagnosticsPlugin, + KayakContextPlugin, + KayakWidgets, + )) + .add_systems(Startup, startup) + .run() +} diff --git a/examples/render_target.rs b/examples/render_target.rs index 484b00ca..1d5bfec1 100644 --- a/examples/render_target.rs +++ b/examples/render_target.rs @@ -1,189 +1,189 @@ -use bevy::{ - prelude::*, - render::{ - camera::RenderTarget, - render_resource::{ - Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, - }, - }, -}; -use kayak_ui::{ - prelude::{widgets::*, *}, - CameraUIKayak, -}; - -// Marks the main pass cube, to which the texture is applied. -#[derive(Component)] -struct MainPassCube; - -#[derive(Component)] -struct MainUI; - -fn startup( - mut commands: Commands, - mut font_mapping: ResMut, - asset_server: Res, - mut meshes: ResMut>, - mut materials: ResMut>, - mut images: ResMut>, -) { - font_mapping.set_default(asset_server.load("roboto.kayak_font")); - - let size = Extent3d { - width: 1024, - height: 1024, - ..default() - }; - - // This is the texture that will be rendered to. - let mut image = Image { - texture_descriptor: TextureDescriptor { - label: None, - size, - dimension: TextureDimension::D2, - view_formats: &[TextureFormat::Bgra8UnormSrgb], - format: TextureFormat::Bgra8UnormSrgb, - mip_level_count: 1, - sample_count: 1, - usage: TextureUsages::TEXTURE_BINDING - | TextureUsages::COPY_DST - | TextureUsages::RENDER_ATTACHMENT, - }, - ..default() - }; - - // fill image.data with zeroes - image.resize(size); - - let image_handle = images.add(image); - - let camera_entity = commands - .spawn(Camera2dBundle { - camera: Camera { - order: -1, - target: RenderTarget::Image(image_handle.clone()), - ..Camera::default() - }, - camera_2d: Camera2d { - clear_color: bevy::core_pipeline::clear_color::ClearColorConfig::Default, - }, - ..Default::default() - }) - .insert(CameraUIKayak) - .id(); - - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - rsx! { - - - - }; - commands.spawn((widget_context, EventDispatcher::default())); - - // Setup 3D scene - // Light - commands.spawn(PointLightBundle { - transform: Transform::from_translation(Vec3::new(0.0, 0.0, 10.0)), - ..default() - }); - - let cube_size = 4.0; - let cube_handle = meshes.add(Mesh::from(shape::Box::new(cube_size, cube_size, cube_size))); - - // This material has the texture that has been rendered. - let material_handle = materials.add(StandardMaterial { - base_color_texture: Some(image_handle), - reflectance: 0.02, - unlit: false, - ..default() - }); - - // Main pass cube, with material containing the rendered first pass texture. - commands - .spawn(PbrBundle { - mesh: cube_handle, - material: material_handle, - transform: Transform { - translation: Vec3::new(0.0, 0.0, 1.5), - rotation: Quat::from_rotation_x(-std::f32::consts::PI / 5.0), - ..default() - }, - ..default() - }) - .insert(MainPassCube); - - // The main pass camera. - let camera_entity = commands - .spawn(Camera3dBundle { - transform: Transform::from_translation(Vec3::new(0.0, 0.0, 15.0)) - .looking_at(Vec3::default(), Vec3::Y), - ..default() - }) - .insert(CameraUIKayak) - .id(); - - // Spawn another UI in 2D space! - let mut widget_context = KayakRootContext::new(camera_entity); - widget_context.add_plugin(KayakWidgetsContextPlugin); - let parent_id = None; - rsx! { - - - - }; - commands.spawn((widget_context, EventDispatcher::default(), MainUI)); -} - -/// Rotates the outer cube (main pass) -fn cube_rotator_system(time: Res