




Pensou por 64 segundos
Que ideia incrível! Vou criar um site com visual de livro real, com animação de virar página ao clicar nas setas.
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Meu Livro</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
background: radial-gradient(ellipse at center, #2c1810 0%, #1a0f0a 60%, #0d0605 100%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: 'Georgia', serif;
overflow: hidden;
}
/* Luz ambiente */
body::before {
content: '';
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 700px;
height: 500px;
background: radial-gradient(ellipse, rgba(255,200,100,0.08) 0%, transparent 70%);
pointer-events: none;
}
.book-title {
color: #d4a96a;
font-size: 1rem;
letter-spacing: 4px;
text-transform: uppercase;
margin-bottom: 30px;
opacity: 0.7;
}
/* Contêiner do livro */
.book-container {
perspective: 2000px;
width: 700px;
height: 480px;
}
.book {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
transform: rotateX(5deg);
filter: drop-shadow(0 40px 60px rgba(0,0,0,0.8));
}
/* Sombra do livro na mesa */
.book-shadow {
position: absolute;
bottom: -60px;
left: 50%;
transform: translateX(-50%);
width: 600px;
height: 40px;
background: radial-gradient(ellipse, rgba(0,0,0,0.6) 0%, transparent 70%);
filter: blur(15px);
}
/* Página esquerda e direita */
.pages-wrapper {
display: flex;
width: 100%;
height: 100%;
position: relative;
}
.page-left,
.page-right {
width: 50%;
height: 100%;
position: relative;
background: #fdf6e3;
padding: 40px 35px;
overflow: hidden;
}
/* Textura de papel */
.page-left::before,
.page-right::before {
content: '';
position: absolute;
inset: 0;
background-image:
repeating-linear-gradient(
0deg,
transparent,
transparent 27px,
rgba(180,160,120,0.12) 27px,
rgba(180,160,120,0.12) 28px
);
pointer-events: none;
}
.page-left {
border-radius: 4px 0 0 4px;
background: linear-gradient(to right, #f5edd8, #fdf6e3);
box-shadow: inset -8px 0 20px rgba(0,0,0,0.15), inset 3px 0 5px rgba(255,255,255,0.3);
}
.page-right {
border-radius: 0 4px 4px 0;
background: linear-gradient(to left, #f5edd8, #fdf6e3);
box-shadow: inset 8px 0 20px rgba(0,0,0,0.15), inset -3px 0 5px rgba(255,255,255,0.3);
}
/* Lombada do livro */
.book-spine {
position: absolute;
left: 50%;
top: 0;
transform: translateX(-50%);
width: 14px;
height: 100%;
background: linear-gradient(to right, #c8a96e, #8b6914, #c8a96e);
z-index: 10;
box-shadow: 0 0 15px rgba(0,0,0,0.4);
}
/* Capa do livro (visível nas bordas) */
.book-cover-left {
position: absolute;
left: -10px;
top: 0;
width: 14px;
height: 100%;
background: linear-gradient(to right, #6b3a1f, #8b4a2a, #6b3a1f);
border-radius: 4px 0 0 4px;
z-index: 5;
}
.book-cover-right {
position: absolute;
right: -10px;
top: 0;
width: 14px;
height: 100%;
background: linear-gradient(to left, #6b3a1f, #8b4a2a, #6b3a1f);
border-radius: 0 4px 4px 0;
z-index: 5;
}
/* Topo e base do livro */
.book-top {
position: absolute;
top: -6px;
left: 0;
right: 0;
height: 8px;
background: linear-gradient(to bottom, #c8a96e, #a07830);
border-radius: 2px 2px 0 0;
z-index: 4;
}
.book-bottom {
position: absolute;
bottom: -6px;
left: 0;
right: 0;
height: 8px;
background: linear-gradient(to top, #a07830, #c8a96e);
border-radius: 0 0 2px 2px;
z-index: 4;
}
/* Conteúdo das páginas */
.page-content {
position: relative;
z-index: 1;
height: 100%;
display: flex;
flex-direction: column;
}
.page-chapter {
font-size: 0.6rem;
letter-spacing: 3px;
text-transform: uppercase;
color: #8b6914;
text-align: center;
margin-bottom: 20px;
opacity: 0.7;
}
.page-heading {
font-size: 1.1rem;
color: #3d2b1f;
text-align: center;
margin-bottom: 18px;
font-style: italic;
line-height: 1.4;
}
.page-divider {
width: 60px;
height: 1px;
background: linear-gradient(to right, transparent, #8b6914, transparent);
margin: 0 auto 18px;
}
.page-text {
font-size: 0.78rem;
color: #3d2b1f;
line-height: 1.85;
text-align: justify;
flex: 1;
hyphens: auto;
}
.page-text p + p {
text-indent: 1.5em;
margin-top: 4px;
}
.page-number {
text-align: center;
font-size: 0.7rem;
color: #8b6914;
margin-top: 15px;
font-style: italic;
opacity: 0.7;
}
/* Ornamento decorativo */
.ornament {
text-align: center;
color: #8b6914;
font-size: 1rem;
margin: 8px 0;
opacity: 0.5;
}
/* Animação de virar página */
.flip-overlay {
position: absolute;
top: 0;
right: 0;
width: 50%;
height: 100%;
transform-origin: left center;
transform-style: preserve-3d;
z-index: 20;
pointer-events: none;
}
.flip-overlay.flipping-forward {
animation: flipForward 0.7s ease-in-out forwards;
}
.flip-overlay.flipping-backward {
animation: flipBackward 0.7s ease-in-out forwards;
}
.flip-front,
.flip-back {
position: absolute;
inset: 0;
backface-visibility: hidden;
border-radius: 0 4px 4px 0;
}
.flip-front {
background: linear-gradient(to left, #f0e6c8, #fdf6e3);
}
.flip-back {
background: linear-gradient(to right, #f0e6c8, #fdf6e3);
transform: rotateY(180deg);
}
@keyframes flipForward {
0% { transform: rotateY(0deg); box-shadow: none; }
30% { box-shadow: -20px 0 40px rgba(0,0,0,0.25); }
100% { transform: rotateY(-180deg); box-shadow: none; }
}
@keyframes flipBackward {
0% { transform: rotateY(-180deg); }
100% { transform: rotateY(0deg); }
}
/* Navegação */
.nav-buttons {
display: flex;
align-items: center;
gap: 30px;
margin-top: 35px;
}
.nav-btn {
background: none;
border: none;
cursor: pointer;
color: #d4a96a;
font-size: 1.4rem;
display


Pensou por 4 segundos
Claro! Aqui está o arquivo completo e funcional:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Meu Livro</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
min-height: 100vh;
background: radial-gradient(ellipse at center, #2c1810 0%, #1a0f0a 60%, #0d0605 100%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: 'Georgia', serif;
overflow: hidden;
}
body::before {
content: '';
position: fixed;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: 700px; height: 500px;
background: radial-gradient(ellipse, rgba(255,200,100,0.08) 0%, transparent 70%);
pointer-events: none;
}
.book-title {
color: #d4a96a;
font-size: 0.85rem;
letter-spacing: 4px;
text-transform: uppercase;
margin-bottom: 25px;
opacity: 0.8;
}
.book-container {
perspective: 2000px;
width: 720px;
height: 480px;
}
.book {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
transform: rotateX(4deg);
filter: drop-shadow(0 40px 60px rgba(0,0,0,0.9));
}
.book-shadow {
position: absolute;
bottom: -55px; left: 50%;
transform: translateX(-50%);
width: 600px; height: 35px;
background: radial-gradient(ellipse, rgba(0,0,0,0.7) 0%, transparent 70%);
filter: blur(18px);
}
.pages-wrapper {
display: flex;
width: 100%;
height: 100%;
position: relative;
border-radius: 4px;
overflow: hidden;
}
.page-left, .page-right {
width: 50%;
height: 100%;
position: relative;
padding: 38px 32px;
overflow: hidden;
}
.page-left::before, .page-right::before {
content: '';
position: absolute;
inset: 0;
background-image: repeating-linear-gradient(
0deg, transparent, transparent 27px,
rgba(160,130,90,0.1) 27px, rgba(160,130,90,0.1) 28px
);
pointer-events: none;
}
.page-left {
background: linear-gradient(to right, #ede4cc, #fdf6e3);
box-shadow: inset -10px 0 25px rgba(0,0,0,0.12), inset 2px 0 4px rgba(255,255,255,0.4);
}
.page-right {
background: linear-gradient(to left, #ede4cc, #fdf6e3);
box-shadow: inset 10px 0 25px rgba(0,0,0,0.12), inset -2px 0 4px rgba(255,255,255,0.4);
}
.book-spine {
position: absolute;
left: 50%; top: 0;
transform: translateX(-50%);
width: 16px; height: 100%;
background: linear-gradient(to right, #b8941e, #7a5510, #c8a940, #7a5510, #b8941e);
z-index: 10;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
}
.book-cover-left {
position: absolute;
left: -12px; top: 0;
width: 16px; height: 100%;
background: linear-gradient(to right, #5a2e10, #7a3e1a, #5a2e10);
border-radius: 4px 0 0 4px;
z-index: 5;
box-shadow: -4px 0 10px rgba(0,0,0,0.5);
}
.book-cover-right {
position: absolute;
right: -12px; top: 0;
width: 16px; height: 100%;
background: linear-gradient(to left, #5a2e10, #7a3e1a, #5a2e10);
border-radius: 0 4px 4px 0;
z-index: 5;
box-shadow: 4px 0 10px rgba(0,0,0,0.5);
}
.book-top {
position: absolute;
top: -7px; left: 0; right: 0;
height: 9px;
background: linear-gradient(to bottom, #d4a940, #9a7020);
border-radius: 3px 3px 0 0;
z-index: 4;
}
.book-bottom {
position: absolute;
bottom: -7px; left: 0; right: 0;
height: 9px;
background: linear-gradient(to top, #9a7020, #d4a940);
border-radius: 0 0 3px 3px;
z-index: 4;
}
.page-content {
position: relative;
z-index: 1;
height: 100%;
display: flex;
flex-direction: column;
}
.page-chapter {
font-size: 0.58rem;
letter-spacing: 3px;
text-transform: uppercase;
color: #8b6914;
text-align: center;
margin-bottom: 14px;
opacity: 0.75;
}
.page-heading {
font-size: 1rem;
color: #3d2b1f;
text-align: center;
margin-bottom: 12px;
font-style: italic;
line-height: 1.4;
}
.page-divider {
width: 70px; height: 1px;
background: linear-gradient(to right, transparent, #8b6914, transparent);
margin: 0 auto 14px;
}
.page-text {
font-size: 0.77rem;
color: #3d2b1f;
line-height: 1.9;
text-align: justify;
flex: 1;
hyphens: auto;
}
.page-text p + p {
text-indent: 1.5em;
margin-top: 2px;
}
.page-number {
text-align: center;
font-size: 0.68rem;
color: #8b6914;
margin-top: 12px;
font-style: italic;
opacity: 0.75;
}
.ornament {
text-align: center;
color: #8b6914;
font-size: 0.9rem;
margin: 6px 0;
opacity: 0.45;
}
/* ── Animação de virar página ── */
.flip-overlay {
position: absolute;
top: 0; right: 0;
width: 50%; height: 100%;
transform-origin: left center;
transform-style: preserve-3d;
z-index: 20;
pointer-events: none;
border-radius: 0 4px 4px 0;
}
.flip-overlay.flipping-forward {
animation: flipForward 0.65s cubic-bezier(0.645,0.045,0.355,1.000) forwards;
}
.flip-overlay.flipping-backward {
animation: flipBackward 0.65s cubic-bezier(0.645,0.045,0.355,1.000) forwards;
}
.flip-front, .flip-back {
position: absolute;
inset: 0;
backface-visibility: hidden;
border-radius: inherit;
}
.flip-front {
background: linear-gradient(to left, #e8dcc0, #fdf6e3);
box-shadow: inset 8px 0 20px rgba(0,0,0,0.1);
}
.flip-back {
background: linear-gradient(to right, #e8dcc0, #fdf6e3);
transform: rotateY(180deg);
box-shadow: inset -8px 0 20px rgba(0,0,0,0.1);
}
@keyframes flipForward {
0% { transform: rotateY(0deg); filter: brightness(1); }
40% { filter: brightness(0.75); box-shadow: -25px 0 50px rgba(0,0,0,0.3); }
100% { transform: rotateY(-180deg); filter: brightness(1); }
}
@keyframes flipBackward {
0% { transform: rotateY(-180deg); filter: brightness(1); }
40% { filter: brightness(0.75); }
100% { transform: rotateY(0deg); filter: brightness(1); }
}
/* ── Navegação ── */
.nav-buttons {
display: flex;
align-items: center;
gap: 35px;
margin-top: 30px;
}
.nav-btn {
background: none;
border: 2px solid rgba(212,169,106,0.4);
cursor: pointer;
color: #d4a96a;
width: 48px; height: 48px;
border-radius: 50%;
font-size: 1.2rem;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
backdrop-filter: blur(4px);
}
.nav-btn:hover:not(:disabled) {
background: rgba(212,169,106,0.15);
border-color: #d4a96a;
transform: scale(1.1);
box-shadow: 0 0 20px rgba(212,169,106,0.3);
}
.nav-btn:disabled {
opacity: 0.2;
cursor: not-allowed;
}
.page-indicator {
color: #d4a96a;
font-size: 0.75rem;
letter-spacing: 2px;
opacity: 0.7;
min-width: 80px;
text-align: center;
}
/* ── Capa especial (página 0) ── */
.cover-page {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
text-align: center;
padding: 20px;
}
.cover-page .cover-ornament-top {
font-size: 1.5rem;
color: #8b6914;
opacity: 0.6;
margin-bottom: 20px;
}
.cover-page .cover-title {
font-size: 1.5rem;
color: #3d2b1f;
font-style: italic;
line-height: 1.4;
margin-bottom: 12px;
}
.cover-page .cover-subtitle {
font-size: 0.75rem;
color: #6b4c2a;
letter-spacing: 2px;
text-transform: uppercase;
margin-bottom: 25px;
}
.cover-page .cover-divider {
width: 80px; height: 1px;
background: linear-gradient(to right, transparent, #8b6914, transparent);
margin-bottom: 20px;
}
.cover-page .cover-author {
font-size: 0.85rem;
color: #6b4c2a;
font-style: italic;
}
.cover-page .cover-year {
font-size: 0.65rem;
color: #8b6914;
letter-spacing: 3px;
margin-top: 30px;
opacity: 0.6;
}
</style>
</head>
<body>
<p class="book-title" id="bookTitleLabel">Título do Livro</p>
<div class="book-container">
<div class="book">
<div class="book-shadow"></div>
<div class="book-top"></div>
<div class="book-bottom"></div>
<div class="book-cover-left"></div>
<div class="book-cover-right"></div>
<div class="book-spine"></div>
<div class="pages-wrapper" id="pagesWrapper">
<!-- Página esquerda -->
<div class="page-left" id="pageLeft">
<div class="page-content" id="pageLeftContent"></div>
</div>
<!-- Página direita -->
<div class="page-right" id="pageRight">
<div class="page-content" id="pageRightContent"></div>
</div>
<!-- Overlay de animação -->
<div class="flip-overlay" id="flipOverlay">
<div class="flip-front"></div>
<div class="flip-back"></div>
</div>
</div>
</div>
</div>
<div class="nav-buttons">
<button class="nav-btn" id="btnPrev" title="Página anterior">←</button>
<span class="page-indicator" id="pageIndicator">Capa</span>
<button class="nav-btn" id="btnNext" title="Próxima página">→</button>
</div>
<script>
// ════════════════════════════════════════════════
// EDITE AQUI O CONTEÚDO DO SEU LIVRO
// ════════════════════════════════════════════════
const BOOK_TITLE = "O Nome do Seu Livro";
const BOOK_AUTHOR = "Seu Nome";
const BOOK_YEAR = "2024";
const BOOK_SUBTITLE = "Um Romance";
// Cada item do array = um par de páginas (esquerda + direita)
// spread: conteúdo que ocupa as DUAS páginas (capa, etc.)
// left / right: conteúdo de cada lado separado
const pages = [
// ── Capa (spread) ──────────────────────────────
{
spread: true,
html: `
<div class="cover-page" style="width:200%; margin-left:-50%; height:100%;">
<div class="cover-ornament-top">❦</div>
<div class="cover-title">${BOOK_TITLE}</div>
<div class="cover-subtitle">${BOOK_SUBTITLE}</div>
<div class="cover-divider"></div>
<div class="cover-author">${BOOK_AUTHOR}</div>
<div class="cover-year">${BOOK_YEAR}</div>
</div>
`
},
// ── Páginas 2–3 ────────────────────────────────
{
left: {
chapter: "Capítulo I",
heading: "O Começo de Tudo",
text: `
<p>Era uma manhã como qualquer outra quando tudo mudou. O sol ainda
não havia rompido completamente o horizonte, e as ruas estavam
envoltas naquela névoa fina que precede os grandes acontecimentos.</p>
<p>Ela acordou com a sensação estranha de que algo diferente
pulsava no ar. Não era medo — era expectativa. O tipo de
sentimento que antecede uma tempestade ou um encontro inevitável.</p>
<p>Levantou-se devagar, os pés tocando o assoalho frio de madeira.
Pela janela, os telhados molhados refletiam a luz cinzenta da manhã
como espelhos imperfeitos.</p>
`
},
right: {
chapter: "Capítulo I",
text: `
<p>A cidade ainda dormia. Apenas os pássaros e os padeiros estavam
acordados naquela hora, cumpliciados no mesmo ritual silencioso de
preparar o dia para os outros.</p>
<p>Ela preparou o café devagar, observando o vapor subir em espirais
preguiçosas. Pensou no sonho que tivera — fragmentos que já
começavam a se dissolver como açúcar na água quente.</p>
<p>Havia uma carta sobre a mesa. Não sabia quando havia chegado,
nem quem a havia deixado. O envelope era simples, sem remetente,
com apenas o seu nome escrito em tinta azul-escura.</p>
`
}
},
// ── Páginas 4–5 ────────────────────────────────
{
left: {
chapter: "Capítulo I",
text: `
<p>Abriu o envelope com cuidado, como se a pressa pudesse quebrar
algo frágil dentro dele. O papel era grosso, levemente amarelado,
do tipo que não se encontra mais nas papelarias comuns.</p>
<p>As palavras eram poucas, mas pesavam mais do que qualquer
romance que ela já havia lido. Três linhas apenas, mas cada uma
delas reconfigurava tudo que ela acreditava saber sobre si mesma.</p>
<p>Ela releu. Depois releu de novo. E pela primeira vez em muitos
anos, sentiu que o chão sob seus pés não era tão sólido quanto
havia suposto.</p>
`
},
right: {
chapter: "Capítulo I",
text: `
<p>Saiu de casa sem jaqueta, sem guarda-chuva, sem o costume de
planejar cada passo. A carta estava no bolso, dobrada em quatro,
e ela podia sentir o peso leve dela contra a coxa.</p>
<p>As ruas começavam a ganhar vida. Os primeiros ônibus passavam
pesados, desenhando sombras longas nas calçadas úmidas. Rostos
sonâmbulos dentro de vidros embaçados.</p>
<p>Ela andou sem destino consciente, mas seus pés pareciam saber
para onde a levavam. Às vezes o corpo entende antes da mente
aquilo que é necessário.</p>
<div class="ornament">— ✦ —</div>
`
}
},
// ── Páginas 6–7 ────────────────────────────────
{
left: {
chapter: "Capítulo II",
heading: "O Encontro",
text: `
<p>O café da esquina era o lugar onde as histórias se cruzavam sem
que ninguém percebesse. Uma mesa de madeira escura, duas cadeiras
de palha, e a janela que emoldurava a rua como um quadro vivo.</p>
<p>Ela entrou sem pensar. O sino na porta tilintou. O cheiro de
café e pão recém-assado a envolveu como um abraço familiar.</p>
<p>Foi então que o viu. Estava de costas, mas havia algo na
posição dos ombros, na inclinação da cabeça sobre o livro aberto,
que ela reconheceu antes mesmo de vê-lo de frente.</p>
`
},
right: {
chapter: "Capítulo II",
text: `
<p>Ele se virou como se soubesse que ela estava lá. Seus olhos
se encontraram por um instante que durou mais do que deveria,
e menos do que ela teria querido.</p>
<p>— Eu sabia que você viria — disse ele, sem surpresa na voz.
Como quem confirma algo que já sabia há muito tempo.</p>
<p>Ela não respondeu imediatamente. Puxou a cadeira devagar, e
a madeira rangeu contra o piso de pedra. Sentou-se. Colocou a
carta sobre a mesa entre os dois.</p>
<p>Ele olhou para o envelope, depois para ela, e um sorriso
pequeno e difícil de decifrar cruzou seus lábios.</p>
`
}
},
// ── Páginas 8–9 ────────────────────────────────
{
left: {
chapter: "Capítulo II",
text: `
<p>— Você a leu — disse ele. Não era uma pergunta.</p>
<p>— Três vezes — respondeu ela. — E ainda não entendo o que
significa.</p>
<p>Ele pegou a xícara entre as mãos, aquecendo os dedos, e
olhou pela janela por um instante antes de voltar o olhar para
ela com uma seriedade que não combinava com o lugar.</p>
<p>— Significa que você tem uma escolha a fazer. E que, dessa
vez, não existe a opção de não escolher.</p>
`
},
right: {
chapter: "Capítulo II",
text: `
<p>Ela quis perguntar muitas coisas ao mesmo tempo. As perguntas
se empilhavam na garganta e nenhuma conseguia sair primeiro.</p>
<p>Fora, a cidade já havia acordado por completo. O movimento
das pessoas na calçada parecia absurdo — toda aquela normalidade
acontecendo do lado de fora enquanto, ali dentro, dois mundos
estavam prestes a colidir.</p>
<p>— Quanto tempo eu tenho? — perguntou ela, finalmente.</p>
<p>Ele olhou para o relógio no pulso, depois para ela com aquele
sorriso ambíguo que ela já começava a aprender a ler.</p>
<p>— Até o anoitecer — disse ele. — Não mais que isso.</p>
<div class="ornament">— ✦ —</div>
`
}
},
// ── Última página (agradecimentos) ─────────────
{
left: {
chapter: "",
heading: "Fim",
text: `
<p style="text-align:center; margin-top: 30px;">
<em>E assim a história chegou ao seu ponto de repouso,<br>
não porque terminou,<br>
mas porque encontrou o lugar certo para respirar.</em>
</p>
<div class="ornament" style="margin-top:30px; font-size:1.4rem;">❦</div>
`
},
right: {
chapter: "Nota do Autor",
text: `
<p>Este livro foi escrito com o coração dividido entre o que é
real e o que poderia ser. Cada personagem carrega um fragmento
de alguém que já existiu, ou de alguém que nunca existiu mas
deveria.</p>
<p>Agradeço a todos que caminharam comigo durante essa escrita —
os que leram os primeiros rascunhos imperfeitos, os que
ofereceram críticas honestas, e os que simplesmente acreditaram
que valia a pena terminar.</p>
<p>A você, leitor, que chegou até aqui: obrigado por emprestar
sua imaginação a estas páginas.</p>
<div class="ornament" style="margin-top: 20px;">— ${BOOK_AUTHOR}</div>
`
}
}
];
// ════════════════════════════════════════════════
// LÓGICA DO LIVRO (não precisa editar abaixo)
// ════════════════════════════════════════════════
let currentSpread = 0;
let isFlipping = false;
const pageLeftContent = document.getElementById('pageLeftContent');
const pageRightContent = document.getElementById('pageRightContent');
const flipOverlay = document.getElementById('flipOverlay');
const btnPrev = document.getElementById('btnPrev');
const btnNext = document.getElementById('btnNext');
const pageIndicator = document.getElementById('pageIndicator');
const bookTitleLabel = document.getElementById('bookTitleLabel');
bookTitleLabel.textContent = BOOK_TITLE;
function buildPageHTML(data, side) {
if (!data) return '';
let html = '';
if (data.chapter !== undefined && data.chapter !== '') {
html += `<div class="page-chapter">${data.chapter}</div>`;
}
if (data.heading) {
html += `<div class="page-heading">${data.heading}</div><div class="page-divider"></div>`;
}
if (data.text) {
html += `<div class="page-text">${data.text}</div>`;
}
return html;
}
function renderSpread(index) {
const spread = pages[index];
if (!spread) return;
if (spread.spread) {
// Página de capa ou spread completo
pageLeftContent.innerHTML = '';
pageRightContent.innerHTML = spread.html || '';
pageRightContent.style.display = 'flex';
pageRightContent.style.alignItems = 'center';
pageRightContent.style.justifyContent = 'center';
} else {
pageRightContent.style.display = '';
pageRightContent.style.alignItems = '';
pageRightContent.style.justifyContent = '';
pageLeftContent.innerHTML = buildPageHTML(spread.left, 'left');
pageRightContent.innerHTML = buildPageHTML(spread.right, 'right');
// Adiciona números de página
const leftPageNum = index * 2;
const rightPageNum = index * 2 + 1;
if (leftPageNum > 0) {
pageLeftContent.innerHTML += `<div class="page-number">${leftPageNum}</div>`;
pageRightContent.innerHTML += `<div class="page-number">${rightPageNum}</div>`;
}
}
// Atualiza indicador
if (index === 0) {
pageIndicator.textContent = 'Capa';
} else if (index === pages.length - 1) {
pageIndicator.textContent = 'Final';
} else {
pageIndicator.textContent = `${index * 2} – ${index * 2 + 1}`;
}
btnPrev.disabled = index === 0;
btnNext.disabled = index === pages.length - 1;
}
function flipPage(direction) {
if (isFlipping) return;
const nextSpread = currentSpread + direction;
if (nextSpread < 0 || nextSpread >= pages.length) return;
isFlipping = true;
btnPrev.disabled = true;
btnNext.disabled = true;
const animClass = direction > 0 ? 'flipping-forward' : 'flipping-backward';
flipOverlay.classList.add(animClass);
setTimeout(() => {
currentSpread = nextSpread;
renderSpread(currentSpread);
flipOverlay.classList.remove(animClass);
isFlipping = false;
}, 650);
}
btnNext.addEventListener('click', () => flipPage(1));
btnPrev.addEventListener('click', () => flipPage(-1));
// Suporte a teclado
document.addEventListener('keydown', e => {
if (e.key === 'ArrowRight') flipPage(1);
if (e.key === 'ArrowLeft') flipPage(-1);
});
// Renderiza a capa inicialmente
renderSpread(0);
</script>
</body>
</html>Salve esse código como livro.html e abra no navegador. Para personalizar, edite a seção marcada com EDITE AQUI no JavaScript:
BOOK_TITLE — título do livroBOOK_AUTHOR — seu nomeBOOK_YEAR — ano de publicaçãoBOOK_SUBTITLE — subtítulopages — adicione quantas páginas quiser seguindo o mesmo padrãoVocê também pode navegar com as setas do teclado além dos botões. Quer que eu ajuste o visual, as cores ou o conteúdo?


Pensou por 5 segundos