Phoenix 

Phoenix is a very barebones window manager that is scriptable via , and which I have taken to instead of Moom to a degree.

This is a snapshot of my configuration:

// ********************************************************************************
//  Setup and TODO
// ********************************************************************************

Phoenix.set({
  daemon: false,
  openAtLogin: true
});

/*
 * API docs: https://github.com/kasper/phoenix/blob/master/docs/API.md
 *
 * TODO:  
 * - [ ] Drag and Drop Snap (can't be implemented in curren Phoenix, apparently)
 * - [ ] New XMonad with precomputed layouts
 * - [ ] Nearest Rectangle Match
 * - [ ] Window overlay test
 * - [ ] Cleanup positionInGrid
 * - [x] More logical handling of sixths
 * - [x] Hint Manager class
 * - [x] Cleanup Constants
 * - [x] Basic Space handling
 * - [x] Move mouse pointer on rotation focus changes
 * - [x] Centered popup
 * - [x] Frame abstraction
 */

// ********************************************************************************
//  Constants
// ********************************************************************************

const INCREMENT = 50;
const PADDING = 8;

// DIRECTIONS
const NONE = "none",
      COLS = "Cols",
      F = FULL = "Full",
      N = NORTH = "North",
      S = SOUTH = "South",
      E = EAST  = "East",
      W = WEST  = "West",
      NW = "North-West",
      NE = "North-East",
      SW = "South-West",
      SE = "South-East";

const TILING_MODES = [NONE, EAST, WEST, COLS];

var MOD = ["shift", "command"];
var ALTMOD = ["shift", "option"];

var HINT_APPEARANCE = "dark";
var HINT_BUTTON = "space";
var HINT_CANCEL = "escape";
var HINT_CHARS = "FJDKSLAGHRUEIWOVNCM";
var LAST_POSITION = {
    window: null,
    grid: "",
    positions: []
}
var LAST_POSITION_INDEX = -1;
var ICON_CACHE = {}

// ********************************************************************************
//  Keyboard Bindings
// ********************************************************************************

// Moom-like bindings
Key.on("return", ["control", "option"], () => {Window.focused().positionInGrid(4,0,3).centerMouse()});
Key.on("left",   ["control", "option"], () => steppedSizing(Window.focused(), [[4,0,2], [6,0,3], [16,0,9]]));
Key.on("right",  ["control", "option"], () => steppedSizing(Window.focused(), [[4,1,3], [6,2,5], [16,6,15]]));
Key.on("up",     ["control", "option"], () => {Window.focused().positionInGrid(6,0,5).centerMouse()});
Key.on("down",   ["control", "option"], () => steppedSizing(Window.focused(), [[8,2,13], [6,1,4]]));
Key.on("left",   ["shift", "control", "option"], () => {Window.focused().positionInGrid(6,0,3).centerMouse()});
Key.on("right",  ["shift", "control", "option"], () => {Window.focused().positionInGrid(6,2,5).centerMouse()});
Key.on("up",     ["shift", "control", "option"], () => {Window.focused().reposition(NORTH).centerMouse()});
Key.on("down",   ["shift", "control", "option"], () => {Window.focused().reposition(SOUTH).centerMouse()});
// Sixths
Key.on(",",      ["shift", "control", "option"], () => {Window.focused().positionInGrid(6,0,0).centerMouse()});
Key.on(".",      ["shift", "control", "option"], () => {Window.focused().positionInGrid(6,1,1).centerMouse()});
Key.on("/",      ["shift", "control", "option"], () => {Window.focused().positionInGrid(6,2,2).centerMouse()});
Key.on(",",      ["control", "option"], () => {Window.focused().positionInGrid(6,3,3).centerMouse()});
Key.on(".",      ["control", "option"], () => {Window.focused().positionInGrid(6,4,4).centerMouse()});
Key.on("/",      ["control", "option"], () => {Window.focused().positionInGrid(6,5,5).centerMouse()});
// Move horizontally between screens
Key.on("right",  ["control", "option", "command"], () => Window.focused().toScreen(EAST).centerMouse());
Key.on("left",   ["control", "option", "command"], () => Window.focused().toScreen(WEST).centerMouse());
// Move horizontally between spaces
Key.on("right",  ["shift", "control", "option", "command"], () => Window.focused().toSpace(EAST));
Key.on("left",   ["shift", "control", "option", "command"], () => Window.focused().toSpace(WEST));


