Memory Book
A tactile photo album with spine-hinged 3D page turns, responsive spreads, and thoughtful keyboard and touch navigation.
Overview
About the Memory Book
A tactile photo album with spine-hinged 3D page turns, responsive spreads, and thoughtful keyboard and touch navigation. It is delivered as editable TypeScript for React. Self-contained, instance-scoped CSS. Tailwind CSS is not required. No animation package required. Its focused API can be adapted to your own content and visual system.
Usage
When to use it
- Photo journals, family memories, and illustrated stories.
- Editorial collections presented as a physical album.
What’s included
Files in the product ZIP
Memory Book source
components/memory-book.tsxEditable React and TypeScript component source.
Working example
examples/example.tsxA minimal import and render example that matches the packaged API.
Installation guide
README.mdManual ZIP installation, styling, compatibility, asset, and usage notes.
Usage
Import and render
Copy the packaged source to the documented path, then use the public API shown below.
import { MemoryBook, type MemoryBookImage } from "@/components/memory-book";const photos: readonly MemoryBookImage[] = [
{ src: "/photos/first.jpg", alt: "A favorite memory", caption: "Summer, 2026" },
{ src: "/photos/second.jpg", alt: "An afternoon together" },
];
export default function Album() {
return <MemoryBook images={photos} width={900} height={320} imageLayout="spread" />;
}Props
Component API
| Prop | Type | Default | Description |
|---|---|---|---|
| images | readonly MemoryBookImage[] | — | Photos with src, descriptive alt, optional caption and layers. Each transparent layer has motion (sway or sway-bounce; default sway-bounce), src, percentage x/y/width/height (defaults 0/0/100/100), and optional origin [x,y] (default [50,50]). Register layers to a clean background with the same canvas/aspect ratio. Set riffle: true to pass a photo by, or omit src for a blank paper page. The book never rests on either: one turn riffles every sheet in between, quickly and in order, straight to the next resting photo. Empty arrays show a placeholder. |
| width | number | 900 | Maximum open-book width in CSS pixels. The book takes each photo's proportions within this limit, so the whole photo always fills it. |
| height | number | 440 | Maximum page height in CSS pixels; scales proportionally with width. The book takes each photo's proportions within this limit. |
| flipDuration | number | 950 | Page turn duration in milliseconds. Zero disables animation. |
| riffleDuration | number | 380 | Duration of each sheet in a riffle; sheets lift a quarter of this apart, so a long run passes in about a second. |
| autoPlay | boolean | false | Automatically turn forward while visible; pauses while the pointer is over the book. Swiping sideways over the book turns pages like a real book (to the left: next, to the right: previous). |
| autoPlayInterval | number | 3000 | Milliseconds each resting photo stays open before the next turn. Riffle and blank pages never wait. |
| loop | boolean | false | Wrap at either boundary. |
| imageLayout | "page" | "spread" | "page" | Page places one photo per page. Spread fills both facing pages with one photo and advances one image per turn. |
| imageRotation | 0 | 90 | 180 | 270 | 0 | Clockwise photo orientation, applied with CSS without editing source files. |
| animateLayers | boolean | true | Gently sway and bounce transparent layers on the open photo. Stops during turns, offscreen, hidden tabs and reduced motion. |
| pageColor | string | "#f5efdf" | Paper color. |
| backgroundColor | string | "#171b19" | Stage background. |
| showControls | boolean | true | Show previous/next buttons and position. Edge buttons remain available. |
| showPageNumbers | boolean | true | Print a small number on each photo page. |
| defaultIndex | number | 0 | Initial zero-based first visible photo, clamped to available photos. |
| onPageChange | (index: number) => void | — | Called once when the turn completes; receives the new zero-based first visible photo index. |
| className | string | — | Optional root class. |
| style | CSSProperties | — | Optional root styles. Layout and background are managed by the component. |
Index means the zero-based first visible photo, not a spread or sheet number. Container resizing preserves it. In page layout, wide containers advance two photos and narrow containers one. In spread layout every turn advances one full-spread photo. In page layout the final unmatched page is blank. The current photo is on the turning front face; the destination is already decoded on the receiver and back face. Inputs during a turn are ignored. Autoplay waits after completion and pauses on hover, keyboard focus, offscreen, and hidden tabs. Reduced motion uses immediate turns. Horizontal swipes preserve vertical scrolling. Single-page mode turns a sheet over its side spine; free corner dragging is outside this release.
Compatibility
Verified project setup
- ReactLoom's preview is tested with Next.js 16.3.8 App Router, React 19.2.8, TypeScript 5.9.3, and Tailwind CSS 4.3.3. This describes the store environment, not the product's minimum requirements.
- This interactive component includes the "use client" directive and must remain behind a Client Component boundary in the Next.js App Router.
- Self-contained, instance-scoped CSS. Tailwind CSS is not required. No animation package required.
- Images
- Provide your own licensed photos. The uploaded photographs are used only in the store demo and are not distributed in the ZIP.
- Fonts
- No font files are included. The component uses system font fallbacks unless your app supplies a matching font.
Installation
Add it to your project
Download the Memory Book ZIP, place the source file at src/components/memory-book.tsx, and copy the example into your own page or feature folder.
Target path
src/components/memory-book.tsxNo additional npm runtime packages are required beyond the React host; follow the styling requirements below.
Styling requirements
- Supply your own licensed image URLs. Uploaded store demo photos are not included in this ZIP.
- Width is the maximum open-book width; height is the maximum page height, both in CSS pixels. Pages scale proportionally to fit their container. Below 620px container width the album shows one photo.
- defaultIndex and onPageChange refer to the zero-based first visible photo. Resize preserves this photo. In page layout double-page navigation advances two photos and single-page navigation one. With imageLayout=spread, one photo spans both facing pages and each turn advances one image. imageRotation rotates the photo clockwise using CSS. An unmatched page is blank.
- Autoplay waits autoPlayInterval milliseconds after a completed turn and pauses on hover, focus, offscreen, and hidden tabs. Reduced motion uses immediate navigation. Repeated input during a turn is ignored.
- Optional image.layers accepts transparent artwork registered to a clean background. Each layer has motion (sway or sway-bounce; default sway-bounce), src and percentage x/y/width/height (0/0/100/100 by default), plus origin [x,y] (50/50 by default). Match the background canvas and aspect ratio. animateLayers defaults true; motion stops during turns, offscreen, hidden tabs and reduced motion. Demo cutouts are not included in the ZIP. Copy the component as-is; styles are embedded. Use a Client Component wrapper when passing onPageChange in Next.js App Router.
- No third-party code, media, or fonts are redistributed. React and React DOM are host dependencies under their respective MIT licenses.
