🎮ArcadeLab

Травник

by GoldenBear87
2293 lines43.1 KB
▶ Play
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Травник</title>

<style>
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@400;500;600;700&family=IM+Fell+English+SC&display=swap');

*{
    box-sizing:border-box;
    -webkit-tap-highlight-color:transparent;
}

html,body{
    margin:0;
    width:100%;
    height:100%;
    overflow:hidden;
    background:#10130f;
    color:#fff;
    font-family:"Cormorant Garamond",Georgia,serif;
    touch-action:none;
}

button{
    font:inherit;
}

#forest{
    position:fixed;
    inset:0;
    width:100%;
    height:100%;
    object-fit:cover;
    z-index:0;
    user-select:none;
    animation:forestBreath 14s ease-in-out infinite alternate;
}

@keyframes forestBreath{
    from{
        transform:scale(1);
    }
    to{
        transform:scale(1.035);
    }
}

.scene-dark{
    position:fixed;
    inset:0;
    z-index:1;
    pointer-events:none;
    background:
        radial-gradient(
            ellipse at 50% 42%,
            rgba(74,92,52,.06),
            rgba(0,0,0,.65) 75%
        ),
        linear-gradient(
            to bottom,
            rgba(0,0,0,.16),
            rgba(0,0,0,.7)
        );
}

.scene-dark::after{
    content:"";
    position:absolute;
    inset:-10%;
    background:
        radial-gradient(
            ellipse at 25% 65%,
            rgba(190,220,170,.07),
            transparent 30%
        ),
        radial-gradient(
            ellipse at 75% 35%,
            rgba(220,210,150,.05),
            transparent 28%
        );
    animation:lightDrift 12s ease-in-out infinite alternate;
}

@keyframes lightDrift{
    from{
        transform:translateX(-2%) translateY(1%);
        opacity:.5;
    }
    to{
        transform:translateX(2%) translateY(-2%);
        opacity:1;
    }
}

/* =================================
   МЕНЮ
================================= */

#menu{
    position:relative;
    z-index:2;
    width:100%;
    height:100%;
    display:flex;
    flex-direction:column;
    align-items:center;
    justify-content:center;
    padding:16px 10px;

    animation:menuAppear .9s ease both;
}

@keyframes menuAppear{
    from{
        opacity:0;
        transform:translateY(18px);
    }
    to{
        opacity:1;
        transform:translateY(0);
    }
}

.title{
    margin:0 0 4px;

    font-family:"IM Fell English SC",serif;
    font-size:clamp(36px,7vw,64px);

    letter-spacing:4px;
    text-align:center;

    color:#efe2bf;

    text-shadow:
        0 3px 12px #000,
        0 0 20px rgba(225,207,151,.25);

    animation:titleFloat 5s ease-in-out infinite;
}

@keyframes titleFloat{
    0%,100%{
        transform:translateY(0);
    }
    50%{
        transform:translateY(-3px);
    }
}

.subtitle{
    margin:0 0 10px;

    color:#eadfbe;

    font-size:clamp(15px,3vw,20px);

    text-align:center;

    text-shadow:0 2px 8px #000;

    animation:softAppear 1.2s ease both;
}

@keyframes softAppear{
    from{
        opacity:0;
    }
    to{
        opacity:1;
    }
}

/* =================================
   КАРУСЕЛЬ
================================= */

.carousel{
    position:relative;

    width:min(1100px,100%);
    height:min(64vh,570px);

    overflow:hidden;

    border-radius:30px;

    touch-action:pan-y;
}

.carousel::before{
    content:"";

    position:absolute;

    left:50%;
    bottom:2%;

    width:min(900px,90%);
    height:28%;

    transform:translateX(-50%);

    background:radial-gradient(
        ellipse,
        rgba(0,0,0,.8),
        rgba(0,0,0,.28) 55%,
        transparent 75%
    );

    filter:blur(13px);

    z-index:0;
}

.books{
    position:absolute;

    left:50%;
    top:0;

    width:max-content;
    min-width:max-content;
    height:100%;

    display:flex;
    align-items:center;

    gap:28px;

    transform:translate3d(-50%,0,0);

    transition:
        transform .75s cubic-bezier(.16,.85,.2,1);

    will-change:transform;
}

.book{
    position:relative;

    flex:0 0 clamp(210px,45vw,330px);
    height:clamp(310px,58vh,470px);

    overflow:visible;

    border-radius:9px 16px 16px 9px;

    cursor:pointer;

    opacity:.43;

    transform:
        scale(.82)
        rotateY(0deg)
        translateY(18px);

    filter:
        brightness(.65)
        saturate(.72)
        drop-shadow(0 15px 18px rgba(0,0,0,.65));

    transition:
        transform .75s cubic-bezier(.16,.85,.2,1),
        opacity .55s ease,
        filter .55s ease;

    transform-style:preserve-3d;

    perspective:1000px;
}

