~kylep/visual-cell-lang

1146fd5a8c78cb99ca9c77872adceeb8a38a3d17 — Kyle Perik 1 year, 7 months ago 945e832
Add buttons to share programs
3 files changed, 76 insertions(+), 28 deletions(-)

M src/game.js
M src/lang.js
M src/main.js
M src/game.js => src/game.js +2 -2
@@ 199,7 199,7 @@ export function addBox(data, gameData, gs) {
    } catch (e) {
      box.failed = true;
      drawBox(box);
      throw e;
      console.error(e);
    }
  }



@@ 310,7 310,7 @@ export function evaluateNewPieces (newKey, gameData, gs) {
        } catch (e) {
          box.failed = true;
          drawBox(box);
          throw e;
          console.error(e);
        }
      });
      box.inputQueue = [];

M src/lang.js => src/lang.js +38 -3
@@ 34,7 34,7 @@ export function parse (code) {
        queuedBranch: {
          ...r.queuedBranch,
          contents: r.queuedBranch.contents
            ? [r.queuedBranch.contents, newContents].join(' ')
            ? [r.queuedBranch.contents, newContents].join('\n')
            : newContents
        }
      }


@@ 91,10 91,26 @@ export function interpret (expression, initial = null) {
      const result = a === b;
      return { push: [result], pop: 2 }
    }
    else if (code === 'lth') {
      const b = r.stack[0];
      const a = r.stack[1];
      const result = a < b;
      return { push: [result], pop: 2 }
    }
    else if (code === 'gth') {
      const b = r.stack[0];
      const a = r.stack[1];
      const result = a > b;
      return { push: [result], pop: 2 }
    }
    else if (code === 'int') {
      const value = parseInt(r.stack[0]);
      return { push: [value], pop: 1 }
    }
    else if (code === 'flt') {
      const value = parseFloat(r.stack[0]);
      return { push: [value], pop: 1 }
    }
    else if (code === 'vec') {
      const y = r.stack[0];
      const x = r.stack[1];


@@ 105,6 121,11 @@ export function interpret (expression, initial = null) {
      const b = r.stack[1];
      return { push: [a.add(b)], pop: 2 }
    }
    else if (code === 'vecmul') {
      const b = r.stack[0];
      const a = r.stack[1];
      return { push: [a.mul(b)], pop: 2 }
    }
    else if (code === 'vecx') {
      const vec = r.stack[0];
      return { push: [vec.x], pop: 2 }


@@ 123,6 144,11 @@ export function interpret (expression, initial = null) {
      const b = r.stack[1];
      return { push: [a * b], pop: 2 }
    }
    else if (code === 'div') {
      const a = r.stack[0];
      const b = r.stack[1];
      return { push: [a / b], pop: 2 }
    }
    else if (code === 'sub') {
      const a = r.stack[0];
      const b = r.stack[1];


@@ 142,6 168,10 @@ export function interpret (expression, initial = null) {
      const branch = r.stack[0];
      return {jump: condition ? branches[branch] : null, pop: 2};
    }
    else if (code === 'jmp') {
      const branch = r.stack[0];
      return {jump: branches[branch], pop: 1};
    }
    else if (code === 'kep') {
      const value = r.stack[1];
      const key = r.stack[0];


@@ 160,8 190,8 @@ export function interpret (expression, initial = null) {
      return {pop: 3};
    }
    else if (code === 'at') {
      const key = r.stack[1];
      const index = r.stack[0];
      const key = r.stack[0];
      const index = r.stack[1];
      return {push: [r.data[key][index]], pop: 2};
    }
    else if (code === 'dup') {


@@ 173,6 203,11 @@ export function interpret (expression, initial = null) {
      const b = r.stack[1];
      return {push: [b, a], pop: 2};
    }
    else if (code === 'arr') {
      const key = r.stack[0];
      r.data[key] = [];
      return {pop: 1};
    }
    else if (code === 'que') {
      const key = r.stack[0];
      const value = r.stack[1];

M src/main.js => src/main.js +36 -23
@@ 15,7 15,7 @@ PIXI.Loader.shared.add('CompassPro', 'compasspro_medium_12.fnt')
PIXI.Loader.shared.add('MatchupPro', 'matchuppro_medium_12.fnt')

const $ = (selector) => document.querySelector(selector);
const el = ({ kind, children, text, value, attributes, classes }) => {
const el = ({ kind, children, text, value, attributes, classes, style }) => {
  const element = document.createElement(kind || 'div');
  if (text) {
    element.textContent = text;


@@ 29,6 29,9 @@ const el = ({ kind, children, text, value, attributes, classes }) => {
  (Object.keys(attributes || {})).forEach(key => {
    element.setAttribute(key, attributes[key]);
  });
  Object.keys(style || {}).forEach(key => {
    element.style[key] = style[key];
  });
  element.classNames = classes || '';
  return element;
}


@@ 157,13 160,14 @@ function save () {
  });
}

function load () {
  const rawSave = localStorage.save;
function load (rawSave) {
  if (!rawSave) {
    return;
  }
  const save = JSON.parse(rawSave);
  gameData.customDefinitions = save.customDefinitions;
  gameData.customDefinitions = {
    ...gameData.customDefinitions, ...save.customDefinitions
  };
  save.boxes.forEach(box => addBox(box, gameData, gs));
  save.connections.map(connection => ({
    ...connection,


@@ 178,7 182,7 @@ function reset () {
  gameData.dataPieces.forEach(piece => gs.dataPieces.removeChild(piece.g));
  gameData.dataPieces = [];
  Array.from(gameData.connections).forEach(connection => removeConnection(piece, gameData, gs))
  load();
  load(localStorage.save);
}

window.save = save;


@@ 189,6 193,7 @@ function initUI() {

  const codeTypeDropdown = el({ kind: 'select' });
  function buildTypeDropdown () {
    const lastValue = codeTypeDropdown.value;
    codeTypeDropdown.innerHTML = '';
    const definitions = Object.keys(gameData.boxDefinitions).concat(Object.keys(gameData.customDefinitions));
    definitions.map(


@@ 196,6 201,7 @@ function initUI() {
    ).forEach(option => {
      codeTypeDropdown.appendChild(option);
    })
    codeTypeDropdown.value = lastValue;
  }
  buildTypeDropdown();
  toolbarEl.appendChild(codeTypeDropdown);


@@ 214,7 220,7 @@ function initUI() {
  });
  toolbarEl.appendChild(codeBoxButton);

  const editorTextbox = el({ kind: 'textarea' });
  const editorTextbox = el({ kind: 'textarea', attributes: { rows: 20 }, style: { width: '15rem' } });
  const editorSaveButton = el({ kind: 'button', text: 'Save' });
  const codeEditorEl = el({
    kind: 'div',


@@ 268,6 274,29 @@ function initUI() {
    reset();
  });
  toolbarEl.appendChild(resetButtonEl);
  const copyText = 'Copy all to Clipboard';
  const copyButtonEl = el({ kind: 'button', text: copyText });
  copyButtonEl.addEventListener('click', () => {
    save();
    navigator.clipboard.writeText(localStorage.save).then(function() {
      copyButtonEl.textContent = "Program Copied to Clipboard!"
      setTimeout(() => {
        copyButtonEl.textContent = copyText;
      }, 2000);
    }, function(err) {
      copyButtonEl.textContent = "Failed to Copy to Clipboard"
      setTimeout(() => {
        copyButtonEl.textContent = copyText;
      }, 2000);
    });
  });
  toolbarEl.appendChild(copyButtonEl);
  const loadButtonEl = el({ kind: 'button', text: "Load Program" });
  loadButtonEl.addEventListener('click', () => {
    const program = prompt('Paste JSON program');
    load(program);
  });
  toolbarEl.appendChild(loadButtonEl);
}

function setup () {


@@ 379,22 408,6 @@ flr #last swp at
      v: parse(`val vecy #v out`),
    }
  });
  loadCodeBox({
    name: 'delay',
    data: {
      tail: [],
      number: 10,
    },
    outputs: ['v'],
    inputs: {
      v: parse(`
val #tail que
#tail len #number get equ #pop jcn
def pop:
  #tail pop #v out
`),
    }
  });

  app.view.tabIndex = 0
  app.view.focus()


@@ 441,7 454,7 @@ def pop:

  gameData.boxDefinitions = boxDefinitions;

  load();
  load(localStorage.save);
  initUI();

  setInterval(save, 10000);