← Back to blog
Guide
Build an interactive 3D bookshelf with Replit
A practical workflow from the first interaction to realistic books and a shelf full of design classics.
Daniil Filatov
· 8 min read
Watch the reel ↗

Thanks for checking out my workflow! This is the focused version of the process I show in the video: one prompt to build the shelf, one to upgrade the books, and one to fill it with real design classics.
Keep everything in the same Replit Agent chat.
Start with the first prompt, review the result, and refine only the problems you can actually see.
Explore the finished bookshelf: The Personal Library
Build with Replit: Replit.com
Animation reference: mawise/bookshelf on GitHub
Realistic GLB model: Hard Cover Books on Fab
My book collection: Design Shelf on Internet Archive
My complete workflow (use as a reference)
Build the first interactive shelf and use the GitHub project to explain the pull-out, flip, and return animation.
Refine the working prototype through short follow-up requests.
Replace the flat procedural books with a realistic GLB model rendered through Three.js.
Give the Agent one Internet Archive list so it can import all books, covers, metadata, and reading links.
Finish with small visual adjustments: better spine designs, natural spacing, a foreground leaf, and realistic shadows.
01 — Build the interactive bookshelf
This is the original prompt I used at the start of the project. Attach your visual reference, paste it into a new Replit project, and let the Agent inspect the GitHub files before it begins building.
The wording below is preserved from the original build prompt. I only reorganized it into clear sections and lists so it is easier to read and copy.
Prompt 01
Let's build a premium interactive digital bookshelf. It's phase 1 of our build, where we're focusing on animation and a visual-quality prototype. The most important outcome is a convincing transition where the same physical book moves out of the shelves, rotates toward the viewer, shows its front and back covers, and returns to its original position. ## STUDY THE REFERENCE PROJECT Before writing code, inspect this MIT-licensed project as a technical animation reference: - Main repository: https://github.com/mawise/bookshelf - Book structure and interaction states: https://github.com/mawise/bookshelf/blob/main/views/index.erb - Core CSS 3D structure: https://github.com/mawise/bookshelf/blob/main/public/css/style.css - Pull-out, rotate, flip, and return animations: https://github.com/mawise/bookshelf/blob/main/public/css/anim.css - Calibre metadata mapping and physical book dimensions: https://github.com/mawise/bookshelf/blob/main/calibre.rb ### Reuse these concepts • Construct each book from separate front cover, back cover, spine, and page-block surfaces. - Show primarily the spine while the book rests on the shelf. - Follow the sequence: resting → hover → pulled forward → front cover → back cover → returned. - Keep only one book selected at a time. - Calculate book height from the cover aspect ratio. - Calculate book thickness from its page count using a restrained nonlinear formula. - Derive a suitable spine color from the cover and automatically choose readable light or dark text. - Reverse the complete animation when another book is selected. Use the repository as a behavioral reference, not as the application foundation. Do not use Ruby, Sinatra, ERB, RMagick, inline JavaScript, or its download routes. Rebuild the relevant behavior as reusable modern React components. If you copy any original source code directly, preserve the repository’s MIT attribution. ## TECHNICAL STACK Use:• Vite - React - TypeScript - Motion for React, imported from motion/react - CSS Modules or structured plain CSS for the 3D geometry - Accessible semantic HTML Do not use Three.js, React Three Fiber, WebGL, Tailwind, authentication, a database, Calibre integration, filtering, or book-management features in this phase. Do not run React state updates on every animation frame. Animate transform properties through Motion values and browser-composited CSS transforms. ## VISUAL DIRECTION Use the attached image only as a reference for composition, spacing, atmosphere, and the physical shelf. Ignore any text or watermark contained inside the reference. Create a full-viewport editorial composition:• Warm off-white background - Large amount of negative space on the left - Minimal black typography - A clean white physical shelf near the bottom of the viewport - A small group of seven books beginning in the right half of the screen - Soft directional lighting - Restrained realistic shadows - Subtle material texture on the covers - Premium art-book or gallery-catalogue feeling Avoid gradients, glassmorphism, generic SaaS styling, blue-purple AI colors, excessive rounded cards, and decorative interface elements. Add a temporary title on the left:“THE PERSONAL LIBRARY” Below it, add:“An interactive collection of books worth keeping.” Add a small instruction:“Select a book” The page should remain visually calm. The books and their physical movement are the main experience. ## BOOK CONSTRUCTION Create a reusable Book3D component with these configurable properties: - ID - Title - Author - Cover image - Cover aspect ratio - Page count - Spine color - Text color - Height - Thickness - Selected state Build every book from actual connected 3D surfaces:• Front cover - Back cover - Spine - Page block - Thin top and bottom page surfaces if needed Use a shared parent perspective so every book exists inside the same three-dimensional space. Apply transform-style: preserve-3d through all required nested wrappers. Keep clipping, opacity, blur, filters, masks, and decorative shadows on separate outer elements so they do not flatten the book’s 3D children. The book must remain physically dimensional throughout the complete animation. Do not replace it with a separate flat image, modal, or duplicate card after selection. Use original placeholder cover designs created with CSS and local assets. Do not depend on unreliable remote placeholder URLs. ## INTERACTION STATES RESTING The book stands naturally on the shelf with its spine facing the viewer. Books can have slightly different heights and thicknesses, but their bottom edges must align precisely with the shelf. ### HOVER OR KEYBOARD FOCUS The book: - Moves slightly upward - Pulls slightly toward the viewer - Rotates by a few degrees - Gains a stronger contact shadow - Moves neighbouring books apart very subtly if this can be done without layout instability The response should feel immediate but weighted. ### SELECTED FRONT COVER On click, tap, or Enter: - Bring the selected book visually above every other book. - Move it forward from its exact shelf position. - Lift it slightly. - Rotate it from spine view until its front cover faces the viewer. - Move it toward the visual center-right of the viewport. - Keep the transformation continuous so the user always understands that it is the same book. - Make the remaining books visually quieter without applying opacity or filters to the selected book’s 3D parent. Use a premium spring transition with minimal bounce. The movement should feel physical, controlled, and slightly heavy. ### BACK COVER When the selected book is clicked again, rotate the same book to show its back cover. Place a short placeholder description and page count on the back. ### RETURN Return the book to its exact original shelf position when: - The visible close button is pressed - Escape is pressed - The background is clicked - Another book is selected The return animation must precisely reverse the movement without jumping between coordinates. Only one book can remain selected at a time. ## INPUT AND ACCESSIBILITY Support: - Mouse hover - Mouse click - Touch tap - Keyboard focus - Enter to select - Escape to close Every book must be a semantic interactive element with an accessible label containing its title and author. Create a visible keyboard focus state that triggers the same physical response as hover. Respect prefers-reduced-motion. In reduced-motion mode, shorten the travel and rotation while keeping the information understandable. ## RESPONSIVE BEHAVIOR Desktop is the primary visual target. For smaller screens:• Reduce perspective intensity and travel distance. - Keep books large enough to tap. - Move the title above the shelf if the left-side composition no longer fits. - Preserve the same interaction states. - Avoid horizontal page overflow during this phase. ## ACCEPTANCE CRITERIA The phase is complete only when: 1. Seven books appear aligned on one physical shelf. 2. Every book has a real front, back, spine, and page block. 3. Hover and keyboard focus feel responsive. 4. A selected book continuously moves from the shelf into a front-cover presentation. 5. A second interaction reveals its back cover. 6. Closing returns it to the exact original location. 7. Selecting another book returns the previous one first. 8. No flat modal or replacement cover is used. 9. The layout works on desktop and mobile. 10. The production build completes without errors. First inspect the reference files and briefly record the concepts being reused in the project documentation. Then continue directly with implementation—do not stop after the analysis or wait for additional approval. After implementation, run the app, test every interaction state, fix visible issues, and summarize what was completed.
Copy includes the complete prompt.
How I refined the first version
The first output gave me the basic shelf and interaction. From there, I stayed in the same Agent chat and fixed things as I noticed them.
I adjusted the sizing, stacking, and overlapping first. Then I matched the perspective of the books and shelf, moved the books closer together, and added drag-controlled 3D rotation.
After that, I experimented with more books, horizontal scrolling, smoother spring movement, and a full book-details view. These were short follow-up requests rather than one universal prompt, because your first result will probably need different fixes.
A simple refinement format that works well: “Fix this specific problem: [what you see]. I want [desired result]. Keep [what already works]. Change only [relevant area]. I’ll test it manually.”
For the final polish, I asked Replit to improve the spine designs, vary the spacing and thickness, make hover more noticeable, add a soft green leaf in the foreground, and introduce warmer, more realistic shadows.
02 — Replace flat books with realistic GLB models
The early books still looked like simple CSS boxes. I replaced them with this Hard Cover Books asset from Fab and rendered them through Three.js.
Before sending the prompt
Download the GLB asset manually from Fab. Fab requires an account and license acceptance, so the Agent should not be expected to download it for you.
Upload the model and any included textures to public/models/fab-hardcover/ in Replit.
Keep the original filenames and folder structure.
Then send the prompt below in the same Agent chat.
The Agent can inspect a local model, identify its meshes and materials, and adapt it to the existing interaction. A marketplace page link alone does not give it the licensed asset file.
Prompt 02
Replace the procedural Three.js book geometry with the downloaded Fab “Hard Cover Books” asset. The asset files are located inside: `public/models/fab-hardcover/` First inspect this directory and identify the primary `.glb` or `.gltf` file and any external texture files referenced by it. Keep the existing CSS bookshelf available as a fallback and preserve the current `?renderer=three` prototype switch. ASSET LOADING • Load the model using Drei `useGLTF`. • Use the real asset file discovered inside `public/models/fab-hardcover/` rather than assuming an exact filename. • Preload the model after resolving its path. • If the downloaded format is `.gltf`, preserve its relative `.bin` and texture paths. • Do not replace the model’s original PBR materials with flat-color materials. • Enable `castShadow` and `receiveShadow` recursively on every relevant mesh. • Keep the model cached and reuse its geometry across book instances. MODEL INSPECTION Inspect the loaded GLTF scene and create a concise internal inventory of: • Root objects • Individual book variants • Mesh names • Material names • Cover or jacket meshes • Spine meshes • Page-block meshes • Available UV channels • Texture maps used by every material Use this inventory to create a reusable adapter for the asset. Do not rely on hardcoded generated names such as `Object_1` throughout the application. Centralize the resolved node and material mapping inside the adapter. Create components such as: • `FabBookAsset` • `FabBookVariant` • `FabBookMaterials` • `BookCoverArtwork` • `normalizeFabBook` BOOK VARIANTS The Fab asset contains multiple hardcover books. • Identify every individual book model contained in the scene. • Make every book available through a stable numeric or string `variant` property. • Use different variants across the six-book Three.js prototype. • Keep one book per component instance rather than rendering the complete original asset set for every shelf item. • Remove any original cameras, lights, backgrounds, floors, and presentation objects included in the downloaded file. NORMALIZATION Normalize every extracted book so it can work inside the existing shelf system. • Calculate its bounding box using `THREE.Box3`. • Centre the model horizontally around its local origin. • Place the lowest point of the book at local Y = 0. • Orient the spine consistently toward the front of the shelf. • Make the front cover face the same direction across every variant. • Normalize the initial scale into the existing shelf measurement system. • Keep the original proportions and bevel quality. • Allow only modest per-book scaling to create different heights, widths, and thicknesses. • Avoid extreme non-uniform scaling that visibly distorts the PBR textures or curved spine. MATERIAL PRESERVATION Preserve every useful material property included with the asset: • Base-color map • Roughness map • Normal map • Ambient-occlusion map • Clear-coat values • Bump or height information • Original texture repeat and wrapping • UV channel assignment Set artwork and color textures to `THREE.SRGBColorSpace`. Keep roughness, normal, and AO textures in their appropriate non-color spaces. Apply `flipY = false` to replacement textures used with GLTF UV coordinates. Use sensible anisotropic filtering for cover artwork viewed at an angle. CUSTOM COVER SUPPORT Extend the existing book data with: • `coverUrl` • `coverFit` • `coverPosition` • `spineColor` • `backColor` • `modelVariant` The component must accept any portrait-oriented image through `coverUrl`. CUSTOMIZATION STRATEGY Inspect whether the asset exposes the front cover or dust jacket as a separate mesh or separate material slot. If the front is separate: • Clone only the material that needs unique artwork. • Preserve its original roughness, normal, AO, and clear-coat properties. • Replace only its color map with the book cover artwork. If the front shares one texture atlas with other surfaces: • Keep the original physical material. • Add a thin artwork plane directly above the front cover surface. • Align it accurately to the cover bounds. • Offset it by only enough to prevent z-fighting. • Match the cover’s corner treatment and orientation. • Keep the artwork plane visually attached to the physical cover during rotation. • Do not stretch portrait artwork. • Use a cover-style crop that preserves aspect ratio and fills the available area. CALIBRE-READY API Prepare the component for future Calibre integration. The final reusable API should support a structure similar to: `<FabBookVariant variant={book.modelVariant} coverUrl={book.coverUrl} title={book.title} author={book.author} />` Only the front-cover image will come directly from Calibre. Prepare separate functions for generating: • A matching spine texture from the title, author, and dominant cover color. • A back-cover texture from the description, publisher, and dominant cover color. Do not implement the Calibre connection during this task, but keep the model API ready for it. For the current prototype, use the existing local cover artwork or generated editorial covers as `coverUrl` values. SPINE CUSTOMIZATION If the asset contains a separately mapped spine: • Clone its material per book. • Generate a high-resolution CanvasTexture containing the title and author. • Use a dominant color sampled from the front cover. • Keep the original normal, roughness, and fabric detail maps. If the spine cannot be addressed separately: • Add a thin mapped spine overlay aligned to the original geometry. • Ensure it follows the complete book rotation. BACK COVER Keep the asset’s original back-cover material during this prototype. Add support for replacing it later without changing the component architecture. INSTANCE SAFETY • Clone materials before applying unique artwork. • Never mutate the shared cached GLTF materials directly. • Reuse geometry wherever possible. • Dispose only textures and cloned materials created by each book instance. • Do not dispose the shared cached source geometry. INTERACTION Wrap every imported book inside the existing interaction groups: 1. Shelf-position group 2. Selection-animation group 3. Drag-rotation group 4. Imported Fab model Preserve: • Hover response • Selection • Inactive sibling behaviour • X and Y drag rotation • Click-versus-drag threshold • Escape to close • Existing spring movement All pointer events should operate on the complete imported book rather than individual internal meshes. LIGHTING Retune the Three.js lighting for the asset’s original PBR materials. • Use a soft studio environment. • Keep a large key light from the upper-left. • Add gentle fill and restrained rim lighting. • Preserve realistic roughness instead of making every cover equally glossy. • Add soft contact shadows beneath the books. • Avoid excessive exposure, bloom, saturated reflections, or pure-black shadows. VISUAL TARGET The imported books should visibly retain: • Real bevels • Curved spines • Physical cover thickness • Detailed page blocks • PBR surface response • Realistic highlights • Contact shadows • Material imperfections The result must look substantially more realistic than the procedural `RoundedBox` books. FALLBACK If the asset cannot load: • Show the existing procedural Three.js books. • Log one concise asset-loading error. • Keep the remainder of the application functional. IMPLEMENTATION PROCESS Implement this only inside the Three.js prototype. Do not remove the existing procedural implementation until the imported asset has been manually approved. Do not run automated browser tests or repeated visual validation. Resolve immediate loading, build, texture-path, and TypeScript errors, then stop and summarize: • The detected GLB filename • Available book variants • Relevant mesh names • Relevant material names • Whether the front cover has a separate material • How `coverUrl` is currently applied • Any limitation discovered in the asset’s UV layout I will test the visual result and imported materials manually.
Copy includes the complete prompt.
Want more prompts like this?
370+ tested prompts across 38 collections, plus the Prompt Builder to remix them.
03 — Import real design books from Internet Archive
Internet Archive is simply the source I used for this project. You can use any book source that gives the Agent consistent titles, authors, covers, metadata, and a stable ID or link.
Other possible sources:
Open Library for open book metadata and covers
Google Books API for titles, authors, descriptions, categories, and cover images
Calibre or Calibre-Web for your own managed library
A personal Notion database, Airtable, CMS, JSON file, or CSV for a fully curated collection
The exact integration will change with the source, but the principle stays the same: give the Agent one structured collection instead of adding every book manually.
For my version, I collected the design classics I wanted inside one public Internet Archive list. Instead of sending books one by one, I gave Replit that single list.
List page: Design Shelf
Structured endpoint: Internet Archive list JSON
How the list link helps
The visual list page is useful for people, but the structured endpoint is better for the Agent. It contains every book identifier. From each identifier, Replit can request:
Original reading page: https://archive.org/details/{identifier}
Ask the Agent to normalize and save the imported data locally. This avoids scraping the page or requesting the complete collection again on every visit.
Prompt 03
Import every book from my public Internet Archive list and replace the current placeholder library data with the imported collection. List page: https://archive.org/details/@daniil_filatov/lists/1/design-shelf Use this JSON endpoint to read the list: https://archive.org/services/users/@daniil_filatov/lists/1 ## Import workflow Read every item from `value.members` and use its `identifier` as the permanent unique ID. For each identifier, fetch: • Metadata: `https://archive.org/metadata/{identifier}` • Cover: `https://archive.org/services/img/{identifier}` • Original page: `https://archive.org/details/{identifier}` Import and normalize these fields when available: • title • creator or author • publication year • description • publisher • subjects or categories • language • page count • availability or access restriction • archive identifier • original Internet Archive URL • cover image Metadata values may be strings, arrays, HTML, or missing. Convert arrays into readable comma-separated text, strip HTML from descriptions, and use sensible fallbacks for missing values without inventing information. ## Local data and covers Create a reusable sync script and expose it as: `npm run sync:archive` Run it once now to import the complete list. Save the normalized collection locally as project data so the public website does not request the complete Internet Archive list every time it loads. Download each available cover into: `public/covers/archive/{identifier}.jpg` Follow redirects and verify that the response is a valid image. If a cover cannot be downloaded, keep the book in the collection and use the existing fallback cover. Use `archiveIdentifier` to prevent duplicates. The IBM Selectric book already added manually must be updated from the imported data instead of duplicated. Preserve the exact order of books from my Internet Archive list. ## 3D books Render every imported book using the existing Fab GLB system. Cycle naturally through the six existing Fab book variants to create realistic variation in height, width, and thickness. Apply the downloaded cover only to the front cover surface using the existing `coverUrl` system. Preserve its aspect ratio and crop without stretching. Generate each spine from the dominant cover color, title, and author. Keep the existing PBR materials, page geometry, lighting, shadows, rounded spines, extraction animation, detail view, rotation, and return animation. ## Book details Populate the existing detail panel with the imported metadata. Add a visible `View on Internet Archive` link that opens the correct original item page in a new tab. Show an availability label when the metadata clearly indicates `Always Available`, `Borrow Only`, or another restricted state. Keep reading status, favorites, rating, and progress as local user-controlled fields. Match saved local data by `archiveIdentifier`. If the sync fails completely, keep the current library data as a fallback. Only replace the placeholder collection after at least one valid book has been imported. Limit concurrent Internet Archive requests to three at a time and retry individual failed requests once. A single failed book must not cancel the full import. Do not add authentication. Do not run automated browser tests; resolve only import, TypeScript, and build errors, then report how many books and covers were successfully imported so I can review everything manually.
Copy includes the complete prompt.
What the finished version can do
Browse a horizontal collection of real design classics.
Pull any book out of the shelf.
Rotate it and inspect the front, spine, pages, and back.
Open a detailed information view.
Filter the collection by design category.
Open the matching Internet Archive page to read or borrow the book.
Quick checklist
The GitHub project is used as a behavior reference, not copied as the application foundation.
The first shelf interaction works before extra features are added.
Refinements stay short and focus on one visible issue at a time.
The real GLB file is uploaded locally before the model prompt is sent.
The Agent uses the structured Internet Archive endpoint rather than scraping the list page.
Every imported cover, metadata record, and reading link matches the correct book.
Make it yours
Explore the finished bookshelf: The Personal Library
Replace my Internet Archive list with your own collection, change the visual direction, and decide how realistic or experimental you want the shelf to feel.
The three prompts give you the full foundation. Everything between them is simply observation, small adjustments, and testing.
FILATOV.DESIGN MEMBERSHIP
Get every prompt behind my work
370+ tested prompts across 38 collections, the Prompt Builder to remix them in seconds, and new drops every week.
$15/month. Cancel anytime.
MORE FROM THE BLOG

Grok Imagine + Grok Build: a cinematic racing website
Turn a crushed can into a Formula 1 car, chain the clips into one continuous film, and build a scroll-driven editorial website around it.

5 niche archives for design inspiration
Five online archives I use for visual research, moodboards and typography studies, far beyond the usual Pinterest search.
Motion graphics with Claude Opus 5.5
The prompts I used to create two branded motion-graphics films in Claude, without plugins or manual keyframes.

Build an animated gradient studio with Replit
Two prompts that build a browser-based gradient generator with draggable color points, motion, noise and 4K export.
