Improved helpers
This commit is contained in:
parent
12bba32b5d
commit
66c436b567
20
README.txt
20
README.txt
@ -29,23 +29,29 @@ Project Clean Escape
|
|||||||
|
|
||||||
Example
|
Example
|
||||||
|
|
||||||
; clear screen
|
|
||||||
(clear)
|
(clear)
|
||||||
|
|
||||||
; draw red square
|
|
||||||
(stroke
|
(stroke
|
||||||
(rect 30 30 100 100) "red" 2)
|
(rect 30 30 100 100) "red" 2)
|
||||||
|
|
||||||
; download result
|
|
||||||
(export)
|
(export)
|
||||||
|
|
||||||
Helpers
|
Helpers
|
||||||
|
|
||||||
Ronin helpers are keywords that facilitates adding coordinates from the canvas into your script. The currently supported helpers are `$rect`, `$pos`, `$circle`, `$line`, `$drag` and `$view`. Holding right-click while using a $helper will run the script as the mouse is injecting coordinates into the script. Paste the following script, and trace a shape in the canvas:
|
Ronin helpers are keywords that facilitates adding coordinates from the canvas into your script. The currently supported helpers are $rect, $pos, $line, $circle & $arc. Holding right-click while using a $helper will run the script as the mouse is injecting coordinates into the script. Paste the following script, and trace a shape in the canvas:
|
||||||
|
|
||||||
; draw a red circle
|
|
||||||
(fill $circle "red")
|
(fill $circle "red")
|
||||||
|
|
||||||
|
Additional helpers are also available to change parts of a shape, these are as follow: $x, $y, $xy, $wh, $a & $r. Paste the following script, and change the position and radius of a circle:
|
||||||
|
|
||||||
|
(clear)
|
||||||
|
(fill
|
||||||
|
(circle $xy $r) "red")
|
||||||
|
|
||||||
|
Extra helpers are available for various transformations, these are as follow: $drag, $view, $poly, $move & $rotate. Paste the following script, and draw the vertices of a line, press escape to stop:
|
||||||
|
|
||||||
|
(clear)
|
||||||
|
(stroke
|
||||||
|
$poly "red")
|
||||||
|
|
||||||
Import/Export
|
Import/Export
|
||||||
|
|
||||||
To save an image in memory, open an image file with Ronin, or drag an image file on the window. You will then be able to import it by using the file image's name. If the image file is `preview.png`, you can import it as follow:
|
To save an image in memory, open an image file with Ronin, or drag an image file on the window. You will then be able to import it by using the file image's name. If the image file is `preview.png`, you can import it as follow:
|
||||||
|
@ -10,12 +10,13 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="./links/theme.css"/>
|
<link rel="stylesheet" type="text/css" href="./links/theme.css"/>
|
||||||
|
|
||||||
<script type="text/javascript" src="./scripts/lib/acels.js"></script>
|
<script type="text/javascript" src="./scripts/lib/acels.js"></script>
|
||||||
<script type="text/javascript" src="./scripts/lib/lisp.js"></script>
|
<script type="text/javascript" src="./scripts/lib/lain.js"></script>
|
||||||
<script type="text/javascript" src="./scripts/lib/source.js"></script>
|
<script type="text/javascript" src="./scripts/lib/source.js"></script>
|
||||||
<script type="text/javascript" src="./scripts/lib/theme.js"></script>
|
<script type="text/javascript" src="./scripts/lib/theme.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="./scripts/client.js"></script>
|
<script type="text/javascript" src="./scripts/client.js"></script>
|
||||||
<script type="text/javascript" src="./scripts/commander.js"></script>
|
<script type="text/javascript" src="./scripts/commander.js"></script>
|
||||||
|
<script type="text/javascript" src="./scripts/lain(old).js"></script>
|
||||||
<script type="text/javascript" src="./scripts/library.js"></script>
|
<script type="text/javascript" src="./scripts/library.js"></script>
|
||||||
<script type="text/javascript" src="./scripts/surface.js"></script>
|
<script type="text/javascript" src="./scripts/surface.js"></script>
|
||||||
|
|
||||||
|
@ -1,80 +1,78 @@
|
|||||||
(clear)
|
(clear)
|
||||||
;
|
;
|
||||||
(open $path)
|
(open $path 0.75)
|
||||||
|
|
||||||
; picker to elementary
|
; picker to elementary
|
||||||
|
|
||||||
(def unit 40)
|
(def unit 10)
|
||||||
(def f
|
(def f
|
||||||
(get-frame))
|
(get-frame))
|
||||||
(def pos-row-1
|
(def pos-row-1
|
||||||
(sub f:h
|
(sub f:h 80))
|
||||||
(mul unit 4)))
|
|
||||||
(def pos-row-2
|
(def pos-row-2
|
||||||
(sub f:h
|
(sub f:h 45))
|
||||||
(mul unit 2)))
|
|
||||||
|
|
||||||
; color picker
|
; color picker
|
||||||
|
|
||||||
(def color-1
|
(def color-1
|
||||||
(pick
|
(pick
|
||||||
(guide
|
(guide
|
||||||
(rect $xy unit unit))))
|
(rect 846 220 unit unit))))
|
||||||
(def color-2
|
(def color-2
|
||||||
(pick
|
(pick
|
||||||
(guide
|
(guide
|
||||||
(rect $xy unit unit))))
|
(rect 584 364 unit unit))))
|
||||||
(def color-3
|
(def color-3
|
||||||
(pick
|
(pick
|
||||||
(guide
|
(guide
|
||||||
(rect $xy unit unit))))
|
(rect 70 538 unit unit))))
|
||||||
(def color-4
|
(def color-4
|
||||||
(pick
|
(pick
|
||||||
(guide
|
(guide
|
||||||
(rect $xy unit unit))))
|
(rect 468 650 unit unit))))
|
||||||
(def color-5
|
(def color-5
|
||||||
(pick
|
(pick
|
||||||
(guide
|
(guide
|
||||||
(rect $xy unit unit))))
|
(rect 254 246 unit unit))))
|
||||||
(def color-6
|
(def color-6
|
||||||
(pick
|
(pick
|
||||||
(guide
|
(guide
|
||||||
(rect $xy unit unit))))
|
(rect 190 502 unit unit))))
|
||||||
(def color-7
|
(def color-7
|
||||||
(pick
|
(pick
|
||||||
(guide
|
(guide
|
||||||
(rect $xy unit unit))))
|
(rect 1084 446 unit unit))))
|
||||||
(def color-8
|
(def color-8
|
||||||
(pick
|
(pick
|
||||||
(guide
|
(guide
|
||||||
(rect $xy unit unit))))
|
(rect 1068 730 unit unit))))
|
||||||
|
|
||||||
; display
|
; display
|
||||||
|
|
||||||
(fill
|
(fill
|
||||||
(circle
|
(circle
|
||||||
(mul unit 2) pos-row-1 unit) color-1)
|
(mul 20 2) pos-row-1 18) color-1)
|
||||||
(fill
|
(fill
|
||||||
(circle
|
(circle
|
||||||
(mul unit 4) pos-row-1 unit) color-2)
|
(mul 20 4) pos-row-1 18) color-2)
|
||||||
(fill
|
(fill
|
||||||
(circle
|
(circle
|
||||||
(mul unit 6) pos-row-1 unit) color-3)
|
(mul 20 6) pos-row-1 18) color-3)
|
||||||
(fill
|
(fill
|
||||||
(circle
|
(circle
|
||||||
(mul unit 8) pos-row-1 unit) color-4)
|
(mul 20 8) pos-row-1 18) color-4)
|
||||||
(fill
|
(fill
|
||||||
(circle
|
(circle
|
||||||
(mul unit 3) pos-row-2 unit) color-5)
|
(mul 20 3) pos-row-2 18) color-5)
|
||||||
(fill
|
(fill
|
||||||
(circle
|
(circle
|
||||||
(mul unit 5) pos-row-2 unit) color-6)
|
(mul 20 5) pos-row-2 18) color-6)
|
||||||
(fill
|
(fill
|
||||||
(circle
|
(circle
|
||||||
(mul unit 7) pos-row-2 unit) color-7)
|
(mul 20 7) pos-row-2 18) color-7)
|
||||||
(fill
|
(fill
|
||||||
(circle
|
(circle
|
||||||
(mul unit 9) pos-row-2 unit) color-8)
|
(mul 20 9) pos-row-2 18) color-8)
|
||||||
;
|
;
|
||||||
(def res
|
(def res
|
||||||
(add color-1:hex ":" color-2:hex ":" color-3:hex ":" color-4:hex ":" color-5:hex ":" color-6:hex ":" color-7:hex ":" color-8:hex))
|
(add color-1:hex ":" color-2:hex ":" color-3:hex ":" color-4:hex ":" color-5:hex ":" color-6:hex ":" color-7:hex ":" color-8:hex))
|
||||||
|
1499
index.html
1499
index.html
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@ body { margin:0px; padding:0px; overflow:hidden; font-family:"input_mono_regular
|
|||||||
#ronin #wrapper #commander textarea { background: none; width: 100%; height: calc(100vh - 105px); resize: none; font-size: 12px;line-height: 15px; padding-right: 15px}
|
#ronin #wrapper #commander textarea { background: none; width: 100%; height: calc(100vh - 105px); resize: none; font-size: 12px;line-height: 15px; padding-right: 15px}
|
||||||
#ronin #wrapper #commander #status { position: absolute; bottom: 0px; line-height: 15px; height: 30px; overflow: hidden; width: calc(100% - 75px); padding-left:45px;}
|
#ronin #wrapper #commander #status { position: absolute; bottom: 0px; line-height: 15px; height: 30px; overflow: hidden; width: calc(100% - 75px); padding-left:45px;}
|
||||||
#ronin #wrapper #commander #status #run { display: block; width: 26px; height: 26px; position: absolute; top: 0px; border-radius: 15px; left:0px; cursor: pointer; border:2px solid #fff; transition: background-color 250ms, border-color 250ms}
|
#ronin #wrapper #commander #status #run { display: block; width: 26px; height: 26px; position: absolute; top: 0px; border-radius: 15px; left:0px; cursor: pointer; border:2px solid #fff; transition: background-color 250ms, border-color 250ms}
|
||||||
|
#ronin #wrapper #commander #status #run:hover { background: none }
|
||||||
#ronin.expand #wrapper #commander { width:100%; }
|
#ronin.expand #wrapper #commander { width:100%; }
|
||||||
#ronin #surface, #ronin #guide { position: absolute; top:0px; -webkit-user-select: none;-webkit-app-region: no-drag; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20'><circle cx='10' cy='10' r='1' fill='%23555'></circle></svg>"); background-size: 10px 10px; background-position: -4px -4px; width:100%; height:100%; transition: left 250ms, opacity 250ms; opacity: 1; }
|
#ronin #surface, #ronin #guide { position: absolute; top:0px; -webkit-user-select: none;-webkit-app-region: no-drag; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20'><circle cx='10' cy='10' r='1' fill='%23555'></circle></svg>"); background-size: 10px 10px; background-position: -4px -4px; width:100%; height:100%; transition: left 250ms, opacity 250ms; opacity: 1; }
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
/* global Commander */
|
/* global Commander */
|
||||||
/* global Surface */
|
/* global Surface */
|
||||||
/* global Library */
|
/* global Library */
|
||||||
/* global Lisp */
|
/* global Lain */
|
||||||
/* global Image */
|
/* global Image */
|
||||||
/* global requestAnimationFrame */
|
/* global requestAnimationFrame */
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ function Client () {
|
|||||||
this.commander = new Commander(this)
|
this.commander = new Commander(this)
|
||||||
this.surface = new Surface(this)
|
this.surface = new Surface(this)
|
||||||
this.library = new Library(this)
|
this.library = new Library(this)
|
||||||
this.lisp = new Lisp(this.library)
|
this.lain = new Lain(this.library)
|
||||||
|
|
||||||
this.bindings = {}
|
this.bindings = {}
|
||||||
|
|
||||||
@ -226,6 +226,7 @@ function Client () {
|
|||||||
}
|
}
|
||||||
const wh = rect.w + ' ' + rect.h
|
const wh = rect.w + ' ' + rect.h
|
||||||
const d = Math.sqrt(((line.a.x - line.b.x) * (line.a.x - line.b.x)) + ((line.a.y - line.b.y) * (line.a.y - line.b.y))).toFixed(2)
|
const d = Math.sqrt(((line.a.x - line.b.x) * (line.a.x - line.b.x)) + ((line.a.y - line.b.y) * (line.a.y - line.b.y))).toFixed(2)
|
||||||
|
const r = d
|
||||||
const a = Math.atan2(pos.y - line.a.y, pos.x - line.a.x).toFixed(2)
|
const a = Math.atan2(pos.y - line.a.y, pos.x - line.a.x).toFixed(2)
|
||||||
const circle = {
|
const circle = {
|
||||||
cx: line.a.x,
|
cx: line.a.x,
|
||||||
@ -239,6 +240,6 @@ function Client () {
|
|||||||
sa: 0,
|
sa: 0,
|
||||||
ea: a
|
ea: a
|
||||||
}
|
}
|
||||||
return { x, y, xy, wh, d, a, line, rect, pos, size, circle, arc, type, 'is-down': type !== 'mouse-up' ? true : null }
|
return { x, y, xy, wh, d, r, a, line, rect, pos, size, circle, arc, type, 'is-down': type !== 'mouse-up' ? true : null }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,21 +30,23 @@ function Commander (client) {
|
|||||||
this._input.onkeydown = (e) => {
|
this._input.onkeydown = (e) => {
|
||||||
if (e.keyCode === 9 || e.which === 9) { e.preventDefault(); this.inject(' ') }
|
if (e.keyCode === 9 || e.which === 9) { e.preventDefault(); this.inject(' ') }
|
||||||
}
|
}
|
||||||
|
client.surface.maximize()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.start = function () {
|
this.start = function () {
|
||||||
this.setStatus('Ready.')
|
|
||||||
this.load(this.splash)
|
|
||||||
this.show()
|
this.show()
|
||||||
|
this._input.value = this.splash
|
||||||
|
setTimeout(() => { this.run() }, 1000)
|
||||||
|
this.setStatus('Ready.')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.run = (txt = this._input.value) => {
|
this.run = (txt = this._input.value) => {
|
||||||
if (this._input.value.indexOf('$') > -1) { txt = this.clean(txt) }
|
if (this._input.value.indexOf('$') > -1) { txt = this.clean(txt) }
|
||||||
client.bindings = {}
|
client.bindings = {}
|
||||||
if (this._input.value.trim() === '') {
|
if (this._input.value.trim() === '') {
|
||||||
client.surface.maximize()
|
|
||||||
}
|
}
|
||||||
client.lisp.run(txt)
|
client.lain.run(`(${txt})`)
|
||||||
this.feedback()
|
this.feedback()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +182,7 @@ function Commander (client) {
|
|||||||
if (word === 'line') { return `(line ${shape.a.x} ${shape.a.y} ${shape.b.x} ${shape.b.y})` }
|
if (word === 'line') { return `(line ${shape.a.x} ${shape.a.y} ${shape.b.x} ${shape.b.y})` }
|
||||||
if (word === 'circle') { return `(circle ${shape.cx} ${shape.cy} ${shape.r})` }
|
if (word === 'circle') { return `(circle ${shape.cx} ${shape.cy} ${shape.r})` }
|
||||||
if (word === 'arc') { return `(arc ${shape.cx} ${shape.cy} ${shape.r} ${shape.sa} ${shape.ea})` }
|
if (word === 'arc') { return `(arc ${shape.cx} ${shape.cy} ${shape.r} ${shape.sa} ${shape.ea})` }
|
||||||
if (word === 'x' || word === 'y' || word === 'xy' || word === 'wh' || word === 'a') { return `${shape}` }
|
if (word === 'x' || word === 'y' || word === 'xy' || word === 'wh' || word === 'a' || word === 'r') { return `${shape}` }
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +242,7 @@ function Commander (client) {
|
|||||||
const name = this.getCurrentFunction()
|
const name = this.getCurrentFunction()
|
||||||
const fn = client.library[name]
|
const fn = client.library[name]
|
||||||
if (!fn) { return }
|
if (!fn) { return }
|
||||||
const fnString = fn.toString().replace('async ', '')
|
const fnString = fn.toString()
|
||||||
if (fnString.indexOf(') => {') < 0) { return }
|
if (fnString.indexOf(') => {') < 0) { return }
|
||||||
const fnParams = fnString.split(') => {')[0].substr(1).split(',').reduce((acc, item) => { return `${acc}${item.indexOf('=') > -1 ? '~' + item.split('=')[0].trim() : item} ` }, '').trim()
|
const fnParams = fnString.split(') => {')[0].substr(1).split(',').reduce((acc, item) => { return `${acc}${item.indexOf('=') > -1 ? '~' + item.split('=')[0].trim() : item} ` }, '').trim()
|
||||||
return `(${(name + ' ' + fnParams).trim()})`
|
return `(${(name + ' ' + fnParams).trim()})`
|
||||||
@ -248,17 +250,14 @@ function Commander (client) {
|
|||||||
|
|
||||||
// Splash
|
// Splash
|
||||||
|
|
||||||
this.splash = `
|
this.splash = `; Ronin v2.50
|
||||||
; Ronin v2.40
|
|
||||||
(clear)
|
|
||||||
(def logo-path "M60,60 L195,60 A45,45 0 0,1 240,105 A45,45 0 0,1 195,150 L60,150 M195,150 A45,45 0 0,1 240,195 L240,240 ")
|
(def logo-path "M60,60 L195,60 A45,45 0 0,1 240,105 A45,45 0 0,1 195,150 L60,150 M195,150 A45,45 0 0,1 240,195 L240,240 ")
|
||||||
(def pos-x
|
;
|
||||||
(mul frame:c 0.25))
|
(clear)
|
||||||
(def pos-y
|
(resize 600 600)
|
||||||
(sub frame:m 150))
|
|
||||||
(stroke
|
(stroke
|
||||||
(svg pos-x pos-y logo-path) theme:f_high 5)
|
(svg 140 140 logo-path) "black" 7)`
|
||||||
`
|
|
||||||
|
|
||||||
function insert (str, add, i) {
|
function insert (str, add, i) {
|
||||||
return [str.slice(0, i), `${add}`, str.slice(i)].join('')
|
return [str.slice(0, i), `${add}`, str.slice(i)].join('')
|
||||||
|
145
scripts/lib/lain.js
Normal file
145
scripts/lib/lain.js
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
// In the real world, it didn’t matter if I was there or not.
|
||||||
|
// When I realized that, I was no longer afraid of losing my body.
|
||||||
|
|
||||||
|
function Lain (lib = {}) {
|
||||||
|
const TYPES = { identifier: 0, number: 1, string: 2, bool: 3, symbol: 4 }
|
||||||
|
|
||||||
|
const Context = function (scope, parent) {
|
||||||
|
this.scope = scope
|
||||||
|
this.parent = parent
|
||||||
|
this.get = function (identifier) {
|
||||||
|
if (identifier in this.scope) {
|
||||||
|
return this.scope[identifier]
|
||||||
|
} else if (this.parent !== undefined) {
|
||||||
|
return this.parent.get(identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const special = {
|
||||||
|
let: function (input, context) {
|
||||||
|
const letContext = input[1].reduce(function (acc, x) {
|
||||||
|
acc.scope[x[0].value] = interpret(x[1], context)
|
||||||
|
return acc
|
||||||
|
}, new Context({}, context))
|
||||||
|
return interpret(input[2], letContext)
|
||||||
|
},
|
||||||
|
def: function (input, context) {
|
||||||
|
if (input.length !== 3) { console.warn('Lain', 'Invalid definition.'); return }
|
||||||
|
const identifier = input[1].host ? input[1].host : input[1].value
|
||||||
|
if (input[1].host) {
|
||||||
|
if (!context.scope[identifier]) { context.scope[identifier] = {} }
|
||||||
|
context.scope[identifier][input[1].value] = interpret(input[2], context)
|
||||||
|
return context.scope[identifier][input[1].value]
|
||||||
|
}
|
||||||
|
context.scope[identifier] = interpret(input[2], context)
|
||||||
|
return context.scope[identifier]
|
||||||
|
},
|
||||||
|
defn: function (input, context) {
|
||||||
|
const identifier = input[1].value
|
||||||
|
if (context.scope[identifier]) { console.warn('Lain', `Redefining function: ${identifier}`) }
|
||||||
|
const fnParams = input[2].type === TYPES.string && input[3] ? input[3] : input[2]
|
||||||
|
const fnBody = input[2].type === TYPES.string && input[4] ? input[4] : input[3]
|
||||||
|
context.scope[identifier] = function () {
|
||||||
|
const lambdaArguments = arguments
|
||||||
|
const lambdaScope = fnParams.reduce(function (acc, x, i) {
|
||||||
|
acc[x.value] = lambdaArguments[i]
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
return interpret(fnBody, new Context(lambdaScope, context))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
λ: function (input, context) {
|
||||||
|
return function () {
|
||||||
|
const lambdaArguments = arguments
|
||||||
|
const lambdaScope = input[1].reduce(function (acc, x, i) {
|
||||||
|
acc[x.value] = lambdaArguments[i]
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
return interpret(input[2], new Context(lambdaScope, context))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
if: function (input, context) {
|
||||||
|
return interpret(input[1], context) ? interpret(input[2], context) : input[3] ? interpret(input[3], context) : []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const interpretList = function (input, context) {
|
||||||
|
if (input.length > 0 && input[0].value in special) {
|
||||||
|
return special[input[0].value](input, context)
|
||||||
|
}
|
||||||
|
const list = []
|
||||||
|
for (let i = 0; i < input.length; i++) {
|
||||||
|
if (input[i].type === TYPES.symbol) {
|
||||||
|
if (input[i].host) {
|
||||||
|
const host = context.get(input[i].host)
|
||||||
|
if (host) {
|
||||||
|
list.push(host[input[i].value])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
list.push(obj => obj[input[i].value])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
list.push(interpret(input[i], context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list[0] instanceof Function ? list[0].apply(undefined, list.slice(1)) : list
|
||||||
|
}
|
||||||
|
|
||||||
|
const interpret = function (input, context) {
|
||||||
|
if (!input) { console.warn('Lain', context.scope); return null }
|
||||||
|
if (context === undefined) {
|
||||||
|
return interpret(input, new Context(lib))
|
||||||
|
} else if (input instanceof Array) {
|
||||||
|
return interpretList(input, context)
|
||||||
|
} else if (input.type === TYPES.identifier) {
|
||||||
|
return context.get(input.value)
|
||||||
|
} else if (input.type === TYPES.number || input.type === TYPES.symbol || input.type === TYPES.string || input.type === TYPES.bool) {
|
||||||
|
return input.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const categorize = function (input) {
|
||||||
|
if (!isNaN(parseFloat(input))) {
|
||||||
|
return { type: TYPES.number, value: parseFloat(input) }
|
||||||
|
} else if (input[0] === '"' && input.slice(-1) === '"') {
|
||||||
|
return { type: TYPES.string, value: input.slice(1, -1) }
|
||||||
|
} else if (input[0] === ':') {
|
||||||
|
return { type: TYPES.symbol, value: input.slice(1) }
|
||||||
|
} else if (input.indexOf(':') > 0) {
|
||||||
|
return { type: TYPES.symbol, host: input.split(':')[0], value: input.split(':')[1] }
|
||||||
|
} else if (input === 'true' || input === 'false') {
|
||||||
|
return { type: TYPES.bool, value: input === 'true' }
|
||||||
|
} else {
|
||||||
|
return { type: TYPES.identifier, value: input }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parenthesize = function (input, list) {
|
||||||
|
if (list === undefined) { return parenthesize(input, []) }
|
||||||
|
const token = input.shift()
|
||||||
|
if (token === undefined) {
|
||||||
|
return list.pop()
|
||||||
|
} else if (token === '(') {
|
||||||
|
list.push(parenthesize(input, []))
|
||||||
|
return parenthesize(input, list)
|
||||||
|
} else if (token === ')') {
|
||||||
|
return list
|
||||||
|
} else {
|
||||||
|
return parenthesize(input, list.concat(categorize(token)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenize = function (input) {
|
||||||
|
const i = input.replace(/^[\s]*;.*\n?/gm, '').split('"')
|
||||||
|
return i.map(function (x, i) {
|
||||||
|
return i % 2 === 0 ? x.replace(/\(/g, ' ( ').replace(/\)/g, ' ) ') : x.replace(/ /g, '!ws!')
|
||||||
|
}).join('"').trim().split(/\s+/).map(function (x) { return x.replace(/!ws!/g, ' ') })
|
||||||
|
}
|
||||||
|
|
||||||
|
this.run = (input) => {
|
||||||
|
return interpret(parenthesize(tokenize(input)))
|
||||||
|
}
|
||||||
|
}
|
@ -86,7 +86,7 @@ function Theme (client) {
|
|||||||
this.active[key] = hex
|
this.active[key] = hex
|
||||||
}
|
}
|
||||||
|
|
||||||
this.read = (key) => {
|
this.get = (key) => {
|
||||||
return this.active[key]
|
return this.active[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,22 +5,23 @@
|
|||||||
|
|
||||||
function Library (client) {
|
function Library (client) {
|
||||||
// IO
|
// IO
|
||||||
this.open = async (name, scale = 1) => { // Import a graphic and scale canvas to fit.
|
this.open = (name, scale = 1) => { // Import a graphic and scale canvas to fit.
|
||||||
const img = client.cache.get(name)
|
const img = client.cache.get(name)
|
||||||
if (!img) { client.log('No data for ' + name); return }
|
if (!img) { client.log('No data for ' + name); return }
|
||||||
const rect = this.rect(0, 0, img.width * scale, img.height * scale)
|
const rect = this.rect(0, 0, img.width * scale, img.height * scale)
|
||||||
await this.resize(rect.w, rect.h).then(this.import(name, rect))
|
this.resize(rect.w, rect.h)
|
||||||
|
this.import(name, rect)
|
||||||
return rect
|
return rect
|
||||||
}
|
}
|
||||||
|
|
||||||
this.import = async (name, shape, alpha = 1) => { // Imports a graphic file with format.
|
this.import = (name, shape, alpha = 1) => { // Imports a graphic file with format.
|
||||||
const img = client.cache.get(name)
|
const img = client.cache.get(name)
|
||||||
if (!img) { client.log('No data for ' + name); return }
|
if (!img) { client.log('No data for ' + name); return }
|
||||||
client.surface.draw(img, shape, alpha)
|
client.surface.draw(img, shape, alpha)
|
||||||
return shape || this.rect(0, 0, img.width, img.height)
|
return shape || this.rect(0, 0, img.width, img.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.export = async (name = 'ronin', type = 'image/png', quality = 1.0) => { // Exports a graphic file with format.
|
this.export = (name = 'ronin', type = 'image/png', quality = 1.0) => { // Exports a graphic file with format.
|
||||||
const ext = type === 'image/png' ? name + '.png' : name + '.jpg'
|
const ext = type === 'image/png' ? name + '.png' : name + '.jpg'
|
||||||
client.source.write(name, ext, client.surface.el.toDataURL(type, 1.0), type)
|
client.source.write(name, ext, client.surface.el.toDataURL(type, 1.0), type)
|
||||||
}
|
}
|
||||||
@ -79,36 +80,36 @@ function Library (client) {
|
|||||||
|
|
||||||
// Frame
|
// Frame
|
||||||
|
|
||||||
this.resize = async (w = client.surface.bounds().w, h = client.surface.bounds().h, fit = true) => { // Resizes the canvas to target w and h, returns the rect.
|
this.resize = (w = client.surface.bounds().w, h = client.surface.bounds().h, fit = true) => { // Resizes the canvas to target w and h, returns the rect.
|
||||||
if (w === this['get-frame']().w && h === this['get-frame']().h) { return }
|
if (w === this['get-frame']().w && h === this['get-frame']().h) { return }
|
||||||
const rect = { x: 0, y: 0, w, h }
|
const rect = { x: 0, y: 0, w, h }
|
||||||
const a = document.createElement('img')
|
const a = document.createElement('img')
|
||||||
const b = document.createElement('img')
|
const b = document.createElement('img')
|
||||||
a.src = client.surface.el.toDataURL()
|
a.src = client.surface.el.toDataURL()
|
||||||
await client.surface.resizeImage(a, b)
|
client.surface.resizeImage(a, b)
|
||||||
client.surface.resize(rect, fit)
|
client.surface.resize(rect, fit)
|
||||||
return client.surface.draw(b, rect)
|
return client.surface.draw(b, rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.rescale = async (w = 1, h) => { // Rescales the canvas to target ratio of w and h, returns the rect.
|
this.rescale = (w = 1, h) => { // Rescales the canvas to target ratio of w and h, returns the rect.
|
||||||
const rect = { x: 0, y: 0, w: this['get-frame']().w * w, h: this['get-frame']().h * (h || w) }
|
const rect = { x: 0, y: 0, w: this['get-frame']().w * w, h: this['get-frame']().h * (h || w) }
|
||||||
const a = document.createElement('img')
|
const a = document.createElement('img')
|
||||||
const b = document.createElement('img')
|
const b = document.createElement('img')
|
||||||
a.src = client.surface.el.toDataURL()
|
a.src = client.surface.el.toDataURL()
|
||||||
await client.surface.resizeImage(a, b)
|
client.surface.resizeImage(a, b)
|
||||||
client.surface.resize(rect, true)
|
client.surface.resize(rect, true)
|
||||||
return client.surface.draw(b, rect)
|
return client.surface.draw(b, rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.crop = async (rect = this['get-frame']()) => { // Crop canvas to rect.
|
this.crop = (rect = this['get-frame']()) => { // Crop canvas to rect.
|
||||||
return client.surface.crop(rect)
|
return client.surface.crop(rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.copy = async (rect = this['get-frame']()) => { // Copy a section of the canvas.
|
this.copy = (rect = this['get-frame']()) => { // Copy a section of the canvas.
|
||||||
return client.surface.copy(rect)
|
return client.surface.copy(rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.paste = async (copy, rect = this['get-frame']()) => { // Paste a section of the canvas.
|
this.paste = (copy, rect = this['get-frame']()) => { // Paste a section of the canvas.
|
||||||
return client.surface.paste(copy, rect)
|
return client.surface.paste(copy, rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +124,7 @@ function Library (client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.view = (a, b) => { // View a part of the canvas.
|
this.view = (a, b) => { // View a part of the canvas.
|
||||||
|
if (!a || !b) { return }
|
||||||
this.guide({ a: { x: a.x, y: a.y }, b: { x: b.x, y: b.y } })
|
this.guide({ a: { x: a.x, y: a.y }, b: { x: b.x, y: b.y } })
|
||||||
this.guide(a)
|
this.guide(a)
|
||||||
this.guide(b)
|
this.guide(b)
|
||||||
@ -142,8 +144,8 @@ function Library (client) {
|
|||||||
return this.color(this.floor(sum[0] / count), this.floor(sum[1] / count), this.floor(sum[2] / count))
|
return this.color(this.floor(sum[0] / count), this.floor(sum[1] / count), this.floor(sum[2] / count))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.orient = async (deg = 0) => { // Orient canvas with angle in degrees.
|
this.orient = (deg = 0) => { // Orient canvas with angle in degrees.
|
||||||
const copy = await this.copy()
|
const copy = this.copy()
|
||||||
const frame = this['get-frame']()
|
const frame = this['get-frame']()
|
||||||
const mode = Math.floor(deg / 90) % 4
|
const mode = Math.floor(deg / 90) % 4
|
||||||
const offset = { x: [0, 0, -frame.w, -frame.w], y: [0, -frame.h, -frame.h, 0] }
|
const offset = { x: [0, 0, -frame.w, -frame.w], y: [0, -frame.h, -frame.h, 0] }
|
||||||
@ -157,8 +159,8 @@ function Library (client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.mirror = { // Mirror canvas, methods: `x`, `y`.
|
this.mirror = { // Mirror canvas, methods: `x`, `y`.
|
||||||
x: async (j = 0) => {
|
x: (j = 0) => {
|
||||||
const copy = await this.copy()
|
const copy = this.copy()
|
||||||
const frame = this['get-frame']()
|
const frame = this['get-frame']()
|
||||||
client.surface.context.save()
|
client.surface.context.save()
|
||||||
client.surface.context.translate(frame.w, 0)
|
client.surface.context.translate(frame.w, 0)
|
||||||
@ -166,8 +168,8 @@ function Library (client) {
|
|||||||
client.surface.context.drawImage(copy, 0, 0)
|
client.surface.context.drawImage(copy, 0, 0)
|
||||||
client.surface.context.restore()
|
client.surface.context.restore()
|
||||||
},
|
},
|
||||||
y: async (j = 0) => {
|
y: (j = 0) => {
|
||||||
const copy = await this.copy()
|
const copy = this.copy()
|
||||||
const frame = this['get-frame']()
|
const frame = this['get-frame']()
|
||||||
client.surface.context.save()
|
client.surface.context.save()
|
||||||
client.surface.context.translate(0, frame.h)
|
client.surface.context.translate(0, frame.h)
|
||||||
@ -240,12 +242,12 @@ function Library (client) {
|
|||||||
|
|
||||||
// Pixels
|
// Pixels
|
||||||
|
|
||||||
this.pixels = async (fn, q = 1, rect = this['get-frame']()) => {
|
this.pixels = (fn, q = 1, rect = this['get-frame']()) => {
|
||||||
if (!fn) { console.warn('Unknown function'); return rect }
|
if (!fn) { console.warn('Unknown function'); return rect }
|
||||||
const img = client.surface.context.getImageData(rect.x, rect.y, rect.w, rect.h)
|
const img = client.surface.context.getImageData(rect.x, rect.y, rect.w, rect.h)
|
||||||
for (let i = 0, loop = img.data.length; i < loop; i += 4) {
|
for (let i = 0, loop = img.data.length; i < loop; i += 4) {
|
||||||
const pixel = [img.data[i], img.data[i + 1], img.data[i + 2], img.data[i + 3]]
|
const pixel = [img.data[i], img.data[i + 1], img.data[i + 2], img.data[i + 3]]
|
||||||
const processed = await fn(pixel, q)
|
const processed = fn(pixel, q)
|
||||||
img.data[i] = this.clamp(parseInt(processed[0]), 0, 255)
|
img.data[i] = this.clamp(parseInt(processed[0]), 0, 255)
|
||||||
img.data[i + 1] = this.clamp(parseInt(processed[1]), 0, 255)
|
img.data[i + 1] = this.clamp(parseInt(processed[1]), 0, 255)
|
||||||
img.data[i + 2] = this.clamp(parseInt(processed[2]), 0, 255)
|
img.data[i + 2] = this.clamp(parseInt(processed[2]), 0, 255)
|
||||||
@ -412,10 +414,10 @@ function Library (client) {
|
|||||||
|
|
||||||
// Arrays
|
// Arrays
|
||||||
|
|
||||||
this.each = async (arr, fn) => { // Run a function for each element in a list.
|
this.each = (arr, fn) => { // Run a function for each element in a list.
|
||||||
for (let i = 0; i < arr.length; i++) {
|
for (let i = 0; i < arr.length; i++) {
|
||||||
const arg = arr[i]
|
const arg = arr[i]
|
||||||
await fn(arg)
|
fn(arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,11 +435,11 @@ function Library (client) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.reduce = async (arr, fn, acc) => {
|
this.reduce = (arr, fn, acc) => {
|
||||||
const length = arr.length
|
const length = arr.length
|
||||||
let result = acc === undefined ? arr[0] : acc
|
let result = acc === undefined ? arr[0] : acc
|
||||||
for (let i = acc === undefined ? 1 : 0; i < length; i++) {
|
for (let i = acc === undefined ? 1 : 0; i < length; i++) {
|
||||||
result = await fn(result, arr[i], i, arr)
|
result = fn(result, arr[i], i, arr)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -589,9 +591,9 @@ function Library (client) {
|
|||||||
return a === b
|
return a === b
|
||||||
}
|
}
|
||||||
|
|
||||||
this.benchmark = async (fn) => { // Logs time taken to execute a function.
|
this.benchmark = (fn) => { // Logs time taken to execute a function.
|
||||||
const start = Date.now()
|
const start = Date.now()
|
||||||
const result = await fn()
|
const result = fn()
|
||||||
console.log(`time taken: ${Date.now() - start}ms`)
|
console.log(`time taken: ${Date.now() - start}ms`)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -174,24 +174,21 @@ function Surface (client) {
|
|||||||
// IO
|
// IO
|
||||||
|
|
||||||
this.draw = function (img, shape = this.getFrame(), alpha = 1) {
|
this.draw = function (img, shape = this.getFrame(), alpha = 1) {
|
||||||
return new Promise(resolve => {
|
this.context.globalAlpha = alpha
|
||||||
this.context.globalAlpha = alpha
|
if (isLine(shape)) {
|
||||||
if (isLine(shape)) {
|
this.context.drawImage(img, shape.a.x, shape.a.y, shape.b.x - shape.a.x, shape.b.y - shape.a.y)
|
||||||
this.context.drawImage(img, shape.a.x, shape.a.y, shape.b.x - shape.a.x, shape.b.y - shape.a.y)
|
} else if (isRect(shape)) {
|
||||||
} else if (isRect(shape)) {
|
const fit = fitRect({ w: img.width, h: img.height }, { w: shape.w, h: shape.h })
|
||||||
const fit = fitRect({ w: img.width, h: img.height }, { w: shape.w, h: shape.h })
|
this.context.drawImage(img, shape.x, shape.y, fit.w, fit.h)
|
||||||
this.context.drawImage(img, shape.x, shape.y, fit.w, fit.h)
|
} else if (isCircle(shape)) {
|
||||||
} else if (isCircle(shape)) {
|
const side = Math.sqrt(Math.pow(shape.r, 2) / 2)
|
||||||
const side = Math.sqrt(Math.pow(shape.r, 2) / 2)
|
const rect = { x: shape.cx - (side), y: shape.cy - (side), w: side * 2, h: side * 2 }
|
||||||
const rect = { x: shape.cx - (side), y: shape.cy - (side), w: side * 2, h: side * 2 }
|
const fit = fitRect({ w: img.width, h: img.height }, { w: rect.w, h: rect.h })
|
||||||
const fit = fitRect({ w: img.width, h: img.height }, { w: rect.w, h: rect.h })
|
this.context.drawImage(img, rect.x, rect.y, fit.w, fit.h)
|
||||||
this.context.drawImage(img, rect.x, rect.y, fit.w, fit.h)
|
} else {
|
||||||
} else {
|
this.context.drawImage(img, shape.x, shape.y, img.width, img.height)
|
||||||
this.context.drawImage(img, shape.x, shape.y, img.width, img.height)
|
}
|
||||||
}
|
this.context.globalAlpha = 1
|
||||||
this.context.globalAlpha = 1
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.crop = function (rect) {
|
this.crop = function (rect) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user