// ********************************************************************************
// Size steps
// ********************************************************************************

function steppedSizing(win, gridPositions) {
    if(!win.isEqual(LAST_POSITION.window)) {
        LAST_POSITION_INDEX = 0;
        LAST_POSITION.window = win;
    } else if(JSON.stringify(LAST_POSITION.positions)!=JSON.stringify(gridPositions)) {
        LAST_POSITION_INDEX = 0;
    }
    res = win.positionInGrid.apply(win, gridPositions[LAST_POSITION_INDEX]).centerMouse();
    LAST_POSITION.grid = gridPositions[LAST_POSITION_INDEX].join(",");
    LAST_POSITION_INDEX = (LAST_POSITION_INDEX + 1) % gridPositions.length;
    LAST_POSITION.positions = gridPositions;
    return res
}


// ********************************************************************************
//  Hints
// ********************************************************************************

class Hints {
  constructor() {
    this.active = false;
    this.keys = [];
    this.hints = {};
    this.escbind = null;
    this.bsbind = null;
    this.id = Math.random();
  } // constructor

  cancel() {
    for (var activator in this.hints) {
      if(this.hints[activator])
          this.hints[activator].modal.close();
    };
    // remove all key bindings
    Key.off(this.escbind);
    Key.off(this.bsbind);
    this.keys.map(Key.off);
    // clear hints
    this.hints = {};
    this.keys = [];
    this.active = false;
    return this;
  } // cancel

  show(windows, prefix) {
    self = this;
    prefix = prefix || "";

    // check if there are too many windows and recurse
    if (windows.length > HINT_CHARS.length) {
      var partitionSize = Math.floor(windows.length / HINT_CHARS.length);
      var lists = _.toArray(_.groupBy(windows, function (win, k) {
        return k % HINT_CHARS.length;
      }));
      for (var j = 0; j < HINT_CHARS.length; j++) {
        return this.show(lists[j], prefix + HINT_CHARS[j]);
      }
      return this;
    }

    var self = this;
    windows.forEach(function (win, i) {
      var label = "",
           hash = win.hash();
      if(!ICON_CACHE[hash]) {
          ICON_CACHE[hash] = win.app().icon()
      }
      if (win.app().windows().length > 1) {
        label += "  |  " + win.title().substr(0, 15) + (win.title().length > 15 ? "…" : "");
      }
      var hint = Modal.build({
        text: prefix + HINT_CHARS[i] + label,
        appearance: HINT_APPEARANCE,
        icon: ICON_CACHE[hash],
        weight: 16,
        duration: 0,
      }).attach(win);

      var activators = Object.keys(self.hints);
      // Check for overlaps - TODO: use Frame

      for (var l = 0; l < activators.length; l++) {
        var hint2 = self.hints[activators[l]].modal;
        if (
               hint.origin.x < hint2.origin.x + hint2.frame().width + PADDING
            && hint.origin.x + hint.frame().width > hint2.origin.x - PADDING
            && hint.origin.y < hint2.origin.y + hint2.frame().height + PADDING
            && hint.origin.y + hint.frame().width > hint2.origin.y - PADDING
        ) {
          hint.origin = {
            x: hint.origin.x,
            y: hint2.origin.y + hint2.frame().height + PADDING
          };
          l = -1;
        }
      }

      self.hints[prefix + HINT_CHARS[i]] = {
        win: win,
        modal: hint,
        position: 0,
        active: true
      };
    });    
    self.escbind = Key.on(HINT_CANCEL, [], function() {
        self.cancel();
    })
    this.active = true;
    return this;
  } // show

