1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! **bevy_grimoire_core** — the engine-free half of world building.
//!
//! Constraint IR, solver backends, Wave Function Collapse, Poisson/Delaunay geometry, and the seeded
//! RNG they all draw from. Nothing here imports `bevy`, and nothing here knows what an SCP is.
//!
//! # Why this is a crate and not a module
//!
//! It always was engine-free — `placement/ir.rs` has carried the sentence *"Nothing here imports
//! `bevy::`"* since long before this crate existed, and `wfc.rs`, `geom.rs` and `scatter.rs` each say
//! the same about themselves. But a comment cannot fail a build. Now the manifest can: `bevy_grimoire_core`
//! depends on `serde`, `ron`, `rand` and `rand_chacha`, so reaching for a `bevy` type or a game
//! concept from in here does not compile.
//!
//! That matters because three consumers need this code and only one of them is the game: the game
//! itself, the offline search (`bin/train`), and the standalone editor described in
//! `docs/2026-08-03-emerge-mapper-plan.md`. The editor is why the split happened now.
//!
//! # The module layout is deliberately unchanged
//!
//! `placement::ir`, `placement::solver`, `placement::solvers`, `placement::scatter` and
//! `placement::manifest` keep the paths they had inside the game, so every `crate::placement::ir::…`
//! inside these files still resolves and the move is reviewable as a pure `git mv`. The game
//! re-exports them at their old paths for the same reason — a workspace split that also rewrites a
//! thousand import lines is a split nobody can diff.
//!
//! # What stayed behind, and why
//!
//! `placement::furnish` is the Bevy boundary of the placement stack (it spawns entities);
//! `placement::mod` binds to the game's run lifecycle; `placement::anomalies` is SCP content. Those
//! are the game's, and `ir.rs:7` already named `furnish.rs` as the boundary before the split.
/// The deterministic RNG, re-exported at its original path.
///
/// It lives in the `bevy_grimoire_rng` crate — a leaf with no dependencies of its own, so every crate
/// here shares the same generator. Copying it instead would create a SECOND definition of the stream
/// every reproducibility claim here rests on, which is the one outcome that had to be avoided. This
/// alias means no caller moved.
pub use bevy_grimoire_rng as rng;
/// Hermite ease between two edges. Pure math, so it lives here rather than in a crate that has a
/// renderer — `bevy_grimoire_anim`'s weight blending and the game's own `util` both take it from one place.