.book::before{
    content:"";

    position:absolute;

    inset:-8px;

    border-radius:16px;

    background:
        radial-gradient(
            ellipse,
            rgba(225,204,146,.2),
            transparent 65%
        );

    opacity:0;

    filter:blur(12px);

    transition:opacity .6s ease;

    pointer-events:none;
}

.book.selected::before{
    opacity:1;
}

.book::after{
    content:"";

    position:absolute;

    top:2%;
    right:-8px;

    width:9px;
    height:96%;

    border-radius:0 8px 8px 0;

    background:
        repeating-linear-gradient(
            to bottom,
            #c9a970 0 2px,
            #80633d 3px 4px
        );

    opacity:.7;

    box-shadow:
        3px 5px 8px rgba(0,0,0,.45);

    z-index:4;
}

.book.selected{
    opacity:1;

    transform:
        scale(1)
        rotateY(0deg)
        translateY(0);

    filter:
        brightness(1)
        saturate(1)
        drop-shadow(0 22px 30px rgba(0,0,0,.8))
        drop-shadow(0 0 22px rgba(255,224,153,.28));

    z-index:5;
}

.book.selected:hover{
    transform:
        scale(1.025)
        rotateY(0deg)
        translateY(-4px);
}

.book.left{
    transform:
        scale(.82)
        rotateY(27deg)
        translateY(18px);
}

.book.right{
    transform:
        scale(.82)
        rotateY(-27deg)
        translateY(18px);
}

.book-cover-wrap{
    position:absolute;
    inset:0;

    overflow:hidden;

    border-radius:8px 15px 15px 8px;

    background:#392d20;

    box-shadow:
        inset 0 0 0 2px rgba(255,235,180,.18),
        inset 8px 0 18px rgba(0,0,0,.25);
}

.book-cover{
    width:100%;
    height:100%;

    display:block;

    object-fit:cover;
    object-position:center;

    border-radius:8px 15px 15px 8px;

    user-select:none;
    -webkit-user-drag:none;

    transition:
        transform .8s cubic-bezier(.16,.85,.2,1),
        filter .5s ease;
}

/* Усиленная обрезка Травника */

.book.herbal .book-cover{
    transform:scale(1.48);
    object-position:center center;
}

.book.herbal.selected .book-cover{
    transform:scale(1.62);
}

/* =================================
   НАЗВАНИЯ
================================= */

.book-name{
    position:absolute;

    left:50%;
    bottom:-43px;

    transform:translateX(-50%);

    min-width:170px;

    text-align:center;

    padding:8px 15px;

    border-radius:20px;

    background:rgba(15,12,8,.78);

    border:1px solid rgba(255,226,166,.28);

    color:#eadbb8;

    font-size:19px;

    letter-spacing:.6px;

    opacity:0;

    transition:
        opacity .45s ease,
        transform .45s ease;

    white-space:nowrap;

    pointer-events:none;

    box-shadow:
        0 5px 15px rgba(0,0,0,.35);
}

.book.selected .book-name{
    opacity:1;

    transform:
        translateX(-50%)
        translateY(-2px);
}

.swipe-hint{
    margin-top:7px;

    height:22px;

    color:rgba(255,240,205,.72);

    font-size:13px;

    letter-spacing:1.5px;

    text-shadow:0 2px 6px #000;

    animation:hintPulse 3s ease-in-out infinite;
}

@keyframes hintPulse{
    0%,100%{
        opacity:.55;
    }
    50%{
        opacity:1;
    }
}

/* =================================
   ТОЧКИ
================================= */

.dots{
    display:flex;

    justify-content:center;

    gap:9px;

    margin-top:10px;
}

.dot{
    width:8px;
    height:8px;

    border-radius:50%;

    background:rgba(255,240,205,.3);

    transition:
        width .45s ease,
        background .45s ease,
        box-shadow .45s ease;
}

.dot.active{
    width:25px;

    border-radius:8px;

    background:#ead09a;

    box-shadow:
        0 0 9px rgba(255,220,150,.45);
}

/* =================================
   КНОПКИ
================================= */