  activate() {
    var self = this;

    if(this.active) {
        self.cancel();
    } else {
      Event.once("mouseDidLeftClick", function() {
        self.cancel();
      });

      this.show(Window.all({visible: true}));      

      var sequence = "";
      self.keys = [];
      HINT_CHARS.split("").forEach(function (hintchar) {
        // set up each individual hint handler
        self.keys.push(Key.on(hintchar, [], function () {
          sequence += hintchar;
          for (var activator in self.hints) {
            var hint = self.hints[activator];
            if (!hint.active) continue;
            if (activator[hint.position] === hintchar) {

              hint.position++;
              if (hint.position === activator.length) {
                hint.win.focus();
                Mouse.move({
                  x: hint.modal.origin.x + hint.modal.frame().width / 2,
                  y: Screen.all()[0].frame().height - hint.modal.origin.y - hint.modal.frame().height / 2
                });
                return self.cancel();
              }
              hint.modal.text = hint.modal.text.substr(1);
            } else {
              hint.modal.close();
              hint.active = false;
            }
          }
        }));        
      });

      self.bsbind = Key.on("delete", [], function () {
        if (!sequence.length) 
          self.cancel();
        var letter = sequence[sequence.length - 1];
        sequence = sequence.substr(0, sequence.length - 1);
        for (var activator in self.hints) {
          var hint = self.hints[activator];
          if (hint.active) {
            hint.position--;
            hint.modal.text = letter + hint.modal.text;
          } else if (activator.substr(0, sequence.length) === sequence) {
            hint.modal.show();
            hint.active = true;
          }
        }
      });
    }    
  } // activate
}


// ********************************************************************************
//  Window Manager Abstraction
// ********************************************************************************

class WindowManager {
  constructor() {
    this.tiling_modes = Array(Screen.all().length)
    this.tiling_modes.fill(NONE)
    this.timers = Array(Screen.all().length)
    this.layouts = Array(Screen.all().length)
  }

  change_tiling_mode() {
    const window = Window.focused(),
          screen = window.screen(),
          index = Screen.all().indexOf(screen),
          visible = screen.windows({visible:true})

    // rotate tiling mode
    this.tiling_modes[index] = TILING_MODES[(TILING_MODES.indexOf(this.tiling_modes[index])+1) % TILING_MODES.length]
    Phoenix.log(index + " " + this.tiling_modes[index])

    this.layouts[index] = new Layout(screen, this.tiling_modes[index])

    var modal = Modal.build({
      text: "Tiling mode: " + this.tiling_modes[index],
      appearance: HINT_APPEARANCE,
      weight: 24,
      icon: App.get('Phoenix').icon(),
      duration: 0.5,
    }).flash(screen)

    Phoenix.log(this.layouts)

    this.layouts[index].windows = visible
    this.layouts[index].apply()

    Phoenix.log(this.layouts)
    return this
  }  

  rotate(dir, focus_only) {
    const window = Window.focused(),
          screen = window.screen(),
          index = Screen.all().indexOf(screen)
    Phoenix.log(index + " " + dir + " " + this.layouts[index].windows.map(x=>x.hash()))
    this.layouts[index].rotate(dir).apply(screen)
    return this
  }
}

const wm = new WindowManager()

Key.on("z", ["shift", "control"],           () => wm.change_tiling_mode())
Key.on("n", ["shift", "control"],           () => wm.rotate(-1, false));
Key.on("n", ["shift", "control", "option"], () => wm.rotate(-1, true));
Key.on("m", ["shift", "control"],           () => wm.rotate(1, false));
Key.on("m", ["shift", "control", "option"], () => wm.rotate(1, true));


