SpinForge is a group-theoretic generator for spin-symmetry-adapted (SSA) and
oriented magnetic crystal structures based on spin space groups.
-## Installation
+[Documentation](https://spglib.github.io/spinforge/) ·
+[PyPI](https://pypi.org/project/spinforge/) ·
+[Issue tracker](https://github.com/spglib/spinforge/issues)
-SpinForge supports Python 3.11 and later.
-
-```shell
-python -m pip install spinforge
-```
-
-For a source checkout and contributor setup, see
-[CONTRIBUTING.md](./CONTRIBUTING.md).
-
-## Quickstart: oriented magnetic structures
-
-Given a primitive crystal structure in `MnTe.cif`, this example enumerates
-collinear SSA candidates with propagation-vector index one and generates every
-maximal oriented descendant:
-
-```python
-from moyopy import Cell
-from pymatgen.core import Structure
-from spinspg.spin import SpinOnlyGroupType
-
-from spinforge.configuration import SSAGenerator
-
-structure = Structure.from_file("MnTe.cif")
-prim_cell = Cell(
- basis=structure.lattice.matrix.tolist(),
- positions=structure.frac_coords.tolist(),
- numbers=list(structure.atomic_numbers),
-)
-magnetic_site_indices = [
- index for index, atomic_number in enumerate(prim_cell.numbers) if atomic_number == 25
-]
-
-generator = SSAGenerator(
- prim_cell=prim_cell,
- magnetic_site_indices=magnetic_site_indices,
-)
-
-for spin_only_group, spin_space_group, adapted_structure in generator.enumerate(
- spin_only_group_type=SpinOnlyGroupType.COLLINEAR,
- k_index=1,
- max_depth=0,
-):
- oriented_structures = generator.generate_oriented(
- adapted_structure,
- spin_only_group=spin_only_group,
- nontrivial_spin_space_group=spin_space_group,
- )
- for magnetic_structure, magnetic_space_subgroup in oriented_structures:
- print(magnetic_structure.formula, magnetic_space_subgroup.msg_type)
-```
-
-`SSAGenerator` requires a primitive input cell. The family-subgroup,
-spin-space-group, and oriented spin-frame equivalence controls are separate.
-See the [enumeration and equivalence guide](./docs/equivalence.md) for the
-precise criteria and the options for larger searches.
-
-## Examples
-
-The paper examples are provided as notebooks in [`examples/paper`](./examples/paper):
-
-- [collinear MnTe](./examples/paper/collinear_MnTe)
-- [coplanar Mn3Sn](./examples/paper/coplanar_Mn3Sn)
-- [noncoplanar CoTa3S6](./examples/paper/noncoplanar_CoTa3S6)
-
-These examples are published as-is. The paper figures, MAGNDATA-derived
-datasets, and the raw 283-material SDFT workflow are not part of this
-repository.
+Installation, tutorials, examples, citation guidance, and API references are
+maintained in the [documentation](https://spglib.github.io/spinforge/). For a
+source checkout and contributor setup, see [CONTRIBUTING.md](./CONTRIBUTING.md).
## Release flow
@@ -129,30 +67,6 @@ Please use
bugs and in-scope feature requests. Security reports follow
[SECURITY.md](./SECURITY.md).
-## Citation
-
-If SpinForge contributes to published work, cite the software metadata in
-[`CITATION.cff`](./CITATION.cff) and the associated oriented-spin-space-group
-paper:
-
-> T. Nomoto, K. Shinohara, H. Watanabe, and R. Arita,
-> “Systematic magnetic structure generation based on oriented spin space
-> groups: Formulation, applications, and high-throughput first-principles
-> calculations,” *Physical Review X* (accepted 2026).
-> [doi:10.1103/8n3w-h2t1](https://doi.org/10.1103/8n3w-h2t1)
-
-```bibtex
-@article{SpinForgePRX2026,
- author = {Nomoto, Takuya and Shinohara, Kohei and Watanabe, Hikaru and Arita, Ryotaro},
- title = {Systematic Magnetic Structure Generation Based on Oriented Spin Space Groups:
- Formulation, Applications, and High-Throughput First-Principles Calculations},
- journal = {Physical Review X},
- year = {2026},
- doi = {10.1103/8n3w-h2t1},
- note = {Accepted}
-}
-```
-
## Data attribution and license
Third-party and literature-derived fixture notices are collected in
diff --git a/docs/THIRD_PARTY_DATA.md b/docs/THIRD_PARTY_DATA.md
index 188841f..8aae547 100644
--- a/docs/THIRD_PARTY_DATA.md
+++ b/docs/THIRD_PARTY_DATA.md
@@ -36,8 +36,9 @@ Please cite:
## MnTe structural model
`src/spinforge/testing/assets/MnTe.cif` and
-`examples/paper/collinear_MnTe/MnTe.cif` are identical, locally serialized
-pymatgen CIFs for the NiAs-type MnTe structure. The lattice constants
+`examples/paper/collinear_MnTe/MnTe.cif` are identical to the documentation
+copy at `docs/paper/MnTe.cif`. They are locally serialized pymatgen CIFs for
+the NiAs-type MnTe structure. The lattice constants
`a = b = 4.17349018 Å` and `c = 6.75345133 Å` follow the supplemental
material to:
@@ -74,3 +75,24 @@ The SpinForge fixture is not a byte-for-byte COD or MAGNDATA record.
within the SpinForge project. Repository history records no external database
file as its source, so no third-party dataset license is asserted for this
file.
+
+## Article example figures
+
+The following PNG schematics under `docs/assets/paper/` illustrate examples
+from the associated article:
+
+- `fig_example_collinear.png`
+- `fig_example_coplanar.png`
+- `fig_example_noncoplanar.png`
+
+The figures were created for:
+
+> T. Nomoto, K. Shinohara, H. Watanabe, and R. Arita,
+> “Systematic magnetic structure generation based on oriented spin space
+> groups: Formulation, applications, and high-throughput first-principles
+> calculations,” *Physical Review X* (accepted 2026).
+> [doi:10.1103/8n3w-h2t1](https://doi.org/10.1103/8n3w-h2t1)
+
+They are included with permission from their copyright holder, granted on
+September 6, 2026. This notice records that permission without asserting a
+Creative Commons license before the article's Version of Record is published.
diff --git a/docs/api/configuration.md b/docs/api/configuration.md
new file mode 100644
index 0000000..1e81d84
--- /dev/null
+++ b/docs/api/configuration.md
@@ -0,0 +1,5 @@
+# Configuration
+
+High-level structure generation and supercell objects.
+
+::: spinforge.configuration
diff --git a/docs/api/irreps.md b/docs/api/irreps.md
new file mode 100644
index 0000000..38a233a
--- /dev/null
+++ b/docs/api/irreps.md
@@ -0,0 +1,6 @@
+# Irreducible representations
+
+Real irreducible-representation and intertwiner utilities used by the
+spin-space-group enumerators.
+
+::: spinforge.irreps
diff --git a/docs/api/magnetic-space-group.md b/docs/api/magnetic-space-group.md
new file mode 100644
index 0000000..2eb7a4e
--- /dev/null
+++ b/docs/api/magnetic-space-group.md
@@ -0,0 +1,5 @@
+# Magnetic space groups
+
+Oriented descendants and magnetic-space-subgroup objects.
+
+::: spinforge.msg
diff --git a/docs/api/mcif.md b/docs/api/mcif.md
new file mode 100644
index 0000000..d6d4b69
--- /dev/null
+++ b/docs/api/mcif.md
@@ -0,0 +1,6 @@
+# MCIF
+
+Write a pymatgen magnetic structure as a symmetrized magnetic CIF in the
+BNS/MAGNDATA convention.
+
+::: spinforge.mcif
diff --git a/docs/api/space-group.md b/docs/api/space-group.md
new file mode 100644
index 0000000..b5bb18c
--- /dev/null
+++ b/docs/api/space-group.md
@@ -0,0 +1,6 @@
+# Space groups
+
+Family and normal space-subgroup enumeration, parent-normalizer actions, and
+translation sublattices.
+
+::: spinforge.space_group
diff --git a/docs/api/spin-space-group.md b/docs/api/spin-space-group.md
new file mode 100644
index 0000000..625c1ac
--- /dev/null
+++ b/docs/api/spin-space-group.md
@@ -0,0 +1,5 @@
+# Spin space groups
+
+Nontrivial spin space groups, symmetry operations, and subgroup enumeration.
+
+::: spinforge.ssg
diff --git a/docs/api/spincif.md b/docs/api/spincif.md
new file mode 100644
index 0000000..7e37533
--- /dev/null
+++ b/docs/api/spincif.md
@@ -0,0 +1,5 @@
+# spinCIF
+
+Read and write SpinForge's supported subset of the draft spinCIF format.
+
+::: spinforge.scif
diff --git a/docs/assets/logo-mark.svg b/docs/assets/logo-mark.svg
new file mode 100644
index 0000000..e9d9bbf
--- /dev/null
+++ b/docs/assets/logo-mark.svg
@@ -0,0 +1,310 @@
+
+
diff --git a/logo.svg b/docs/assets/logo.svg
similarity index 100%
rename from logo.svg
rename to docs/assets/logo.svg
diff --git a/docs/assets/paper/fig_example_collinear.png b/docs/assets/paper/fig_example_collinear.png
new file mode 100644
index 0000000..98361e2
Binary files /dev/null and b/docs/assets/paper/fig_example_collinear.png differ
diff --git a/docs/assets/paper/fig_example_coplanar.png b/docs/assets/paper/fig_example_coplanar.png
new file mode 100644
index 0000000..59ca34f
Binary files /dev/null and b/docs/assets/paper/fig_example_coplanar.png differ
diff --git a/docs/assets/paper/fig_example_noncoplanar.png b/docs/assets/paper/fig_example_noncoplanar.png
new file mode 100644
index 0000000..ad04f6d
Binary files /dev/null and b/docs/assets/paper/fig_example_noncoplanar.png differ
diff --git a/docs/changelog.md b/docs/changelog.md
new file mode 100644
index 0000000..786b75d
--- /dev/null
+++ b/docs/changelog.md
@@ -0,0 +1 @@
+--8<-- "CHANGELOG.md"
diff --git a/docs/citation.md b/docs/citation.md
new file mode 100644
index 0000000..5d26bf7
--- /dev/null
+++ b/docs/citation.md
@@ -0,0 +1,26 @@
+# Citation
+
+If SpinForge contributes to published work, cite both the software metadata in
+[`CITATION.cff`](https://github.com/spglib/spinforge/blob/main/CITATION.cff) and
+the associated oriented-spin-space-group paper:
+
+> T. Nomoto, K. Shinohara, H. Watanabe, and R. Arita,
+> “Systematic magnetic structure generation based on oriented spin space
+> groups: Formulation, applications, and high-throughput first-principles
+> calculations,” *Physical Review X* (accepted 2026).
+> [doi:10.1103/8n3w-h2t1](https://doi.org/10.1103/8n3w-h2t1)
+
+```bibtex
+@article{SpinForgePRX2026,
+ author = {Nomoto, Takuya and Shinohara, Kohei and Watanabe, Hikaru and Arita, Ryotaro},
+ title = {Systematic Magnetic Structure Generation Based on Oriented Spin Space Groups:
+ Formulation, Applications, and High-Throughput First-Principles Calculations},
+ journal = {Physical Review X},
+ year = {2026},
+ doi = {10.1103/8n3w-h2t1},
+ note = {Accepted}
+}
+```
+
+SpinForge is distributed under the BSD 3-Clause License. Third-party data
+retain the terms listed in the [data notices](THIRD_PARTY_DATA.md).
diff --git a/docs/classification-model.md b/docs/classification-model.md
new file mode 100644
index 0000000..fe6e436
--- /dev/null
+++ b/docs/classification-model.md
@@ -0,0 +1,83 @@
+# Classification model
+
+!!! abstract "Page contract"
+
+ - **Starting point:** You understand the objects in the
+ [domain model](domain-model.md) but not which distinctions SpinForge
+ preserves.
+ - **Destination:** You can identify which setting changes the search space,
+ an equivalence relation, or only the orientation of a result.
+ - **Next:** Apply those distinctions in
+ [Control an enumeration](control-enumeration.md).
+ - **Skip:** Use the [exact reference](equivalence.md) directly when the
+ conceptual distinctions are already familiar.
+
+The [SpinForge article](https://doi.org/10.1103/8n3w-h2t1) is the authoritative
+source for the underlying theory and derivations. This page only maps those
+concepts to package decisions.
+
+## The decisions are independent
+
+| Question | SpinForge decision | What changes |
+|---|---|---|
+| What kind of spin configuration is sought? | `SpinOnlyGroupType.COLLINEAR`, `.COPLANAR`, or `.NONCOPLANAR` | The compatible spin-only groups and spin-space-group assignments |
+| Which translation lattices are admissible? | An index bound with `k_index`, or a lattice fixed by `with_propagation_vectors()` | The spatial families and supercells searched |
+| How far below the parent spatial symmetry should the search go? | `max_depth` and `multiplicity_preserving` | The family space subgroups retained |
+| Should parent-conjugate spatial families be listed separately? | `up_to_parent_conjugacy` | The number of family-subgroup representatives |
+| Should a coplanar mirror partner remain distinct after orientation? | `preserve_spin_planochirality` | The oriented descendants returned |
+
+Changing one row does not silently change the others. In particular, retaining
+more family-space-group conjugates is distinct from changing spin-frame
+equivalence, and orientation is a later classification step rather than a new
+family-subgroup search.
+
+## Spin class
+
+The requested spin-only-group type classifies the allowed geometry of the
+candidate moments:
+
+- `COLLINEAR`: all moments lie on one spin axis;
+- `COPLANAR`: moments lie in one spin plane but need not share an axis;
+- `NONCOPLANAR`: moments are not restricted to one plane.
+
+This is an input classification, not a label inferred from experimental data.
+If a propagation-vector constraint is incompatible with the selected class,
+an empty enumeration can be the correct result.
+
+## Translation constraint
+
+`k_index` gives a finite index bound when the translation lattice is unknown.
+`SSAGenerator.with_propagation_vectors()` instead fixes the commensurate
+translation lattice from measured or calculated propagation vectors.
+
+These are alternative ways to supply the translation constraint. When
+propagation vectors are present, their lattice supplies the index, and an
+explicit `k_index` must equal that computed index. See
+[use propagation vectors](propagation-vectors.md) for coordinate-frame handling
+and [control enumeration](control-enumeration.md) for practical search choices.
+
+## Spatial-family breadth
+
+`max_depth` bounds the translationengleiche Hermann groups visited beneath the
+parent. It is not a generic "subgroup depth" for every emitted family.
+`multiplicity_preserving=True` additionally removes family subgroups that split
+the selected magnetic-site orbits incompatibly with the package's multiplicity
+criterion.
+
+By default, `up_to_parent_conjugacy=True` retains one representative of each
+family-subgroup class under the crystallographic parent $G$. The `False`
+setting retains the separate parent-conjugate embeddings.
+
+## Keep spin-frame and spatial equivalence separate
+
+For a fixed family group $G'$, compatible spin-space groups are identified up
+to a global orthogonal change of spin frame. The high-level generator also
+reduces them by the applicable parent normalizer $N_G(G')$. These relations do
+not become weaker when parent-conjugate family groups are retained separately.
+
+Orientation then uses the axes of the fixed family subgroup. For coplanar results,
+`preserve_spin_planochirality=True` keeps enantiomorphs related by an improper
+spin transformation distinct; `False` identifies them.
+
+For the formal actions, defaults, and lower-level API behavior, consult the
+[enumeration and equivalence reference](equivalence.md).
diff --git a/docs/control-enumeration.md b/docs/control-enumeration.md
new file mode 100644
index 0000000..98b8ce9
--- /dev/null
+++ b/docs/control-enumeration.md
@@ -0,0 +1,96 @@
+# Control an enumeration
+
+!!! abstract "Page contract"
+
+ - **Starting point:** You can construct an `SSAGenerator` and run the
+ quickstart search.
+ - **Destination:** You can choose the five search controls deliberately.
+ - **Next:** Check the implemented relations in
+ [Enumeration and equivalence](equivalence.md) when candidate counts need
+ explanation.
+ - **Skip:** The quickstart settings already cover your calculation.
+
+## Start with the smallest relevant search
+
+Select the moment geometry required by the problem, then keep the default
+equivalence reductions:
+
+```python
+from spinspg.spin import SpinOnlyGroupType
+
+candidates = generator.enumerate(
+ spin_only_group_type=SpinOnlyGroupType.COLLINEAR,
+ k_index=1,
+ max_depth=0,
+ up_to_parent_conjugacy=True,
+)
+```
+
+Use `COLLINEAR`, `COPLANAR`, or `NONCOPLANAR` according to the moment geometry
+you intend to model. Moving to a less restrictive type changes the physical
+search, not merely its cost.
+
+## Set the translation bound
+
+Without measured propagation vectors, `k_index` is required. It is the index
+of the final invariant translation lattice that bounds enumeration:
+
+- `k_index=1` restricts the final lattice to the primitive translation lattice.
+- A larger value admits compatible family translation lattices whose indices
+ divide that value.
+
+If commensurate propagation vectors are known, construct the generator with
+`SSAGenerator.with_propagation_vectors()` instead. SpinForge then derives the
+lattice and supplies its index automatically; follow [Constrain an enumeration
+with propagation vectors](propagation-vectors.md).
+
+## Set the Hermann depth
+
+`max_depth` controls which translationengleiche Hermann groups are searched.
+Their bounded klassengleiche descendants remain included.
+
+| Value | Hermann groups retained |
+|---|---|
+| `0` | Parent only |
+| `1` | Parent and maximal proper subgroups (default) |
+| `None` | All subgroup depths |
+
+Begin at `0` when validating a workflow. Increase the depth only when the
+target family symmetry requires it.
+
+## Choose the spatial reduction
+
+Keep `up_to_parent_conjugacy=True` to return one representative for family
+space subgroups related by the crystallographic parent. Set it to `False` only
+when you need every conjugate family subgroup explicitly:
+
+```python
+all_conjugates = generator.enumerate(
+ spin_only_group_type=SpinOnlyGroupType.COLLINEAR,
+ k_index=1,
+ max_depth=0,
+ up_to_parent_conjugacy=False,
+)
+```
+
+This option changes family-subgroup reduction. It does not disable the
+spin-frame equivalence applied within each retained family subgroup.
+
+## Choose the magnetic-site filter
+
+By default, the generator omits family subgroups that change the multiplicity
+of the supplied magnetic sites. Disable this constructor-time filter only when
+those splittings are part of the intended search:
+
+```python
+generator = SSAGenerator(
+ prim_cell=primitive_cell,
+ magnetic_site_indices=magnetic_site_indices,
+ multiplicity_preserving=False,
+)
+```
+
+Change one control at a time and record the number of returned candidates. For
+the exact equivalence relations and subgroup construction, see
+[Enumeration and equivalence](equivalence.md). For the underlying scientific
+derivation, see the [SpinForge article](https://doi.org/10.1103/8n3w-h2t1).
diff --git a/docs/domain-model.md b/docs/domain-model.md
new file mode 100644
index 0000000..ec3697c
--- /dev/null
+++ b/docs/domain-model.md
@@ -0,0 +1,88 @@
+# Domain model
+
+!!! abstract "Page contract"
+
+ - **Starting point:** You can recognize a magnetic structure but are new to
+ SpinForge's vocabulary.
+ - **Destination:** You can follow an enumeration result from its
+ crystallographic input to an oriented magnetic structure.
+ - **Next:** Learn which distinctions affect a candidate set in the
+ [classification model](classification-model.md).
+ - **Skip:** This page when SpinForge's objects and workflow stages are
+ already familiar.
+
+For derivations and the full scientific treatment, see the
+[SpinForge article](https://doi.org/10.1103/8n3w-h2t1).
+
+## One workflow, several distinct objects
+
+``` mermaid
+flowchart TB
+ A[Primitive cell and magnetic sites]
+ B[Family space subgroup]
+ C[Spin space group and spin-only group]
+ D[SSA structure supercell + moment basis]
+ E[Oriented magnetic structure and magnetic space subgroup]
+
+ A -->|enumerate spatial families| B
+ B -->|assign spin rotations| C
+ C -->|construct allowed moments| D
+ D -->|orient relative to lattice| E
+```
+
+SpinForge keeps these stages separate because they answer different
+questions. A family space subgroup (shortened below to *family subgroup*) is a
+spatial symmetry choice relative to the crystallographic parent. A spin space
+group adds how spatial operations act on spins. A spin-symmetry-adapted (SSA)
+structure represents the magnetic-moment subspace allowed by that symmetry.
+An oriented result finally relates the spin frame to the crystal lattice.
+
+## Input state
+
+[`SSAGenerator`][spinforge.configuration.SSAGenerator] starts from:
+
+- a primitive [`moyopy.Cell`](https://spglib.github.io/moyo/python/api/#moyopy.Cell);
+- indices identifying the magnetic sites in that exact cell;
+- optionally, propagation vectors that fix a commensurate translation lattice.
+
+The cell defines the crystallographic parent space group $G$. The magnetic
+site indices determine which parent-site orbits must support moments. Search
+bounds and propagation vectors limit the translation lattices considered; they
+do not become additional atoms or moments in the input object.
+
+## Enumeration state
+
+Calling `SSAGenerator.enumerate()` returns tuples of:
+
+1. a `SpinOnlyGroup`, which records the requested collinear, coplanar, or
+ noncoplanar spin-only symmetry;
+2. a [`NontrivialSpinSpaceGroup`][spinforge.ssg.NontrivialSpinSpaceGroup],
+ which records the nontrivial coupling between spatial and spin operations;
+3. a
+ [`SpinSymmetryAdaptedStructure`][spinforge.configuration.SpinSymmetryAdaptedStructure],
+ which contains a supercell and a basis for symmetry-allowed magnetic
+ moments.
+
+These are candidate symmetry classes, not predicted ground states. SpinForge
+does not rank them by energy or fit them to measurements.
+
+## Generated and oriented state
+
+`SpinSymmetryAdaptedStructure.generate()` selects a moment configuration from
+the adapted basis. If the basis has more than one dimension, its coefficients
+are sampled; pass a NumPy random generator when the selected point must be
+reproducible.
+
+`SSAGenerator.generate_oriented()` performs a different step: it enumerates
+the allowed orientations of the spin frame relative to the family subgroup's
+crystallographic axes. Each result pairs a pymatgen `Structure`, with Cartesian
+moments in its `magmom` site property, with a
+[`MagneticSpaceSubgroup`][spinforge.msg.MagneticSpaceSubgroup].
+
+!!! tip "What to read next"
+
+ - Read the [classification model](classification-model.md) to choose the
+ boundary and equivalence controls that change a candidate set.
+ - Follow [your first structure](quickstart.md) to run this workflow.
+ - Use the [configuration API](api/configuration.md) when you need exact
+ signatures and return types.
diff --git a/docs/equivalence.md b/docs/equivalence.md
index 0ce2af7..e1a3ebe 100644
--- a/docs/equivalence.md
+++ b/docs/equivalence.md
@@ -1,4 +1,23 @@
-# Enumeration and equivalence
+# Enumeration and equivalence reference
+
+This is the exact technical reference for the enumeration bounds and
+equivalence relations implemented by SpinForge.
+
+!!! abstract "Page contract"
+
+ - **Starting point:** You understand the objects and stages in the
+ [domain model](domain-model.md) and need to interpret candidate counts or
+ implement against the enumeration APIs.
+ - **Destination:** You can state which group action identifies each class
+ and what each search control retains.
+ - **Next:** Check exact signatures in the
+ [configuration API](api/configuration.md).
+ - **Skip:** You only need to run the default workflow; use
+ [Your first structure](quickstart.md) instead.
+
+The [SpinForge article](https://doi.org/10.1103/8n3w-h2t1) remains the
+authoritative source for derivations and the broader scientific treatment.
+This page records the software contract rather than repeating that material.
## Equivalence criteria at a glance
@@ -36,7 +55,9 @@ For the parent-normalizer action that classifies normal space subgroups, the act
inverse conjugation. Thus a stored normalizer transformation $h_x$ maps a subgroup $H_x$
to the representative $H_r$ when
-$$h_x^{-1}H_xh_x=H_r.$$
+$$
+h_x^{-1}H_xh_x=H_r.
+$$
The corresponding stabilizer consists of the normalizer transformations $h$ satisfying
$h^{-1}H_rh=H_r$. Code and API descriptions use the concrete phrases "equivalent objects,"
@@ -64,7 +85,9 @@ Let $G$ be the parent space group and $T$ its primitive translation subgroup. A
SpinForge follows the Hermann theorem. For every $G'\leq G$, there is a unique intermediate group
-$$G'\leq M\leq G$$
+$$
+G'\leq M\leq G
+$$
such that $M$ is a t-subgroup of $G$ and $G'$ is a k-subgroup of $M$. Thus $M$ and $G'$ have the same point group, while $G$ and $M$ have the same translation group $T$. This separates the finite point-group choice from the bounded translation-lattice choice:
@@ -75,7 +98,9 @@ such that $M$ is a t-subgroup of $G$ and $G'$ is a k-subgroup of $M$. Thus $M$ a
`with_propagation_vectors()` fixes the final commensurate invariant lattice
-$$L=\{t\in T\mid k_i\cdot t\in\mathbb{Z}\text{ for every supplied }k_i\}.$$
+$$
+L=\{t\in T\mid k_i\cdot t\in\mathbb{Z}\text{ for every supplied }k_i\}.
+$$
In that case, only family lattices satisfying $L\leq T'\leq T$ are considered, and the relative lattice $L\leq T'$ replaces the unrestricted index-$n/d$ search. An explicitly supplied `k_index` must equal $[T:L]$.
@@ -109,7 +134,9 @@ The lower-level `SpinSpaceGroupEnumerator` receives one fixed family space group
`SpinSpaceSubgroupEnumerator` instead consumes an enumerated `FamilySpaceSubgroup`. The family object records the inclusion $G'\leq G$ and the induced action of $N_G(G')/G'$. By default the class returns representatives under
-$$N_G(G') \times O(3).$$
+$$
+N_G(G') \times O(3).
+$$
It first classifies invariant space subgroups $H'\trianglelefteq G'$ under $N_G(G')$. For each representative $H'$, it then classifies its spin-rotation assignments under the stabilizer of $H'$ in $N_G(G')$ together with the global $O(3)$ spin-frame action. Results are expressed in the translation-lattice basis of $G'$; `SSAGenerator` transforms them to the translation-lattice basis of the parent group $G$ for magnetic-structure generation.
@@ -128,7 +155,9 @@ The criteria exposed by the enumeration APIs are therefore:
There is no separate `up_to_family_space_group_conjugacy` option. For an invariant subgroup $H'\trianglelefteq G'$ and spin representation $U$, preconjugation by $g\in G'$ gives
-$$U^g(x)=U(g^{-1}xg)=U(g)^{-1}U(x)U(g),$$
+$$
+U^g(x)=U(g^{-1}xg)=U(g)^{-1}U(x)U(g),
+$$
which is already identified by the global $O(3)$ spin-frame equivalence. Such a boolean would therefore not change the abstract SSG classes. `SSAGenerator.up_to_parent_conjugacy` remains independent and controls only whether $G$-conjugate family space subgroups are retained separately.
diff --git a/docs/examples.md b/docs/examples.md
new file mode 100644
index 0000000..ba33cbf
--- /dev/null
+++ b/docs/examples.md
@@ -0,0 +1,43 @@
+# Examples
+
+!!! abstract "Page contract"
+
+ - **Starting point:** You have completed
+ [Your first structure](quickstart.md) and want to map that workflow to a
+ physical example.
+ - **Destination:** You can choose the notebook whose spin-only-group class
+ and translation bound match your task.
+ - **Next:** Open that notebook and use the article for its scientific
+ interpretation.
+ - **Skip:** This page if you only need an exact API signature.
+
+The repository contains the notebooks used for three representative examples
+in the [SpinForge article](https://doi.org/10.1103/8n3w-h2t1). Each follows the
+same software workflow: choose the magnetic sites, select a spin-only-group
+class and `k_index`, enumerate SSA structures, generate oriented descendants,
+and write spinCIF output. The article is the source for the formalism,
+derivations, and physical interpretation.
+
+## Schematic overview
+
+The figures summarize the enumerated spin space groups and representative
+oriented structures. Follow each figure to its corresponding notebook for the
+software workflow, and use the article for interpretation.
+
+=== "Collinear MnTe"
+
+ { .paper-figure }
+
+ Continue with the [collinear MnTe notebook](https://github.com/spglib/spinforge/blob/main/docs/paper/collinear_MnTe.ipynb).
+
+=== "Coplanar Mn₃Sn"
+
+ { .paper-figure }
+
+ Continue with the [coplanar Mn₃Sn notebook](https://github.com/spglib/spinforge/blob/main/docs/paper/coplanar_Mn3Sn.ipynb).
+
+=== "Noncoplanar CoTa₃S₆"
+
+ { .paper-figure }
+
+ Continue with the [noncoplanar CoTa₃S₆ notebook](https://github.com/spglib/spinforge/blob/main/docs/paper/noncoplanar_CoTa3S6.ipynb).
diff --git a/docs/export-files.md b/docs/export-files.md
new file mode 100644
index 0000000..f15e9aa
--- /dev/null
+++ b/docs/export-files.md
@@ -0,0 +1,72 @@
+# Export result files
+
+!!! abstract "Page contract"
+
+ - **Starting point:** You have the five objects returned by enumeration and
+ orientation: `spin_only_group`, `spin_space_group`, `adapted`,
+ `magnetic_structure`, and `magnetic_space_subgroup`.
+ - **Destination:** You have a spinCIF, an MCIF, or both, plus a basic parse
+ check.
+ - **Next:** Apply your downstream calculation's checks to the parsed
+ structure.
+ - **Skip:** If the workflow remains entirely in Python. If the format is
+ undecided, read [Choose an output format](file-formats.md) first.
+
+## Write spinCIF
+
+Use the orientation-aware constructor for a structure returned by
+`generate_oriented()`. It applies the same orientation to the stored spin
+operations:
+
+```python
+from spinforge.scif import SpinCifWriter
+
+spin_cif = SpinCifWriter.from_oriented(
+ adapted,
+ spin_space_group,
+ magnetic_structure,
+ magnetic_space_subgroup,
+ spin_only_group=spin_only_group,
+)
+spin_cif.write_file("candidate.scif")
+```
+
+Do not replace this with the plain `SpinCifWriter(...)` constructor for an
+oriented result; that constructor expects magnetic moments in the original
+enumeration frame.
+
+## Write MCIF
+
+The oriented `magnetic_structure` already contains Cartesian moments in its
+`magmom` site property:
+
+```python
+from spinforge.mcif import MCifWriter
+
+MCifWriter(magnetic_structure).write_file("candidate.mcif")
+```
+
+Pass `symprec` or `mag_symprec` to `MCifWriter` when the default symmetry-search
+tolerances are unsuitable for the structure.
+
+## Check the files
+
+Parse the spinCIF with SpinForge and expand its asymmetric unit:
+
+```python
+from spinforge.scif import SpinCifReader
+
+spin_structure = SpinCifReader.from_file("candidate.scif").get_structure()
+```
+
+Parse the MCIF with pymatgen:
+
+```python
+from pymatgen.core import Structure
+
+magnetic_structure_from_file = Structure.from_file("candidate.mcif")
+```
+
+A successful parse catches syntax and expansion errors. Add application-level
+checks for composition, lattice, positions, and moment vectors before using a
+round-tripped structure in a calculation.
diff --git a/docs/file-formats.md b/docs/file-formats.md
new file mode 100644
index 0000000..5157888
--- /dev/null
+++ b/docs/file-formats.md
@@ -0,0 +1,40 @@
+# Choose an output format
+
+!!! abstract "Page contract"
+
+ - **Starting point:** You have an oriented magnetic structure but have not
+ chosen a file representation.
+ - **Destination:** You know which format preserves the object needed by the
+ next tool.
+ - **Next:** Write and check it with
+ [Export result files](export-files.md).
+ - **Skip:** If the workflow remains entirely in Python.
+
+| Choose | When you need to preserve | SpinForge interface |
+|---|---|---|
+| spinCIF (`.scif`) | The spin space group, including independent spatial and spin operations | [`SpinCifWriter`][spinforge.scif.SpinCifWriter] and [`SpinCifReader`][spinforge.scif.SpinCifReader] |
+| MCIF (`.mcif`) | The magnetic space group of one oriented magnetic structure in BNS/MAGNDATA convention | [`MCifWriter`][spinforge.mcif.MCifWriter] |
+
+The distinction is about symmetry, not only filename syntax. A spinCIF records
+the spin-space description carried by a SpinForge result. An MCIF
+records the magnetic space group that `MCifWriter` identifies from the
+oriented structure and its Cartesian `magmom` site property.
+
+Choose spinCIF when another calculation or archive needs the spin-space-group
+description. Choose MCIF when the consumer understands conventional magnetic
+crystallographic symmetry but not spin-space symmetry. You can write both when
+you need both representations.
+
+## Format limits
+
+- The spinCIF dictionary is preliminary. SpinForge stamps the supported draft
+ revision, [`SPINCIF_REVISION`][spinforge.scif.SPINCIF_REVISION], into each
+ file. The reader supports files written by SpinForge and the FINDSPINGROUP
+ reference files; it is not a general-purpose spinCIF parser.
+- MCIF output supports partial occupancy of a single species at a site. It does
+ not support mixed solid-solution sites because those sites cannot pass
+ through the symmetry identification used by the writer.
+
+To write and check either format, continue to [Export result files](export-files.md).
+For the scientific relation between spin and magnetic symmetry, see the
+[SpinForge article](https://doi.org/10.1103/8n3w-h2t1).
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..bd2f484
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,97 @@
+---
+hide:
+ - toc
+---
+
+# Forge magnetic structures from symmetry
+
+SpinForge generates spin-symmetry-adapted and oriented magnetic crystal
+structures from crystallographic symmetry. Use this page to choose a route
+based on what you already know and what you need to do.
+
+[Choose a route](#choose-your-route){ .md-button .md-button--primary }
+[Install SpinForge](installation.md){ .md-button }
+
+!!! note "Project scope"
+
+ SpinForge generates symmetry-compatible candidates. It does not determine
+ or refine a magnetic structure from experimental or first-principles data.
+
+## Choose your route
+
+You do not need to read the documentation from beginning to end. Each route
+below states its prerequisite, reading order, and destination. Follow one route
+until it meets your goal, then stop or branch to another.
+
+
+
+- :material-compass-outline:{ .lg .middle } **Understand the model**
+
+ ---
+
+ **Start here if:** SpinForge's domain vocabulary or representation of a
+ magnetic structure is new to you.
+
+ **Read:** [Domain model](domain-model.md) →
+ [Classification model](classification-model.md)
+
+ **You will be able to:** explain what SpinForge represents, which stages it
+ distinguishes, and why different equivalence relations produce different
+ candidate sets.
+
+ **You can skip:** installation, tutorials, and API details if you only need
+ the conceptual model.
+
+- :material-school-outline:{ .lg .middle } **Learn SpinForge**
+
+ ---
+
+ **Start here if:** you know the magnetic-crystallography concepts and are
+ new to the package.
+
+ **Read:** [Installation](installation.md) →
+ [Your first structure](quickstart.md) → [Examples](examples.md)
+
+ **You will be able to:** install SpinForge, enumerate a first set of
+ candidates, and inspect the result.
+
+ **You can skip:** the conceptual route when its terminology is already
+ familiar. Return to the classification model if a result count or grouping
+ is unexpected.
+
+- :material-tools:{ .lg .middle } **Complete a task**
+
+ ---
+
+ **Start here if:** SpinForge is installed and you can already run a basic
+ enumeration.
+
+ **Go directly to:** [Control enumeration](control-enumeration.md),
+ [Use propagation vectors](propagation-vectors.md), or
+ [Export files](export-files.md).
+
+ **You will be able to:** change the search and equivalence settings or
+ write the selected candidates for downstream use.
+
+ **You can skip:** the tutorial and unrelated task guides.
+
+- :material-code-braces:{ .lg .middle } **Check exact behavior**
+
+ ---
+
+ **Start here if:** you are implementing against SpinForge or verifying an
+ exact contract.
+
+ **Go directly to:** [Enumeration and equivalence](equivalence.md),
+ [File formats](file-formats.md), or the relevant
+ [API reference](api/configuration.md). Consult the
+ [Classification model](classification-model.md) when the meaning of a
+ returned object or equivalence relation matters.
+
+ **You will be able to:** confirm signatures, return types, object
+ relationships, and classification semantics.
+
+ **You can skip:** tutorials and task guides when you already know which API
+ surface you need.
+
+