diff --git a/README.md b/README.md
index b50ad4ec5a9612f421b19db30a27fdcebf19d8a8..913b8897cc0de3cbc1aa0ce89837845795fdd211 100644
--- a/README.md
+++ b/README.md
@@ -1,122 +1,149 @@
-`big-brain` is a [Utility AI](https://en.wikipedia.org/wiki/Utility_system)
-library for games, built for the [Bevy Game Engine](https://bevyengine.org/)
-
-It lets you define complex, intricate AI behaviors for your entities based on
-their perception of the world. Definitions are heavily data-driven, using
-plain Rust, and you only need to program Scorers (entities that look at your
-game world and come up with a Score), and Actions (entities that perform
-actual behaviors upon the world). No other code is needed for actual AI
-behavior.
-
-See [the documentation](https://docs.rs/big-brain) for more details.
-
-## Example
-
-First, you define actions and considerations, which are just plain old `Bevy`
-`Component`s and `System`s.
-
-### Scorers
-
-`Scorers`s are entities that look at the world and evaluate into `Score` values.
-
-```rust
-use bevy::prelude::*;
-use big_brain::prelude::*;
-
-#[derive(Debug, Clone)]
-pub struct Thirsty;
-
-impl Thirsty {
-    fn build() -> ThirstyBuilder {
-        ThirstyBuilder
-    }
-}
-
-#[derive(Debug, Clone)]
-pub struct ThirstyBuilder;
-
-impl ScorerBuilder for ThirstyBuilder {
-    fn build(&self, cmd: &mut Commands, scorer: Entity, _actor: Entity) {
-        cmd.entity(scorer).insert(Thirsty);
-    }
-}
-
-pub fn thirsty_scorer_system(
-    thirsts: Query<&Thirst>,
-    mut query: Query<(&Actor, &mut Score), With<Thirsty>>,
-) {
-    for (Actor(actor), mut score) in query.iter_mut() {
-        if let Ok(thirst) = thirsts.get(*actor) {
-            score.set(thirst.thirst);
-        }
-    }
-}
-```
-
-### Actions
-
-`Action`s are the actual things your entities will _do_.
-
-```rust
-use bevy::prelude::*;
-use big_brain::prelude::*;
-
-#[derive(Debug, Clone)]
-pub struct Drink;
-
-impl Drink {
-    pub fn build() -> DrinkBuilder {
-        DrinkBuilder
-    }
-}
-
-#[derive(Debug, Clone)]
-pub struct DrinkBuilder;
-
-impl ActionBuilder for DrinkBuilder {
-    fn build(&self, cmd: &mut Commands, action: Entity, _actor: Entity) {
-        cmd.entity(action).insert(Drink);
-    }
-}
-
-fn drink_action_system(
-    mut thirsts: Query<&mut Thirst>,
-    mut query: Query<(&Actor, &mut ActionState), With<Drink>>,
-) {
-    for (Actor(actor), mut state) in query.iter_mut() {
-        if let Ok(mut thirst) = thirsts.get_mut(*actor) {
-            match *state {
-                ActionState::Requested => {
-                    thirst.thirst = 10.0;
-                    *state = ActionState::Success;
-                }
-                ActionState::Cancelled => {
-                    *state = ActionState::Failure;
-                }
-                _ => {}
-            }
-        }
-    }
-}
-```
-
-### Thinker Definition
-
-Finally, you can use it when define the `Thinker`, which you can attach as a
-regular Component:
-
-```rust
-cmd.spawn().insert(Thirst::new(70.0, 2.0)).insert(
-    Thinker::build()
-        .picker(FirstToScore { threshold: 80.0 })
-        .when(Thirsty::build(), Drink::build()),
-);
-```
-
-## License
-
-This project is licensed under [the Parity License](LICENSE.md). Third-party contributions are licensed under Apache-2.0 and belong to their respective authors.
-
-The Parity License is a copyleft license that, unlike the GPL family, allows you to license derivative and connected works under permissive licenses like MIT or Apache-2.0. It's free to use provided the work you do is freely available!
-
-For proprietary use, please [contact me](mailto:kzm@zkat.tech?subject=big-brain%20license), or just [sponsor me on GitHub](https://github.com/users/zkat/sponsorship) under the appropriate tier to [acquire a proprietary-use license](LICENSE-PATRON.md)! This funding model helps me make my work sustainable and compensates me for the work it took to write this crate!
+# big-brain
+
+`big-brain` is a [Utility AI](https://en.wikipedia.org/wiki/Utility_system)
+library for games, built for the [Bevy Game Engine](https://bevyengine.org/)
+
+It lets you define complex, intricate AI behaviors for your entities based on
+their perception of the world. Definitions are heavily data-driven, using
+plain Rust, and you only need to program Scorers (entities that look at your
+game world and come up with a Score), and Actions (entities that perform
+actual behaviors upon the world). No other code is needed for actual AI
+behavior.
+
+See [the documentation](https://docs.rs/big-brain) for more details.
+
+### Features
+
+* Highly concurrent/parallelizable evaluation.
+* Integrates smoothly with Bevy.
+* Easy AI definition using idiomatic Rust builders. You don't have to be some genius to define behavior that _feels_ realistic to players.
+* High performance--supports hundreds of thousands of concurrent AIs.
+* Graceful degradation--can be configured such that the less frame time is available, the slower an AI might "seem", without dragging down framerates, by simply processing fewer events per tick.
+* Proven game AI model.
+* Low code overhead--you only define two types of application-dependent things, and everything else is building blocks!
+* Highly composable and reusable.
+* State machine-style continuous actions/behaviors.
+* Action cancellation.
+
+### Example
+
+First, you define actions and considerations, which are just plain old Bevy
+Components and Systems. As a developer, you write application-dependent code
+to define [`Scorers`](#scorers) and [`Actions`](#actions), and then put it
+all together like building blocks, using [`Thinkers`](#thinkers) that will
+define the actual behavior.
+
+#### Scorers
+
+`Scorer`s are entities that look at the world and evaluate into `Score` values. You can think of them as the "eyes" of the AI system. They're a highly-parallel way of being able to look at the `World` and use it to make some decisions later.
+
+They are created by types that implement `ScorerBuilder`.
+
+```rust
+use bevy::prelude::*;
+use big_brain::prelude::*;
+
+#[derive(Debug, Clone)]
+pub struct Thirsty;
+
+impl Thirsty {
+    fn build() -> ThirstyBuilder {
+        ThirstyBuilder
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct ThirstyBuilder;
+
+impl ScorerBuilder for ThirstyBuilder {
+    fn build(&self, cmd: &mut Commands, scorer: Entity, _actor: Entity) {
+        cmd.entity(scorer).insert(Thirsty);
+    }
+}
+
+pub fn thirsty_scorer_system(
+    thirsts: Query<&Thirst>,
+    mut query: Query<(&Actor, &mut Score), With<Thirsty>>,
+) {
+    for (Actor(actor), mut score) in query.iter_mut() {
+        if let Ok(thirst) = thirsts.get(*actor) {
+            score.set(thirst.thirst);
+        }
+    }
+}
+```
+
+#### Actions
+
+`Action`s are the actual things your entities will _do_. They are connected to `ActionState`s, and are created by types implementing `ActionBuilder`.
+
+```rust
+use bevy::prelude::*;
+use big_brain::prelude::*;
+
+#[derive(Debug, Clone)]
+pub struct Drink;
+
+impl Drink {
+    pub fn build() -> DrinkBuilder {
+        DrinkBuilder
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct DrinkBuilder;
+
+impl ActionBuilder for DrinkBuilder {
+    fn build(&self, cmd: &mut Commands, action: Entity, _actor: Entity) {
+        cmd.entity(action).insert(Drink);
+    }
+}
+
+fn drink_action_system(
+    mut thirsts: Query<&mut Thirst>,
+    mut query: Query<(&Actor, &mut ActionState), With<Drink>>,
+) {
+    for (Actor(actor), mut state) in query.iter_mut() {
+        if let Ok(mut thirst) = thirsts.get_mut(*actor) {
+            match *state {
+                ActionState::Requested => {
+                    thirst.thirst = 10.0;
+                    *state = ActionState::Success;
+                }
+                ActionState::Cancelled => {
+                    *state = ActionState::Failure;
+                }
+                _ => {}
+            }
+        }
+    }
+}
+```
+
+#### Thinkers
+
+Finally, you can use it when define the `Thinker`, which you can attach as a
+regular Component:
+
+```rust
+cmd.spawn().insert(Thirst::new(70.0, 2.0)).insert(
+    Thinker::build()
+        .picker(FirstToScore { threshold: 80.0 })
+        .when(Thirsty::build(), Drink::build()),
+);
+```
+
+### Contributing
+
+1. Install the latest Rust toolchain (stable supported).
+2. `cargo run --example thirst`
+3. Happy hacking!
+
+### License
+
+This project is licensed under [the Parity License](LICENSE.md). Third-party contributions are licensed under Apache-2.0 and belong to their respective authors.
+
+The Parity License is a copyleft license that, unlike the GPL family, allows you to license derivative and connected works under permissive licenses like MIT or Apache-2.0. It's free to use provided the work you do is freely available!
+
+For proprietary use, please [contact me](mailto:kzm@zkat.tech?subject=big-brain%20license), or just [sponsor me on GitHub](https://github.com/users/zkat/sponsorship) under the appropriate tier to [acquire a proprietary-use license](LICENSE-PATRON.md)! This funding model helps me make my work sustainable and compensates me for the work it took to write this crate!
+
diff --git a/src/actions.rs b/src/actions.rs
index e2093a584af86dab2bf280e1a472845993bbe276..0e7ad6f318f483690aa4d36ae1532d642c79b779 100644
--- a/src/actions.rs
+++ b/src/actions.rs
@@ -1,16 +1,40 @@
+/*!
+Defines Action-related functionality. This module includes the ActionBuilder trait and some Composite Actions for utility.
+*/
 use std::sync::Arc;
 
 use bevy::prelude::*;
 
 use crate::thinker::{ActionEnt, Actor};
 
+/**
+The current state for an Action.
+*/
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum ActionState {
+    /**
+    Initial state. No action should be performed.
+    */
     Init,
+    /**
+    Action requested. The Action-handling system should start executing this Action ASAP and change the status to the next state.
+    */
     Requested,
+    /**
+    The action has ongoing execution. The associated Thinker will try to keep executing this Action as-is until it changes state or it gets Cancelled.
+    */
     Executing,
+    /**
+    An ongoing Action has been cancelled. The Thinker might set this action for you, so for Actions that execute for longer than a single tick, **you must check whether the Cancelled state was set** and change do either Success or Failure. Thinkers will wait on Cancelled actions to do any necessary cleanup work, so this can hang your AI if you don't look for it.
+    */
     Cancelled,
+    /**
+    The Action was a success. This is used by Composite Actions to determine whether to continue execution.
+    */
     Success,
+    /**
+    The Action failed. This is used by Composite Actions to determine whether to halt execution.
+    */
     Failure,
 }
 
@@ -27,10 +51,10 @@ impl ActionState {
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub struct ActionBuilderId;
+pub(crate) struct ActionBuilderId;
 
 #[derive(Debug, Clone)]
-pub struct ActionBuilderWrapper(pub ActionBuilderId, pub Arc<dyn ActionBuilder>);
+pub(crate) struct ActionBuilderWrapper(pub ActionBuilderId, pub Arc<dyn ActionBuilder>);
 
 impl ActionBuilderWrapper {
     pub fn new(builder: Arc<dyn ActionBuilder>) -> Self {
@@ -38,22 +62,55 @@ impl ActionBuilderWrapper {
     }
 }
 
+/**
+Trait that must be defined by types in order to be `ActionBuilder`s. `ActionBuilder`s' job is to spawn new `Action` entities. In general, most of this is already done for you, and the only method you really have to implement is `.build()`.
+
+The `build()` method MUST be implemented for any `ActionBuilder`s you want to define.
+*/
 pub trait ActionBuilder: std::fmt::Debug + Send + Sync {
+    /**
+    MUST insert your concrete Action component into the `action` [`Entity`], using `cmd`. You _may_ use `actor`, but it's perfectly normal to just ignore it.
+
+    ### Example
+
+    ```no_run
+    struct MyBuilder;
+    struct MyAction;
+
+    impl ActionBuilder for MyBuilder {
+        fn build(&self, cmd: &mut Commands, action: Entity, actor: Entity) {
+            cmd.entity(action).insert(MyAction);
+        }
+    }
+    ```
+    */
     fn build(&self, cmd: &mut Commands, action: Entity, actor: Entity);
+
+    /**
+    Don't implement this yourself unless you know what you're doing.
+     */
     fn attach(&self, cmd: &mut Commands, actor: Entity) -> Entity {
         let action_ent = ActionEnt(cmd.spawn().id());
-        cmd.entity(action_ent.0).insert(ActionState::new()).insert(Actor(actor));
+        cmd.entity(action_ent.0)
+            .insert(ActionState::new())
+            .insert(Actor(actor));
         self.build(cmd, action_ent.0, actor);
         action_ent.0
     }
 }
 
+/**
+[`ActionBuilder`] for the [`Steps`] component. Constructed through `Steps::build()`.
+*/
 #[derive(Debug)]
 pub struct StepsBuilder {
     steps: Vec<Arc<dyn ActionBuilder>>,
 }
 
 impl StepsBuilder {
+    /**
+    Adds an action step. Order matters.
+    */
     pub fn step(&mut self, action_builder: impl ActionBuilder + 'static) -> &mut Self {
         self.steps.push(Arc::new(action_builder));
         self
@@ -63,13 +120,31 @@ impl StepsBuilder {
 impl ActionBuilder for StepsBuilder {
     fn build(&self, cmd: &mut Commands, action: Entity, actor: Entity) {
         let child_action = self.steps[0].attach(cmd, actor);
-        cmd.entity(action).insert(Steps {
-            active_step: 0,
-            active_ent: ActionEnt(child_action),
-            steps: self.steps.clone(),
-        }).push_children(&[child_action]);
+        cmd.entity(action)
+            .insert(Steps {
+                active_step: 0,
+                active_ent: ActionEnt(child_action),
+                steps: self.steps.clone(),
+            })
+            .push_children(&[child_action]);
     }
 }
+
+/**
+Composite Action that executes a series of steps in sequential order, as long as each step results in a `Success`ful [`ActionState`].
+
+### Example
+
+```ignore
+Thinker::build()
+    .when(
+        MyScorer,
+        Steps::build()
+            .step(MyAction::build())
+            .step(MyNextAction::build())
+        )
+```
+*/
 #[derive(Debug)]
 pub struct Steps {
     steps: Vec<Arc<dyn ActionBuilder>>,
@@ -78,11 +153,17 @@ pub struct Steps {
 }
 
 impl Steps {
+    /**
+    Construct a new [`StepsBuilder`] to define the steps to take.
+    */
     pub fn build() -> StepsBuilder {
         StepsBuilder { steps: Vec::new() }
     }
 }
 
+/**
+System that takes care of executing any existing [`Steps`] Actions.
+*/
 pub fn steps_system(
     mut cmd: Commands,
     mut steps_q: Query<(Entity, &Actor, &mut Steps)>,
diff --git a/src/choices.rs b/src/choices.rs
index cc8a30e5157646161e58ec48a0146d470ec7625b..560cf271ea969ccd29e582265aee8ba78a168179 100644
--- a/src/choices.rs
+++ b/src/choices.rs
@@ -11,8 +11,8 @@ use crate::{
 // Contains different types of Considerations and Actions
 #[derive(Debug, Clone)]
 pub struct Choice {
-    pub scorer: ScorerEnt,
-    pub action: ActionBuilderWrapper,
+    pub(crate) scorer: ScorerEnt,
+    pub(crate) action: ActionBuilderWrapper,
 }
 impl Choice {
     pub fn calculate(&self, scores: &Query<&Score>) -> f32 {
diff --git a/src/evaluators.rs b/src/evaluators.rs
index e7d92c32f1971dbf9c51f3c17eae4dbc99cf8a76..b5f7d1176809645a075cc1585fbda241729ed31c 100644
--- a/src/evaluators.rs
+++ b/src/evaluators.rs
@@ -1,7 +1,17 @@
+/*!
+Utilities for turning values of 0.0..=100.0 into different curves.
+*/
+
+/**
+Trait that any evaluators must implement. Must return an `f32` value between `0.0..=100.0`.
+ */
 pub trait Evaluator: std::fmt::Debug + Sync + Send {
     fn evaluate(&self, value: f32) -> f32;
 }
 
+/**
+[`Evaluator`] for linear values. That is, there's no curve to the value mapping.
+ */
 #[derive(Debug)]
 pub struct LinearEvaluator {
     xa: f32,
@@ -39,6 +49,9 @@ impl Evaluator for LinearEvaluator {
     }
 }
 
+/**
+[`Evaluator`] with an exponent curve. The value will grow according to its `power` parameter.
+ */
 #[derive(Debug)]
 pub struct PowerEvaluator {
     xa: f32,
@@ -79,6 +92,9 @@ impl Evaluator for PowerEvaluator {
     }
 }
 
+/**
+[`Evaluator`] with a "Sigmoid", or "S-like" curve.
+ */
 #[derive(Debug)]
 pub struct SigmoidEvaluator {
     xa: f32,
diff --git a/src/lib.rs b/src/lib.rs
index 4893c46b53af000f7672695b839f8a5260d71b5e..b739e0fe155108612348c9abe0e39f65b61fe87b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,12 +1,165 @@
+/*!
+`big-brain` is a [Utility AI](https://en.wikipedia.org/wiki/Utility_system)
+library for games, built for the [Bevy Game Engine](https://bevyengine.org/)
+
+It lets you define complex, intricate AI behaviors for your entities based on
+their perception of the world. Definitions are heavily data-driven, using
+plain Rust, and you only need to program Scorers (entities that look at your
+game world and come up with a Score), and Actions (entities that perform
+actual behaviors upon the world). No other code is needed for actual AI
+behavior.
+
+See [the documentation](https://docs.rs/big-brain) for more details.
+
+## Features
+
+* Highly concurrent/parallelizable evaluation.
+* Integrates smoothly with Bevy.
+* Easy AI definition using idiomatic Rust builders. You don't have to be some genius to define behavior that _feels_ realistic to players.
+* High performance--supports hundreds of thousands of concurrent AIs.
+* Graceful degradation--can be configured such that the less frame time is available, the slower an AI might "seem", without dragging down framerates, by simply processing fewer events per tick.
+* Proven game AI model.
+* Low code overhead--you only define two types of application-dependent things, and everything else is building blocks!
+* Highly composable and reusable.
+* State machine-style continuous actions/behaviors.
+* Action cancellation.
+
+## Example
+
+First, you define actions and considerations, which are just plain old Bevy
+Components and Systems. As a developer, you write application-dependent code
+to define [`Scorers`](#scorers) and [`Actions`](#actions), and then put it
+all together like building blocks, using [`Thinkers`](#thinkers) that will
+define the actual behavior.
+
+### Scorers
+
+`Scorer`s are entities that look at the world and evaluate into [`Score`](scorers::Score) values. You can think of them as the "eyes" of the AI system. They're a highly-parallel way of being able to look at the `World` and use it to make some decisions later.
+
+They are created by types that implement [`ScorerBuilder`](scorers::ScorerBuilder).
+
+```
+use bevy::prelude::*;
+use big_brain::prelude::*;
+
+#[derive(Debug, Clone)]
+pub struct Thirsty;
+
+impl Thirsty {
+    fn build() -> ThirstyBuilder {
+        ThirstyBuilder
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct ThirstyBuilder;
+
+impl ScorerBuilder for ThirstyBuilder {
+    fn build(&self, cmd: &mut Commands, scorer: Entity, _actor: Entity) {
+        cmd.entity(scorer).insert(Thirsty);
+    }
+}
+
+pub fn thirsty_scorer_system(
+    thirsts: Query<&Thirst>,
+    mut query: Query<(&Actor, &mut Score), With<Thirsty>>,
+) {
+    for (Actor(actor), mut score) in query.iter_mut() {
+        if let Ok(thirst) = thirsts.get(*actor) {
+            score.set(thirst.thirst);
+        }
+    }
+}
+```
+
+### Actions
+
+`Action`s are the actual things your entities will _do_. They are connected to [`ActionState`](actions::ActionState)s, and are created by types implementing [`ActionBuilder`](actions::ActionBuilder).
+
+```
+use bevy::prelude::*;
+use big_brain::prelude::*;
+
+#[derive(Debug, Clone)]
+pub struct Drink;
+
+impl Drink {
+    pub fn build() -> DrinkBuilder {
+        DrinkBuilder
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct DrinkBuilder;
+
+impl ActionBuilder for DrinkBuilder {
+    fn build(&self, cmd: &mut Commands, action: Entity, _actor: Entity) {
+        cmd.entity(action).insert(Drink);
+    }
+}
+
+fn drink_action_system(
+    mut thirsts: Query<&mut Thirst>,
+    mut query: Query<(&Actor, &mut ActionState), With<Drink>>,
+) {
+    for (Actor(actor), mut state) in query.iter_mut() {
+        if let Ok(mut thirst) = thirsts.get_mut(*actor) {
+            match *state {
+                ActionState::Requested => {
+                    thirst.thirst = 10.0;
+                    *state = ActionState::Success;
+                }
+                ActionState::Cancelled => {
+                    *state = ActionState::Failure;
+                }
+                _ => {}
+            }
+        }
+    }
+}
+```
+
+### Thinkers
+
+Finally, you can use it when define the [`Thinker`](thinker::Thinker), which you can attach as a
+regular Component:
+
+```no_run
+cmd.spawn().insert(Thirst::new(70.0, 2.0)).insert(
+    Thinker::build()
+        .picker(FirstToScore { threshold: 80.0 })
+        .when(Thirsty::build(), Drink::build()),
+);
+```
+
+## Contributing
+
+1. Install the latest Rust toolchain (stable supported).
+2. `cargo run --example thirst`
+3. Happy hacking!
+
+## License
+
+This project is licensed under [the Parity License](LICENSE.md). Third-party contributions are licensed under Apache-2.0 and belong to their respective authors.
+
+The Parity License is a copyleft license that, unlike the GPL family, allows you to license derivative and connected works under permissive licenses like MIT or Apache-2.0. It's free to use provided the work you do is freely available!
+
+For proprietary use, please [contact me](mailto:kzm@zkat.tech?subject=big-brain%20license), or just [sponsor me on GitHub](https://github.com/users/zkat/sponsorship) under the appropriate tier to [acquire a proprietary-use license](LICENSE-PATRON.md)! This funding model helps me make my work sustainable and compensates me for the work it took to write this crate!
+
+*/
+
 pub mod evaluators;
 pub mod pickers;
 
 pub mod actions;
-pub mod choices;
+mod choices;
 pub mod scorers;
 pub mod thinker;
 
 pub mod prelude {
+    /*!
+    Convenience module with the core types you're most likely to use when working with Big Brain. Mean to be used like `use big_brain::prelude::*;`
+    */
     use super::*;
 
     pub use super::BigBrainPlugin;
@@ -18,6 +171,22 @@ pub mod prelude {
 
 use bevy::prelude::*;
 
+/**
+Core [`Plugin`] for Big Brain behavior. Required for any of the [`Thinker`](thinker::Thinker)-related magic to work.
+
+### Example
+
+```no_run
+use bevy::prelude::*;
+use big_brain::prelude::*;
+
+App::build()
+    .add_plugins(DefaultPlugins)
+    .add_plugin(BigBrainPlugin)
+    // ...insert entities and other systems.
+    .run();
+*/
+
 pub struct BigBrainPlugin;
 
 impl Plugin for BigBrainPlugin {
diff --git a/src/pickers.rs b/src/pickers.rs
index 0ac71e3687b22a3bec4e521d664e0402ec49e367..c54bbea8a1c1ad7079fdb64a2a439e5f0757143d 100644
--- a/src/pickers.rs
+++ b/src/pickers.rs
@@ -1,16 +1,42 @@
+/*!
+Pickers are used by Thinkers to determine which of its Scorers will "win".
+*/
+
 use bevy::prelude::*;
 
 use crate::{choices::Choice, scorers::Score};
 
+/**
+Required trait for Pickers. A Picker is given a slice of choices and a query that can be passed into `Choice::calculate`.
+
+Implementations of `pick` must return `Some(Choice)` for the `Choice` that was picked, or `None`.
+ */
 pub trait Picker: std::fmt::Debug + Sync + Send {
     fn pick(&self, _choices: &[Choice], _utilities: &Query<&Score>) -> Option<Choice>;
 }
 
+/**
+Picker that chooses the first `Choice` with a [`Score`] higher than its configured `threshold`.
+
+### Example
+
+```no_run
+Thinker::build()
+    .picker(FirstToScore::new(80.))
+    // .when(...)
+```
+ */
 #[derive(Debug, Clone, Default)]
 pub struct FirstToScore {
     pub threshold: f32,
 }
 
+impl FirstToScore {
+    pub fn new(threshold: f32) -> Self {
+        Self { threshold }
+    }
+}
+
 impl Picker for FirstToScore {
     fn pick(&self, choices: &[Choice], utilities: &Query<&Score>) -> Option<Choice> {
         for choice in choices {
diff --git a/src/scorers.rs b/src/scorers.rs
index 5bdc42446f8b822801c6732de63956ffe1f68cab..c2c4cc5a71066cdda65acd18615b6e61e0d607b9 100644
--- a/src/scorers.rs
+++ b/src/scorers.rs
@@ -1,16 +1,33 @@
+/*!
+Scorers look at the world and boil down arbitrary characteristics into a range of 0.0..=100.0. This module includes the ScorerBuilder trait and some built-in Composite Scorers.
+*/
+
 use std::sync::Arc;
 
 use bevy::prelude::*;
 
 use crate::thinker::{Actor, ScorerEnt};
 
+/**
+Score value between `0.0..=100.0` associated with a Scorer.
+ */
 #[derive(Debug, Clone, Default)]
 pub struct Score(pub(crate) f32);
 
 impl Score {
+    /**
+    Returns the `Score`'s current value.
+     */
     pub fn get(&self) -> f32 {
         self.0
     }
+    /**
+    Set the `Score`'s value.
+
+    ### Panics
+
+    Panics if `value` isn't within `0.0..=100.0`.
+     */
     pub fn set(&mut self, value: f32) {
         if !(0.0..=100.0).contains(&value) {
             panic!("Score value must be between 0.0 and 100.0");
@@ -19,8 +36,33 @@ impl Score {
     }
 }
 
+/**
+Trait that must be defined by types in order to be `ScorerBuilder`s. `ScorerBuilder`s' job is to spawn new `Scorer` entities. In general, most of this is already done for you, and the only method you really have to implement is `.build()`.
+
+The `build()` method MUST be implemented for any `ScorerBuilder`s you want to define.
+*/
 pub trait ScorerBuilder: std::fmt::Debug + Sync + Send {
+    /**
+    MUST insert your concrete Scorer component into the Scorer [`Entity`], using `cmd`. You _may_ use `actor`, but it's perfectly normal to just ignore it.
+
+    ### Example
+
+    ```no_run
+    struct MyBuilder;
+    struct MyScorer;
+
+    impl ScorerBuilder for MyBuilder {
+        fn build(&self, cmd: &mut Commands, action: Entity, actor: Entity) {
+            cmd.entity(action).insert(MyScorer);
+        }
+    }
+    ```
+    */
     fn build(&self, cmd: &mut Commands, scorer: Entity, actor: Entity);
+
+    /**
+    Don't implement this yourself unless you know what you're doing.
+     */
     fn attach(&self, cmd: &mut Commands, actor: Entity) -> Entity {
         let scorer_ent = cmd.spawn().id();
         cmd.entity(scorer_ent)
@@ -31,6 +73,9 @@ pub trait ScorerBuilder: std::fmt::Debug + Sync + Send {
     }
 }
 
+/**
+Scorer that always returns the same, fixed score. Good for combining with things creatively!
+ */
 #[derive(Debug, Clone)]
 pub struct FixedScore(f32);
 
@@ -55,6 +100,20 @@ impl ScorerBuilder for FixedScoreBuilder {
     }
 }
 
+/**
+Composite Scorer that takes any number of other Scorers and returns the sum of their [`Score`] values if each _individual_ [`Score`] is at or above the configured `threshold`.
+
+### Example
+
+```ignore
+Thinker::build()
+    .when(
+        AllOrNothing::build()
+          .push(MyScorer)
+          .push(MyOtherScorer),
+        MyAction::build());
+```
+ */
 #[derive(Debug)]
 pub struct AllOrNothing {
     threshold: f32,
@@ -100,7 +159,10 @@ pub struct AllOrNothingBuilder {
 }
 
 impl AllOrNothingBuilder {
-    pub fn when(&mut self, scorer: impl ScorerBuilder + 'static) -> &mut Self {
+    /**
+    Add another Scorer to this [`ScorerBuilder`].
+     */
+    pub fn push(&mut self, scorer: impl ScorerBuilder + 'static) -> &mut Self {
         self.scorers.push(Arc::new(scorer));
         self
     }
@@ -123,6 +185,20 @@ impl ScorerBuilder for AllOrNothingBuilder {
     }
 }
 
+/**
+Composite Scorer that takes any number of other Scorers and returns the sum of their [`Score`] values if the _total_ summed [`Score`] is at or above the configured `threshold`.
+
+### Example
+
+```ignore
+Thinker::build()
+    .when(
+        SumOfScorers::build()
+          .push(MyScorer)
+          .push(MyOtherScorer),
+        MyAction::build());
+```
+ */
 #[derive(Debug)]
 pub struct SumOfScorers {
     threshold: f32,
diff --git a/src/thinker.rs b/src/thinker.rs
index 45df9aa2f4f11d696283ffc4afd7ca33fc7f4a4e..84b0099d69e00a27d2bc2df181ff118e447b54c7 100644
--- a/src/thinker.rs
+++ b/src/thinker.rs
@@ -1,3 +1,7 @@
+/*!
+Thinkers are the "brain" of an entity. You attach Scorers to it, and the Thinker picks the right Action to run based on the resulting Scores.
+*/
+
 use std::{
     sync::Arc,
     time::{Duration, Instant},
@@ -12,15 +16,40 @@ use crate::{
     scorers::{Score, ScorerBuilder},
 };
 
+/**
+Wrapper for Actor entities. In terms of Scorers, Thinkers, and Actions, this is the [`Entity`] actually _performing_ the action, rather than the entity a Scorer/Thinker/Action is attached to. Generally, you will use this entity when writing Queries for Action and Scorer systems.
+ */
 #[derive(Debug, Clone, Copy)]
 pub struct Actor(pub Entity);
 
 #[derive(Debug, Clone, Copy)]
-pub struct ActionEnt(pub Entity);
+pub(crate) struct ActionEnt(pub Entity);
 
 #[derive(Debug, Clone, Copy)]
-pub struct ScorerEnt(pub Entity);
+pub(crate) struct ScorerEnt(pub Entity);
+
+/**
+The "brains" behind this whole operation. A `Thinker` is what glues together `Actions` and `Scorers` and shapes larger, intelligent-seeming systems.
+
+Note: Thinkers are also Actions, so anywhere you can pass in an Action (or [`ActionBuilder`]), you can pass in a Thinker (or [`ThinkerBuilder`]).
 
+### Example
+
+```no_run
+pub fn init_entities(mut cmd: Commands) {
+    cmd.spawn()
+        .insert(Thirst::new(70.0, 2.0))
+        .insert(Hunger::new(50.0, 3.0))
+        .insert(
+            Thinker::build()
+                .picker(FirstToScore::new(80.0))
+                .when(Thirsty::build(), Drink::build())
+                .when(Hungry::build(), Eat::build())
+                .otherwise(Meander::build()),
+        );
+}
+```
+ */
 #[derive(Debug)]
 pub struct Thinker {
     picker: Arc<dyn Picker>,
@@ -30,16 +59,22 @@ pub struct Thinker {
 }
 
 impl Thinker {
+    /**
+    Make a new [`ThinkerBuilder`]. This is what you'll actually use to configure Thinker behavior.
+     */
     pub fn build() -> ThinkerBuilder {
         ThinkerBuilder::new()
     }
 }
 
+/**
+This is what you actually use to configure Thinker behavior. It's a plain old [`ActionBuilder`], as well.
+ */
 #[derive(Debug, Default)]
 pub struct ThinkerBuilder {
-    pub picker: Option<Arc<dyn Picker>>,
-    pub otherwise: Option<ActionBuilderWrapper>, // Arc<dyn ActionBuilder>?
-    pub choices: Vec<ChoiceBuilder>,
+    picker: Option<Arc<dyn Picker>>,
+    otherwise: Option<ActionBuilderWrapper>,
+    choices: Vec<ChoiceBuilder>,
 }
 
 impl ThinkerBuilder {
@@ -51,11 +86,17 @@ impl ThinkerBuilder {
         }
     }
 
+    /**
+    Define a [`Picker`](crate::pickers::Picker) for this Thinker.
+     */
     pub fn picker(mut self, picker: impl Picker + 'static) -> Self {
         self.picker = Some(Arc::new(picker));
         self
     }
 
+    /**
+    Define an [`ActionBuilder`](crate::actions::ActionBuilder) and [`ScorerBuilder`](crate::scorers::ScorerBuilder) pair.
+     */
     pub fn when(
         mut self,
         scorer: impl ScorerBuilder + 'static,
@@ -66,6 +107,9 @@ impl ThinkerBuilder {
         self
     }
 
+    /**
+    Default `Action` to execute if the `Picker` did not pick any of the given choices.
+     */
     pub fn otherwise(mut self, otherwise: impl ActionBuilder + 'static) -> Self {
         self.otherwise = Some(ActionBuilderWrapper::new(Arc::new(otherwise)));
         self