// ********************************************************************************
//  Layout Abstraction
// ********************************************************************************

class Layout {
  constructor(screen, mode) {
    this.frames = []
    this.windows = []
    switch(mode) {
      case EAST:
        this.east(screen)
        break;
      case WEST:
        this.west(screen)
        break;
      case COLS:
        this.cols(screen)
        break;
    }
  }

  east(screen) {
    const f = screen.flippedVisibleFrame(),
          v = screen.windows({visible:true}),   
          c = v.length-1,
          w = f.width/2,
          h = ~~(f.height/c),
          self = this
    this.screen = screen
    if(v.length === 1) {
      this.frames.push(new Frame(f.x, f.y, f.width, f.height).pad())
    } else {
      // main window
      self.frames.push(new Frame(f.x, f.y, w, f.height)
          .displace(f.width/2, 0).pad())
      // secondary windows
      for(var i=0; i<c; i++) {
          self.frames.push(new Frame(f.x, f.y, w, h)
              .displace(0, h*i).pad())
      }        
    }
    return this
  }

  west(screen) {
    const f = screen.flippedVisibleFrame(),
          v = screen.windows({visible:true}),   
          c = v.length-1,
          w = f.width/2,
          h = ~~(f.height/c),
          self = this
    this.screen = screen
    if(v.length === 1) {
      self.frames.push(new Frame(f.x, f.y, f.width, f.height).pad())
    } else {
      // main window
      self.frames.push(new Frame(f.x, f.y, w, f.height)
          .pad())
      // secondary windows
      for(var i=0; i<c; i++) {
          self.frames.push(new Frame(f.x, f.y, w, h)
              .displace(w, h*i).pad())
      }
    }
    return this
  }

  cols(screen) {
    const f = screen.flippedVisibleFrame(),
          v = screen.windows({visible:true}),   
          c = v.length,
          w = ~~(f.width/c),
          h = f.height,
          self = this
    this.screen = screen

    // all windows
    for(var i=0; i<c; i++) {
        self.frames.push(new Frame(f.x, f.y, w, h)
            .displace(w*i, 0).pad())
    }
    return this
  }

  none(screen) {
    this.frames = []
    return this
  }

  rotate(dir) {
    this.windows.rotate(dir)
    return this
  }

  apply() {
    const self = this
    if(this.frames.length)
      for(var i=0;i<self.windows.length;i++) {
        self.windows[i].setFrame(self.frames[i])
      }
    return this
  }
}


// ********************************************************************************
//  Frame Abstraction
// ********************************************************************************

class Frame {
  constructor(x, y, width, height) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
  }

  pad() {
    return new Frame(
      this.x + PADDING/2, 
      this.y + PADDING/2,
      this.width - PADDING,
      this.height - PADDING
    )
  }

  snap(screen, dir) {
    var s = screen.flippedVisibleFrame(),
        f = new Frame(this.x, this.y, this.width, this.height);
    if ([E, NE, SE].indexOf(dir) > -1) f.x += s.width - f.width;
    if ([SE, SW].indexOf(dir) > -1)    f.y += s.height - f.height;
    if (dir === F)                     f.width = s.width;
    if ([F, E, W].indexOf(dir) > -1)   f.height = s.height;
    return f;
  }

  displace(x, y) {
    return new Frame(
      this.x + x,
      this.y + y,
      this.width,
      this.height
    )
  }

  log() {
    Phoenix.log(this.x + ", " + this.y + ", " + this.width + ", " + this.height);
    return this;
  }

  rect() {
    return {
      x: this.x,
      y: this.y,
      width: this.width,
      height: this.height
    }
  }

  ratio(a, b) {
    var wr = b.width / a.width,
        hr = b.height / a.height;

    return ({x, y, width, height}) => {
        x = Math.round(b.x + (x - a.x) * wr);
        y = Math.round(b.y + (y - a.y) * hr);
        width = Math.round(width * wr);
        height = Math.round(height * hr);        
        return {x, y, width, height}
    }
  }
}


