diff --git a/.claude/rules/doc-structure.md b/.claude/rules/doc-structure.md index 00b12b7..4b1f2ab 100644 --- a/.claude/rules/doc-structure.md +++ b/.claude/rules/doc-structure.md @@ -4,65 +4,7 @@ paths: - "**/*.mdx" --- -# Structuring and linking docs +# Doc structure -## Pick the right category (Diátaxis) - -Every page does exactly one of these jobs. Mixing them inside one page is why docs end up -feeling unfocused: - -- **Tutorial** — a guided first experience. Optimizes for the reader finishing - successfully, not for completeness. -- **How-to guide** — solves one specific, named problem for someone who already knows the - basics. Skips background explanation. -- **Reference** — describes the thing accurately and completely (an API, a config schema, - a component's props). No opinions, no narrative — facts, kept accurate as the thing - changes. -- **Explanation** — the why: design rationale, tradeoffs, how pieces fit together. The only - category where discussing alternatives and context belongs. - -Not sure which one a page is? That's the sign it's trying to do two jobs — split it. - -## Fully documenting a component: don't skip details - -When writing reference or explanation content for a package or component, cover what a -careful reviewer would ask about, not just the happy path: - -- What it's for, in one sentence a newcomer understands without prior context. -- Its public surface: what a consumer actually calls, imports, or configures. -- Invariants and constraints: what must be true before and after, what it assumes the - caller already did. -- Failure modes: what happens when it's misused, and what signals that (error, log, - silent no-op). -- Edge cases that aren't obvious from the signature — ordering, concurrency, lifecycle, - platform-specific behavior. -- Why it's built this way, when the reason isn't obvious. Link to an explanation page - rather than re-explaining inline. - -Missing one of these isn't a style problem, it's a coverage gap — the kind of thing a -reader hits in production with nowhere to look it up. - -## Sections and metadata - -- One H1 per page, matching the frontmatter title. -- A one- or two-sentence summary right under the H1: what this page is and who it's for, - before anything else. -- Sentence-case headings throughout (see `writing-style.md`). - -## Linking instead of duplicating - -- Never restate content that already exists on another page. Link to the canonical page - instead — two copies of the same explanation will drift, a link can't. -- Link relatively within the same project folder (`../other-page`); link from the docs - root when crossing into another project's docs (`/docs//...`). -- When a decision has real tradeoffs and a future reader will reasonably ask "why was it - done this way", record it once as a short decision note (what, why, alternatives - considered) and link to it from everywhere it's relevant. Don't re-litigate it inline on - every page that touches it. - -## Multi-project layout - -Each project under the `tsvrc` org gets `docs//` in this repo (see the root -`CLAUDE.md` for why this is one repo, not one repo per project). Don't duplicate a concept -shared by two projects — document it once under whichever project owns it, and link from -the other. +See [STYLE_GUIDE.md](../../STYLE_GUIDE.md), the "Doc structure" section, canonical for +this repo. Written for any contributor, human or AI, not just for Claude specifically. diff --git a/.claude/rules/writing-style.md b/.claude/rules/writing-style.md index e318106..e609b23 100644 --- a/.claude/rules/writing-style.md +++ b/.claude/rules/writing-style.md @@ -4,54 +4,7 @@ paths: - "**/*.mdx" --- -# Writing style: sound human, say only what's needed +# Writing style -Docs written by an LLM have a recognizable smell, and readers trust content less once they -notice it. Avoid it. - -## Cut, don't pad - -- If a reader can see it by reading the code, don't restate it here. A doc earns its place - by adding what code can't show: why, tradeoffs, what breaks, what to do next. -- Before adding a paragraph, check what it adds beyond the paragraph before it or the code - itself. If nothing, delete it. -- One idea per section. If two sections could swap order without anything breaking, that's - a list wearing the structure of an argument — tighten it. - -## Words and phrases to avoid - -These are statistically over-represented in LLM output and read as filler to anyone who has -seen a lot of AI-generated text: delve, leverage (verb), robust, seamless, comprehensive, -cutting-edge, pivotal, meticulous, landscape / realm / tapestry (as metaphors), utilize, -"in order to", streamline, foster, elevate, unlock, harness, ecosystem (unless it's -literally an ecosystem), myriad, plethora, crucial, paramount, nuanced, "it's worth noting", -"it's important to note", "at its core", "best practices" (name the actual practice instead). - -Hedging kills technical writing — cut "could potentially", "may eventually", "it's worth -mentioning". State the fact or the tradeoff directly. - -## Sentence and paragraph shape - -- Vary sentence length on purpose. A row of same-length sentences reads like a template. -- Don't open with "In today's...", "Let's explore...", or "In this doc, we will...". Start - with the actual point. -- Avoid the "It's not X, it's Y" construction. State the positive claim. -- Sentence case for headings ("Set up your environment"), not title case - ("Set Up Your Environment"). -- Skip chatbot artifacts entirely — "I hope this helps", "Great question", "Feel free to - reach out". This is documentation, not a chat reply. - -## Punctuation and formatting - -- Avoid em dashes for asides in prose; use a comma, a colon, or a full stop instead. (An em - dash inside a bolded-term list item is fine: `- **Term** — one-line description`.) -- Don't bold more than one phrase per section — bolding everything bolds nothing. -- Reach for prose over bullets when explaining an idea with real connections between its - parts. Bullets suit genuinely parallel, independent items — flags, a checklist, install - steps. A bulleted list of bare noun phrases ("Fast. Reliable. Secure.") explains nothing; - say what's actually fast, reliable, or secure, and why. - -## Read it back before committing - -Read the page out loud, or run it through text-to-speech mentally. Rewrite anything you -wouldn't actually say to a colleague. This one pass catches most of the above. +See [STYLE_GUIDE.md](../../STYLE_GUIDE.md), the "Writing style" section, canonical for +this repo. Written for any contributor, human or AI, not just for Claude specifically. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8111524..38731c5 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,5 +7,5 @@ - [ ] Commits are signed off (`git commit -s`) per the [DCO](https://developercertificate.org/) — this certifies you wrote the change or otherwise have the right to submit it under this project's license. - [ ] If AI tooling helped write part of this PR, that's disclosed in this description (see `CONTRIBUTING.md`), and you've personally reviewed, understood, and checked it renders correctly. - [ ] `npm run build` passes locally (`onBrokenLinks: 'throw'` catches broken links this way). -- [ ] The change follows `.claude/rules/doc-structure.md` and `.claude/rules/writing-style.md`. +- [ ] The change follows `STYLE_GUIDE.md`. - [ ] If this documents `tsvrc-core` behavior, it matches what the code actually does. diff --git a/AGENTS.md b/AGENTS.md index 857fc14..81906c4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,7 +3,8 @@ ## Project overview Docusaurus site (TypeScript, Node 20+) documenting every project under the `tsvrc` org, -namespaced under `docs//` rather than one repo per project. +namespaced under `docs//` rather than one repo per project. See +[CONTRIBUTING.md](CONTRIBUTING.md) for the multi-project layout and the i18n workflow. ## Setup @@ -18,10 +19,18 @@ namespaced under `docs//` rather than one repo per project. ## Code style -- Follow `.claude/rules/doc-structure.md` (Diátaxis categories, linking instead of - duplicating) and `.claude/rules/writing-style.md` (avoid AI-sounding prose) for any - `.md`/`.mdx` change, despite the `.claude/` path these apply to any contributor. -- See `CONTRIBUTING.md` for the multi-project layout and the i18n contribution path. +Follow [STYLE_GUIDE.md](STYLE_GUIDE.md) for any `.md`/`.mdx` change: Diátaxis categories, +linking instead of duplicating, avoiding AI-sounding prose. + +## Gotchas + +- `sidebars.ts` is hand-written per project, not a blanket autogenerated tree. A + `dirName` pointed straight at a leaf folder returns an unlabeled flat list, so a + category's `label` has to come from the wrapping `{type: 'category', ...}` node, not a + `_category_.json`. +- `tsvrc-core` (code) and this repo (docs) aren't wired together, no submodule, no + build-time fetch, and can drift. Changed public API or behavior in `tsvrc-core`, or + something under `docs/tsvrc/`? Check the other side still matches. ## Commit / PR rules diff --git a/CLAUDE.md b/CLAUDE.md index 19da31b..858e128 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,132 +1,6 @@ -# TsVRC docs + -This repo is the documentation site for the `tsvrc` GitHub org (Docusaurus, TypeScript). -It documents TsVRC and any other project under the org, namespaced by folder — not one -docs repo per project. - -## Structure - -- `docs//` — one folder per project (e.g. `docs/tsvrc/`). A new project gets a - new folder here, not a new repo. -- Content follows the Diátaxis framework (tutorial / how-to / reference / explanation). - Read `.claude/rules/doc-structure.md` before adding or restructuring a page. -- `sidebars.ts` is hand-written per project, not a single blanket - `{type: 'autogenerated', dirName: '.'}`. Each project gets one top-level category - (see the `Framework` category for `tsvrc`) built from `{type: 'autogenerated', dirName: '/'}` - subtrees grouped as Getting started / How-to guides / Reference / Explanations. That - grouping is what keeps Diátaxis categories visually separated in the sidebar. A new - project needs its own top-level category added there the same way; it won't show up - from folder presence alone. Each folder-level category's `label` lives in `sidebars.ts` - itself, not in a `_category_.json`: `dirName` pointed straight at a leaf folder - returns its files as a flat, unlabeled list, so the label has to come from the - wrapping `{type: 'category', ...}` node instead. Ordering *within* an autogenerated - subtree still comes from each page's `sidebar_position` frontmatter. -- Writing style — grammar, tone, avoiding AI-sounding prose, avoiding noise — is defined in - `.claude/rules/writing-style.md`. Read it before writing or editing any `.md`/`.mdx` file. - -## Internationalization (i18n) - -This site is set up for `en` (default) and `es`, but only `en` has real content right -now — `es` currently covers only the two marketing pages (`src/pages/index.tsx`, -`src/pages/framework.tsx`) plus one worked-example doc page (see below), not the rest of -the docs. - -- **Docs content** (`docs//`): stays English-only, unversioned, exactly where - it is. This is deliberate, not a gap to fill by default — per Docusaurus's own i18n - convention, the default locale's docs live directly under `docs/`, and a - translation is added later as a parallel tree at - `i18n//docusaurus-plugin-content-docs/current//`, mirroring the - same relative paths and filenames. Adding a language never touches the English - files. Sidebar category labels live in `sidebars.ts` itself (see the Structure - section above), not in a translatable `_category_.json`, so they render in English - for every locale regardless of `i18n//docusaurus-plugin-content-docs/current.json`. - That's deliberate for now, since a half-translated sidebar over English content would be - worse than an English one. Translating them means giving `sidebars.ts` locale-aware - labels (e.g. via `docusaurus-plugin-content-docs`'s own i18n message extraction) once - real doc translations exist to justify it. -- **The two marketing pages**: translated today via `@docusaurus/Translate`/ - `translate()` in the component source, with per-locale strings in - `i18n//code.json`. Adding a language means running - `docusaurus write-translations --locale ` and filling in that locale's - `code.json` — the component code itself doesn't change. -- **Theme chrome** (pagination, admonition labels, sidebar buttons, etc.): never - override these in this site's own `code.json`. Docusaurus ships its own - professionally translated defaults per locale; only `homepage.*`/`framework.*` keys - belong in this site's `code.json`. -- Adding a third locale: add it to `i18n.locales` (and `localeConfigs`) in - `docusaurus.config.ts`, run `write-translations`, translate `code.json` plus - `docusaurus-theme-classic/{navbar,footer}.json`. Docs stay English until someone - actually translates them into the new `i18n//docusaurus-plugin-content-docs/current/` - tree. -- **Translation quality: never translate literally.** When writing or updating any - `code.json` (or any other translated string) for `es` or any future locale, use the - term a professional in that field, in that language, actually uses — not a word-for-word - rendering of the English. Before translating a technical or domain term (Unity/UdonSharp/ - VRChat/GitHub concepts especially), check how it's rendered in that language's official or - most-trusted sources (e.g. Unity's own localized manual at `docs.unity3d.com/es/...`, VRChat's - Spanish-speaking creator community, GitHub's own glossary/docs) rather than guessing or - machine-translating. Two patterns come up constantly and cut opposite ways, so check per - term instead of assuming: - - **Many technical/proper nouns are conventionally left in English**, even in otherwise - fully translated prose — e.g. in Spanish, Unity's own docs never translate `GameObject`, - `Inspector`, `Prefab`, `Script`, or `Play Mode`; GitHub's Spanish glossary keeps `issue` - and `pull request` as loanwords (GitHub's own UI ships English-only, so the loanword is - literally what a user clicks). This repo's own code identifiers (`_ts.Memory`, `TsStart`, - `TsBehaviour`, class/property names inside example code or referring to it) are never - translated either — including inside descriptive text, e.g. `_ts.Name` must stay - `_ts.Name`, not become `_ts.Nombre`. - - **Other English phrasing has a real idiomatic equivalent that isn't the literal - word-for-word choice** — e.g. "extends"/inheritance reads more naturally in Spanish as - "hereda de" than a calque like "extiende"; Unity's Spanish manual calls `Instantiate()` - "instanciar", not a generic "generar/crear". Prefer the term the target community - actually uses in casual technical speech, not a dictionary's first hit. - - Also double-check direction/meaning survived translation, not just word choice — a - literal-sounding translation can silently invert an "A extends B" relationship if you're - not reading the translated sentence back for what it actually asserts. - - A word can be the "correct" dictionary or OS-level technical term and still not be what - this content's actual audience says day to day — e.g. "arranque" is standard Spanish for - booting an OS, but reads stiffer than "inicio"/"iniciar" for a script or behaviour starting - up in casual creator-facing prose. When a general web search and a native speaker's ear - disagree, defer to the native speaker: ask or take their correction over the search result. -- **Worked example**: `docs/tsvrc/intro.md` has a real Spanish translation at - `i18n/es/docusaurus-plugin-content-docs/current/tsvrc/intro.md`: same filename, - same relative path, translated content. Copy that pattern for any other doc page. - Verified in-browser: the translated page renders correctly, and links from it to - still-untranslated pages fall back to English cleanly under the same `/es/` prefix. -- **Headings that other pages link to by anchor** need an explicit, language-stable id, - or translating the heading text breaks the anchor. Docusaurus's MDX v3 syntax for this - is a comment, not `{#id}` (that's the old, now-invalid MDX v1/v2 form and fails the - build): `## Play Mode tests: TsPlayModeTestBase {/* #play-mode-tests-tsplaymodetestbase */}` - (see `docs/tsvrc/testing/testing-your-world.md`). Keep the same id across every - language's version of that heading. - -## Commands - -- `npm start` — dev server at http://localhost:3000, hot-reloads content but not - `docusaurus.config.ts` (restart the server after config changes). -- `npm run build` — production build. Run this before calling a doc change done; - `onBrokenLinks: 'throw'` means a broken link fails the build. - -## Cross-repo: tsvrc/tsvrc-core and tsvrc/docs - -This repo documents code that lives in the separate `tsvrc/tsvrc-core` repo. The two are not -wired together technically — no submodule, no build-time fetch (see below for why). Nothing -keeps them in sync automatically: - -- Changed public API, behavior, or the package description in `tsvrc/tsvrc-core`? Check whether - `docs/tsvrc/` needs a matching update. -- Changed something in `docs/tsvrc/`? Check it still matches what `tsvrc/tsvrc-core` actually - does before publishing. - -A global hook flags this when either repo's docs-relevant files change. It's a nudge to go -check, not proof the two are actually in sync. - -## Why there's no cross-repo build wiring - -We evaluated pulling `tsvrc/tsvrc-core`'s docs into this site via a git submodule at build time -and rejected it. Surveying large community projects — Kubernetes, React, Vue, Python, -Node.js, Docker — shows the dominant patterns are docs-in-the-code-repo (single product) or -a fully self-contained docs repo, and for multi-product orgs, one consolidated repo -namespaced by project (Docker moved to this after abandoning per-product federation). None -of them merge separate repos into one build. Keep this repo self-contained unless a project -genuinely outgrows it. +@AGENTS.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e1e2683..2ef27b8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,22 +13,15 @@ This site follows the [Diátaxis framework](https://diataxis.fr/) (tutorial / how-to / reference / explanation) and a house writing style aimed at not reading like AI-generated -prose. Read these before writing or editing any page: - -- [`.claude/rules/doc-structure.md`](.claude/rules/doc-structure.md): which of the four - categories a page belongs to, section conventions, linking instead of duplicating. -- [`.claude/rules/writing-style.md`](.claude/rules/writing-style.md): words/phrases to - avoid, sentence shape, formatting rules. - -Despite the `.claude/` path, both are written for any contributor, human or AI-assisted, -not just for Claude specifically. +prose. Read [STYLE_GUIDE.md](STYLE_GUIDE.md) before writing or editing any page: which of +the four categories a page belongs to, section conventions, linking instead of +duplicating, words/phrases to avoid, sentence shape, formatting rules. ## Multi-project layout Each project under the `tsvrc` org gets its own `docs//` folder here rather than -its own docs repo (see the root [`CLAUDE.md`](CLAUDE.md) for why). Adding docs for a new -project means adding a folder here and a matching top-level category in `sidebars.ts`, -not creating a new repo. +its own docs repo. Adding docs for a new project means adding a folder here and a +matching top-level category in `sidebars.ts`, not creating a new repo. ## Adding a translation @@ -36,10 +29,24 @@ Docs content stays English-only and unversioned under `docs//`. A trans lives in a parallel tree at `i18n//docusaurus-plugin-content-docs/current//`, mirroring the same relative paths and filenames; adding a language never touches the English files. See -`docs/tsvrc/intro.md` and its Spanish counterpart for a worked example to copy. Before -translating a technical term, check how the target language's own community or official -docs (Unity's localized manual, GitHub's glossary) actually render it rather than -translating literally. +`docs/tsvrc/intro.md` and its Spanish counterpart for a worked example to copy. +`src/pages/` translates differently: via `@docusaurus/Translate` in the component source, +with strings in `i18n//code.json`. + +A heading another page links to by anchor needs a stable id that survives translation, +since translating the heading text changes the anchor. Docusaurus's MDX v3 syntax for this +is a comment, not `{#id}`: `## Play Mode tests {/* #play-mode-tests */}`. Sidebar category +labels live in `sidebars.ts` itself, not a translatable file, so they render in English for +every locale regardless of translated content underneath. Don't override Docusaurus's +theme chrome (pagination, admonition labels, sidebar buttons) in this site's own +`code.json`; it ships its own translated defaults per locale. + +Before translating a technical term, check how the target language's own community or +official docs (Unity's localized manual, GitHub's glossary, VRChat's community) actually +render it rather than translating literally. Some terms stay in English even in translated +prose, others have a real idiomatic equivalent that isn't the literal word-for-word choice. +This repo's own code identifiers (`_ts.Memory`, `TsStart`) are never translated, including +inside prose. ## Submitting a pull request diff --git a/README.md b/README.md index b599a36..1f6cc91 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,39 @@ -# Website +# TsVRC docs -This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. +[![Deploy](https://github.com/tsvrc/docs/actions/workflows/deploy.yml/badge.svg)](https://github.com/tsvrc/docs/actions/workflows/deploy.yml) +[![License: CC BY 4.0](https://img.shields.io/badge/license-CC%20BY%204.0-58a6ff?labelColor=161b22)](LICENSE) -## License - -This repository, including the Docusaurus site's own source code, is licensed under -[CC BY 4.0](LICENSE). Code samples embedded in a project's doc pages (under -`docs//`) that are drawn directly from that project's own repository keep that -project's license, not this repository's, since they originate there. Check the linked -project's own `LICENSE` for the specific terms. - -The TsVRC name and logo are governed separately, see -[TRADEMARK.md](https://github.com/tsvrc/.github/blob/main/TRADEMARK.md). +The [Docusaurus](https://docusaurus.io/) site behind [tsvrc.com](https://tsvrc.com), +documenting every project under the `tsvrc` GitHub org. Framework code lives in +[`tsvrc/tsvrc-core`](https://github.com/tsvrc/tsvrc-core); this repo is docs and content +only. -## Installation +## Development ```bash npm install +npm start ``` -**Note**: feel free to use the package manager of your choice. - -## Local Development - -```bash -npm run start -``` - -This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. - -## Build +`npm start` runs a hot-reloading dev server at `http://localhost:3000`. Content changes +reload live; changes to `docusaurus.config.ts` need a server restart. ```bash npm run build ``` -This command generates static content into the `build` directory and can be served using any static contents hosting service. +Builds the static site into `build/`. `onBrokenLinks: 'throw'` means a broken internal +link fails this command, so run it before calling a doc change done. ## Deployment -Using SSH: +Every push to `main` builds and deploys to GitHub Pages automatically via +[`.github/workflows/deploy.yml`](.github/workflows/deploy.yml). There's no manual deploy +step. -```bash -USE_SSH=true npm run deploy -``` - -Not using SSH: - -```bash -GIT_USER= npm run deploy -``` +## Support -If you are using GitHub Pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. +Support TsVRC at [tsvrc.com/support](https://tsvrc.com/support). ## Contributing @@ -61,3 +43,13 @@ layout, and how to submit a change. Community conduct is covered by the and [GOVERNANCE.md](https://github.com/tsvrc/.github/blob/main/GOVERNANCE.md) covers how decisions get made. Found a security issue? See [SECURITY.md](SECURITY.md) rather than opening a public issue. + +## License + +This repository is licensed under [CC BY 4.0](LICENSE). Code samples embedded in a +project's doc pages (under `docs//`) that are drawn directly from that project's +own repository keep that project's license, not this repository's, since they originate +there. Check the linked project's own `LICENSE` for the specific terms. + +The TsVRC name and logo are governed separately, see +[TRADEMARK.md](https://github.com/tsvrc/.github/blob/main/TRADEMARK.md). diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md new file mode 100644 index 0000000..63c6f76 --- /dev/null +++ b/STYLE_GUIDE.md @@ -0,0 +1,107 @@ +# Style guide + +Conventions for any doc content in this repo, human-written or AI-assisted. Applies to +every `.md`/`.mdx` file under `docs/`, `i18n/`, and `src/pages/`. + +## Doc structure + +### Pick the right category (Diátaxis) + +Every page does exactly one of these jobs. Mixing them inside one page is why docs end up +feeling unfocused: + +- **Tutorial** — a guided first experience. Optimizes for the reader finishing + successfully, not for completeness. +- **How-to guide** — solves one specific, named problem for someone who already knows the + basics. Skips background explanation. +- **Reference** — describes the thing accurately and completely (an API, a config schema, + a component's props). No opinions, no narrative, facts kept accurate as the thing + changes. +- **Explanation** — the why: design rationale, tradeoffs, how pieces fit together. The only + category where discussing alternatives and context belongs. + +Not sure which one a page is? That's the sign it's trying to do two jobs, split it. + +### Fully documenting a component: don't skip details + +When writing reference or explanation content for a package or component, cover what a +careful reviewer would ask about, not just the happy path: + +- What it's for, in one sentence a newcomer understands without prior context. +- Its public surface: what a consumer actually calls, imports, or configures. +- Invariants and constraints: what must be true before and after, what it assumes the + caller already did. +- Failure modes: what happens when it's misused, and what signals that (error, log, + silent no-op). +- Edge cases that aren't obvious from the signature: ordering, concurrency, lifecycle, + platform-specific behavior. +- Why it's built this way, when the reason isn't obvious. Link to an explanation page + rather than re-explaining inline. + +Missing one of these isn't a style problem, it's a coverage gap: the kind of thing a +reader hits in production with nowhere to look it up. + +### Sections and metadata + +- One H1 per page, matching the frontmatter title. +- A one- or two-sentence summary right under the H1: what this page is and who it's for, + before anything else. +- Sentence-case headings throughout (see Writing style below). + +### Linking instead of duplicating + +- Never restate content that already exists on another page. Link to the canonical page + instead: two copies of the same explanation will drift, a link can't. +- Link relatively within the same project folder (`../other-page`); link from the docs + root when crossing into another project's docs (`/docs//...`). +- When a decision has real tradeoffs and a future reader will reasonably ask "why was it + done this way", record it once as a short decision note (what, why, alternatives + considered) and link to it from everywhere it's relevant. Don't re-litigate it inline on + every page that touches it. + +## Writing style: sound human, say only what's needed + +Docs written by an LLM have a recognizable smell, and readers trust content less once they +notice it. Avoid it. + +### Cut, don't pad + +- If a reader can see it by reading the code, don't restate it here. A doc earns its place + by adding what code can't show: why, tradeoffs, what breaks, what to do next. +- Before adding a paragraph, check what it adds beyond the paragraph before it or the code + itself. If nothing, delete it. +- One idea per section. If two sections could swap order without anything breaking, that's + a list wearing the structure of an argument, tighten it. + +### Words and phrases to avoid + +These are statistically over-represented in LLM output and read as filler to anyone who has +seen a lot of AI-generated text: delve, leverage (verb), robust, seamless, comprehensive, +cutting-edge, pivotal, meticulous, landscape / realm / tapestry (as metaphors), utilize, +"in order to", streamline, foster, elevate, unlock, harness, ecosystem (unless it's +literally an ecosystem), myriad, plethora, crucial, paramount, nuanced, "it's worth noting", +"it's important to note", "at its core", "best practices" (name the actual practice instead). + +Hedging kills technical writing: cut "could potentially", "may eventually", "it's worth +mentioning". State the fact or the tradeoff directly. + +### Sentence and paragraph shape + +- Vary sentence length on purpose. A row of same-length sentences reads like a template. +- Don't open with "In today's...", "Let's explore...", or "In this doc, we will...". Start + with the actual point. +- Avoid the "It's not X, it's Y" construction. State the positive claim. +- Sentence case for headings ("Set up your environment"), not title case + ("Set Up Your Environment"). +- Skip chatbot artifacts entirely: "I hope this helps", "Great question", "Feel free to + reach out". This is documentation, not a chat reply. + +### Punctuation and formatting + +- Avoid em dashes for asides in prose; use a comma, a colon, or a full stop instead. (An em + dash inside a bolded-term list item is fine: `- **Term** — one-line description`.) +- Don't bold more than one phrase per section, bolding everything bolds nothing. +- Reach for prose over bullets when explaining an idea with real connections between its + parts. Bullets suit genuinely parallel, independent items: flags, a checklist, install + steps. A bulleted list of bare noun phrases ("Fast. Reliable. Secure.") explains nothing; + say what's actually fast, reliable, or secure, and why. diff --git a/docusaurus.config.ts b/docusaurus.config.ts index f6cafa1..aa63bbb 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -85,6 +85,11 @@ const config: Config = { label: 'GitHub', position: 'right', }, + { + to: '/support', + label: 'Support', + position: 'right', + }, { type: 'localeDropdown', position: 'right', @@ -106,6 +111,10 @@ const config: Config = { label: 'GitHub', href: 'https://github.com/tsvrc', }, + { + label: 'Support', + to: '/support', + }, ], copyright: `Copyright © ${new Date().getFullYear()} TsVRC. Not affiliated with or endorsed by VRChat Inc.`, }, diff --git a/i18n/es/code.json b/i18n/es/code.json index 9bf93f8..70748de 100644 --- a/i18n/es/code.json +++ b/i18n/es/code.json @@ -175,5 +175,32 @@ }, "framework.meta.description": { "message": "TsVRC Core es un framework para crear mundos de VRChat con UdonSharp: inicialización estructurada, conexión de dependencias y generación de código en el editor." + }, + "support.meta.title": { + "message": "Apoya a TsVRC" + }, + "support.meta.description": { + "message": "Apoya a TsVRC en Patreon o Ko-fi." + }, + "support.hero.title": { + "message": "Apoya a TsVRC" + }, + "support.hero.subtitle": { + "message": "Apoyar a TsVRC es completamente opcional, y se agradece de verdad si decides hacerlo." + }, + "support.options.title": { + "message": "Formas de apoyar" + }, + "support.options.patreon.description": { + "message": "Una membresía mensual en patreon.com/Tsvrc." + }, + "support.options.patreon.cta": { + "message": "Apoya en Patreon" + }, + "support.options.kofi.description": { + "message": "Propinas puntuales o una membresía mensual en ko-fi.com/tsvrc." + }, + "support.options.kofi.cta": { + "message": "Apoya en Ko-fi" } -} \ No newline at end of file +} diff --git a/i18n/es/docusaurus-theme-classic/footer.json b/i18n/es/docusaurus-theme-classic/footer.json index 8cb58e9..4a53372 100644 --- a/i18n/es/docusaurus-theme-classic/footer.json +++ b/i18n/es/docusaurus-theme-classic/footer.json @@ -11,6 +11,10 @@ "message": "GitHub", "description": "The label of footer link with label=GitHub linking to https://github.com/tsvrc" }, + "link.item.label.Support": { + "message": "Apoyar", + "description": "The label of footer link with label=Support linking to /support" + }, "copyright": { "message": "Copyright © 2026 TsVRC. No afiliado ni respaldado por VRChat Inc.", "description": "The footer copyright" diff --git a/i18n/es/docusaurus-theme-classic/navbar.json b/i18n/es/docusaurus-theme-classic/navbar.json index f493c28..b6ae456 100644 --- a/i18n/es/docusaurus-theme-classic/navbar.json +++ b/i18n/es/docusaurus-theme-classic/navbar.json @@ -18,5 +18,9 @@ "item.label.GitHub": { "message": "GitHub", "description": "Navbar item with label GitHub" + }, + "item.label.Support": { + "message": "Apoyar", + "description": "Navbar item with label Support" } } \ No newline at end of file diff --git a/src/components/support/Hero.tsx b/src/components/support/Hero.tsx new file mode 100644 index 0000000..630238d --- /dev/null +++ b/src/components/support/Hero.tsx @@ -0,0 +1,18 @@ +import Translate from '@docusaurus/Translate'; + +export default function Hero() { + return ( +
+
+