#openButton,
#backButton{
    border:
        1px solid rgba(255,232,175,.4);

    color:#f5e6c4;

    background:
        linear-gradient(
            180deg,
            rgba(94,71,40,.95),
            rgba(44,31,19,.95)
        );

    border-radius:15px;

    padding:13px 28px;

    min-width:220px;

    font-size:19px;

    cursor:pointer;

    box-shadow:
        0 8px 18px rgba(0,0,0,.5),
        inset 0 1px rgba(255,255,255,.15);

    transition:
        transform .18s ease,
        filter .25s ease,
        box-shadow .35s ease;

    margin-top:12px;

    animation:buttonGlow 4s ease-in-out infinite;
}

@keyframes buttonGlow{
    0%,100%{
        box-shadow:
            0 8px 18px rgba(0,0,0,.5),
            inset 0 1px rgba(255,255,255,.15);
    }

    50%{
        box-shadow:
            0 8px 20px rgba(0,0,0,.55),
            0 0 17px rgba(220,197,140,.17),
            inset 0 1px rgba(255,255,255,.18);
    }
}

#openButton:active,
#backButton:active{
    transform:scale(.94);

    filter:brightness(1.3);

    box-shadow:
        0 3px 10px rgba(0,0,0,.5),
        0 0 25px rgba(255,220,150,.35);
}

/* =================================
   ОТКРЫТИЕ
================================= */

#opening{
    position:fixed;

    inset:0;

    z-index:10;

    display:none;

    align-items:center;
    justify-content:center;

    background:
        radial-gradient(
            circle,
            rgba(92,76,42,.18),
            #080906 70%
        );

    opacity:0;
}

#opening.show{
    display:flex;

    animation:
        openingSceneIn .35s ease forwards;
}

@keyframes openingSceneIn{
    from{
        opacity:0;
    }
    to{
        opacity:1;
    }
}

.opening-book{
    width:min(62vw,430px);
    aspect-ratio:.7;

    border-radius:8px;

    overflow:hidden;

    box-shadow:
        0 0 70px rgba(255,230,170,.2),
        0 25px 60px rgba(0,0,0,.8);

    transform-origin:left center;
}

.opening-book img{
    width:100%;
    height:100%;

    display:block;

    object-fit:cover;
}

.opening-book.animate{
    animation:
        bookOpen .95s
        cubic-bezier(.18,.82,.2,1)
        forwards;
}

@keyframes bookOpen{

    0%{
        transform:
            perspective(1000px)
            rotateY(0deg)
            scale(.72);

        opacity:0;
    }

    22%{
        opacity:1;
    }

    55%{
        transform:
            perspective(1000px)
            rotateY(-22deg)
            scale(1.02);

        opacity:1;
    }

    100%{
        transform:
            perspective(1000px)
            rotateY(-82deg)
            scale(1.08);

        opacity:0;
    }
}

/* =================================
   ЧИТАТЕЛЬ
================================= */

#reader{
    position:fixed;

    inset:0;

    z-index:9;

    display:none;

    flex-direction:column;

    align-items:center;
    justify-content:center;

    padding:12px;

    background:
        radial-gradient(
            circle,
            rgba(0,0,0,.12),
            rgba(0,0,0,.78)
        );

    opacity:0;
}

#reader.show{
    display:flex;

    animation:
        readerIn .65s ease forwards;
}

@keyframes readerIn{
    from{
        opacity:0;
        transform:scale(.97);
    }

    to{
        opacity:1;
        transform:scale(1);
    }
}

#reader.closing{
    display:flex;

    animation:
        readerOut .65s ease forwards;
}

@keyframes readerOut{
    from{
        opacity:1;
        transform:scale(1);
    }

    to{
        opacity:0;
        transform:scale(.96) translateY(15px);
    }
}

.book-spread{
    position:relative;

    width:min(96vw,1050px);
    height:min(76vh,680px);

    display:flex;

    overflow:hidden;

    border-radius:7px;

    box-shadow:
        0 25px 60px rgba(0,0,0,.75),
        0 0 30px rgba(255,220,150,.12);

    perspective:1400px;
}

.book-spread.page-turn{
    animation:
        spreadTurn .45s ease;
}

@keyframes spreadTurn{
    0%{
        transform:
            rotateY(0deg)
            scale(1);
    }

    45%{
        transform:
            rotateY(2deg)
            scale(.985);
    }

    100%{
        transform:
            rotateY(0deg)
            scale(1);
    }
}

.page{
    position:relative;

    width:50%;
    height:100%;

    overflow:hidden;

    background-image:url(
        "https://img.magnific.com/premium-vector/old-parchment-paper-sheet-vintage-aged-texture-vector-illustration_969400-501.jpg?semt=ais_hybrid&w=740&q=80"
    );

    background-size:cover;
    background-position:center;

    color:#3e2d1c;

    padding:clamp(20px,4vw,48px);

    box-shadow:
        inset 0 0 30px rgba(60,35,10,.18);

    transition:
        filter .4s ease;
}

