SvelteKit
Purpose
Organize Svelte pages, components, and their supporting code by ownership and
actual reuse. Use (+page) and (+lib) to distinguish page-private code from
shared components at route branches, without adding wrappers to every leaf.
Use Svelte 5 component contracts and focused Svelte Helpers instead of duplicating
common types and utilities.
Copyable instructions
## SvelteKit
### Pages and component placement
Keep route pages focused on composition. Place feature-specific state, derived
presentation data, and interaction behavior in the closest component that owns
it. A parent coordinates shared source state; it does not precompute every
child's labels, images, and display details merely because it has the data.
Use these placement conventions:
- A leaf route keeps `+page.svelte` and its private components/helpers beside
each other. Do not add a `(+page)` wrapper when there are no route children.
- At a branch with its own page and real child routes, put that page and its
private supporting code in `(+page)/`.
- Put code shared by two or more pages or components in `(+lib)/` at their
nearest common route ancestor. Create it only when that reuse exists.
- A zone shared by sibling routes can have its own `(+lib)/`. Move components
shared across zones to `src/routes/(+lib)/`, not to an arbitrary zone.
- Keep application-specific presentation components near their route consumers.
Use `$lib` for portable helpers and shared infrastructure, rather than as a
default dumping ground for page-specific components.
- Split large components by coherent UI responsibilities: for example, move tab
content into separate components while the shell owns tab and save coordination.
- Avoid speculative shared abstractions and unrelated file moves.
Example with two independent zones:
```text
src/
lib/
format-value.ts # portable utility
routes/
(+lib)/
BrandHeader.svelte # actually used by both zones
(zone-a)/
workspace/ # /workspace has a page AND child routes
(+page)/
+page.svelte # /workspace
WorkspaceSummary.svelte # private to that page
(+lib)/
ItemSummary.svelte # used by list and details
list/ # leaf route: no wrapper
+page.svelte # /workspace/list
ListFilters.svelte
details/
+page.svelte # /workspace/details
DetailPanel.svelte
(zone-b)/
(+lib)/
SectionHeader.svelte # used by multiple pages in this zone
help/
+page.svelte # /help
HelpContent.svelte
contact/
+page.svelte # /contact
```
SvelteKit route groups in parentheses do not add URL segments. `(+page)` and
`(+lib)` are project naming conventions, not special SvelteKit APIs. Keep
`(+lib)` free of route entry files. Do not also put a second `+page.svelte` at the
parent URL already owned by `(+page)/+page.svelte`.
A private component can start as one sibling file. If it grows subcomponents,
keep its shell as `Editor.svelte` and place the parts under `Editor/`. Do not
assume importing a directory automatically resolves an `index.svelte`.
### Svelte 5 and Svelte Helpers
Before using `@atom-forge/svelte-helpers`, start with
`node_modules/@atom-forge/svelte-helpers/README-AI.md` at the package root, then
follow its documentation pointers and check the exported types for the installed
version. Follow dependency symlinks to the library repository when present. This
is a filesystem Markdown path, not a package import subpath. Use the helpers where
their contracts fit; do not introduce a local replacement for a suitable helper.
- Import type-only helpers with `import type`.
- Use `ClassProp` for a public class prop, and `ChildrenProp` or
`ChildrenPropOptional` for required or optional children snippets. Specify a
tuple argument type when the snippet receives parameters.
- For native-element wrappers, prefer Svelte's specific HTML attribute types.
Use `AnyProp` only for deliberately broad additional props, as the final member
of the intersection, and forward attributes intentionally.
- Use `XOR` for mutually exclusive prop variants and `AtLeastOne` when at least
one field is required. These describe compile-time contracts, not runtime
validation. Include an empty `XOR` alternative only when selecting no variant is allowed.
- Use `variantMap` to map boolean variant props to an internal value. Wrap it in
`$derived` when the value should follow prop changes; take a one-time snapshot
only when ignoring later changes is intentional.
- Render ordinary children with `{@render children()}` or
`{@render children?.()}`, not legacy slots. Use `RenderSnippet` when an API
expects a component but the content is a snippet; check its installed props
before wiring it to a modal or drawer.
- Use `debounce` or `debounceAsync` for interactions that benefit from delayed
callbacks. Handle async failures and stale responses separately; debouncing
alone does not guarantee response order.
- Treat `as` as a type assertion, not conversion or validation. Do not use it to
hide a real type mismatch or assume it is required for template expressions.
Example of a small component with typed optional children:
```svelte
<script lang="ts">
import type { ClassProp, ChildrenPropOptional } from '@atom-forge/svelte-helpers';
let { class: classes, children }: ClassProp & ChildrenPropOptional = $props();
</script>
<section class={classes}>
{@render children?.()}
</section>
```
Usage
Adopt this note for SvelteKit placement and Svelte 5 component best practices. Zone names and component
names in the tree are illustrative, not prescribed product structure. Move code
only when a task needs it; do not reorganize the whole application solely to
make the existing tree match the example.
SvelteKit
Purpose
Organize Svelte pages, components, and their supporting code by ownership and actual reuse. Use
(+page)and(+lib)to distinguish page-private code from shared components at route branches, without adding wrappers to every leaf. Use Svelte 5 component contracts and focused Svelte Helpers instead of duplicating common types and utilities.Copyable instructions
## SvelteKit ### Pages and component placement Keep route pages focused on composition. Place feature-specific state, derived presentation data, and interaction behavior in the closest component that owns it. A parent coordinates shared source state; it does not precompute every child's labels, images, and display details merely because it has the data. Use these placement conventions: - A leaf route keeps `+page.svelte` and its private components/helpers beside each other. Do not add a `(+page)` wrapper when there are no route children. - At a branch with its own page and real child routes, put that page and its private supporting code in `(+page)/`. - Put code shared by two or more pages or components in `(+lib)/` at their nearest common route ancestor. Create it only when that reuse exists. - A zone shared by sibling routes can have its own `(+lib)/`. Move components shared across zones to `src/routes/(+lib)/`, not to an arbitrary zone. - Keep application-specific presentation components near their route consumers. Use `$lib` for portable helpers and shared infrastructure, rather than as a default dumping ground for page-specific components. - Split large components by coherent UI responsibilities: for example, move tab content into separate components while the shell owns tab and save coordination. - Avoid speculative shared abstractions and unrelated file moves. Example with two independent zones: ```text src/ lib/ format-value.ts # portable utility routes/ (+lib)/ BrandHeader.svelte # actually used by both zones (zone-a)/ workspace/ # /workspace has a page AND child routes (+page)/ +page.svelte # /workspace WorkspaceSummary.svelte # private to that page (+lib)/ ItemSummary.svelte # used by list and details list/ # leaf route: no wrapper +page.svelte # /workspace/list ListFilters.svelte details/ +page.svelte # /workspace/details DetailPanel.svelte (zone-b)/ (+lib)/ SectionHeader.svelte # used by multiple pages in this zone help/ +page.svelte # /help HelpContent.svelte contact/ +page.svelte # /contact ``` SvelteKit route groups in parentheses do not add URL segments. `(+page)` and `(+lib)` are project naming conventions, not special SvelteKit APIs. Keep `(+lib)` free of route entry files. Do not also put a second `+page.svelte` at the parent URL already owned by `(+page)/+page.svelte`. A private component can start as one sibling file. If it grows subcomponents, keep its shell as `Editor.svelte` and place the parts under `Editor/`. Do not assume importing a directory automatically resolves an `index.svelte`. ### Svelte 5 and Svelte Helpers Before using `@atom-forge/svelte-helpers`, start with `node_modules/@atom-forge/svelte-helpers/README-AI.md` at the package root, then follow its documentation pointers and check the exported types for the installed version. Follow dependency symlinks to the library repository when present. This is a filesystem Markdown path, not a package import subpath. Use the helpers where their contracts fit; do not introduce a local replacement for a suitable helper. - Import type-only helpers with `import type`. - Use `ClassProp` for a public class prop, and `ChildrenProp` or `ChildrenPropOptional` for required or optional children snippets. Specify a tuple argument type when the snippet receives parameters. - For native-element wrappers, prefer Svelte's specific HTML attribute types. Use `AnyProp` only for deliberately broad additional props, as the final member of the intersection, and forward attributes intentionally. - Use `XOR` for mutually exclusive prop variants and `AtLeastOne` when at least one field is required. These describe compile-time contracts, not runtime validation. Include an empty `XOR` alternative only when selecting no variant is allowed. - Use `variantMap` to map boolean variant props to an internal value. Wrap it in `$derived` when the value should follow prop changes; take a one-time snapshot only when ignoring later changes is intentional. - Render ordinary children with `{@render children()}` or `{@render children?.()}`, not legacy slots. Use `RenderSnippet` when an API expects a component but the content is a snippet; check its installed props before wiring it to a modal or drawer. - Use `debounce` or `debounceAsync` for interactions that benefit from delayed callbacks. Handle async failures and stale responses separately; debouncing alone does not guarantee response order. - Treat `as` as a type assertion, not conversion or validation. Do not use it to hide a real type mismatch or assume it is required for template expressions. Example of a small component with typed optional children: ```svelte <script lang="ts"> import type { ClassProp, ChildrenPropOptional } from '@atom-forge/svelte-helpers'; let { class: classes, children }: ClassProp & ChildrenPropOptional = $props(); </script> <section class={classes}> {@render children?.()} </section> ```Usage
Adopt this note for SvelteKit placement and Svelte 5 component best practices. Zone names and component names in the tree are illustrative, not prescribed product structure. Move code only when a task needs it; do not reorganize the whole application solely to make the existing tree match the example.