// ********************************************************************************
//  Window Extensions
// ********************************************************************************


// Snap a window in a given direction
Window.prototype.to = function(direction) {
  var s = this.screen(),
      f = s.flippedVisibleFrame(),
  frame = new Frame(
    f.x,
    f.y,
    f.width / 2,
    f.height / 2,
  ).snap(s, direction).pad();
  this.setFrame(frame);
};


// Move a window to a given screen
Window.prototype.toScreen = function(dir) {
  var screen = null;
  if(dir===EAST) {
    screen = Screen.all().filter((a) => {return a.origin().x > this.screen().origin().x}).sort((a,b) => {return a.origin().x > b.origin().x})[0]
  }
  else if(dir===WEST) {
    screen = Screen.all().filter((a) => {return a.origin().x < this.screen().origin().x}).sort((a,b) => {return a.origin().x < b.origin().x})[0];
  }
  if(screen) {
    ratio = Frame.prototype.ratio(this.screen().flippedVisibleFrame(), screen.flippedVisibleFrame());  
    this.setFrame(ratio(this.frame()));
  }
  return this;
};


Window.prototype.reposition = function (dir) {
  var l = LAST_POSITION.window,
      g = LAST_POSITION.grid;

    if(this.isEqual(l)) {
        if(dir === NORTH) {
            switch(g) {
                case "4,0,2": this.positionInGrid(4,0,0); break;
                case "4,2,2": this.positionInGrid(4,0,0); break;
                case "4,1,3": this.positionInGrid(4,1,1); break;
                case "4,3,3": this.positionInGrid(4,1,1); break;

                case "6,0,3": this.positionInGrid(6,0,0); break;
                case "6,3,3": this.positionInGrid(6,0,0); break;
                case "6,2,5": this.positionInGrid(6,2,2); break;
                case "6,5,5": this.positionInGrid(6,2,2); break;

                case "6,1,4": this.positionInGrid(6,1,1); break;                
                case "6,4,4": this.positionInGrid(6,1,1); break;                
            }
        } else if (dir === SOUTH) {
            switch(g) {
                case "4,0,2": this.positionInGrid(4,2,2); break;
                case "4,0,0": this.positionInGrid(4,2,2); break;
                case "4,1,3": this.positionInGrid(4,3,3); break;
                case "4,1,1": this.positionInGrid(4,3,3); break;

                case "6,0,3": this.positionInGrid(6,3,3); break;
                case "6,0,0": this.positionInGrid(6,3,3); break;
                case "6,2,5": this.positionInGrid(6,5,5); break;
                case "6,2,2": this.positionInGrid(6,5,5); break;

                case "6,1,4": this.positionInGrid(6,4,4); break;                
                case "6,1,1": this.positionInGrid(6,4,4); break;                
            }           
        }
    }
    return this
}


Window.prototype.positionInGrid = function (cells, start, end) {
  LAST_POSITION = {
      window: this,
      grid: cells + "," + start + "," + end
  }
  var cols = ~~(cells / 2);
  var screen = this.screen();
  var cellwidth = (screen.width() - ((cols - 1) * PADDING)) / cols;
  var cellheight = (screen.height() - PADDING) / 2;

  var startc = start % cols,
    startw = ~~(start / cols),
    startl = screen.origin().x + (cellwidth + PADDING) * startc,
    startt = screen.origin().y + (cellheight + PADDING) * startw,
    startr = startl + cellwidth,
    startb = startt + cellheight;

  var endc = end % cols,
    endw = ~~(end / cols),
    endl = screen.origin().x + (cellwidth + PADDING) * endc,
    endt = screen.origin().y + (cellheight + PADDING) * endw,
    endr = endl + cellwidth,
    endb = endt + cellheight;

  var frame = this.frame();
  frame.x = Math.min(startl, endl);
  frame.y = Math.min(startt, endt);
  frame.width = Math.max(startr, endr) - frame.x;
  frame.height = Math.max(startb, endb) - frame.y;
  this.setFrame(frame);
  return this;
}


