diff --git a/core/modules/gridbuilder/config/grid.ninesixty_12.yml b/core/modules/gridbuilder/config/grid.ninesixty_12.yml
new file mode 100644
index 0000000..5299ec8
--- /dev/null
+++ b/core/modules/gridbuilder/config/grid.ninesixty_12.yml
@@ -0,0 +1,7 @@
+id: ninesixty_12
+label: '960px wide, 12 column grid'
+type: 0
+width: 960
+columns: 12
+padding_width: 20
+gutter_width: 10
diff --git a/core/modules/gridbuilder/config/grid.ninesixty_16.yml b/core/modules/gridbuilder/config/grid.ninesixty_16.yml
new file mode 100644
index 0000000..bbe86be
--- /dev/null
+++ b/core/modules/gridbuilder/config/grid.ninesixty_16.yml
@@ -0,0 +1,7 @@
+id: ninesixty_16
+label: '960px wide, 16 column grid'
+type: 0
+width: 960
+columns: 16
+padding_width: 20
+gutter_width: 10
diff --git a/core/modules/gridbuilder/config/grid.six_column_fluid.yml b/core/modules/gridbuilder/config/grid.six_column_fluid.yml
new file mode 100644
index 0000000..106c7e2
--- /dev/null
+++ b/core/modules/gridbuilder/config/grid.six_column_fluid.yml
@@ -0,0 +1,9 @@
+id: six_column_fluid
+label: Six column fluid
+type: 1
+width: 100
+columns: 6
+padding_width: 1.5
+gutter_width: 2
+breakpoints:
+  - 'module.gridbuilder.tablet'
diff --git a/core/modules/gridbuilder/config/grid.three_column_fluid.yml b/core/modules/gridbuilder/config/grid.three_column_fluid.yml
new file mode 100644
index 0000000..6b1a5c4
--- /dev/null
+++ b/core/modules/gridbuilder/config/grid.three_column_fluid.yml
@@ -0,0 +1,9 @@
+id: three_column_fluid
+label: Three column fluid
+type: 1
+width: 100
+columns: 3
+padding_width: 1.5
+gutter_width: 2
+breakpoints:
+  - 'module.gridbuilder.smartphone'
diff --git a/core/modules/gridbuilder/config/grid.twelve_column_fluid.yml b/core/modules/gridbuilder/config/grid.twelve_column_fluid.yml
new file mode 100644
index 0000000..348246a
--- /dev/null
+++ b/core/modules/gridbuilder/config/grid.twelve_column_fluid.yml
@@ -0,0 +1,9 @@
+id: twelve_column_fluid
+label: Twelve column fluid
+type: 1
+width: 100
+columns: 12
+padding_width: 1.5
+gutter_width: 2
+breakpoints:
+  - 'module.gridbuilder.standard'
diff --git a/core/modules/gridbuilder/config/gridbuilder.breakpoints.yml b/core/modules/gridbuilder/config/gridbuilder.breakpoints.yml
new file mode 100644
index 0000000..d8f354c
--- /dev/null
+++ b/core/modules/gridbuilder/config/gridbuilder.breakpoints.yml
@@ -0,0 +1,3 @@
+smartphone: '(min-width: 0px)'
+tablet: 'all and (min-width: 321px) and (max-width: 760px)'
+standard: 'all and (min-width: 761px)'
diff --git a/core/modules/gridbuilder/gridbuilder-admin.css b/core/modules/gridbuilder/gridbuilder-admin.css
new file mode 100644
index 0000000..30229f8
--- /dev/null
+++ b/core/modules/gridbuilder/gridbuilder-admin.css
@@ -0,0 +1,32 @@
+#grid-form {
+  width: 350px;
+  border-right: 1px solid #ADADAD;
+  padding: 0.5em;
+  float: left;
+  margin-right: -400px;
+}
+#griddemonstrator {
+  float: left;
+  height: 300px;
+  margin-left: 400px;
+}
+#griddemonstrator .col {
+  float: left;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  -moz-background-clip: padding-box !important;
+  -webkit-background-clip: padding-box !important;
+  background-clip: padding-box !important;
+  height: 300px;
+  background-color: #C5D6DB;
+}
+#griddemonstrator .col .inner {
+  background-color: #4B6E78;
+  width: 100%;
+  height: 100%;
+  display: block;
+}
+#griddemonstrator .col.first {
+  margin-left: 0;
+}
diff --git a/core/modules/gridbuilder/gridbuilder-admin.js b/core/modules/gridbuilder/gridbuilder-admin.js
new file mode 100644
index 0000000..b37e67c
--- /dev/null
+++ b/core/modules/gridbuilder/gridbuilder-admin.js
@@ -0,0 +1,119 @@
+(function ($) {
+
+Drupal.behaviors.gridBuilder = {
+  attach: function(context) {
+    // Initialize responsive layout editor.
+    Drupal.gridBuilder.init();
+  }
+}
+
+Drupal.gridBuilder = Drupal.gridBuilder || {};
+
+/**
+ * Initialize gridbuilder behavior.
+ */
+Drupal.gridBuilder.init = function() {
+  // Set up container for grid demonstration.
+  $('form').parent().append('<div id="griddemonstrator"></div>');
+  $('input[name="type"]').change(Drupal.gridBuilder.typeChange);
+
+  Drupal.gridBuilder.gridType = $('input[name="type"]:checked').val() == 1 ? '%' : 'px';
+  if (Drupal.gridBuilder.gridType == '%') {
+    // Fake a sensible previous value for fixed grid.
+    Drupal.gridBuilder.prevValue = {
+      'fullWidth': '960',
+      'columns': '12',
+      'paddingWidth': '20',
+      'gutterWidth': '10',
+    };
+  }
+  else {
+    // Fake a sensible previous value for fluid grid.
+    Drupal.gridBuilder.prevValue = {
+      'fullWidth': '100',
+      'columns': '12',
+      'paddingWidth': '1.5',
+      'gutterWidth': '2',
+    };
+  }
+
+  // When any of the parameter values change, rebuild the demo.
+  $('#edit-width').change(Drupal.gridBuilder.reBuildDemonstration);
+  $('#edit-columns').change(Drupal.gridBuilder.reBuildDemonstration);
+  $('#edit-padding-width').change(Drupal.gridBuilder.reBuildDemonstration);
+  $('#edit-gutter-width').change(Drupal.gridBuilder.reBuildDemonstration);
+
+  // Build the initial version of the demo.
+  Drupal.gridBuilder.reBuildDemonstration();
+}
+
+/**
+ * React to grid type changes.
+ */
+Drupal.gridBuilder.typeChange = function(event) {
+  // Remember previous value, and restore the earlier value for this size.
+  var prevValue = {
+    'fullWidth': $('#edit-width').val(),
+    'columns': $('#edit-columns').val(),
+    'paddingWidth': $('#edit-padding-width').val(),
+    'gutterWidth': $('#edit-gutter-width').val(),
+  };
+  $('#edit-width').val(Drupal.gridBuilder.prevValue.fullWidth);
+  $('#edit-columns').val(Drupal.gridBuilder.prevValue.columns);
+  $('#edit-padding-width').val(Drupal.gridBuilder.prevValue.paddingWidth);
+  $('#edit-gutter-width').val(Drupal.gridBuilder.prevValue.gutterWidth);
+  Drupal.gridBuilder.prevValue = prevValue;
+
+  var newVal = 'px';
+  if ($(this).val() == 1) {
+    // User selected fluid layout, switch to % based sizes.
+    newVal = '%';
+  }
+  Drupal.gridBuilder.gridType = newVal;
+
+  // Switch the suffix helper field to proper value.
+  $('.form-item-width .field-suffix, .form-item-padding-width .field-suffix, .form-item-gutter-width .field-suffix').html(newVal);
+
+  // Rebuild our demonstration grid.
+  Drupal.gridBuilder.reBuildDemonstration();
+}
+
+Drupal.gridBuilder.reBuildDemonstration = function() {
+  // Retrieve all numeric values. All of them should be ints.
+  var width = '100';
+  if (Drupal.gridBuilder.gridType == 'px') {
+    var width = parseInt($('#edit-width').val());
+  }
+  var columns = parseInt($('#edit-columns').val());
+  var paddingWidth = parseInt($('#edit-padding-width').val());
+  var gutterWidth = parseInt($('#edit-gutter-width').val());
+
+  // Compute column widths.
+  var coloumnWidth = (width - ((columns - 1) * gutterWidth)) / columns;
+  var innerWidth = coloumnWidth - (paddingWidth * 2);
+
+  // Add CSS style generated for this setup.
+  var columnHTML =
+    '<style type="text/css"> #griddemonstrator .col { ' +
+    'width: ' + coloumnWidth + Drupal.gridBuilder.gridType + '; '+
+    'margin-left: ' + gutterWidth + Drupal.gridBuilder.gridType + '; ' +
+    'padding: 0 ' + paddingWidth + Drupal.gridBuilder.gridType + '; } ';
+
+  if (Drupal.gridBuilder.gridType == '%') {
+    // Use 960px as a sensible demonstration method for the fluid grid.
+    width = '960px';
+  }
+  else {
+    width += Drupal.gridBuilder.gridType;
+  }
+  columnHTML += '#griddemonstrator { width: ' + width + '; } </style>';
+
+  // Add number of columns as needed.
+  for (var i = 0; i < columns; i++) {
+    columnHTML += '<div class="col' + (i == 0 ? ' first' : '') + '"><div class="inner"></div></div>';
+  }
+
+  $('#griddemonstrator').html(columnHTML);
+}
+
+})(jQuery);
diff --git a/core/modules/gridbuilder/gridbuilder.admin.inc b/core/modules/gridbuilder/gridbuilder.admin.inc
new file mode 100644
index 0000000..78f1aad
--- /dev/null
+++ b/core/modules/gridbuilder/gridbuilder.admin.inc
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Administration functions to maintain a common set of grids for layouts.
+ */
+
+use Drupal\gridbuilder\Grid;
+
+/**
+ * Page callback: Presents list of grids.
+ *
+ * @see gridbuilder_menu()
+ */
+function gridbuilder_page_list() {
+  $controller = entity_list_controller('grid');
+  return $controller->render();
+}
+
+/**
+ * Page callback: Presents the grid editing form.
+ *
+ * @see gridbuilder_menu()
+ */
+function gridbuilder_page_edit(Grid $grid) {
+  drupal_set_title(t('<em>Edit grid</em> @label', array('@label' => $grid->label())), PASS_THROUGH);
+  return entity_get_form($grid);
+}
+
+/**
+ * Page callback: Provides the new grid addition form.
+ *
+ * @see gridbuilder_menu()
+ */
+function gridbuilder_page_add() {
+  $grid = entity_create('grid', array());
+  return entity_get_form($grid);
+}
+
+/**
+ * Page callback: Form constructor for grid deletion confirmation form.
+ *
+ * @see gridbuilder_menu()
+ */
+function gridbuilder_delete_confirm($form, &$form_state, Grid $grid) {
+  // Always provide entity id in the same form key as in the entity edit form.
+  $form['id'] = array('#type' => 'value', '#value' => $grid->id());
+  $form_state['grid'] = $grid;
+  return confirm_form($form,
+    t('Are you sure you want to remove the grid %title?', array('%title' => $grid->label())),
+    'admin/structure/grids',
+    t('This action cannot be undone.'),
+    t('Delete'),
+    t('Cancel')
+  );
+}
+
+/**
+ * Form submission handler for gridbuilder_delete_confirm().
+ */
+function gridbuilder_delete_confirm_submit($form, &$form_state) {
+  $grid = $form_state['grid'];
+  $grid->delete();
+  drupal_set_message(t('Grid %label has been deleted.', array('%label' => $grid->label())));
+  watchdog('gridbuilder', 'Grid %label has been deleted.', array('%label' => $grid->label()), WATCHDOG_NOTICE);
+  $form_state['redirect'] = 'admin/structure/grids';
+}
diff --git a/core/modules/gridbuilder/gridbuilder.info b/core/modules/gridbuilder/gridbuilder.info
new file mode 100644
index 0000000..43d5f2f
--- /dev/null
+++ b/core/modules/gridbuilder/gridbuilder.info
@@ -0,0 +1,9 @@
+name = Grid builder
+description = Simple grid system builder.
+package = Core
+version = VERSION
+core = 8.x
+dependencies[] = config
+dependencies[] = breakpoint
+configure = admin/structure/grids
+
diff --git a/core/modules/gridbuilder/gridbuilder.module b/core/modules/gridbuilder/gridbuilder.module
new file mode 100644
index 0000000..1c85848
--- /dev/null
+++ b/core/modules/gridbuilder/gridbuilder.module
@@ -0,0 +1,242 @@
+<?php
+
+/**
+ * @file
+ * Simple grid builder tool.
+ */
+
+use Drupal\gridbuilder\Grid;
+
+/**
+ * Fixed width grid.
+ */
+const GRIDBUILDER_FIXED = 0;
+
+/**
+ * Fluid width grid.
+ */
+const GRIDBUILDER_FLUID = 1;
+
+/**
+ * Implements hook_menu().
+ */
+function gridbuilder_menu() {
+  $items = array();
+  $items['admin/structure/grids'] = array(
+    'title' => 'Grids',
+    'description' => 'Manage list of grids which can be used with layouts.',
+    'page callback' => 'gridbuilder_page_list',
+    'access callback' => 'user_access',
+    'access arguments' => array('administer gridbuilder'),
+    'file' => 'gridbuilder.admin.inc',
+  );
+  $items['admin/structure/grids/add'] = array(
+    'title' => 'Add grid',
+    'page callback' => 'gridbuilder_page_add',
+    'access callback' => 'user_access',
+    'access arguments' => array('administer gridbuilder'),
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'gridbuilder.admin.inc',
+  );
+  $items['admin/structure/grids/grid/%gridbuilder/edit'] = array(
+    'title' => 'Edit grid',
+    'page callback' => 'gridbuilder_page_edit',
+    'page arguments' => array(4),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer gridbuilder'),
+    'type' => MENU_CALLBACK,
+    'file' => 'gridbuilder.admin.inc',
+  );
+  $items['admin/structure/grids/grid/%gridbuilder/delete'] = array(
+    'title' => 'Delete',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('gridbuilder_delete_confirm', 4),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer gridbuilder'),
+    'type' => MENU_CALLBACK,
+    'file' => 'gridbuilder.admin.inc',
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_permission().
+ */
+function gridbuilder_permission() {
+  return array(
+    'administer gridbuilder' => array(
+      'title' => t('Administer grid builder grids'),
+      'description' => t('Administer grids created with the grid builder.'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_entity_info().
+ */
+function gridbuilder_entity_info() {
+  $types['grid'] = array(
+    'label' => 'Grid',
+    'entity class' => 'Drupal\gridbuilder\Grid',
+    'controller class' => 'Drupal\Core\Config\Entity\ConfigStorageController',
+    'form controller class' => array(
+      'default' => 'Drupal\gridbuilder\GridFormController',
+    ),
+    'list controller class' => 'Drupal\Core\Config\Entity\ConfigEntityListController',
+    'list path' => 'admin/structure/grids',
+    'uri callback' => 'gridbuilder_uri',
+    'config prefix' => 'grid',
+    'entity keys' => array(
+      'id' => 'id',
+      'label' => 'label',
+      'uuid' => 'uuid',
+    ),
+  );
+  return $types;
+}
+
+/**
+ * Entity URI callback.
+ *
+ * @param Drupal\gridbuilder\Grid $grid
+ *   Grid configuration entity instance.
+ *
+ * @return array
+ *   Entity URI information.
+ */
+function gridbuilder_uri(Grid $grid) {
+  return array(
+    'path' => 'admin/structure/grids/grid/' . $grid->id(),
+  );
+}
+
+/**
+ * Look up one grid setup based on machine name.
+ *
+ * @return Drupal\gridbuilder\Grid
+ *   Grid configuration entity instance.
+ */
+function gridbuilder_load($id) {
+  return entity_load('grid', $id);
+}
+
+/**
+ * API function to get all grids on the site.
+ *
+ * @return array
+ *   List of Drupal\gridbuilder\Grid instances keyed by id.
+ */
+function gridbuilder_load_all() {
+  return entity_load_multiple('grid');
+}
+
+/**
+ * Return generated CSS for a given grid.
+ *
+ * @param (string) $name
+ *   Machine name of the grid.
+ * @param (string) $wrapper_selector
+ *   (optional) Wrapper CSS selector to use to scope the CSS.
+ * @param (string) $span_selector_prefix
+ *   (optional) Column span selector prefix to scope the CSS.
+ * @param (boolean) $skip_spacing
+ *    Whether we should skip including spacing in the output. Useful for tight
+ *    layout demonstration presentation.
+ *
+ * @return
+ *   Fully assembled CSS string.
+ */
+function gridbuilder_get_css($name, $wrapper_selector = NULL, $span_selector_prefix = NULL, $skip_spacing = FALSE) {
+  // First attempt to let other modules provide CSS for this grid. If users are
+  // not happy with the CSS generated here, they can provide their own and skip
+  // our CSS generation.
+  $css = module_invoke_all('gridbuilder_get_css', $name);
+  if (!empty($css)) {
+    return join('', $css);
+  }
+
+  $grid = gridbuilder_load($name);
+  $css = '';
+
+  // If the wrapper selector was not provided, generate one. This is useful for
+  // specific administration use cases when we scope the classes by grids.
+  if (empty($wrapper_selector)) {
+    $wrapper_selector = '.rld-container-' . $grid->id();
+  }
+
+  // If the span selector was not provided, generate one. This is useful for
+  // the front end to apply varying span widths under different names.
+  if (empty($span_selector_prefix)) {
+    $span_selector_prefix = '.rld-span_';
+  }
+
+  // If spacing is to be skipped, override the gutter and padding temporarily.
+  if ($skip_spacing) {
+    $grid->gutter_width = $grid->padding_width = 0;
+  }
+
+  switch ($grid->type) {
+    case GRIDBUILDER_FLUID:
+      $size_suffix = '%';
+      // Override to 100% whatever it was.
+      $grid->width = '100';
+      break;
+    case GRIDBUILDER_FIXED:
+      $size_suffix = 'px';
+      break;
+  }
+
+
+  // Because we use the border-box box model, we only need to substract the
+  // size of margins from the full width and divide the rest by number of
+  // columns to get a value for column size.
+  $colwidth = ($grid->width - (($grid->columns - 1) * $grid->gutter_width)) / $grid->columns;
+
+  $css = $wrapper_selector . ' .rld-col {
+  border: 0px solid rgba(0,0,0,0);
+  float: left;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  -moz-background-clip: padding-box !important;
+  -webkit-background-clip: padding-box !important;
+  background-clip: padding-box !important;
+  margin-left: ' . $grid->gutter_width . $size_suffix . ';
+  padding: 0 ' . $grid->padding_width  . $size_suffix . ';
+}
+' . $wrapper_selector . ' .rld-col' . $span_selector_prefix .'first {
+  margin-left: 0;
+  clear: both;
+}
+';
+  for ($i = 1; $i <= $grid->columns; $i++) {
+    $css .= $wrapper_selector . ' ' . $span_selector_prefix . $i . " {\n";
+    if ($i == 1) {
+      // The first column does not yet have any margins.
+      $css .= '  width: ' . $colwidth * $i . $size_suffix . ";\n";
+    }
+    elseif ($i == $grid->columns) {
+      // The full width column always spans 100%.
+      $css .= "  width: " . $grid->width . $size_suffix . ";\n  margin-left: 0;\n";
+    }
+    else {
+      // Other columns absorb all columns that they need to include and one
+      // less margin before them.
+      $css .= '  width: ' . (($colwidth * $i) + ($grid->gutter_width * ($i -1))) . $size_suffix . ";\n";
+    }
+    $css .= "}\n";
+  }
+
+  return $css;
+}
+
+/**
+ * Get the grid plugin manager instance.
+ *
+ * @return Drupal\layout\Plugin\Type\GridBuilderManager
+ *   The grid plugin manager instance.
+ */
+function gridbuilder_manager() {
+  return drupal_container()->get('plugin.manager.gridbuilder');
+}
+
diff --git a/core/modules/gridbuilder/lib/Drupal/gridbuilder/Grid.php b/core/modules/gridbuilder/lib/Drupal/gridbuilder/Grid.php
new file mode 100644
index 0000000..ebfe963
--- /dev/null
+++ b/core/modules/gridbuilder/lib/Drupal/gridbuilder/Grid.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\gridbuilder\Grid.
+ */
+
+namespace Drupal\gridbuilder;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+
+/**
+ * Defines the grid entity.
+ */
+class Grid extends ConfigEntityBase {
+
+  /**
+   * The grid ID (machine name).
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The grid UUID.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The grid label.
+   *
+   * @var string
+   */
+  public $label;
+
+  /**
+   * The grid type: whether the grid is fixed (0) or fluid (1).
+   *
+   * @var int
+   */
+  public $type;
+
+  /**
+   * Width of grid in pixels (or 100 for fluid grids).
+   *
+   * @var int
+   */
+  public $width;
+
+  /**
+   * Number of columns in this grid.
+   *
+   * @var int
+   */
+  public $columns;
+
+  /**
+   * Column padding value. Understood in pixels for fixed grids (eg. 10) or as percentage for fluid grids (eg. 1.5).
+   *
+   * @var int
+   */
+  public $padding_width;
+
+  /**
+   * Gutter width value. Understood in pixels for fixed grids (eg. 20) or as percentage for fluid grids (eg. 2).
+   *
+   * @var int
+   */
+  public $gutter_width;
+
+  /**
+   * List of breakpoint machine names that this grid will apply to.
+   *
+   * @var array
+   */
+  public $breakpoints;
+
+}
diff --git a/core/modules/gridbuilder/lib/Drupal/gridbuilder/GridBuilderBundle.php b/core/modules/gridbuilder/lib/Drupal/gridbuilder/GridBuilderBundle.php
new file mode 100644
index 0000000..2528ae9
--- /dev/null
+++ b/core/modules/gridbuilder/lib/Drupal/gridbuilder/GridBuilderBundle.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\gridbuilder\GridBuilderBundle.
+ */
+
+namespace Drupal\gridbuilder;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * GridBuilder dependency injection container.
+ */
+class GridBuilderBundle extends Bundle {
+
+  /**
+   * Overrides Symfony\Component\HttpKernel\Bundle\Bundle::build().
+   */
+  public function build(ContainerBuilder $container) {
+    // Register the GridBuilderManager class with the dependency injection container.
+    $container->register('plugin.manager.gridbuilder', 'Drupal\gridbuilder\Plugin\Type\GridBuilderManager');
+  }
+}
diff --git a/core/modules/gridbuilder/lib/Drupal/gridbuilder/GridFormController.php b/core/modules/gridbuilder/lib/Drupal/gridbuilder/GridFormController.php
new file mode 100644
index 0000000..d092874
--- /dev/null
+++ b/core/modules/gridbuilder/lib/Drupal/gridbuilder/GridFormController.php
@@ -0,0 +1,173 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\gridbuilder\GridFormController.
+ */
+
+namespace Drupal\gridbuilder;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityFormController;
+
+/**
+ * Form controller for the grid edit/add forms.
+ */
+class GridFormController extends EntityFormController {
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::prepareEntity().
+   *
+   * Prepares the grid object filling in a few default values.
+   */
+  protected function prepareEntity(EntityInterface $grid) {
+    if (empty($grid->width)) {
+      // Set some defaults for the user if this is a new grid.
+      $grid->type = GRIDBUILDER_FLUID;
+      $grid->width = 100;
+      $grid->columns = 12;
+      $grid->padding_width = 1.5;
+      $grid->gutter_width = 2;
+    }
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state, EntityInterface $grid) {
+    $form['label'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Label'),
+      '#maxlength' => 255,
+      '#default_value' => $grid->label(),
+      '#required' => TRUE,
+    );
+    $form['id'] = array(
+      '#type' => 'machine_name',
+      '#default_value' => $grid->id(),
+      '#machine_name' => array(
+        'exists' => 'gridbuilder_load',
+        'source' => array('label'),
+      ),
+      '#disabled' => !$grid->isNew(),
+    );
+
+    // Master grid configuration.
+    $form['type'] = array(
+      '#type' => 'radios',
+      '#title' => t('Type of grid'),
+      '#options' => array(GRIDBUILDER_FLUID => t('Fluid'), GRIDBUILDER_FIXED => t('Fixed to specific width')),
+      '#default_value' => $grid->type,
+    );
+    $form['width'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Grid width'),
+      '#description' => t('Only meaningful if using a fixed grid. Enter a pixel size (eg. 960).'),
+      '#default_value' => $grid->width,
+      '#states' => array(
+        'visible' => array('input[name="type"]' => array('value' => GRIDBUILDER_FIXED)),
+      ),
+      '#field_suffix' => $grid->type == GRIDBUILDER_FIXED ? 'px' : '%',
+    );
+
+    // Grid detail configuration.
+    $form['columns'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Number of grid columns'),
+      '#default_value' => $grid->columns,
+    );
+    $form['padding_width'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Column padding'),
+      '#description' => t('Column padding in pixels (for fixed grids, eg. 10) or percentages (for fluid grids, eg. 1.5). Enter 0 for no padding.'),
+      '#default_value' => $grid->padding_width,
+      '#field_suffix' => $grid->type == GRIDBUILDER_FIXED ? 'px' : '%',
+    );
+
+    $form['gutter_width'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Gutter width'),
+      '#description' => t('Gutter width in pixels (for fixed grids, eg. 20) or percentages (for fluid grids, eg. 2). Enter 0 for no gutter.'),
+      '#default_value' => $grid->gutter_width,
+      '#field_suffix' => $grid->type == GRIDBUILDER_FIXED ? 'px' : '%',
+    );
+
+    $grid_breakpoints = entity_load('breakpoint_group', 'module.gridbuilder.gridbuilder');
+    $breakpoint_options = array();
+    foreach ($grid_breakpoints->breakpoints as $key => $breakpoint) {
+      $breakpoint_options[$key] = $breakpoint->label();
+    }
+    $form['breakpoints'] = array(
+      '#title' => t('Breakpoints where this grid will apply'),
+      '#type' => 'checkboxes',
+      '#options' => $breakpoint_options,
+      '#default_value' => (array) $grid->breakpoints,
+    );
+
+    $form['#attached']['css'][] = drupal_get_path('module', 'gridbuilder') . '/gridbuilder-admin.css';
+    $form['#attached']['js'][] = drupal_get_path('module', 'gridbuilder') . '/gridbuilder-admin.js';
+
+    return parent::form($form, $form_state, $grid);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::validate().
+   */
+  public function validate(array $form, array &$form_state) {
+    // Force width to 100 if fluid width. That is in percentages.
+    if ($form_state['values']['type'] == GRIDBUILDER_FLUID) {
+      $form_state['values']['width'] = 100;
+    }
+
+    if ((intval($form_state['values']['width']) != $form_state['values']['width']) || $form_state['values']['width'] == 0) {
+      // Width should be a positive integer.
+      form_set_error('columns', t('The width should be a positive number.'));
+    }
+    if ((intval($form_state['values']['columns']) != $form_state['values']['columns']) || $form_state['values']['columns'] == 0) {
+      // Columns should be a positive integer.
+      form_set_error('columns', t('The number of columns should be a positive number.'));
+    }
+    if (!is_numeric($form_state['values']['padding_width'])) {
+      // Padding can be float as well (eg. 1.5 for 1.5% for fluid grids).
+      form_set_error('padding_width', t('The column padding should be a number. Enter 0 (zero) for no padding.' . $form_state['values']['padding_width']));
+    }
+    if (!is_numeric($form_state['values']['gutter_width'])) {
+      // Gutter can be float too (eg. 1.5 for 1.5% for fluid grids).
+      form_set_error('gutter_width', t('The gutter width should be a number. Enter 0 (zero) for no gutter.'));
+    }
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::actions().
+   */
+  protected function actions(array $form, array &$form_state) {
+    // Only includes a Save action for the entity, no direct Delete button.
+    return array(
+      'submit' => array(
+        '#value' => t('Save'),
+        '#validate' => array(
+          array($this, 'validate'),
+        ),
+        '#submit' => array(
+          array($this, 'submit'),
+          array($this, 'save'),
+        ),
+      ),
+    );
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::save().
+   */
+  public function save(array $form, array &$form_state) {
+    $grid = $this->getEntity($form_state);
+    $grid->save();
+
+    watchdog('gridbuilder', 'Grid @label saved.', array('@label' => $grid->label()), WATCHDOG_NOTICE);
+    drupal_set_message(t('Grid %label saved.', array('%label' => $grid->label())));
+
+    $form_state['redirect'] = 'admin/structure/grids';
+  }
+
+}
+
diff --git a/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/Derivative/GridBuilder.php b/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/Derivative/GridBuilder.php
new file mode 100644
index 0000000..e5187d1
--- /dev/null
+++ b/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/Derivative/GridBuilder.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\gridbuilder\Plugin\Derivative\GridBuilder.
+ */
+
+namespace Drupal\gridbuilder\Plugin\Derivative;
+
+use Drupal\Component\Plugin\Derivative\DerivativeInterface;
+
+/**
+ * GridBuilder plugin derivative definition.
+ */
+class GridBuilder implements DerivativeInterface {
+
+  /**
+   * List of derivatives.
+   *
+   * Associative array keyed by grid config key name. The values of the array are
+   * associative arrays themselves with metadata about the grid.
+   *
+   * @var array
+   */
+  protected $derivatives = array();
+
+  /**
+   * Implements DerivativeInterface::getDerivativeDefinition().
+   */
+  public function getDerivativeDefinition($derivative_id, array $base_plugin_definition) {
+    if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
+      return $this->derivatives[$derivative_id];
+    }
+    $this->getDerivativeDefinitions($base_plugin_definition);
+    return $this->derivatives[$derivative_id];
+  }
+
+  /**
+   * Implements DerivativeInterface::getDerivativeDefinitions().
+   */
+  public function getDerivativeDefinitions(array $base_plugin_definition) {
+    // Use module_invoke() because plugins are active even if the module is not
+    // enabled.
+    $this->derivatives = array();
+    $grids = module_invoke('gridbuilder', 'load_all');
+    if (!empty($grids)) {
+      foreach ($grids as $key => $grid) {
+        $this->derivatives[$key] = array(
+          'grid' => $grid,
+          'class' => 'Drupal\gridbuilder\Plugin\gridbuilder\gridbuilder\EqualColumnGrid',
+        );
+      }
+    }
+    return $this->derivatives;
+  }
+
+}
diff --git a/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/GridBuilderInterface.php b/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/GridBuilderInterface.php
new file mode 100644
index 0000000..cbde3af
--- /dev/null
+++ b/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/GridBuilderInterface.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\gridbuilder\Plugin\GridBuilderInterface.
+ */
+
+namespace Drupal\gridbuilder\Plugin;
+
+/**
+ * Defines the shared interface for all gridbuilder plugins.
+ */
+interface GridBuilderInterface {
+
+  /**
+   * Generates grid CSS for this grid system.
+   *
+   * @param (string) $wrapper_selector
+   *   (optional) Wrapper CSS selector to use to scope the CSS.
+   * @param (string) $col_selector_prefix
+   *   (optional) Column selector prefix to scope the CSS.
+   * @param (boolean) $skip_spacing
+   *    Whether we should skip including spacing in the output. Useful for tight
+   *    layout demonstration presentation.
+   *
+   * @return string
+   *   Grid CSS for this grid system.
+   */
+  public function getGridCss($wrapper_selector = NULL, $col_selector_prefix = NULL, $skip_spacing = FALSE);
+}
diff --git a/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/Type/GridBuilderManager.php b/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/Type/GridBuilderManager.php
new file mode 100644
index 0000000..d85a149
--- /dev/null
+++ b/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/Type/GridBuilderManager.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\gridbuilder\Plugin\Type\GridBuilderManager.
+ */
+
+namespace Drupal\gridbuilder\Plugin\Type;
+
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Component\Plugin\Factory\ReflectionFactory;
+
+/**
+ * GridBuilder plugin manager.
+ */
+class GridBuilderManager extends PluginManagerBase {
+
+  protected $defaults = array(
+    'class' => 'Drupal\gridbuilder\Plugin\gridbuilder\gridbuilder\EqualColumnGrid',
+  );
+
+  /**
+   * Overrides Drupal\Component\Plugin\PluginManagerBase::__construct().
+   */
+  public function __construct() {
+    // Create gridbuilder plugin derivatives from declaratively defined grids.
+    $this->discovery = new DerivativeDiscoveryDecorator(new AnnotatedClassDiscovery('gridbuilder', 'gridbuilder'));
+    $this->factory = new ReflectionFactory($this);
+  }
+}
diff --git a/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/gridbuilder/gridbuilder/EqualColumnGrid.php b/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/gridbuilder/gridbuilder/EqualColumnGrid.php
new file mode 100644
index 0000000..a365aaa
--- /dev/null
+++ b/core/modules/gridbuilder/lib/Drupal/gridbuilder/Plugin/gridbuilder/gridbuilder/EqualColumnGrid.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\gridbuilder\Plugin\gridbuilder\gridbuilder\EqualColumnGrid.
+ */
+
+namespace Drupal\gridbuilder\Plugin\gridbuilder\gridbuilder;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\gridbuilder\Plugin\GridBuilderInterface;
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\Core\Annotation\Plugin;
+
+/**
+ * @Plugin(
+ *  id = "equal_column_grid",
+ *  derivative = "Drupal\gridbuilder\Plugin\Derivative\GridBuilder"
+ * )
+ */
+class EqualColumnGrid extends PluginBase implements GridBuilderInterface {
+
+  /**
+   * Overrides Drupal\Component\Plugin\PluginBase::__construct().
+   */
+  public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+    // Get definition by discovering the declarative information.
+    $definition = $discovery->getDefinition($plugin_id);
+    parent::__construct($configuration, $plugin_id, $discovery);
+  }
+
+
+  /**
+   * Implements Drupal\gridbuilder\Plugin\GridBuilderInterface::getGridCss().
+   */
+  public function getGridCss($wrapper_selector = NULL, $col_selector_prefix = NULL, $skip_spacing = FALSE) {
+    $definition = $this->getDefinition();
+    $grid = $definition['grid'];
+    $css = '';
+
+    // If the wrapper selector was not provided, generate one. This is useful for
+    // specific administration use cases when we scope the classes by grids.
+    // @todo update legacy selector (in concert with rlayout module).
+    if (empty($wrapper_selector)) {
+      $wrapper_selector = '.rld-container-' . $grid->id;
+    }
+
+    // If the span selector was not provided, generate one. This is useful for
+    // the front end to apply varying span widths under different names.
+    if (empty($col_selector_prefix)) {
+      $col_selector_prefix = '.rld-span_';
+    }
+
+    // If spacing is to be skipped, override the gutter and padding temporarily.
+    if ($skip_spacing) {
+      $grid->gutter_width = $grid->padding_width = 0;
+    }
+
+    // @todo: type constants are in the module.
+    switch ($grid->type) {
+      case 1:
+        $size_suffix = '%';
+        // Override to 100% whatever it was.
+        $grid->width = '100';
+        break;
+      case 0:
+        $size_suffix = 'px';
+        break;
+    }
+
+    // Because we use the border-box box model, we only need to substract the
+    // size of margins from the full width and divide the rest by number of
+    // columns to get a value for column size.
+    $colwidth = ($grid->width - (($grid->columns - 1) * $grid->gutter_width)) / $grid->columns;
+
+    $css = $wrapper_selector . ' .rld-col {
+  border: 0px solid rgba(0,0,0,0);
+  float: left;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  -moz-background-clip: padding-box !important;
+  -webkit-background-clip: padding-box !important;
+  background-clip: padding-box !important;
+  margin-left: ' . $grid->gutter_width . $size_suffix . ';
+  padding: 0 ' . $grid->padding_width  . $size_suffix . ';
+}
+' . $wrapper_selector . ' .rld-col' . $span_selector_prefix .'first {
+  margin-left: 0;
+  clear: both;
+}
+';
+    for ($i = 1; $i <= $grid->columns; $i++) {
+      $css .= $wrapper_selector . ' ' . $span_selector_prefix . $i . " {\n";
+      if ($i == 1) {
+        // The first column does not yet have any margins.
+        $css .= '  width: ' . $colwidth * $i . $size_suffix . ";\n";
+      }
+      elseif ($i == $grid->columns) {
+        // The full width column always spans 100%.
+        $css .= "  width: " . $grid->width . $size_suffix . ";\n  margin-left: 0;\n";
+      }
+      else {
+        // Other columns absorb all columns that they need to include and one
+        // less margin before them.
+        $css .= '  width: ' . (($colwidth * $i) + ($grid->gutter_width * ($i -1))) . $size_suffix . ";\n";
+      }
+      $css .= "}\n";
+    }
+
+    return $css;
+  }
+
+}
