[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-1235":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":9,"languages":9,"totalLinesOfCode":9,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":13,"subscribersCount":13,"size":13,"stars1d":13,"stars7d":13,"stars30d":14,"stars90d":13,"forks30d":13,"starsTrendScore":13,"compositeScore":15,"rankGlobal":9,"rankLanguage":9,"license":9,"archived":16,"fork":16,"defaultBranch":17,"hasWiki":18,"hasPages":16,"topics":19,"createdAt":9,"pushedAt":9,"updatedAt":20,"readmeContent":21,"aiSummary":22,"trendingCount":13,"starSnapshotCount":13,"syncStatus":23,"lastSyncTime":24,"discoverSource":25},1235,"illustrated-explainer-spec","vthinkxie\u002Fillustrated-explainer-spec","vthinkxie","Spec for an infinite drill-down illustrated explainer — type a topic, click anywhere on the image to generate the next page.",null,333,46,1,0,16,5.02,false,"main",true,[],"2026-06-12 02:00:25","# Drill-Down Explainer Spec\n\n\n\nhttps:\u002F\u002Fgithub.com\u002Fuser-attachments\u002Fassets\u002Fea111127-f1f8-4d7a-bded-2414bb8e03fc\n\n\n\nA stack-agnostic spec for an AI illustrated explainer: type a topic, click anywhere on the image to drill into that spot, repeat forever — with the painting style preserved across every page.\n\nHand this spec to any capable coding LLM (or human). As long as every behavior in §12 passes, the technology choice is yours.\n\n---\n\n## 1. Product Shape\n\nA locally-run single-page web app. The user types a topic and gets back an illustrated explainer page; clicking anywhere on the image generates the next page that \"drills into\" that location (zoom-in, cross-section, inner mechanism), preserving the painting style exactly. The user can drill infinitely deep, go back, and jump to any prior page.\n\n## 2. Core Loop\n\n```\n[topic input box]\n       │ submit query\n       ▼\n[Page 1: a single 16:9 illustration]\n       │ user clicks anywhere on the image at (x, y)\n       ▼\n[Next page: drills into the (x, y) area of the previous page]\n       │ click again\n       ▼\n   …infinitely\n```\n\n## 3. State Model\n\nThe whole document is an **ordered array of pages** plus a \"current index\" pointer. Each page is a self-contained object:\n\n- `id` — a stable content fingerprint (see §6)\n- `imageUrl` — the URL of the generated image\n- `parentId` — id of the previous page (`null` for the first page)\n- `parentClick` — the click coordinates on the parent page (`null` for the first page)\n- `initialQuery` — the original topic string (only set on the first page; `null` otherwise)\n\nWhen the user clicks the image, **truncate** all pages after the current one and append the new page. This means clicking from a middle page creates a new branch, but the UI always sees a single linear array.\n\n## 4. Client Responsibilities (Deliberately Thin)\n\nThe client only does three things:\n\n1. POST the topic string or click coordinates to `\u002Fapi\u002Fpage`, receive a page object, append it to the array.\n2. Render the current page's image. On click, use `getBoundingClientRect()` to convert pixel coordinates into **normalized coordinates (0–1)** before sending — this way the client never needs to know the image's real resolution.\n3. Provide: a Back button, jump-to-any-page (thumbnail strip), and a Reset button.\n\nThe client **does not** hold any prompts, does not hold any API keys, and never calls a model directly.\n\n## 5. Single Server Endpoint\n\n`POST \u002Fapi\u002Fpage`. The request body is one of two shapes:\n\n```\n{ \"query\": \"\u003Ctopic>\" }                                          \u002F\u002F first page\n{ \"parentId\": \"\u003Cid>\", \"parentClick\": { \"x\": 0..1, \"y\": 0..1 } } \u002F\u002F subsequent page\n```\n\nResponse: `{ \"page\": \u003CPage> }`.\n\nThe server must validate strictly: `query` is 1–300 chars; `parentId` matches the content-fingerprint shape; `x` and `y` are finite floats within `[0, 1]`.\n\n## 6. Content-Addressed Caching\n\nPage ids are not random — they are **deterministic hashes**:\n\n- First-page id = `hash(\"first\" + version + normalize(query))`\n  - `normalize`: trim, collapse whitespace, lowercase\n- Child-page id = `hash(\"child\" + version + parentId + round(x, 2) + round(y, 2))`\n  - Coordinates are rounded to 2 decimal places to prevent pixel-level jitter from fragmenting the cache\n\nGenerated images are written to `\u003Cstatic>\u002Fgenerated\u002F\u003Cid>.png`. On every request, first check whether that file exists and is non-empty — if so, return its URL immediately without calling the model.\n\nEffects:\n- The same query always produces the same first page.\n- Clicking the same spot on the same page always produces the same child.\n- `Back` and thumbnail jumps are free (no regeneration).\n- Bumping the `version` string invalidates all caches at once.\n\n## 7. The Critical Trick for Child Pages (the Soul of the Project)\n\nTo make \"drill into where I pointed\" understandable to an image model, **do not** ask the model to parse coordinate numbers. Instead:\n\n1. Server reads the parent PNG.\n2. On a canvas, copy the original image, then composite a prominent **red ring + filled center dot** at `(x * width, y * height)` — a half-transparent ring, a high-contrast outline, and a solid inner dot, with a radius of about 4% of the image width.\n3. Send this **composited image (with the red marker)** as a reference image, alongside the prompt, to the image model.\n4. The prompt explicitly tells the model: \"The red circle marks where the reader pointed. Generate the next page by drilling into whatever the red circle is on (zoom in, internal structure, mechanism). **Do not include the red circle in the output.** Match the painting style of the provided image exactly — same line weight, paper tone, palette, and title typography.\"\n\nThis step translates the abstract action of \"pointing\" into something image models are natively good at: looking at pictures.\n\n## 8. Style Coherence (with Verbatim Prompts)\n\nDefine **one detailed style description string** that is the single source of truth. Both prompts below reference it by inclusion — never re-write the style across prompts.\n\n### Shared style description\n\n```\nPainting style (must remain consistent across every page):\n- Light warm paper background with generous margins\n- Clean, even dark gray or black ink outlines, consistent thin line weight\n- Soft watercolor washes, pale palette: ivory, pale green, pale blue, light gray, with restrained warm accents\n- A large serif title printed at the top center of the image\n- Calm, well-composed scene with breathing room\n\nStrict exclusions:\n- No decorative borders, seals, parchment aging, ornate fonts, or vintage texture\n- No 3D render, photorealism, neon, dark themes, or modern app UI cards\n- No dense paragraphs of text, watermarks, or tiny unreadable labels\n- No tourist map roads, landmarks, transit, or \"traveler-guide\" framing\n```\n\n### First-page prompt\n\n`{query}` is the **only** user-controlled slot. Trim it; reject anything outside 1–300 chars before substitution.\n\n```\n{STYLE_DESCRIPTION}\n\nSubject: {query}\n\nCompose a single 16:9 illustrated explainer page about the subject above.\nLet the scene's content (objects, layout, metaphor) be whatever best\nexplains the subject — cross-section, exploded view, timeline, anatomy,\nflow, comparison, or scene — chosen to fit this specific topic.\n\nOutput a single PNG image, 16:9. Print the title clearly inside the image.\n```\n\n### Child-page prompt\n\nThis prompt has **no slots**. The \"where the user pointed\" signal is delivered visually via the red-marker reference image (see §7), not via text.\n\n```\n{STYLE_DESCRIPTION}\n\nYou are continuing an illustrated explainer book.\nThe provided image is the previous page. A red circle marks\nthe area the reader pointed at.\n\nGenerate the next page: a single 16:9 image that goes deeper\ninto whatever the red circle is on — zoom in, expand its inner\nstructure, or show its mechanism.\n\nCritical: match the painting style of the provided image exactly\n— same line weight, same paper tone, same pastel palette, same\ntitle typography. The two pages must feel like consecutive spreads\nin the same hand-drawn book.\n\nDo NOT include the red circle or any cursor mark in the output.\n\nOutput a single PNG image, 16:9.\n```\n\n### Model-call shape\n\n- Both prompts are sent to a multimodal image-generation model that accepts `(text, optional reference image) → image bytes`.\n- For the child page, the request carries **two parts**: the prompt text **and** the parent image with the red marker composited onto it (PNG, base64 inline).\n- Request the model to emit a 16:9 image. If the API exposes an aspect-ratio knob, set it to `16:9`; otherwise rely on the prompt instruction.\n- Read the first inline-image part from the response; ignore any text parts.\n\n## 9. Concurrency and Failure Handling\n\n- The server **serializes generation requests in-process** (a simple promise tail is enough). Reason: image generation is slow and expensive, and concurrent runs often duplicate work on the same parent.\n- Cache hits are synchronous — they could skip the lock — but it's simpler to put them inside it.\n- Use `AbortController` + a configurable timeout when calling the model.\n- Non-200 response, or no inline image in the response → return 500. The client just shows \"Generation failed, try clicking elsewhere.\" Do not auto-retry.\n\n## 10. Security and Boundaries\n\n- The API key is read only from server-side environment variables; it is never sent to the browser.\n- The browser can only send a query string and normalized coordinates — all prompts are hard-coded on the server. User input is never spliced into prompts outside a single explicit \"topic\" slot.\n- Generated file paths are derived from the id; the client cannot specify file names, eliminating path-traversal risk.\n- Validate three things: query length, coordinate range `[0, 1]`, and `parentId` matching the hash regex.\n\n## 11. UI Element Inventory\n\n- **Top bar**: app name; `X \u002F N` page counter; Back button (disabled on the first page); Reset button (disabled when there are no pages).\n- **Topic input**: single-line input + Generate button; both disabled while loading.\n- **Canvas area**: full-width display of the current page's image; a translucent overlay during loading (\"Generating the next page…\"); on click, hand normalized coordinates up to the page state. Cursor is a pointer; clicks emit a brief ripple animation at the click point.\n- **Thumbnail strip**: bottom row, one tile per generated page with its index; current page highlighted; click to jump; collapsible.\n- **Error banner**: a single red line; clears automatically on the next successful generation.\n\n## 12. Acceptance Checklist (Behavioral, Stack-Agnostic)\n\n- Type \"how volcanoes work\" → a watercolor-style explainer page with the title printed inside, no map elements.\n- Type \"how a smartphone is built\" → a same-style cross-section \u002F exploded view, not a tourist map.\n- Click a visible object on the image → the next page clearly \"drills into that object,\" and the painting style (line weight, paper, palette) is nearly indistinguishable from the previous page.\n- Drill 5 pages deep → the style stays consistent.\n- Back returns to the previous page; thumbnails jump to any page **without** triggering a new generation (verify in the network panel).\n- Reset clears state back to the empty topic input.\n- After restarting the server, typing the same query returns instantly (disk-cache hit).\n- Two rapid consecutive clicks → the second request is processed only after the first completes.\n\n---\n\n## License\n\nDo whatever you want with this spec.\n\n---\n\nInspired by [flipbook.page](https:\u002F\u002Fflipbook.page\u002F).\n","该项目是一个无限钻取图解说明器，用户输入主题后，可以通过点击图像任意位置生成下一页，实现无限深入探索。其核心功能是通过点击图像特定区域来生成更详细的解释页面，同时保持绘画风格的一致性。技术上，它采用了一个简洁的客户端-服务器架构，客户端仅负责渲染页面和发送请求，而服务器端则处理逻辑并返回新的页面对象。适合用于需要对复杂概念或结构进行逐步详细解析的场景，如教育、培训或产品介绍等。",2,"2026-06-11 02:42:31","CREATED_QUERY"]