.page:first-child{
    border-right:
        1px solid rgba(60,35,10,.35);
}

.page h2{
    margin:0 0 18px;

    font-family:
        "IM Fell English SC",
        "Cormorant Garamond",
        Georgia,
        serif;

    font-size:
        clamp(23px,4vw,36px);

    text-align:center;

    color:#49331d;

    font-weight:600;

    letter-spacing:.4px;
}

.page p{
    margin:0;

    font-size:
        clamp(16px,2.3vw,22px);

    line-height:1.58;

    text-align:left;

    font-weight:500;
}

.page::after{
    content:"";

    position:absolute;

    inset:0;

    pointer-events:none;

    background:
        linear-gradient(
            90deg,
            rgba(70,40,10,.08),
            transparent 15%,
            transparent 85%,
            rgba(70,40,10,.08)
        );
}

.reader-controls{
    display:flex;

    gap:10px;

    align-items:center;
    justify-content:center;

    margin-top:12px;
}

.reader-controls button{
    min-width:52px;
    height:45px;

    border:
        1px solid rgba(255,232,175,.35);

    border-radius:12px;

    background:rgba(40,28,16,.9);

    color:#eadbb8;

    font-size:25px;

    cursor:pointer;

    transition:
        transform .18s ease,
        filter .25s ease;
}

.reader-controls button:active{
    transform:scale(.9);
    filter:brightness(1.35);
}

#pageInfo{
    min-width:110px;

    text-align:center;

    color:#eadbb8;

    font-size:15px;
}

#backButton{
    min-width:150px;

    margin-top:8px;
}

/* =================================
   ВЫХОД ИЗ КНИГИ
================================= */

#reader.exiting .book-spread{
    animation:
        bookClose .65s
        cubic-bezier(.2,.8,.2,1)
        forwards;
}

@keyframes bookClose{

    0%{
        transform:
            perspective(1400px)
            rotateY(0deg)
            scale(1);

        opacity:1;
    }

    45%{
        transform:
            perspective(1400px)
            rotateY(-8deg)
            scale(.98);

        opacity:.9;
    }

    100%{
        transform:
            perspective(1400px)
            rotateY(72deg)
            scale(.78)
            translateX(20px);

        opacity:0;
    }
}

/* =================================
   МОБИЛЬНАЯ ВЕРСИЯ
================================= */

@media(max-width:650px){

    .carousel{
        height:60vh;
    }

    .books{
        gap:18px;
    }

    .book{
        flex-basis:245px;
        height:390px;
    }

    .book.left{
        transform:
            scale(.76)
            rotateY(30deg)
            translateY(18px);
    }

    .book.right{
        transform:
            scale(.76)
            rotateY(-30deg)
            translateY(18px);
    }

    .book.herbal .book-cover{
        transform:scale(1.54);
    }

    .book.herbal.selected .book-cover{
        transform:scale(1.67);
    }

    .book-name{
        bottom:-39px;
        font-size:16px;
    }

    .book-spread{
        width:98vw;
        height:68vh;
    }

    .page{
        padding:16px;
    }

    .page p{
        font-size:15px;
        line-height:1.45;
    }
}
</style>
</head>

<body>

<img
    id="forest"
    src="https://images.pexels.com/photos/17491580/pexels-photo-17491580.jpeg"
    alt=""
>

<div class="scene-dark"></div>


<!-- =================================
     МЕНЮ
================================= -->

<section id="menu">

    <h1 class="title">
        ТРАВНИК
    </h1>

    <p class="subtitle">
        Выберите книгу
    </p>


    <div
        class="carousel"
        id="carousel"
    >

        <div
            class="books"
            id="books"
        >


            <!-- ЦВЕТНИК -->

            <div
                class="book selected"
                data-index="0"
            >

                <div class="book-cover-wrap">

                    <img
                        class="book-cover"
                        src="https://basket-15.wbbasket.ru/vol2261/part226117/226117052/images/big/1.webp"
                        alt="Цветник"
                    >

                </div>

                <div class="book-name">
                    Цветник
                </div>

            </div>


            <!-- ЛЕЧЕБНИК -->

            <div
                class="book"
                data-index="1"
            >

                <div class="book-cover-wrap">

                    <img
                        class="book-cover"
                        src="https://cdn.eksmo.ru/v2/ITD000000000608288/COVER/cover1__w820.jpg"
                        alt="Лечебник"
                    >

                </div>

                <div class="book-name">
                    Лечебник
                </div>

            </div>


            <!-- ТРАВНИК -->

            <div
                class="book herbal"
                data-index="2"
            >

                <div class="book-cover-wrap">

                    <img
                        class="book-cover"
                        src="https://ogorod.ua/_sh/47/4703b_4.jpg"
                        alt="Травник"
                    >

                </div>

                <div class="book-name">
                    Травник
                </div>

            </div>

        </div>

    </div>


    <div class="swipe-hint">
        СВАЙП ВЛЕВО ИЛИ ВПРАВО
    </div>


    <div class="dots">

        <span class="dot active"></span>
        <span class="dot"></span>
        <span class="dot"></span>

    </div>


    <button id="openButton">
        Открыть книгу
    </button>