+ Support TsVRC +

+

+ + Supporting TsVRC is entirely optional, and genuinely appreciated if you choose to. + +

+
+
+ ); +} diff --git a/src/components/support/Options.tsx b/src/components/support/Options.tsx new file mode 100644 index 0000000..97b7df0 --- /dev/null +++ b/src/components/support/Options.tsx @@ -0,0 +1,63 @@ +import Link from '@docusaurus/Link'; +import Translate, { translate } from '@docusaurus/Translate'; + +type Option = { + id: string; + name: string; + description: string; + cta: string; + href: string; +}; + +function useOptions(): Option[] { + return [ + { + id: 'patreon', + name: 'Patreon', + description: translate({ + id: 'support.options.patreon.description', + message: 'A monthly membership at patreon.com/Tsvrc.', + }), + cta: translate({ id: 'support.options.patreon.cta', message: 'Support on Patreon' }), + href: 'https://www.patreon.com/Tsvrc', + }, + { + id: 'kofi', + name: 'Ko-fi', + description: translate({ + id: 'support.options.kofi.description', + message: 'One-time tips or a monthly membership at ko-fi.com/tsvrc.', + }), + cta: translate({ id: 'support.options.kofi.cta', message: 'Support on Ko-fi' }), + href: 'https://ko-fi.com/tsvrc', + }, + ]; +} + +export default function Options() { + const options = useOptions(); + return ( +
+

+ Ways to support +

+
+ {options.map((option) => ( +
+
+

{option.name}

+

{option.description}

+
+ + {option.cta} + +
+ ))} +
+
+ ); +} diff --git a/src/pages/support.tsx b/src/pages/support.tsx new file mode 100644 index 0000000..ad2272e --- /dev/null +++ b/src/pages/support.tsx @@ -0,0 +1,19 @@ +import type { ReactNode } from 'react'; +import Layout from '@theme/Layout'; +import { translate } from '@docusaurus/Translate'; +import Hero from '@site/src/components/support/Hero'; +import Options from '@site/src/components/support/Options'; + +export default function Support(): ReactNode { + return ( + + + + + ); +}