diff --git a/src/all_building_blocks/base_building_blocks.jl b/src/all_building_blocks/base_building_blocks.jl
index e6b75a8890f0aade116fe5e6a32a41490bb095f2..cd7d0137fb5c1a9c55b887fb2515e834ff9c92c8 100644
--- a/src/all_building_blocks/base_building_blocks.jl
+++ b/src/all_building_blocks/base_building_blocks.jl
@@ -15,8 +15,9 @@ Main interface:
 - [`qvec`](@ref) returns area under curve for (part of) the gradient waveform.
 
 Sub-types need to implement:
-- `Base.keys`: returns sequence of keys to all the components
-- `Base.getindex`: returns the actual component for each key
+- `Base.keys`: returns sequence of keys to all the components.
+- `Base.getindex`: returns the actual component for each key.
+- [`duration`](@ref): total duration of the building block.
 """
 abstract type BaseBuildingBlock <: ContainerBlock end
 
@@ -106,7 +107,7 @@ Gets the sequence of [`GradientWaveform`](@ref) from the event with key `first`
 Setting `first` to nothing indicates to start from the beginning of the `building_block`.
 Similarly, setting `last` to nothing indicates to continue till the end of the `building_block`.
 """
-function waveform_seqeuence(bb::BaseBuildingBlock, first, last)
+function waveform_sequence(bb::BaseBuildingBlock, first, last)
     started = isnothing(first)
     current_grad = current_start = nothing
     parts = GradientWaveform[]
diff --git a/src/all_building_blocks/building_blocks.jl b/src/all_building_blocks/building_blocks.jl
new file mode 100644
index 0000000000000000000000000000000000000000..75354d50beaa60358cbfd5899956fb4626820fc7
--- /dev/null
+++ b/src/all_building_blocks/building_blocks.jl
@@ -0,0 +1,75 @@
+module BuildingBlocks
+import LinearAlgebra: norm
+import ..BaseBuildingBlocks: BaseBuildingBlock, events, waveform_sequence
+import ...Variables: VariableType, duration, make_generic
+import ...Components: BaseComponent, DelayedEvent
+import ...Readouts: InstantReadout, ADC
+import ...Pulses: RFPulseBlock
+import ...Gradients: GradientBlock
+import ...BuildingBlocks: scanner_constraints!, make_generic
+
+"""
+    BuildingBlock(waveform, events; min_duration=nothing, orientation=nothing)
+
+Generic [`BaseBuildingBlock`](@ref) that can capture any overlapping gradients, RF pulses, and/or readouts.
+The gradients cannot contain any free variables.
+
+## Arguments
+- `waveform`: Sequence of 2-element tuples with (time, (Gx, Gy, Gz)). If `orientation` is set then the tuple is expected to look like (time, G). This cannot contain any free variables.
+- `events`: Sequence of 2-element tuples with (index, pulse/readout). The start time of the pulse/readout at the start of the gradient waveform element with index `index` (use [`DelayedEvent`](@ref) to make this earlier or later).
+- `duration`: duration of this `BuildingBlock`. If not set then it will be assumed to be the time of the last element in `waveform`.
+- `orientation`: orientation of the gradients in the waveform. If not set, then the full gradient vector should be given explicitly.
+"""
+struct BuildingBlock <: BaseBuildingBlock
+    parts :: Vector{<:BaseComponent}
+    function BuildingBlock(parts::AbstractVector{<:BaseComponent})
+        res = new(duration, parts)
+        for (_, part) in waveform_sequence(parts)
+            scanner_constraints!(part)
+        end
+        return res
+    end
+end
+
+function BuildingBlock(waveform::AbstractVector, events::AbstractVector; duration=nothing, orientation=nothing)
+    events = Any[events...]
+    waveform = Any[waveform...]
+    ndim = isnothing(orientat) ? 1 : 3
+    zero_grad = isnothing(orientation) ? zeros(3) : 0.
+    if length(waveform) == 0 || waveform[1][1] > 0.
+        pushfirst!(waveform, (0., zero_grad))
+        events = [(i+1, e) for (i, e) in events]
+    end
+
+    if isnothing(min_duration)
+        min_duration = waveform[end][1]
+    end
+    if !(min_duration ≈ waveform[end][1])
+        @assert min_duration > waveform[end][1]
+        push!(waveform, (min_duration, zero_grad))
+    end
+    components = BaseComponent[]
+    for (index_grad, ((prev_time, prev_grad), (time, grad))) in enumerate(zip(waveform[1:end-1], waveform[2:end]))
+        duration = time - prev_time
+        if norm(prev_grad) <= 1e-12 && norm(grad) <= 1e-12
+            push!(components, NoGradientBlock{ndim}(duration))
+        elseif norm(prev_grad) ≈ norm(grad)
+            push!(components, ConstantGradientBlock(prev_grad, duration))
+        else
+            push!(components, ChangingGradientBlock(prev_grad, (grad .- prev_grad) ./ duration, duration))
+        end
+        while length(events) > 0 && index_grad == events[1][1]
+            (_, event) = popfirst!(events)
+            push!(components, event)
+        end
+    end
+    return components
+end
+
+make_generic(other_block::BaseBuildingBlock) = BuildingBlock(duration(other_block), [other_block...])
+Base.keys(bb::BuildingBlock) = 1:length(bb.parts)
+Base.getindex(bb::BuildingBlock, i::Integer) = bb.parts[i]
+
+duration(go::BuildingBlock) = go.duration
+
+end
\ No newline at end of file
diff --git a/src/overlapping/generic.jl b/src/overlapping/generic.jl
deleted file mode 100644
index 27bba0e856665015d8ecbcbc67a41772f528a4f7..0000000000000000000000000000000000000000
--- a/src/overlapping/generic.jl
+++ /dev/null
@@ -1,46 +0,0 @@
-module Generic
-import ..Abstract: AbstractOverlapping, interruptions, duration, waveform_sequence
-import ...Variables: VariableType, duration
-import ...Wait: WaitBlock
-import ...Readouts: InstantReadout, ADC
-import ...Pulses: RFPulseBlock
-import ...Gradients: GradientBlock
-import ...BuildingBlocks: scanner_constraints!, make_generic
-
-"""
-    GenericWaveform(duration, waveform, interruptions)
-
-Generic description that can capture any overlapping gradients, RF pulses, and/or readouts.
-
-Interruptions are stores as tuples with 3 fields:
-- `index`: which part of the `waveform` is being interrupted (cannot be a free variable).
-- `time`: time of the interruption relative to the start of the `waveform` part (between 0 and the length of this part). This can be a variable.
-- `block`: [`RFPulseBlock`](@ref) or [`InstantReadout`](@ref)
-"""
-struct GenericOverlapping <: AbstractOverlapping
-    duration :: VariableType
-    waveform :: Vector{Union{WaitBlock, GradientBlock}}
-    interruptions :: Vector{NamedTuple{(:index, :time, :object), Tuple{Int64, <:VariableType, <:Union{RFPulseBlock, InstantReadout, ADC}}}}
-    function GenericOverlapping(duration::VariableType, waveform::AbstractVector, interruptions::AbstractVector=[])
-        res = new(duration, waveform, interruptions)
-        scanner_constraints!.(waveform)
-        return res
-    end
-end
-
-
-GenericOverlapping(other_waveform::AbstractOverlapping) = GenericOverlapping(duration(other_waveform), waveform_sequence(other_waveform), interruptions(other_waveform))
-
-make_generic(ao::AbstractOverlapping) = GenericOverlapping(
-    duration(ao), 
-    waveform_sequence(ao), 
-    [(index=i.index, time=i.time, object=make_generic(i.object)) for i in interruptions(ao)]
-)
-
-waveform_sequence(go::GenericOverlapping) = go.waveform
-interruptions(go::GenericOverlapping) = go.interruptions
-duration(go::GenericOverlapping) = go.duration
-
-make_generic(wait::WaitBlock) = GenericOverlapping(duration(wait), [], [])
-
-end
\ No newline at end of file