</section>


<!-- =================================
     АНИМАЦИЯ ОТКРЫТИЯ
================================= -->

<section id="opening">

    <div class="opening-book">

        <img
            id="openingCover"
            src=""
            alt=""
        >

    </div>

</section>


<!-- =================================
     ЧИТАТЕЛЬ
================================= -->

<section id="reader">

    <div class="book-spread">

        <article
            class="page"
            id="leftPage"
        >

            <h2></h2>
            <p></p>

        </article>


        <article
            class="page"
            id="rightPage"
        >

            <h2></h2>
            <p></p>

        </article>

    </div>


    <div class="reader-controls">

        <button id="prevPage">
            ‹
        </button>

        <div id="pageInfo">
            1 / 7
        </div>

        <button id="nextPage">
            ›
        </button>

    </div>


    <button id="backButton">
        Вернуться
    </button>

</section>


<script>

/* =================================
   ЭЛЕМЕНТЫ
================================= */

const carousel =
    document.getElementById("carousel");

const booksContainer =
    document.getElementById("books");

const books =
    [...document.querySelectorAll(".book")];

const dots =
    [...document.querySelectorAll(".dot")];

const openButton =
    document.getElementById("openButton");

const menu =
    document.getElementById("menu");

const opening =
    document.getElementById("opening");

const openingCover =
    document.getElementById("openingCover");

const openingBook =
    document.querySelector(".opening-book");

const reader =
    document.getElementById("reader");

const backButton =
    document.getElementById("backButton");

const spread =
    document.querySelector(".book-spread");

const leftPage =
    document.getElementById("leftPage");

const rightPage =
    document.getElementById("rightPage");

const prevPage =
    document.getElementById("prevPage");

const nextPage =
    document.getElementById("nextPage");

const pageInfo =
    document.getElementById("pageInfo");


let selectedBook = 0;
let currentPage = 0;

let touchStartX = 0;
let touchStartY = 0;

let readerStartX = 0;
let readerStartY = 0;


/* =================================
   КНИГИ
================================= */

