ESP32-S3 Bench Guide
ESP32‑S3 N16R8 벤치 가이드: 실시간 핀아웃, 강의, 시뮬레이터 및 벤치 로그
경영 개념을 쉬운 말로 하나씩, 인도 고전 구절과 함께 읽을 수 있다 무료이며 회원가입 필요 없음
Management concepts in plain words, one idea at a time, each read beside a cited passage from India's classical texts. Free to read, with no account.
교육TypeScript · CSSGitHub @obvioshek온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Myveda - A Next.js web application
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Two things live in this repository:
/, for myvedaverse.in: Management is new. Its questions are not. It presents both halves of Veda Verse in the first screen: management ideas read alongside India's classical texts, and a community where every answer says how the writer knows. It is set in the flat, ruled "Modernist" design (Archivo, a red accent, square corners). Visitors can answer a sample question, open what a classical text said, guess whether real passages are documented or a view, and try an example community thread. Signing in is optional./home and the pages around it. Members ask questions and share what they know, and every post says what it rests on: Asking, Documented, Lived, Told or My view. There are no public counts, and the daily Edition ends.Built with Next.js 16.4 (App Router), React 19, Prisma 8 (@prisma/orm-postgres) on PostgreSQL, and Supabase Auth.
npm install
cp .env.example .env # then set DATABASE_URL
npm run db:migrate # create the tables
npm run db:seed # sample members, circles, questions and house pieces
npm run dev
The landing page works with no configuration at all: everything on it runs in the browser, and the only things it remembers (the concept to "Continue" with, and the reader's note) stay in that browser's local storage. The product needs the database.
To put the site live on myvedaverse.in, follow DEPLOY.md. It covers hosting, database, sign-in email and DNS records.
Copy .env.example to .env. Use .env rather than .env.local, because the Prisma CLI and the seed script read it too.
| Variable | What it does |
|---|---|
DATABASE_URL | PostgreSQL 15 or newer. Required for the product; optional for the landing page. |
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY | Email magic-link sign-in. A member's profile is created the first time they sign in, and they start with onboarding. |
NEXT_PUBLIC_SITE_URL | The site's public address, used in the sign-in email link, canonical and share tags, robots.txt and the sitemap. Defaults to https://myvedaverse.in in production and http://localhost:3000 in development. |
SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM | Outgoing email: the weekly email and its confirmations, problem reports (sent to the contact address), and the early list's confirmations. Without them, addresses are saved but nothing is sent, and the report form offers to open the reader's own email instead. With GoDaddy email, use smtpout.secureserver.net, port 465, and the mailbox's address and password. |
CRON_SECRET | Lets Vercel Cron call /api/weekly, which sends the weekly email. Any long random string; Vercel sends it with each call. Without it (or without email set up) the route does nothing. |
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION, NEXT_PUBLIC_BING_SITE_VERIFICATION | Optional. The content value of Google Search Console's or Bing Webmaster Tools' HTML-tag verification, if you verify the site that way instead of with a DNS record. See DEPLOY.md, "Getting found on Google". |
DEMO_LOGIN | 1 allows signing in as a seeded member without email; 0 turns it off. It is on by default in development and off in production. Never enable it on a real deployment, because it lets anyone act as any member. |
| Screen | Path | What it does |
|---|---|---|
| Sign in | /signin | Email magic link (Supabase), or a demo member when demo sign-in is on. |
| Onboarding | /welcome | Pick at least 3 topics, what brings you here, up to 3 "Ask me about" topics, people and a circle to follow, then a Documented-or-Told check. |
| Home | /home | Today's Edition: a short daily selection from people, circles and topics you follow, plus the house. Each post gives the reason it is there, and open questions you could answer appear in a box. Following is newest first since your last visit. |
| Reader | /read/[slug], /note/[id] | House pieces, with their sources, what's Documented kept apart from what's Told, and corrections. Tap a paragraph to ask about it or add context. Replies are grouped by how they relate (adds context, builds on, disagrees, asks). |
| Question | /q/[id] | Answers are grouped: the one that helped, answers, builds-on, and "several views" when people disagree. Only the asker marks the answer that helped. |
| Communities | /c, /c/[slug] | Circles, boards, cohorts and practice groups, each with its own memory rules. Threads, spoiler-gated chapters, archive and charter. Cohorts take applications. |
| Profile | /u/[handle] | Ask-me-about and curious-about topics; posts, answers and questions. Follow, mute, block or report. Your own profile has a dashboard only you can see. |
| Discover | /discover, /t/[topic] | Search across questions, posts, people, topics and circles, with an "Only Documented" filter. Topic pages list what's best documented, open questions, circles and people. |
| Library | /library | Saved items with private notes and a label filter, collections (private or shared with a circle), drafts and reading history. |
| Inbox | /inbox | Answers, builds-on, mentions and thanks arrive right away, but are held until 8 am during quiet hours (10 pm to 8 am in your time zone). Circle activity waits for a daily or weekly digest. Counts and "trending" notifications are never sent. You can reply straight from the Inbox. |
These live in the server actions in actions/app/, not just in the UI:
app/(landing)/ is the landing site: the page itself, the unit chapters at /learn and /learn/[slug], /early-list (where confirmation emails land) and /privacy, with its own root layout and stylesheet (landing.css).
content/landing.ts, and the components are in components/landing/. The design follows the Veda Verse Modernist site design (v2) home page, with its copy review: every verse shown is cited, and a slot with no verified content stays empty rather than showing a placeholder. Only the interactive parts (header, continue band, hero question, question cards, unit tabs, "What the classics add", example thread, search, toast) are client components. The fonts (Archivo and Tiro Devanagari Sanskrit) are served from public/fonts.HeroTry); the question cards ask first and open the classical answer on request (QuestionCards); the units are tabs that open on the unit last read, with progress on each chapter (UnitTabs); and "What the classics add" (ClassicsAdd) sets modern ideas beside passages by theme, each with what the passage adds and where the two part ways, and links to a five-step walk for newcomers at /learn/start. Both draw their pairs from content/learn/readings.ts (THEMES and WALK). Everything shown is the chapters' own text: the passage, the chapter's paragraph on how it meets the idea, and the lesson's adds and differs notes. Only the walk's short "what to notice" lines are written there. Pick documented passages with quoted text that a newcomer can follow; the build fails if a pick is missing, has no quote or has no notes. Every card and verse links to the lesson where its passage is read. The header links to the chapters, glossary, revision sheets and community. The sections run in one order, from curiosity to joining: the hero and its question; three questions worth a second look; the units and chapters, with live counts; "What the classics add", with the texts the chapters quote; and the community. The community section shows an example thread (ThreadPreview) laid out the way the app lays out a question: replies grouped by how they relate, each labelled with what it rests on, a disagreement with its reason, Helpful kept private, and the four labels to choose from. Numbered notes beside it (COMMUNITY_NOTES in content/landing.ts) explain each mark. Every note and every behaviour in the example must match a rule the app enforces; keep them in step with it. The header's "Community" link (on every landing page) and the footer's "How it works" go to that section; "Join the community" opens the app at , which sends anyone not signed in to first. So does "Ask the community about this", under each concept's reflection prompt. It keeps the concept and chapter in local storage (, key ) while the reader signs in and, if new, onboards. The app's then opens the composer once as a question about that concept, and forgets it; anything older than a day is dropped. There is no separate sign-in link, so the static pages make no request to find out who is signed in.These keep the site comfortable to use, accessible (WCAG 2.2 AA), fast and safe. Check a change against them before adding to it.
Navigation. Every page is listed once, in content/nav.ts (SITE_MAP): three groups, Learn, Practise and Keep track. A label is the page's name, a noun phrase (only "Start here" is a verb), and the page's eyebrow repeats it. The header's Menu and every footer (PageShell and the home page) are built from it, so a new page goes there and nowhere else. The header itself keeps the five places readers go most: Chapters, Glossary, Practice, Revision and Community. Practice and the Menu show how many questions are due for review (components/learn/DueBadge.tsx). On phones the header slides away while reading down a page and returns on the way up (components/landing/HeaderHide.tsx); a chapter's reading strip sits at the foot of the screen there. The Menu closes on Escape, a click outside it, Back on a touch screen, or a page chosen in it.
Reading. Concept text is 17px on 28px lines, at most 68 characters wide (.prose in learn.css); the lead line is 18px. Tables scroll sideways inside their frame with a shadow at the edge that has more, and each scrolling table is focusable, with role="region" and a label, so keyboards can scroll it. Each concept's summary ends with a button to the next concept (or, after the last, the chapter test). On a chapter page, J and K move between concepts and / opens search. "Saved to Continue" shows once a visit, not on every concept.
Tap targets. Header links, the Menu and its links are at least 44px tall; nothing that can be tapped is under 24px. Links inside sentences are underlined, not told apart by colour alone.
Accessibility. Every page has one h1 (in the community, phone layouts keep it for screen readers when the top bar shows the title), and heading levels don't skip. Never put a button or link inside something with role="button". Use aria-label only on elements that have a role, and aria-current, not aria-pressed, for links. The site was checked with axe-core (WCAG 2.2 AA rules) in both themes at phone and desktop widths, and with Lighthouse; keep both clean.
One idea per section, said once. The home page shows the core idea (a modern idea beside a passage) once as a thing to do ("Try one idea"), then the chapters, then "Read two ways", then the community: a unit shows its first six chapters with a link to the rest, a classics card shows what the passage adds and opens "Where they differ" on request, and the texts quoted are one line linking to /learn/texts. Every page, the home page included, uses the same header (components/landing/SiteHeader.tsx). A closed concept shows only its name and line; its "Before you read" question comes first once it is opened, so a chapter reads as a short list. Introductions stay to two sentences; a list's search comes before anything else on its page (the glossary).
npm run db:migrate # apply migrations (reads DATABASE_URL from .env)
npm run db:seed # product sample data; safe to re-run, refuses once real members exist
npm run db:seed:topics # only the topic list; use this on the live database
After changing the contract, run npm run contract:emit (with prisma 8.0.0-rc.15 or newer; the lockfile's older build writes a contract the runtime's types can't read), then npx prisma migration plan --name <name> --from <current storage hash>, then npm run db:migrate. Give every new model @@rls: row-level security with no policies keeps Supabase's public Data API closed. The app connects as the tables' owner, so RLS doesn't restrict the app. Note that in Prisma 8, .update() and .delete() only change the first matching row. Use updateAndCount() or deleteAndCount() when you mean all of them.
| Command | Does |
|---|---|
npm run dev | Development server |
npm run build / npm start | Production build and server |
npm run lint | ESLint |
npm run db:migrate / npm run db:seed | Apply migrations / load the product's sample data |
npm run db:seed:topics | Load only the topic list (for a real deployment) |
npm run vercel-build | What Vercel runs on each deploy. On production deploys it first migrates and loads topics (scripts/prepare-db.ts); previews only build |
/home/signincomponents/learn/ask.tsvv-askAppProvidercontent/learn/units/ (Unit 1, management and managerial economics, is units/unit-1/; Unit 2, organisational behaviour and HRM, is units/unit-2/; Unit 4, managerial accounting and financial management, is units/unit-4/; Unit 6, strategic management, is units/unit-6/; Unit 7, marketing management, is units/unit-7/; units keep their syllabus numbers, so Units 3 and 5 are simply not written yet; each has chapters.json, glossary.json and lessons/, one file per chapter). content/learn/index.ts joins the units for the pages, and content/learn/lesson-kit.ts defines a guided lesson and the rules for writing one. It also holds the style guide for explaining a concept: the problem first, a plain definition beside the exam definition, an Indian example with real numbers, how it works (with a diagram where the idea is a grid, curve or sequence), what it is often confused with, where it breaks, and a closed "Go deeper" section for experienced readers. Every chapter is written this way. Unit 2 has four groups in its index.ts (organisational behaviour; human resource management; performance, careers and change; employee relations and global HR), and a new chapter takes the next number so that glossary terms, which point at chapters by number, keep working. Each chapter is a static page at /learn/<slug>; every concept opens in place into a question to answer first, the core idea, a quick check, the Ancient lens, a reflection prompt and a one-page summary. The text runs in one wide column; a slim strip stays at the top while reading, showing the current concept and how many are done, and its Contents button opens the chapter's concepts, its glossary terms (opening in place) and the unit's chapters. Quotes are HTML: the English rendering in curly quotes, then the original in its own script as <span lang="xx" class="og"> (Tamil keeps class="ta"), then its transliteration as <i lang="xx-Latn">, then <span class="ref"> for the reference. Sanskrit is shown in Devanagari as printed editions write it, with consonant-final words joined to the next and a final m before a consonant as anusvāra. Passages come from many traditions and languages: Sanskrit, Pali, Tamil, Hindi, Marathi, Bengali, Malayalam, Kannada, Telugu and Tibetan so far. Add one only after checking its original wording against an edition or a reliable digital text, and leave out what cannot be checked rather than quoting from memory. Scripts other than Devanagari use fonts already on readers' devices (font stacks by lang in landing.css), so they add nothing to download. Passages are marked documented (it exists in a named text and the concept is a fair reading) or view (an interpretive parallel); keep that mark when adding them. /learn lists every unit, with two ways in above the units: a six-chapter path for readers new to management and an index by problem ("Setting a price", "Leading a team") for working managers, both in content/learn/paths.ts, which the build checks. In the header, "Chapters" opens a two-pane menu on wide screens (components/learn/ChapterPanel.tsx): the units on the left with how many chapters the reader has finished, the chosen unit's chapters on the right in their groups, and a link back to the concept read last. It opens on click, not hover, and on the current chapter's unit. Menus use each chapter's short title where chapters.json gives one. /learn/glossary the glossary, /learn/revision every lesson's summary, ready to print, and /learn/practice the practice page described below, /learn/formulas the formula sheet, and /learn/plan a study plan. The reader picks an exam date, the units and their study days a week (components/learn/Planner.tsx, settings in local storage under vv-plan). Their unfinished chapters, in syllabus order, are shared out over the weeks before the exam by reading time. The last tenth of the time, between 3 and 14 days, is kept for revision. The plan itself isn't stored: it is worked out again from the reader's progress on each visit, so finished chapters drop out. The sheet is gathered from the chapters' own text by content/learn/formulas.ts: every <div class="eq"> line with an "=" in it, and every row of a table with a column headed "Formula". It is grouped by unit, chapter and concept, and lines worked through with figures are marked as worked examples. To put a formula on the sheet, write it in a chapter in one of those two forms. The header search reads /search-index.json, built by content/learn/search.ts.units/unit-2 to the new unit's folder (say units/unit-3), replace its data, give it its own id, n, title and groups in its index.ts, and list it in units/index.ts. The index, menus, search, glossary, revision sheets and sitemap pick it up. The build fails, with a list of what's wrong, if two chapters share a slug or two glossary terms an id, if a term points at a missing chapter, or if a lesson doesn't match its chapter (a block without a lesson, a passage used twice or not at all, an answer that isn't one of its options).content/learn/connections.ts works this out from the glossary links. A chapter is connected to another when its text uses at least two of that chapter's glossary terms; one shared term is too often a passing example. About two in three chapters have a connection.content/learn/term-links.ts). The first mention of each term in a block links to its glossary entry, and on the chapter page components/learn/GlossaryTips.tsx opens the definition in a card beside the term instead. A term matches by its phrase in any case, plural or hyphenated, or by its bracketed abbreviation exactly ("IRR"). A bracket that isn't an abbreviation, like "(Fayol)", is ignored. One-word terms link only within their own chapter, headings, links and figures are never touched, and a term isn't linked in the block it names. No term needs any markup in chapters.json; a new glossary entry is picked up on the next build.components/learn/tools/, listed by "<chapter slug>#<block id>" in its index.ts. Add one there, keeping to the chapter's example and formulas, and only the pages that show it load its code./learn/transfer moves a reader's progress to another device without an account or a server. "Make a code" packs what the browser holds into a code to copy, a link or a .txt file: concepts done, the review list, the study plan's settings, the Continue link and, if they choose, their reflection notes. The code is JSON, compressed with deflate-raw where the browser can, then base64url, starting VV1z. (or VV1. uncompressed). The link carries the code after #t=, which browsers don't send to a server, and the page removes it from the address bar once read. On the other device the page shows what a code holds before anything changes, then merges it (components/learn/transfer.ts). Concepts done are joined. A question on both review lists keeps the less advanced entry. Notes, the plan and the Continue link are added only where the device has none. A code is untrusted input: only known keys and well-formed ids are kept, and sizes are capped. The page isn't indexed, since a link to it may carry someone's code./learn/progress, "Your progress", gathers what the site keeps for the reader on one page (components/learn/Overview.tsx): concepts and chapters done, the review due, the study plan's countdown, and each unit's progress with the next concept to read. It also shows "Your notes", every "Reflect & discuss" note in syllabus order, linked to its lesson. It reads only the browser's storage and isn't indexed.device) beside the text size (components/learn/Theme.tsx, vv-theme). Dark is a set of token overrides under html[data-theme="dark"] at the end of landing.css, screen only, so printing stays black on white. Text on red uses --on-accent, and red hover states use --accent-hover and --accent-press, so both themes read well. The chapters' diagrams draw with fixed colours; those are mapped by value (ink to light, greys lighter, white panels to the ground), so new diagrams should keep to the existing palette (#201e1d, #605d5d, #ec3013, #ae1800, #eae9e9, #ffffff). Like the text size, the theme is applied by a beforeInteractive script before the page paints.components/learn/Listen.tsx). It reads the text as shown but skips originals in other scripts and their transliterations (their English rendering is read), diagrams, tables and a closed "Go deeper". It speaks in short pieces, since some browsers stop long ones, and only one concept speaks at a time. It doesn't appear where the browser has no speech.components/learn/TextSize.tsx, stored under vv-text). The choice sets data-text on <html>, and landing.css zooms <main> to match, so tables and figures scale with the text; the chapter's sticky reading strip keeps its size. A small beforeInteractive script in the landing layout (through next/script, not a hand-written <head> tag, which breaks hydration) applies a saved choice before the page paints.public/sw.js, registered in production by components/learn/Offline.tsx in the landing layout) keeps a copy of each learning page as it is opened. It fetches from the network first, and with no connection serves the copy, or a short "this page isn't saved" note. Built files and fonts are cached once fetched, and the question bank and search index are refreshed in the background. "Save all chapters" on /learn asks the worker to keep every chapter, the glossary, revision, formula, practice, plan and transfer pages, and their data, in one go. The app (/home and the rest), server actions and anything that isn't a GET are never touched. A small note appears while the reader is offline. next.config.ts serves /sw.js uncached, so a new version reaches readers on their next visit. To change what is cached, edit sw.js and raise its VERSION, which clears the old caches./learn/practice is for testing yourself on the chapters' check questions, with two modes. Spaced review brings back questions the reader got wrong. The first wrong answer to a check, in a lesson or in practice, puts the question on the reader's review list for the next day. Each right answer when it's due pushes it back 3, then 7, then 21 days, and a right answer at 21 days takes it off the list. Another wrong answer starts it over (components/learn/review.ts, local storage key vv-review). Mixed practice can also be glossary terms as cards: the reader recalls a term's meaning, turns the card, and says whether they knew it. A term they didn't know joins the same review list, under glossary#<term id>#t, so review sessions mix questions and cards; /learn/glossary links to it as "Practise them as cards". The site also keeps each chapter's last 20 answers, right or wrong, on the device (components/learn/stats.ts, vv-stats; a right guess counts as wrong, and term cards don't count). A chapter with at least 5 answers and fewer than 70% right is "weak": "Your progress" lists the weakest, and mixed practice can be limited to them. Transfer codes carry this record, and on merge a chapter's record already on the device is kept. Each chapter ends with "Test yourself": /learn/practice?chapter=<slug> starts a chapter test of all its questions in a new order. Mixed practice can also run as a mock test: no feedback until the reader submits, answers can be changed and revisited, and there is an optional time limit (1 or 1½ minutes a question) that submits automatically. The results go through every question with the reader's answer, the right one and why, and misses and blanks join the review list. After a wrong answer, in a lesson, in practice or in a mock test's review, the concept's "Don't confuse it with" note appears as a hint. content/learn/mixups.ts takes the first warning of each <p class="mixup"> and keeps only <b> and <i>; 379 of the 384 concepts have one. Practice also has blank-page recall: the reader sees only a concept's name, writes what they remember (not saved), then ticks the points of its one-page summary they covered. Recalling 80% or more counts as remembered. Fewer puts the concept on the review list (<slug>#<block>#r), so recall and questions share one spaced review. Each lesson's summary links to "Recall it from a blank page" (/learn/practice?recall=<slug>/<block>). The summaries come from /practice-recall.json, fetched only when recall is used. Before answering a question, the reader can mark it as a guess (or press G). A right answer that was a guess still counts as right, but it joins the review list for tomorrow, as a miss would. Either way, mixed practice draws 10, 20 or 40 questions evenly across the chapters of the units the reader picks, or only the chapters they've started. It then lists the concepts behind the missed questions, with links to reread them. The questions come from /practice-bank.json, built from the lessons by content/learn/practice.ts and fetched only by this page. A question is remembered by its chapter, its block and a hash of its wording (content/learn/question-id.ts). Adding or reordering questions keeps the reader's review list intact; rewording a question drops just that one from it. /learn shows a "Due for review" band when anything is due, and each unit has a "Practise this unit" link./learn/texts lists the 21 classical texts the chapters quote, on a timeline, and /learn/texts/<id> gives each one: what it is, how far its date and author are known, a "Read with care" note, free full texts and translations in print, and every passage the chapters take from it, linked to its lesson. The data is in content/learn/texts.ts (the intros, dates and links) and content/learn/text-refs.ts (the matchers that tell which text a passage's reference names, so a new passage is picked up when built). The build fails if a text has no passage or a passage names no text. Every quoted passage (components/learn/PassageQuote.tsx) links to its text's page, and has Share, Discuss and Report links under it. /learn/reading-guide (content/learn/reading-guide.ts) explains the marks in names such as ā, ṣ and ṛ, how Tamil and other Dravidian names are spelled, and 15 words that don't translate (dharma, karma and so on), each listing the chapters that use it. Chapters and text pages have "Cite this page" in APA, MLA and Chicago (CiteThis.tsx).components/learn/ReportProblem.tsx) that actions/report.ts emails to the contact address only; it stores nothing. A hidden field stops bots, and reports are capped at 5 per network address in 10 minutes and 100 an hour in all. /learn/corrections lists what has been corrected and when, from content/learn/corrections.ts; add an entry there whenever a report leads to a change in meaning./learn/quiz builds a quiz from chosen chapters (a teacher's or a study group's), as a link that carries the questions' ids, so nothing is stored (content/learn/quiz-link.ts, at most 50 questions). The link opens it in practice as a test, and the results can be downloaded for Anki. The study plan adds itself to a calendar as an .ics file (components/learn/ics.ts). /glossary.csv and /glossary-anki.txt are the glossary as a spreadsheet and as Anki cards, and /learn/revision/pack prints a revision pack for the chosen units or chapters: summaries, "Don't confuse it with" notes, formulas and key terms, each of which can be left out./learn/check is a short placement check (content/learn/placement.ts): four questions a unit, from chapters spread through it, then where to start. /learn/apply has 12 workplace situations (content/learn/scenarios.ts) where the reader picks the idea that helps most; each option names a chapter and concept, so the answer links to its lesson and, where one fits, a passage that met the same problem. The build checks every name. /learn/map draws how the chapters connect, from content/learn/connections.ts.app/(landing)/learn/[slug]/opengraph-image.tsx), and each passage a card at /learn/<slug>/share/<n> (built with the site, cached for a day) that the Share dialog offers to download or share. lib/og.tsx draws them with Archivo from assets/og (the weights merged so accented letters match), and ogText swaps letters the font lacks (ṛ becomes ri) so the renderer never fetches a font./learn/weekly shows this week's pair, a modern idea and a passage, from content/learn/weekly.ts: the walk first, then the themed pairs, then every passage with lesson notes, a unit at a time, starting again when they run out. A new week starts each Monday (India time) from 26 October 2026. /feed.xml is the same as a feed. Chrome shows a feed as raw XML, and XSLT, the old way to dress one up, is being removed from browsers, so a browser opening /feed.xml (a page visit, which sends Sec-Fetch-Dest: document) is redirected to /learn/weekly/feed: the feed's address to copy, and the weeks in it. Feed readers send no such header and get the XML (next.config.ts). The email (actions/weekly.ts, the weeklySubscriber table) works like the early list: double opt-in, unconfirmed addresses deleted after 30 days, and confirming or stopping takes a button press on /weekly-email. Vercel Cron calls /api/weekly each morning (vercel.json); it sends this week's email to anyone who hasn't had it, at most 150 a run, with a List-Unsubscribe header./hi is the start of a Hindi edition: an introduction, the five-step walk (/hi/start) and a glossary (/hi/glossary) with the words that don't translate and all of Unit 1's terms. The Hindi is in content/hi/ (index.ts and glossary-unit1.ts); quotes keep their English references, and the build fails if a walk step, a word or a Unit 1 term has no Hindi. The pages are paired with their English ones by hreflang, in the metadata and the sitemap. Hindi text is set in Noto Sans Devanagari from public/fonts, which only Hindi pages download. The chapters are still in English./early-list still serves the links in confirmation emails already sent, and the early list is stored in the earlyListEntry table by actions/earlyList.ts. An address counts once it's confirmed from the inbox, unconfirmed ones are deleted after 30 days, and confirming or removing takes a button press, so mail scanners can't do either.app/(app)/ is the product, the community, with its own root layout and stylesheet (product.css). It uses the same "Modernist" design as the learning pages: Archivo throughout, the same colour tokens, square corners, 2px rules, the red-square mark and favicon, and a red bar for whatever is current or chosen. The five labels look as they do in the home page's example thread (Asking in red, Documented solid ink, Lived on the surface, Told dashed, My view outlined). The reader's theme and text size (vv-theme, vv-text) carry over: the app's layout runs the same beforeInteractive scripts, product.css repeats the dark tokens under html[data-theme="dark"], and the account panel (the initials at the top right, on phones too) holds the same Text size and Theme controls, with links to the chapters and practice. The rail on wide screens also links to Chapters, Practice and Glossary. Signed-in screens share app/(app)/(shell)/layout.tsx.
/c explains the four kinds (circle, board, cohort, practice, from COMMUNITY_FORMATS) before listing them, and each community's page says what its kind means. A member adding a note picks its label, as in the composer: the note box suggests one from the text until they choose (suggestNoteBasis in lib/app/labels.ts), shows what the chosen label means, and a Documented note must say in its text where it can be checked, a link, page, chapter, verse, year, ISBN or DOI (namesASource; postNote checks it again). "What the labels mean" under each thread lists the four. Ctrl or ⌘ + Enter adds a note.lib/app/ holds the server-side building blocks: the session (session.ts), what the viewer follows and mutes (viewer.ts), the Edition and Following feeds (feed.ts), a loader per screen, notification delivery (notify.ts) and the label rules (labels.ts).actions/app/ holds the server actions. Each returns { ok, error }, so refusals reach the member instead of being swallowed in production.components/app/ holds the product's client components.src/prisma/contract.prisma, with migrations in migrations/. The product's tables sit alongside the tables of an earlier landing-page demo (post, feedItem, reel and so on), which nothing uses any more.Fewer choices at once (Hick's law). The time to choose grows with the number of choices in view, so each decision point offers few. They are grouped under a label, the likeliest first, the default already chosen, and the rest a tap away. Each page leads with one or two main actions. /learn opens on the units and one recommended start, the five-step walk with the 2-minute check beside it. Five of its problems show, with the rest behind "more". The tools come after the chapters, in two labelled groups: "For an exam" and "Going further". A choice set has a default whenever one is sensible (20 questions, every unit, the first kind of report). The same destination isn't offered twice in one place: the footer drops Home, since the brand above it goes there, and a chapter's Contents holds the chapter, its terms and its unit, and nothing else. Text size and theme live in the Menu and the footer. The header follows the Menu's order (Chapters, Glossary, Practice, Revision, Community). Where the device has its own share sheet, the share dialog leads with it and leaves out WhatsApp and LinkedIn, which the sheet already holds. Practice keeps its less common settings (mock test, weak or started chapters only) under "More options", which opens by itself when one is on, and explains spaced review under "How the spacing works", open only until the reader has something on their list. On a chapter, the first button is the next thing to do: the first concept, "Continue" with the next one not done, or, once all are done, the chapter test. One button opens or closes every concept.
Within reach. On phones a practice question's "Next" docks to the foot of the screen once answered, and a mock test's Previous and Next stick there; on touch screens every button is at least 44px tall. A closed concept opens from anywhere on its head. "Back to top" appears in the corner after two screens. The Menu starts with "Continue" and the concept read last.
Looking pressable. Whatever can be pressed says so before it is touched, and answers in every state, in both stylesheets. At rest: buttons are ruled or filled boxes; a ghost button and every link set in text are underlined (lightly, fully under the pointer); a card or row that is a link ends in an arrow (back or forward by direction, and ↗ for a new tab, which screen readers also hear: NewTab in components/landing/Arrow.tsx); a part that opens ends in a red + that turns to − (the same glyph on every summary); a choice among a few is joined boxes with the chosen one in ink (text size and theme included); a field lightens under the pointer, and its hint is fainter than typed text. Pointing: the arrow leans the way it goes, cards and rows tint, and a closed concept's head and its Open button tint together; hover looks for chips, tabs and choices sit inside @media (hover: hover), so a tap on a phone doesn't leave one looking chosen. Pressing: buttons sink 1px and darken; anything without its own pressed style dims while held (a weightless :where(...):active rule), and the browser's tap flash is the site's ink. Focus: the red ring turns light on red grounds, and a card whose title link has focus rings the whole card. Where you are: the header link for the current page or section has a red bar under it (components/landing/CurrentLink.tsx; Chapters marks itself on any chapter), the Menu and footer mark the page, and the Menu's icon becomes a cross while open. Honest: a disabled button ignores the pointer; a community card or notification is one target (a stretched link), so its hover tells the truth; panels that scroll (Menu, Chapters, Contents) shade the edge that has more. Roles match behaviour: links that change the address (Library, a profile, a community's sections, For you and Following) are a nav with aria-current, not tabs; a choice made in place (Asking or Sharing, Daily or Weekly) is buttons with aria-pressed; true tabs move with the arrow keys.
Being found. A feature that only the Menu lists is a feature few readers meet. Each one is reached in three ways:
SITE_MAP carries a line saying what it is for (about) and the words readers use for it (also: "mock test" and "flashcards" for Practice, "dark mode" for the theme). content/learn/search.ts indexes them with the units, the display settings, the keyboard shortcuts, offline reading and sign-in. Those other names count as much as a title does. An empty search box says what search covers and offers three searches to try. A search with no results points to the chapters, the glossary and the community. A new page needs its about and also, or search won't know it.scenariosFor), and its place on the map (/learn/map#<slug> opens the map on it). Practice points to the study plan, the formula sheet and the quiz maker, and its results point to progress. The report dialog links to the corrections page, and the walk ends with Practice and the weekly email.#display). Keyboard shortcuts are listed by ? on any page, by the footer where there is a keyboard, and by search (#keys, components/landing/Shortcuts.tsx); add a new key there. Icon-only buttons name themselves on hover. Every page offers the weekly feed to feed readers through <link rel="alternate">.Two things a concept can do but doesn't show, dotted terms and J/K, are told once in the first concept opened (components/learn/ReadingTip.tsx). The tip stops for good on "Got it" or the first time the reader uses either one.
Reach (Fitts's law). The time to hit a target grows with its distance and shrinks with its size. The "Reach" sections at the end of landing.css, learn.css and product.css apply this in four ways:
@media (pointer: coarse)) and at least 24px with a mouse.::after laid over the space around it (the glossary card's close button, faces in the community). A control with a set height grows its min-height and takes the same negative margin, since padding inside a min-height would shrink its share of the layout. A list row with one link is one target (the timeline, a chapter's connections, the study plan's weeks, earlier weekly ideas).::after is placed from inside its element's border, so a bordered element adds 2px to its reach.learn.css, "Phones: the strip docks"). Dialogs rise as sheets from the bottom, and the community's bottom-bar items share the bar's whole width.To check a change, measure what a tap actually lands on rather than the drawn box. Sample document.elementFromPoint on a 2px grid around each control, at a phone width with touch emulation and at a desktop width.
Familiar ways (Jakob's law). Readers spend most of their time on other sites, so this one behaves as those do:
components/landing/layer.ts adds a history entry when a layer opens and takes it off when it is closed any other way. A page chosen from inside a layer replaces that entry, so Back never has a step that does nothing. A layer opened by the same tap that closed another waits for that step back to land. With a mouse, Back keeps its usual meaning.device). The footer ends with a copyright line, and deeper pages have breadcrumbs. iPhones get a home-screen icon (app/apple-icon.png).Seen as groups (Gestalt). The eye groups what is near, alike, lined up, framed together or in front before it reads a word, so the layout has to say what belongs together. The "Seen as groups" sections at the end of landing.css, learn.css and product.css hold these rules:
subgrid on /learn), so the rules over their lists line up however their headings wrap. These pairs share a baseline: a term and its meaning, a concept's number and its title, a post's author and its labels, and the footer's brand and column labels. A row's words stay on the column's edge. A hovered row's tint and red bar reach out into the margin rather than sit on its first letters.--scrim) dims the page behind it. The scrim darkens the page in both themes; made of the ink, it used to lighten a dark page. The Menu, the chapters panel and Contents now dim the page as search and the dialogs do. A press on the dimmed page closes the layer and does nothing else. A box that floats casts the flat sheet's shadow (--sheet, a hard offset with no blur); a panel hanging from a bar needs none. While one of the header's layers is open, the header comes forward over the bars docked at the foot of the screen.To check a change, measure gaps from ink (lines of text, rules, the edges of tinted regions) rather than from boxes. A heading's gap below should be smaller than its gap above. Compare baselines with a zero-size inline-block placed before the first word, and look at every layer open in both themes, at phone and desktop widths.
Words, seen as groups (Gestalt for text). Readers group words the way they group shapes: the same word reads as the same thing, the same grammar as one set, and a word next to another as its partner. The copy follows the same principles as the layout:
To check a change, read the page's words in order, without the layout: the eyebrow, headings and buttons should tell its story on their own. Search the code for the retired words above before adding new copy.
Feedback. A thin red line along the top shows a page is loading if it takes more than a moment (components/landing/NavProgress.tsx, in both layouts); cards and rows that are links darken as they are tapped. What loads after the page shows its shape meanwhile: the practice panel, and every community screen (app/(app)/(shell)/loading.tsx), use skeletons (.sk).
Recovering from mistakes. A practice session in progress is kept for the tab (sessionStorage, half a day), so leaving the page or reloading offers to continue it; leaving a mock test part-way asks first. Forms keep what was typed when sending fails (the weekly sign-up holds its field in state, since a form action clears uncontrolled fields), and mark the field with aria-invalid and the message. Destructive actions ask first (clearing the review list) or can be undone (marking a concept not done).
Landing on a #part. Long pages skip drawing sections far off screen (content-visibility), which made jumps to a #part land thousands of pixels away. A page opened at a #part now draws every section from the start (data-landing, set by a script in the landing layout before the first paint), and components/landing/HashLanding.tsx settles on the part after in-page and client-side jumps. New long lists that use content-visibility should be added to the data-landing rule in learn.css. Accessibility checkers misread skipped sections (contrast and target size); check those with every section drawn.
Type scale. Text uses ten sizes, as tokens in :root (--fs-2xs 11px up to --fs-h4 22px), in landing.css and product.css; headings above that scale with the screen. Use a token rather than a new pixel size.
Missing pages and errors. app/global-not-found.tsx answers any address that matches no page (the site has two root layouts, hence experimental.globalNotFound in next.config.ts), and not-found.tsx in each route group answers a missing chapter, text or question. A not-found file belongs to every page in its group, so it imports no stylesheet of its own (its styles are in landing.css); otherwise every page would load that stylesheet too. error.tsx in each group, and app/global-error.tsx as a last resort, say that progress on the device is safe and offer to try again.
Search results and sharing. Titles stay under about 65 characters and descriptions under 160. A page that sets openGraph replaces the layout's, image included, so it lists DEFAULT_OG_IMAGES from lib/meta.ts: the site's card at /share.png. Chapters and passages have their own images.
Bundles. Client components may import only types from content/learn/index.ts, or from any module that imports it (practice.ts, readings.ts and so on): importing a value would put every chapter in the browser's download. That once made the practice page 4 MB of JavaScript. Small helpers that client code needs, like questionId, cardId and recallId, live in content/learn/question-id.ts. A client page that fills in after loading holds its space meanwhile (aria-busy on the practice panel), so the page doesn't jump.
Security headers. next.config.ts sends a Content-Security-Policy on production builds: scripts, styles, fonts, images and requests from the site itself only (Supabase is used from the server alone), no framing, no plugins, and forms posting only to the site. Next.js's inline scripts need 'unsafe-inline'; nonces would make every page dynamic. Preview deployments also allow Vercel's toolbar. Adding a third-party script, font or API called from the browser means adding its origin there. The weekly-email cron route compares its secret in constant time.