diff --git a/src/pathways.jl b/src/pathways.jl
new file mode 100644
index 0000000000000000000000000000000000000000..e8ebbd092d5a78ce3724c8c1d6e7ef1343bf1896
--- /dev/null
+++ b/src/pathways.jl
@@ -0,0 +1,137 @@
+module Pathways
+import LinearAlgebra: norm
+import StaticArrays: SVector, SMatrix
+import ..Variables: qval, bval
+
+"""
+    PathWay(sequence::Sequence, pulse_effects::Vector{:Symbol/Number}, readout_index=1)
+
+Describes how a specific spin/isochromat might experience the sequence.
+
+Only a single pathway through the RF pulses is considered,
+so that at every point in time the spins are in one of the following four states:
+- +longitudinal: initial relaxed state
+- +transverse: excited state. During this time gradients will affect the [`area_under_curve`](@ref) (or [`qval`](@ref)) and [`bval`](@ref).
+- -longitudinal: inverse state
+- -transverse: inverse excited state. During this time all gradients will have the inverse effect compared with +transverse.
+
+The RF pulses cause mappings between these different states as described below.
+
+## Parameters
+- `sequence`: MRI [`Sequence`](@ref) to be considered.
+- `pulse_effects`: How each RF pulse affects the spins. This can be one of the following:
+    - `:skip`/`:ignore`/0: This RF pulse leaves the spins unaffected.
+    - `:refocus`/`:invert`/180: Flips the sign of the spin state (i.e., +longitudinal <-> -longitudinal, +transverse <-> -transverse)
+    - `:excite`/90: Takes spin state one step along the following sequence +longitudinal -> +transverse -> -longitudinal -> -transverse -> +longitudinal
+    - `:neg_excite`/270/-90: Inverse step compared with `:excite`.
+- `readout_index`: After encountering the number of pulses as defined in `pulse_effects`, continue the `PathWay` until the readout given by `index` is reached. If set to 0 the `PathWay` is terminated immediately after the last RF pulse.
+
+## Attributes
+Over the pathway the following values are computed. Each can be accessed by calling the appropriate function:
+
+### Timings
+- [`duration_state`](@ref): The total amount of time spent in a specific state in this pathway (+longitudinal, +transverse, -longitudinal, or -transverse)
+- [`duration_transverse`](@ref): The total amount of time the spins spent in the transverse plane in ms. This can be used to quantify the expected effect of T2-decay.
+- [`duration_dephase`](@ref): The total amount of time the spins spent in the +transverse relative to -transverse state in ms. The absolute value of this can be used to quantify the expected effect of T2'-decay.
+
+### Effect of gradients
+- [`qvec`](@ref): Net displacement vector in k-space/q-space.
+- [`qval`](@ref)/[`area_under_curve`](@ref): size of the displacement in k-space/q-space. For a spoiled pathway, this should be large compared with 1/voxel size; for unspoiled pathways it should be (close to) zero.
+- [`bmat`](@ref): Net diffusion weighting due to gradients along the [`PathWay`](@ref) in matrix form.
+- [`bval`](@ref): Net diffusion weighting due to gradients along the [`PathWay`](@ref) as a single number.
+"""
+struct PathWay
+    # user provided
+    sequence :: Sequence
+    pulse_effects :: Vector{Union{:Symbol, :Number}}
+    readout_index :: Integer
+
+    # computed
+    duration_states :: SVector{4, Float64}
+    qvec :: SVector{3, Float64}
+    bmat :: SMatrix{3, 3, Float64, 9}
+end
+
+"""
+    duration_state(pathway::PathWay, transverse::Bool, positive::Bool)
+
+Returns how long the [`PathWay`](@ref) spent in a specific state.
+
+The requested state can be set using `transverse` and `positive` as follows:
+- `transverse=false`, `positive=true`: +longitudinal
+- `transverse=true`, `positive=true`: +transverse
+- `transverse=false`, `positive=false`: -longitudinal
+- `transverse=true`, `positive=false`: -transverse
+"""
+function duration_state(pathway::PathWay, transverse, positive)
+    index = Dict([
+        (false, true) => 1,
+        (true, true) => 2,
+        (false, false) => 3,
+        (true, false) => 4,
+    ])[(Bool(transverse), Bool(positive))]
+    return pathway.duration_states[index]
+end
+
+"""
+    duration_transverse(pathway::PathWay)
+
+Returns the total amount of time that spins following the given [`PathWay`](@ref) spent in the transverse plane.
+This determines the amount of T2-weighting as ``e^{t/T_2}``, where ``t`` is the `duration_transverse`.
+
+Also see [`duration_dephase`](@ref) for T2'-weighting.
+"""
+function duration_transverse(pathway::Pathway)
+    return duration_state(pathway, true, true) + duration_state(pathway, true, false)
+end
+
+"""
+    duration_dephase(pathway::PathWay)
+
+Returns the net time that spins following the given [`PathWay`](@ref) spent in the +transverse versus the -transverse state.
+This determines the amount of T2'-weighting as ``e^{t/T_2'}``, where ``t`` is the `duration_dephase`.
+
+Also see [`duration_transverse`](@ref) for T2-weighting.
+"""
+function duration_dephase(pathway::Pathway)
+    return duration_state(pathway, true, true) - duration_state(pathway, true, false)
+end
+
+
+"""
+    qvec(pathway::PathWay)
+
+Return net displacement vector in k-space/q-space experienced by the spins following a specific [`PathWay`](@ref).
+
+Only gradients active while the spins are in the transverse plane are considered.
+"""
+qvec(pathway::PathWay) = pathway.qvec
+
+"""
+    qval(pathway::PathWay)
+
+Return net displacement in k-space/q-space experienced by the spins following a specific [`PathWay`](@ref).
+
+Only gradients active while the spins are in the transverse plane are considered.
+"""
+qval(pathway::PathWay) = norm(qvec(pathway))
+
+"""
+    bmat(pathway::PathWay)
+
+Return 3x3 diffusion-weighted matrix experienced by the spins following a specific [`PathWay`](@ref).
+
+Only gradients active while the spins are in the transverse plane are considered.
+"""
+bmat(pathway::PathWay) = pathway.bmat
+
+"""
+    bval(pathway::PathWay)
+
+Return size of diffusion-weighting experienced by the spins following a specific [`PathWay`](@ref).
+
+Only gradients active while the spins are in the transverse plane are considered.
+"""
+bval(pathway::PathWay) = norm(bmat(pathway))
+
+end
\ No newline at end of file