const booksData = [

    {
        name:"Цветник",

        pages:[

            {
                title:"Ромашка",
                text:"Ромашка — знакомый полевой цветок с белыми лепестками. В травниках её часто описывают как растение с приятным ароматом и нежным цветением."
            },

            {
                title:"Василёк",
                text:"Василёк отличается яркими синими цветками. Он растёт среди луговых трав и особенно хорошо заметен летом."
            },

            {
                title:"Одуванчик",
                text:"Одуванчик легко узнать по жёлтой корзинке цветков. После цветения появляются лёгкие семена, которые ветер разносит далеко."
            },

            {
                title:"Календула",
                text:"Календула имеет яркие оранжевые или жёлтые цветки. Её часто выращивают в садах как декоративное растение."
            },

            {
                title:"Мак",
                text:"Мак известен крупными цветками с тонкими лепестками. В разных видах и сортах окраска может отличаться."
            },

            {
                title:"Лютик",
                text:"Лютики встречаются на лугах и влажных участках. Их блестящие жёлтые лепестки хорошо заметны среди зелёной травы."
            },

            {
                title:"Колокольчик",
                text:"Колокольчики получили название благодаря форме своих цветков. Они могут иметь голубую, синюю, фиолетовую или белую окраску."
            },

            {
                title:"Незабудка",
                text:"Незабудку легко узнать по небольшим цветкам нежных оттенков. Это невысокое растение часто встречается во влажных местах."
            },

            {
                title:"Ландыш",
                text:"Ландыш образует небольшие белые цветки, похожие на колокольчики. Растение имеет сильный характерный аромат."
            },

            {
                title:"Иван-чай",
                text:"Иван-чай — высокое растение с розовыми или пурпурными цветками. Он часто появляется на солнечных полянах и открытых местах."
            },

            {
                title:"Клевер",
                text:"Клевер образует округлые соцветия. Его цветки привлекают множество насекомых, особенно пчёл."
            },

            {
                title:"Тысячелистник",
                text:"Тысячелистник имеет множество мелких цветков, собранных в плотные соцветия. Его листья отличаются характерной рассечённой формой."
            },

            {
                title:"Мальва",
                text:"Мальва — высокое растение с крупными цветками. Её часто выращивают возле домов и в садовых цветниках."
            },

            {
                title:"Конец цветника",
                text:"Вы закончили раздел Цветника. Здесь собраны описания растений. Не используйте незнакомые растения в пищу или для лечения."
            }

        ]
    },


    {
        name:"Лечебник",

        pages:[

            {
                title:"Мята",
                text:"Мята имеет свежий характерный аромат. Её листья часто используют в напитках и кулинарии."
            },

            {
                title:"Крапива",
                text:"Крапива покрыта мелкими жалящими волосками. В природе она встречается на опушках, возле дорог и в местах с влажной почвой."
            },

            {
                title:"Мелисса",
                text:"Мелисса обладает приятным лимонным ароматом. Её выращивают в садах и используют преимущественно как ароматное растение."
            },

            {
                title:"Шалфей",
                text:"Шалфей имеет плотные серо-зелёные листья и характерный запах. Разные виды шалфея сильно отличаются друг от друга."
            },

            {
                title:"Чабрец",
                text:"Чабрец — небольшое ароматное растение. Он образует низкие кустики и хорошо переносит солнечные места."
            },

            {
                title:"Ромашка аптечная",
                text:"Аптечная ромашка имеет небольшие соцветия с белыми лепестками и жёлтой серединой. Её часто выращивают специально для сбора."
            },

            {
                title:"Липа",
                text:"Липа — крупное дерево с сердцевидными листьями. Во время цветения она наполняет воздух заметным сладким ароматом."
            },

            {
                title:"Шиповник",
                text:"Шиповник — кустарник с цветками и красными плодами. Его легко узнать по многочисленным шипам на ветвях."
            },

            {
                title:"Малина",
                text:"Малина образует кусты с колючими побегами и знакомыми ягодами. Она встречается в садах и в дикой природе."
            },

            {
                title:"Чистотел",
                text:"Чистотел — растение с жёлтыми цветками и характерным оранжевым соком. Дикорастущие растения нельзя использовать самостоятельно."
            },

            {
                title:"Подорожник",
                text:"Подорожник часто растёт вдоль тропинок. Его листья имеют заметные продольные жилки."
            },

            {
                title:"Зверобой",
                text:"Зверобой отличается небольшими жёлтыми цветками. Он встречается на солнечных полянах и сухих участках."
            },

            {
                title:"Безопасность",
                text:"Не пробуйте неизвестные растения, ягоды или семена. Даже растение, похожее на знакомое, может оказаться другим видом."
            },

            {
                title:"Конец лечебника",
                text:"Лечебник закончен. Настоящее лечение должно проводиться по совету родителей, врача или другого квалифицированного специалиста."
            }

        ]
    },


    {
        name:"Травник",

        pages:[

            {
                title:"Крапива",
                text:"Крапива — многолетнее травянистое растение. Её легко узнать по зелёным листьям с характерными зубчатыми краями."
            },

            {
                title:"Подорожник",
                text:"Подорожник часто растёт рядом с тропинками и дорогами. Его широкие листья имеют заметные продольные жилки."
            },

            {
                title:"Зверобой",
                text:"Зверобой — растение с небольшими жёлтыми цветками. В природе он встречается на солнечных местах и полянах."
            },

            {
                title:"Мята",
                text:"Мята любит достаточно влажную почву и быстро разрастается. Её легко узнать по свежему запаху листьев."
            },

            {
                title:"Мелисса",
                text:"Мелисса похожа на некоторые другие растения семейства яснотковых. Главная особенность — приятный лимонный аромат."
            },

            {
                title:"Чабрец",
                text:"Чабрец образует маленькие кустики и любит солнечные места. Во время цветения над ним часто можно увидеть насекомых."
            },

            {
                title:"Шиповник",
                text:"Шиповник — колючий кустарник. Его красные плоды появляются после цветения и сохраняются довольно долго."
            },

            {
                title:"Клевер",
                text:"Клевер имеет характерные тройчатые листья и округлые цветочные головки. На лугах его часто посещают пчёлы."
            },

            {
                title:"Тысячелистник",
                text:"Название растения связано с сильно рассечёнными листьями. Соцветия состоят из большого количества маленьких цветков."
            },

            {
                title:"Иван-чай",
                text:"Иван-чай может образовывать большие заросли. Его высокие стебли хорошо заметны среди другой растительности."
            },

            {
                title:"Липовый цвет",
                text:"Липа во время цветения становится особенно заметной благодаря приятному аромату. Её цветки появляются рядом с крупными листьями."
            },

            {
                title:"Одуванчик",
                text:"Одуванчик умеет быстро распространять семена. Лёгкие семянки подхватывает ветер, поэтому растение встречается почти повсюду."
            },

            {
                title:"Правила травника",
                text:"Всегда точно определяйте растение. Не собирайте растения возле загрязнённых дорог и промышленных территорий."
            },

            {
                title:"Конец травника",
                text:"Вы дочитали Травник. В природе много интересных растений, но наблюдать за ними безопаснее всего вместе со взрослыми."
            }

        ]
    }

];


