Skip to content

Add EPUB Reader (Fixed Layout) project#2

Open
Mario55666 wants to merge 24 commits into
mainfrom
claude/epub-reader-animations-hs80cg
Open

Add EPUB Reader (Fixed Layout) project#2
Mario55666 wants to merge 24 commits into
mainfrom
claude/epub-reader-animations-hs80cg

Conversation

@Mario55666

@Mario55666 Mario55666 commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds Source-Code/EpubReader/: vanilla HTML/CSS/JS EPUB reader built on epub.js — fixed-layout detection, per-page animation/script re-triggering, popup windows for videos/links, format-aware viewer, embedded-font detection.
  • Adds Source-Code/EpubVisualEditor/: vanilla HTML/CSS/JS visual EPUB editor (JSZip + CodeMirror) — DOM explorer with layer-type badges and transparency readout, unique per-object identification (stable ids even when InDesign-style shared classes are reused), HTML/CSS editors with live preview and a common-properties panel (with "Ninguno" color toggles), button editor, 16-preset CSS animation catalog with live preview, inline/bulk text editing, per-chapter undo/redo, per-tab help system, format-aware viewer, "Probar como lector" popup, and clean EPUB re-export.
  • Adds Source-Code/EpubButtonCatalog/: a self-contained interactive button catalog for EPUB3, delivered as a single XHTML-valid HTML file plus a ready-to-read .epub with Anime.js bundled inside:
    • Six CSS hover effects inspired by Prismic's CSS hover effects article: sliding underline, liquid fill, double-sided 3D flip, holographic gradient, lift with shadow, border draw.
    • Each button pairs its hover effect with an Anime.js v3 click animation using camelCase CSS properties (backgroundColor, borderRadius, letterSpacing, rotateY, translateX, scale).
    • 600×800 book-format container with internal scroll and reflowable content; a collapsible button list for quick navigation (scroll + highlight); three modal dialogs (welcome on load, confirmation with the exact required wording, test dialog); an event-diagnostic tool; a JS-status badge that exposes script-disabled readers at a glance; and a CSS fallback animation so taps always give visual feedback even without Anime.js.
    • Robust tap handling documented in Spanish comments: click + touchend listeners with preventDefault() and a timestamp guard — automated touch test confirms exactly one dialog open per tap (no double-fire), plus touch-action: manipulation to kill the 300 ms tap delay.
  • Editor bug fix (root cause of "buttons don't respond in Probar como lector"): resolveAssets ignored script[src], so JavaScript packaged inside an EPUB never loaded in the reader-preview popup — interactive books appeared dead there. Chapter scripts are now resolved to blob URLs (with text/javascript media type) like images/stylesheets, and reverted to their original relative paths on export. The editing iframe still blocks script execution by design (sandbox without allow-scripts); the popup is where interactivity runs, matching a real reader.

Test plan

  • Catalog standalone (Playwright, desktop context): welcome dialog on load, JS badge flips to active, hover effects verified via computed styles (underline ::after transform, holographic background-position), click animations verified mid-flight (elastic scale, backgroundColor interpolation), confirmation dialog with exact required text per button, "Probar efecto" dialog with exact required text, diagnostic output (JS active, Anime.js version, listener count), button-list navigation with highlight.
  • Catalog touch context (Playwright, has_touch + is_mobile): welcome dialog closed by tap; tapping a catalog button opens the confirmation dialog exactly once (MutationObserver counted 1 open — no double-fire from touchend+click).
  • Catalog packaged as EPUB3 (scripted manifest property, Anime.js bundled) and opened through the editor: editing iframe correctly shows the red "JavaScript inactivo" badge (scripts blocked by design), chapter script resolved to a blob URL, and in the "Probar como lector" popup: JS badge active, welcome dialog shown, bundled Anime.js loaded, buttons respond to click with the correct confirmation dialog, diagnostic reports all green.
  • Re-export of the catalog EPUB from the editor: script src reverted from blob URL to js/anime.min.js, XHTML still well-formed, bundled library intact.
  • catalogo-botones.html validated as well-formed XML (parseable as application/xhtml+xml by strict EPUB readers): CDATA-wrapped script, self-closed void elements, no raw angle brackets in comments.
  • All previous EpubReader/EpubVisualEditor test suites still pass.

Mario55666 and others added 24 commits July 16, 2026 01:49
Vanilla HTML/CSS/JS EPUB reader built on epub.js. Detects EPUB3
fixed-layout ("diseño fijo") books via rendition:layout metadata and
renders them page by page at their intended size (spread: none)
instead of reflowing text, re-dispatching DOMContentLoaded/load on
every page swap so CSS keyframe animations and embedded <script>
content keep working as you navigate. Verified end-to-end in a
headless browser: page-load animations, an actively-updating <canvas>
particle animation, and a click-triggered CSS flip transition driven
by JS all render and respond correctly.

Adds Source-Code/EpubReader/{index.html,style.css,script.js} and a
matching entry in the project list in README.md.
Replace the short drag/drop hint with a titled step-by-step explainer
(¿Cómo funciona esta aplicación?) so first-time visitors understand
how to open a book, that fixed-layout animated EPUBs are detected
automatically, and how to navigate.
Add a link/video modal (#linkModal) and intercept clicks inside the
rendered EPUB content in the capture phase:

- Absolute (external) <a href="..."> links — the ones epub.js already
  treats as target="_blank" instead of internal navigation — now open
  in the modal: direct video files (.mp4/.webm/.ogv/.ogg/.mov) get a
  <video> player, YouTube/Vimeo links get their embed iframe, and any
  other external link gets an iframe preview with an "open in new tab"
  fallback.
- Clicking an inline <video> element in the page also opens it larger
  in the same modal.
- Relative links (chapters within the book) are left untouched so
  normal reading navigation keeps working.
- Modal closes on the × button, clicking outside the box, or Escape;
  closing/opening a new book clears it so nothing keeps playing in the
  background.

Verified with Playwright against a test EPUB covering all 5 cases
(external link, YouTube link, direct video file link, inline <video>
click, and internal chapter link) — each behaves as intended and no
browser popup windows are opened.

Also documents the new behavior in the "¿Cómo funciona esta
aplicación?" empty-state steps.
Replace the in-page modal overlay with an actual window.open() popup,
enlarged and centered on the user's screen, per explicit request:

- Direct video files and YouTube/Vimeo links get a self-written HTML
  page in the popup with a full-size <video>/<iframe> player.
- Other external links navigate the popup straight to the href, so the
  linked site renders with its own layout/scripts intact instead of
  hitting X-Frame-Options iframe-embedding blocks (a real limitation
  of the previous modal approach for arbitrary external links).
- Clicking an inline <video> in the page also enlarges it the same way.
- Internal chapter links are untouched (still normal in-reader nav).
- Popups are tracked and closed together when a new book loads.
- If the browser's popup blocker stops the window, a small toast
  explains that instead of silently doing nothing.

Fixed a real bug caught in testing: the "noopener" window-feature makes
window.open() return null by design, which broke tracking/closing and
meant nothing was ever written into the video/embed popups (a blank
window would open and just hang). Now using manual `popup.opener =
null` for opener isolation on generic links, since only that path needs
it — the video/embed popups don't navigate anywhere untrusted.

Re-verified with Playwright: external link, YouTube link, direct video
file link, inline <video> click, and internal chapter link — all 5
cases behave correctly and no browsing context leaks are opened for
external content the reader doesn't control.
… its fonts

Screen adapts to the book's format:
- fitViewerToBook()/syncViewerSize() size the #viewer box to the exact
  aspect ratio the EPUB declares (book-level <meta property="rendition:
  viewport"> if present, else each page's own <meta name="viewport">),
  like object-fit: contain, instead of stretching fixed-layout pages
  into a generic rectangle. Reflowable books are unaffected.
- Found and fixed a real epub.js quirk while wiring this up: Rendition
  only re-displays content after a manager resize if `rendition.location`
  is already set (Rendition#onResized), which isn't true yet on the very
  first page — resizing at that moment silently cleared the view and
  never redrew it. Fixed by determining the aspect ratio *before* the
  initial renderTo() (peekBookAspectRatio() loads the first section's
  markup ahead of time), with a location-aware deferred-resize guard
  (pendingSizeSync, flushed from the 'relocated' handler) as a safety
  net for the rare book whose pages vary in size.

Identify, don't distort, typography:
- This reader has never injected font CSS into EPUB content (each page
  renders in its own sandboxed iframe with the book's original
  stylesheet), so the author's fonts already came through untouched.
  Made that guarantee visible: syncFontBadge()/detectPageFont() scan the
  rendered page for @font-face rules (fonts the book embeds itself) and
  fall back to the computed body font, showing whichever is active in a
  badge next to the title — proof nothing is being substituted, not a
  behavior change.

Verified with Playwright: viewer aspect ratio matches a 1200x1600 test
book exactly (and stays correct across window resizes) with content no
longer disappearing, reflowable books keep their normal wide reading
pane, and the font badge correctly reports both an embedded @font-face
name and a plain CSS font-family fallback.
…declared

Fullscreen leaving blank margins:
- fullscreenBtn only called requestFullscreen()/exitFullscreen() and
  never resynced the viewer's size afterward, so it kept whatever pixel
  size it had in windowed mode inside the now much bigger (or smaller)
  #stage — added a 'fullscreenchange' listener that calls
  syncViewerSize() (via rAF) so both the box and epub.js's internal
  layout catch up.
- While verifying that fix, found the real root cause of a subtler
  version of the same symptom: the `.viewer` CSS had a `transition:
  width/height` (added earlier purely for polish) that made
  syncViewerSize()'s getBoundingClientRect() read a mid-animation size
  one frame after the box started resizing, instead of the final target
  — epub.js's internal content got resized to that stale, smaller size
  while the box's own white background kept animating on to the correct
  larger one, leaving a visible gap of blank background around the
  actual page content. Resizes must apply instantly for anything that
  measures the box programmatically, so the transition is removed.

Font detection gave false confidence:
- The previous badge only checked whether the page's CSS *declared* an
  @font-face, not whether the browser actually managed to load it — a
  book can declare a custom font and still silently render with a
  fallback if the font file 404s or isn't in the EPUB's manifest, and
  the old badge would call that "Fuente incrustada: X" regardless.
  Rewrote it on the CSS Font Loading API (document.fonts, the same API
  epub.js itself uses internally for this purpose) to check each
  FontFace's real .status: a genuinely loaded custom font still shows
  green, but one that failed to load now shows an orange
  "Fuente incrustada no cargó: X" badge plus a console warning
  explaining the likely cause, instead of a false all-clear.

Verified with Playwright: a real embedded TrueType font loads and
renders correctly (computed font-family matches, badge green); the same
font missing from the manifest is correctly flagged as failed (badge
orange, warning logged); fullscreen on both a portrait fixed-layout book
and a reflowable book now fills available space with content and
background matching exactly, no gap.
Vanilla JS app (JSZip + CodeMirror, no build step) with a DOM explorer,
HTML/CSS editors with live preview and autocomplete, inline or bulk
text editing, per-chapter undo/redo, and export to a new .epub file.
…l Editor

Selecting an object now assigns it a stable, unique id instead of relying
on shared classes (common in InDesign-exported EPUBs, where many unrelated
objects reuse the same class), so HTML/CSS/animation edits target exactly
the selected object. Also fixes a bug where applied CSS (and now
animations) never survived export.

Adds an "Animación" tab with a catalog of 16 ready-to-use CSS animations
(entrances, bounce, pulse, shake, swing, flip, blur, grayscale), inspired
by the CSS properties anime.js documents: adjustable duration/delay/easing/
repeat, a live preview on the actual selected object, and a persistent
apply step.
… bugs

- Fix: previewing an animation on an object that already has an applied
  CSS/animation rule (persisted with an #id selector) was silently
  overridden by CSS specificity, making "Reproducir vista previa" appear
  broken after the first "Aplicar" on that object.
- Fix: selecting an object read its computed color/background/transparency
  through the editor's own selection-highlight overlay, always reporting a
  contaminated ~12% tint instead of the object's real value.
- Fix: layer type detection (image vs vector) read the src/href attribute
  after asset resolution had already rewritten it to a blob: URL, losing
  the file extension needed to tell an <img src="x.svg"> from a raster.
- Add a "Ninguno" toggle for the color/background pickers, since
  <input type=color> can't otherwise represent "don't set this".
- Add a DOM-tree layer-type badge (image/vector/text/container) and a
  per-selection transparency readout.
- Add a button editor (label + href) for button/anchor/input[button]
  elements, plus an "insert button" action.
- Size the viewer to the EPUB's own declared page format (viewport meta /
  rendition:viewport) instead of always stretching to fill the pane.
- Add a "Probar como lector" popup window rendering the current chapter
  clean of editor markup, to demonstrate the EPUB as an end reader sees it.
- Add a per-tab help panel explaining what each tool does and how it maps
  to the underlying .xhtml/.epub file.
- Add the footer credit.
…ader preview

New Source-Code/EpubButtonCatalog: a self-contained XHTML-valid catalog of
six buttons pairing Prismic-inspired CSS hover effects (sliding underline,
liquid fill, 3D flip, holographic, lift, border draw) with Anime.js click
animations (camelCase CSS properties). Includes a 600x800 book container
with reflowable content, a button navigation list, welcome/confirmation/
test modal dialogs, an event diagnostic tool, and robust tap handling
(click + touchend with preventDefault and a timestamp guard, verified to
fire exactly once per tap). Ships as both a single .html and a packaged
.epub with Anime.js bundled.

Editor fix: resolveAssets ignored script[src], so JavaScript packaged in
an EPUB never loaded in the "Probar como lector" popup and interactive
books appeared dead there — the root cause of buttons not responding to
click or touch. Chapter scripts are now resolved to blob URLs (with js
media type) like images and stylesheets, reverted to their original
relative paths on export. The editing iframe still blocks script
execution by design (sandbox without allow-scripts).
…sertion

Single-file variant of the visual EPUB editor whose "Botones" tab holds an
11-button catalog (the original 5 designs plus the 6 Prismic-inspired
hover effects from EpubButtonCatalog). Fixes two defects in the
consolidated variant: inserting a catalog button never copied its CSS
into the chapter (the extraction code was an empty stub reading rules
from a just-created blank style element), so buttons arrived unstyled in
the exported EPUB; and updateInsertButtonState() was called on every
chapter load but never defined, throwing a ReferenceError. The catalog
CSS now lives in a single BUTTON_CATALOG_CSS map injected both into the
editor page (thumbnail previews) and into the chapter's customCss on
insertion, so each button travels complete (class + pseudo-elements +
keyframes) inside the exported EPUB. Also ports the script[src] blob
resolution and the sandboxed editing iframe from the main editor.
Mesa de trabajo in the viewer statusbar: a Mover toggle that lets any
object be dragged and dropped to a fixed position (absolute coordinates
anchored to a body{position:relative} rule that travels with the export),
move up/down buttons that reorder the selected object among its siblings,
and a delete button (plus the Supr key) — all going through the undo/redo
history. Native HTML5 drags of links/images are suppressed in move mode
so dragging an <a> or <img> doesn't leave the operation hanging, and a
drag is cancelled cleanly if the pointer leaves the page.

Button editing: clicking a catalog style while a button/anchor is
selected now swaps that button's epub-btn-* class (injecting the new
style's CSS) instead of inserting a duplicate; with no button selected
it inserts a new one as before.
…ooter

The workspace now stacks vertically (viewer on top, tools below, full
width) for portrait screen reading, with the minimum width relaxed from
1366px to 720px. The generic help panel is replaced by per-screen
contextual help: each of the 7 tabs has its own text explaining what the
tool does and how it affects the EPUB file, shown automatically on the
first visit to each screen (step-by-step tutorial) and on demand via the
"?" button, updating live when switching tabs. The footer now credits
Curso de Infografía 2026 · Docente: Mg Mario Quiroz Martinez.
…th live coordinates

When the EPUB declares a page size, the editing viewer now renders the
chapter iframe at the document's ORIGINAL pixel dimensions and scales it
visually with a CSS transform to fit entirely in the pane: no scrollbars
(container clips, inner document overflow hidden via an editor-only rule
stripped on export), and all in-document coordinates remain real pixels
of the original. The status bar reports the original document dimensions
and current scale, live cursor coordinates inside the document, and the
selected object's position and size; the layer info panel shows the same
position/size for the selection.
The button editor now covers the full interactive workflow: per-button
text and background color pickers (written as an #id rule that overrides
the catalog class and travels in the export), a hyperlink field for
chapter files, anchors or external URLs, and EPUB-context actions — a
button can play a chosen animation preset on any object with an id, or
toggle another object's visibility. Actions are declared as data-*
attributes and executed by a small runtime script embedded in the
chapter (ES5, click+touchend with double-fire guard), deliberately
written without <, ampersands or comparison operators because
XMLSerializer escapes those into entities inside XHTML, which corrupted
the first version of the script when exported.
…learer errors

Real-world EPUBs URL-encode file names in the OPF/NCX (spaces become
%20); zip lookups used the encoded path verbatim, got null, and crashed
before the book could render. Paths now fall back to their decoded form
for chapters and assets, a chapter without a readable body reports a
meaningful error instead of failing later, and the load-failure toast
explains what a valid .epub requires.
…clared page

Chapters whose content overflows the declared page size (an EPUB
declaring 600x800 with a longer chapter) were clipped by the no-scroll
fixed-page mode, showing only part of the document. The viewer now
measures the real content size after load (and again 400ms later, once
async blob images have laid out), uses the larger of declared vs real
dimensions for the scaled frame so the whole document is always visible,
and reports both sizes in the status bar.
… hidden objects

The sandboxed editing viewer never runs the EPUB's action script, so a
configured button appeared to do nothing until previewed as a reader.
The button editor now has 'Probar accion' (the editor itself replays the
configured animation/toggle inside the viewer), 'Ubicar boton' (enables
move mode and walks through drag placement), and prominent modal dialogs
that confirm each configuration step and explain how the action behaves
in a real reader. Objects hidden by the show/hide action render as
semi-transparent orange-dashed ghosts in the editor only (rule lives in
the internal stylesheet, stripped on export), and the Botones help text
now documents the full configuration workflow.
…always-visible button config

Probar accion, Ubicar and a new Revisar (reader preview) button now live
in the workspace toolbar under the viewer, enabled by selection. The
viewer always locks to the EPUB output format with no scrolling anywhere:
books without a declared page size get a 600x800 default expanded to the
real content, and workspace drags are clamped to the page bounds so no
object can land outside the mesa de trabajo. The button configuration
panel (text, hyperlink, colors, animation/object-state actions) is now
permanently visible in the Botones tab, disabled until a button is
selected, instead of hidden - which made users believe the whole
configuration system was missing.
InDesign-style animated EPUBs keep every animated object at opacity:0
until the book's own script triggers its entry animation; that script is
sandboxed out of the editing viewer, so such books rendered as an empty
page with nothing selectable. A workspace toggle (on by default) now
forces opacity/visibility and suppresses animations inside the editing
viewer only - verified against a real 1920x1080 InDesign EPUB where all
847 objects (68 previously invisible) became selectable, with the
exported file free of any editor-only classes.
applyButtonEdit silently returned for anything that was not a
button/anchor/input, so selecting an InDesign container and pressing
Actualizar Boton did nothing and Probar accion then reported no action
configured. The configuration panel now enables for any selected object:
colors and animation/visibility actions apply to all elements, the text
field disables itself for containers with children (edited via the Texto
tab instead), and hyperlinks on non-anchor objects are stored as
data-enlace and navigated by the exported runtime on tap. Verified
against the real InDesign EPUB: a container was configured with an
animate action plus link, tested in-viewer, and exported intact.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants