diff --git a/module/VuFindConsole/src/VuFindConsole/Controller/UtilController.php b/module/VuFindConsole/src/VuFindConsole/Controller/UtilController.php
index 93376f15d84fef8616cf7ecf8c7c0f6b3a940059..9362261dfd775261c4c409f5241416379b48bc75 100644
--- a/module/VuFindConsole/src/VuFindConsole/Controller/UtilController.php
+++ b/module/VuFindConsole/src/VuFindConsole/Controller/UtilController.php
@@ -456,6 +456,19 @@ class UtilController extends AbstractBase
         return $this->getSuccessResponse();
     }
 
+    /**
+     * Compile CSS files from LESS.
+     *
+     * @return \Zend\Console\Response
+     */
+    public function cssbuilderAction()
+    {
+        $argv = $this->consoleOpts->getRemainingArgs();
+        $compiler = new \VuFindTheme\LessCompiler();
+        $compiler->compile($argv);
+        return $this->getSuccessResponse();
+    }
+
     /**
      * Abstract delete method.
      *
diff --git a/module/VuFindTheme/src/VuFindTheme/LessCompiler.php b/module/VuFindTheme/src/VuFindTheme/LessCompiler.php
new file mode 100644
index 0000000000000000000000000000000000000000..fff9a18bc496a80d87f032ed260a033cd3a33541
--- /dev/null
+++ b/module/VuFindTheme/src/VuFindTheme/LessCompiler.php
@@ -0,0 +1,189 @@
+<?php
+/**
+ * Class to compile LESS into CSS within a theme.
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Theme
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org   Main Site
+ */
+namespace VuFindTheme;
+use \Zend\Console\Console;
+
+/**
+ * Class to compile LESS into CSS within a theme.
+ *
+ * @category VuFind2
+ * @package  Theme
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org   Main Site
+ */
+class LessCompiler
+{
+    /**
+     * Base path of VuFind.
+     *
+     * @var string
+     */
+    protected $basePath;
+
+    /**
+     * Fake base path used for generating absolute paths in CSS.
+     *
+     * @var string
+     */
+    protected $fakePath = '/zzzz_basepath_zzzz/';
+
+    /**
+     * Constructor
+     */
+    public function __construct()
+    {
+        $this->basePath = realpath(__DIR__ . '/../../../../');
+    }
+
+    /**
+     * Compile the scripts.
+     *
+     * @param array $themes Array of themes to process (empty for ALL themes).
+     *
+     * @return void
+     */
+    public function compile(array $themes)
+    {
+        if (empty($themes)) {
+            $themes = $this->getAllThemes();
+        }
+
+        foreach ($themes as $theme) {
+            $this->processTheme($theme);
+        }
+    }
+
+    /**
+     * Compile scripts for the specified theme.
+     *
+     * @param string $theme Theme name
+     *
+     * @return void
+     */
+    protected function processTheme($theme)
+    {
+        $config = $this->basePath . '/themes/' . $theme . '/theme.config.php';
+        if (!file_exists($config)) {
+            return;
+        }
+        $config = include($config);
+        if (!isset($config['less'])) {
+            Console::writeLine("No LESS in " . $theme);
+            return;
+        }
+        Console::writeLine("Processing " . $theme);
+        foreach ($config['less'] as $less) {
+            $this->compileFile($theme, $less);
+        }
+    }
+
+    /**
+     * Compile a LESS file inside a theme.
+     *
+     * @param string $theme Theme containing file
+     * @param string $less  Relative path to LESS file
+     *
+     * @return void
+     */
+    protected function compileFile($theme, $less)
+    {
+        $finalOutDir = $this->basePath . '/themes/' . $theme . '/css/';
+        list($fileName, ) = explode('.', $less);
+        $finalFile = $finalOutDir . $fileName . '.css';
+
+        Console::writeLine("\tcompiling '" . $less .  "' into '" . $finalFile . "'");
+        $start = microtime(true);
+
+        $directories = array();
+        $info = new ThemeInfo($this->basePath . '/themes', $theme);
+        foreach (array_keys($info->getThemeInfo()) as $curTheme) {
+            $directories["{$this->basePath}/themes/$curTheme/less/"]
+                = $this->fakePath . "themes/$curTheme/css/less";
+        }
+        $lessDir = $this->basePath . '/themes/' . $theme . '/less/';
+        $outDir = sys_get_temp_dir();
+        $outFile = \Less_Cache::Regen(
+            array($lessDir . $less => $this->fakePath . "themes/$theme/css/less"),
+            array(
+                'cache_dir' => $outDir,
+                'cache_method' => false,
+                'compress' => true,
+                'import_dirs' => $directories
+            )
+        );
+        $css = file_get_contents($outDir . '/' . $outFile);
+        if (!is_dir(dirname($finalFile))) {
+            mkdir(dirname($finalFile));
+        }
+        file_put_contents($finalFile, $this->makeRelative($css, $less));
+
+        Console::writeLine("\t\t" . (microtime(true)-$start) . ' sec');
+    }
+
+    /**
+     * Convert fake absolute paths to working relative paths.
+     *
+     * @param string $css  Generated CSS
+     * @param string $less Relative LESS filename
+     *
+     * @return string
+     */
+    protected function makeRelative($css, $less)
+    {
+        // Figure out how deep the LESS file is nested -- this will
+        // affect our relative path.
+        $depth = preg_match_all('|/|', $less, $matches);
+        $relPath = '../../../';
+        for ($i = 0; $i < $depth; $i++) {
+            $relPath .= '/../';
+        }
+        return str_replace($this->fakePath, $relPath, $css);
+    }
+
+    /**
+     * Get a list of all available themes.
+     *
+     * @return array
+     */
+    protected function getAllThemes()
+    {
+        $baseDir = $this->basePath . '/themes/';
+        $dir = opendir($baseDir);
+        $list = array();
+        while ($line = readdir($dir)) {
+            if (is_dir($baseDir . $line)
+                && file_exists($baseDir . $line . '/theme.config.php')
+            ) {
+                $list[] = $line;
+            }
+        }
+        closedir($dir);
+        return $list;
+    }
+}
\ No newline at end of file
diff --git a/util/cssBuilder.php b/util/cssBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..a2cca7905e9246b20b6ba620654e50b93cb6327e
--- /dev/null
+++ b/util/cssBuilder.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Compile CSS files from LESS.
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Utilities
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki Wiki
+ */
+
+// Load the Zend framework -- this will automatically trigger the appropriate
+// controller action based on directory and file names
+define('CLI_DIR', __DIR__);     // save directory name of current script
+require_once __DIR__ . '/../public/index.php';