/* =================================
   ЦЕНТРИРОВАНИЕ
================================= */

function centerSelectedBook(){

    const selected =
        books[selectedBook];

    if(!selected) return;


    const rowCenter =
        booksContainer.offsetWidth / 2;


    const bookCenter =
        selected.offsetLeft +
        selected.offsetWidth / 2;


    const shift =
        rowCenter - bookCenter;


    booksContainer.style.transform =
        `translate3d(calc(-50% + ${shift}px),0,0)`;
}


/* =================================
   ВИД КНИГ
================================= */

function updateBookAppearance(){

    books.forEach(
        (book,index)=>{

            book.classList.remove(
                "selected",
                "left",
                "right"
            );


            if(index === selectedBook){

                book.classList.add(
                    "selected"
                );

            }
            else if(index < selectedBook){

                book.classList.add(
                    "left"
                );

            }
            else{

                book.classList.add(
                    "right"
                );

            }

        }
    );


    dots.forEach(
        (dot,index)=>{

            dot.classList.toggle(
                "active",
                index === selectedBook
            );

        }
    );


    requestAnimationFrame(
        centerSelectedBook
    );
}


/* =================================
   ВЫБОР
================================= */

function selectBook(index){

    if(index < 0){

        index =
            books.length - 1;

    }


    if(index >= books.length){

        index = 0;

    }


    selectedBook = index;

    updateBookAppearance();
}


/* =================================
   ОТКРЫТЬ
================================= */

function openBook(){

    const selected =
        books[selectedBook];

    if(!selected) return;


    const cover =
        selected.querySelector(
            ".book-cover"
        );

    if(!cover) return;


    openingCover.src =
        cover.src;


    menu.style.display =
        "none";


    opening.style.display =
        "flex";


    opening.classList.remove(
        "show"
    );


    openingBook.classList.remove(
        "animate"
    );


    void opening.offsetWidth;


    opening.classList.add(
        "show"
    );


    openingBook.classList.add(
        "animate"
    );


    setTimeout(
        ()=>{

            opening.classList.remove(
                "show"
            );

            opening.style.display =
                "none";


            reader.classList.remove(
                "closing"
            );


            reader.style.display =
                "flex";


            void reader.offsetWidth;


            reader.classList.add(
                "show"
            );


            currentPage = 0;

            showSpread();

        },
        980
    );
}


/* =================================
   КНОПКА
================================= */

openButton.addEventListener(
    "click",
    openBook
);


/* =================================
   НАЖАТИЕ НА КНИГИ
================================= */

books.forEach(
    (book,index)=>{

        book.addEventListener(
            "click",
            ()=>{

                if(index !== selectedBook){

                    selectBook(index);

                }
                else{

                    openBook();

                }

            }
        );

    }
);


/* =================================
   СВАЙП КНИГ
================================= */

carousel.addEventListener(
    "touchstart",
    event=>{

        const touch =
            event.changedTouches[0];

        touchStartX =
            touch.clientX;

        touchStartY =
            touch.clientY;

    },
    {passive:true}
);


carousel.addEventListener(
    "touchend",
    event=>{

        const touch =
            event.changedTouches[0];


        const dx =
            touch.clientX -
            touchStartX;


        const dy =
            touch.clientY -
            touchStartY;


        if(Math.abs(dx) < 45){

            return;

        }


        if(
            Math.abs(dx) <=
            Math.abs(dy)
        ){

            return;

        }


        if(dx < 0){

            selectBook(
                selectedBook + 1
            );

        }
        else{

            selectBook(
                selectedBook - 1
            );

        }

    },
    {passive:true}
);