// Resize a window by coeff units in the given direction
// coeff: -n shrinks by pixels units, +n grows by n pixels
Window.prototype.resize = function (dir, coeff) {
  var frame = this.frame()

  if (dir === W)                frame.x += coeff * -1
  if (dir === N)                frame.y += coeff * -1
  if ([E, W].indexOf(dir) > -1) frame.width  += coeff
  if ([N, S].indexOf(dir) > -1) frame.height += coeff

  this.setFrame(frame)
  return this
}


Window.prototype.toSpace = function (dir) {
  var curSpace = this.spaces()[0],
      newSpace = curSpace.next()

  if (dir === WEST)
    newSpace = curSpace.previous()

  curSpace.removeWindows([this])
  newSpace.addWindows([this])
  this.focus()
  return this
}


Window.prototype.centerMouse = function() {
    Mouse.move({
        x: this.frame().x + this.frame().width / 2,
        y: this.frame().y + this.frame().height / 2
    })
    return this
}


Window.prototype.log = function() {
  Phoenix.log(this.frame().x + "," + this.frame().y + "," + this.frame().width + "," + this.frame().height)
  return this
}


// ********************************************************************************
//  Modal Extensions
// ********************************************************************************

// Flash a modal in the center of a given screen
Modal.prototype.flash = function(screen) {
  var tf = this.frame(),
      sf = screen.frame();
  this.origin = {
    x: sf.x + sf.width/2  - tf.width/2,
    y: sf.y + sf.height/2 - tf.height/2
  }
  this.show();
  return this;
}


Modal.prototype.attach = function(window) {
  var tf = this.frame(),
      wf = window.frame(),
      sf = window.screen().frame();

  this.origin = {
    x: Math.min(
      Math.max(wf.x + wf.width/2 - tf.width/2, sf.x), 
      sf.x + sf.width - tf.width
    ),
    y: Math.min(
      Math.max(Screen.all()[0].frame().height - (wf.y + wf.height/2 + tf.height / 2), sf.y),
      sf.y + sf.height - tf.height
    )
  };
  this.show();
  return this;
}


// ********************************************************************************
//  Screen Extensions
// ********************************************************************************

Screen.prototype.width = function () { // DEPRECATED
  return this.flippedVisibleFrame().width - PADDING * 2
}


Screen.prototype.height = function () { // DEPRECATED
  return this.flippedVisibleFrame().height - PADDING * 2
}


Screen.prototype.origin = function () { // DEPRECATED
  return {
    x: this.flippedVisibleFrame().x + PADDING,
    y: this.flippedVisibleFrame().y + PADDING
  }
}


// ********************************************************************************
//  Utilities
// ********************************************************************************

Array.prototype.rotate = (function() {
  const unshift = Array.prototype.unshift,
        splice = Array.prototype.splice

  return function(count) {
    var len = this.length >>> 0,
        count = count >> 0;
    unshift.apply(this, splice.call(this, count % len, len));
    return this;
  }
})()

function opposite(dir) {
  switch (dir) {
    case N: return S;
    case S: return N;
    case E: return W;
    case W: return E;
    case NW: return SE;
    case NE: return SW;
    case SW: return NE;
    case SE: return NW;
  }
}


// ********************************************************************************
//  Startup
// ********************************************************************************

const HintManager = new Hints()

Key.on("space",  ["shift", "command"], () => HintManager.activate());

Modal.build({
  text: "Ready",
  appearance: HINT_APPEARANCE,
  weight: 24,
  icon: App.get('Phoenix').icon(),
  duration: 0.5,
}).flash(Screen.all()[0]);

This page is referenced in: