Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
# Feature templates — `features.ts`
## Purpose
Owns every renderer that produces a per-feature file in the scaffolded
output: `i18n`, `networking` (basic + full), `api`, `api-schemas`,
`storage`, `auth`, `form-builder`, and `r3f`. The renderers are pure
functions over `ProjectOptions`; the `r3f` renderer additionally branches
on `options.r3fModules` to wire camera / physics / particles / character
/ pathfinding subsystems into the emitted scene.
The companion `templates.ts` module covers the project-level renderers;
the two together replace the upstream `src/templates/*.ts` and
`src/templates/features/*.ts` blob set. `renderFeature(feature,
options)` is the single dispatch entry the generator uses; individual
`render*Feature` helpers are exported for tools that want to render a
single feature in isolation (for example, a "show me the API skeleton"
preview pane in an IDE extension).
## Features
- Eight per-feature renderers — every closed `FeatureModule` value has a
dedicated implementation.
- `renderNetworkFeature` vs `renderNetworkFullFeature` selected by
`options.networkingComplexity`.
- `renderR3fFeature` composes the camera / physics / particles imports
+ scene fragments based on `options.r3fModules`.
- `featurePath(feature)` returns the canonical output path for each
feature (the generator uses this to assemble the file list).
## Usage: Basic
```ts
import { renderFeature, featurePath } from "@suaveplan/electrobun/templates";
const content = renderFeature("i18n", opts);
const path = featurePath("i18n");
// path === "src/features/i18n.ts"
```
## Usage: Advanced
```ts
import {
featurePath,
renderFeature,
} from "@suaveplan/electrobun/templates";
const featureFiles = opts.features.map((f) => ({
path: featurePath(f),
content: renderFeature(f, opts),
}));
```
## API Reference
- `renderI18nFeature()`, `renderNetworkFeature()`,
`renderNetworkFullFeature()`, `renderApiFeature()`,
`renderApiSchemasFeature()`, `renderStorageFeature()`,
`renderAuthFeature()`, `renderFormBuilderFeature()`,
`renderR3fFeature(options)`.
- `renderFeature(feature: FeatureModule, options: ProjectOptions):
string` — dispatch table.
- `featurePath(feature: FeatureModule): string`.
## Implementation Notes
The `r3f` renderer is the only one whose output is materially shaped by
`ProjectOptions` beyond the basic "the feature is enabled" toggle. The
imports and scene fragments are assembled by joining arrays of strings,
which makes the relative ordering deterministic and the diff-noise low
when a new R3F module is added: the test for "r3f renderer emits the
requested modules" pins the order so a refactor cannot silently
re-shuffle imports.
The `networking` renderer dispatches on `options.networkingComplexity`
rather than `options.networking` because the upstream contract used
`"basic"` / `"full"` to gate the full mesh layer. Keeping the same
contract means downstream electrobun projects already on the
`networkingComplexity` shape do not need to migrate.
`featurePath` lives here rather than in the generator because the
mapping is per-feature; the generator consumes it as a thin lookup. If
a future feature lands with a non-default output path, the change is
local to `features.ts`.