/* =================================
   КЛАВИАТУРА
================================= */

window.addEventListener(
    "keydown",
    event=>{

        if(
            menu.style.display !==
            "none"
        ){

            if(
                event.key ===
                "ArrowRight"
            ){

                selectBook(
                    selectedBook + 1
                );

            }


            if(
                event.key ===
                "ArrowLeft"
            ){

                selectBook(
                    selectedBook - 1
                );

            }


            if(
                event.key ===
                "Enter"
            ){

                openBook();

            }

        }

    }
);


/* =================================
   ПОКАЗ СТРАНИЦ
================================= */

function showSpread(){

    const data =
        booksData[selectedBook];

    if(!data) return;


    const total =
        data.pages.length;


    const leftData =
        data.pages[currentPage];


    const rightData =
        data.pages[
            currentPage + 1
        ];


    leftPage.querySelector("h2")
        .textContent =
        leftData
        ? leftData.title
        : "";


    leftPage.querySelector("p")
        .textContent =
        leftData
        ? leftData.text
        : "";


    rightPage.querySelector("h2")
        .textContent =
        rightData
        ? rightData.title
        : "";


    rightPage.querySelector("p")
        .textContent =
        rightData
        ? rightData.text
        : "";


    const spreadNumber =
        Math.floor(
            currentPage / 2
        ) + 1;


    const spreadTotal =
        Math.ceil(
            total / 2
        );


    pageInfo.textContent =
        `${spreadNumber} / ${spreadTotal}`;


    prevPage.disabled =
        currentPage <= 0;


    nextPage.disabled =
        currentPage + 2 >= total;


    prevPage.style.opacity =
        prevPage.disabled
        ? ".35"
        : "1";


    nextPage.style.opacity =
        nextPage.disabled
        ? ".35"
        : "1";


    spread.classList.remove(
        "page-turn"
    );


    void spread.offsetWidth;


    spread.classList.add(
        "page-turn"
    );
}


/* =================================
   ВПЕРЁД
================================= */

nextPage.addEventListener(
    "click",
    ()=>{

        const total =
            booksData[
                selectedBook
            ].pages.length;


        if(
            currentPage + 2 <
            total
        ){

            currentPage += 2;

            showSpread();

        }

    }
);


/* =================================
   НАЗАД
================================= */

prevPage.addEventListener(
    "click",
    ()=>{

        if(
            currentPage - 2 >= 0
        ){

            currentPage -= 2;

            showSpread();

        }

    }
);


/* =================================
   КРАСИВЫЙ ВЫХОД ИЗ КНИГИ
================================= */

function closeReader(){

    reader.classList.remove(
        "show"
    );


    reader.classList.add(
        "closing"
    );


    setTimeout(
        ()=>{

            reader.style.display =
                "none";

            reader.classList.remove(
                "closing"
            );


            menu.style.display =
                "flex";


            menu.style.animation =
                "none";


            void menu.offsetWidth;


            menu.style.animation =
                "menuAppear .75s ease both";


            requestAnimationFrame(
                centerSelectedBook
            );

        },
        650
    );
}


backButton.addEventListener(
    "click",
    closeReader
);


/* =================================
   СВАЙП СТРАНИЦ
================================= */

reader.addEventListener(
    "touchstart",
    event=>{

        const touch =
            event.changedTouches[0];


        readerStartX =
            touch.clientX;


        readerStartY =
            touch.clientY;

    },
    {passive:true}
);


reader.addEventListener(
    "touchend",
    event=>{

        const touch =
            event.changedTouches[0];


        const dx =
            touch.clientX -
            readerStartX;


        const dy =
            touch.clientY -
            readerStartY;


        if(
            Math.abs(dx) < 55
        ){

            return;

        }


        if(
            Math.abs(dx) <=
            Math.abs(dy)
        ){

            return;

        }


        if(dx < 0){

            nextPage.click();

        }
        else{

            prevPage.click();

        }

    },
    {passive:true}
);


/* =================================
   ЗАПУСК
================================= */

updateBookAppearance();


window.addEventListener(
    "load",
    ()=>{

        updateBookAppearance();

        setTimeout(
            centerSelectedBook,
            100
        );

        setTimeout(
            centerSelectedBook,
            500
        );

    }
);


window.addEventListener(
    "resize",
    ()=>{

        requestAnimationFrame(
            centerSelectedBook
        );

    }
);

</script>

</body>
</html>

Game Source: Травник

Creator: GoldenBear87

Libraries: none

Complexity: complex (2293 lines, 43.1 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-goldenbear87" to link back to the original. Then publish at arcadelab.ai/publish.