commit
56faf32c69
@ -62,13 +62,14 @@ npm start
|
|||||||
- `(range start end ~step)`
|
- `(range start end ~step)`
|
||||||
- `(get item key)` Gets an object's parameter with name.
|
- `(get item key)` Gets an object's parameter with name.
|
||||||
- `(set item key val)` Sets an object's parameter with name as value.
|
- `(set item key val)` Sets an object's parameter with name as value.
|
||||||
|
- `(of h ...keys)`
|
||||||
- `(frame)` Returns a rect of the frame.
|
- `(frame)` Returns a rect of the frame.
|
||||||
- `(center)` Returns a position of the center of the frame.
|
- `(center)` Returns a position of the center of the frame.
|
||||||
- `(scale rect w h)`
|
- `(scale rect w h)`
|
||||||
- `(resize ~w ~h)`
|
- `(resize w h)` Resizes the canvas to target w and h, returns the rect.
|
||||||
|
- `(rescale w h)` Rescales the canvas to target ratio of w and h, returns the rect.
|
||||||
- `(crop rect)`
|
- `(crop rect)`
|
||||||
- `(clone a b)`
|
- `(clone a b)`
|
||||||
- `(of h ...keys)`
|
|
||||||
- `(theme variable ~el)`
|
- `(theme variable ~el)`
|
||||||
- `(gradient [x1 y1 x2 y2] ~colors 'black'])`
|
- `(gradient [x1 y1 x2 y2] ~colors 'black'])`
|
||||||
- `(pixels rect fn q)`
|
- `(pixels rect fn q)`
|
||||||
@ -79,10 +80,9 @@ npm start
|
|||||||
- `(open path)` Imports a graphic file and resizes the frame.
|
- `(open path)` Imports a graphic file and resizes the frame.
|
||||||
- `(folder ~path)` Returns the content of a folder path.
|
- `(folder ~path)` Returns the content of a folder path.
|
||||||
- `(exit ~force)` Exits Ronin.
|
- `(exit ~force)` Exits Ronin.
|
||||||
- `(ronin)`
|
|
||||||
- `(time)` Returns timestamp in milliseconds.
|
- `(time)` Returns timestamp in milliseconds.
|
||||||
- `(animate ~play)` Toggles animation.
|
- `(animate ~play)` Toggles animation.
|
||||||
- `(js)`
|
- `(js)` Javascript interop.
|
||||||
- `(test name a b)`
|
- `(test name a b)`
|
||||||
|
|
||||||
## Extras
|
## Extras
|
||||||
|
@ -8,7 +8,7 @@ function Library (ronin) {
|
|||||||
this.export = (path, format = 'image/png', quality = 1.0) => { // Exports a graphic file with format.
|
this.export = (path, format = 'image/png', quality = 1.0) => { // Exports a graphic file with format.
|
||||||
if (!path) { console.warn('Missing export path'); return path }
|
if (!path) { console.warn('Missing export path'); return path }
|
||||||
var dataUrl = ronin.surface.el.toDataURL(format, quality)
|
var dataUrl = ronin.surface.el.toDataURL(format, quality)
|
||||||
const data = dataUrl.replace(/^data:image\/png;base64,/, '')
|
const data = dataUrl.replace(/^data:image\/png;base64,/, '').replace(/^data:image\/jpeg;base64,/, '')
|
||||||
fs.writeFileSync(path, data, 'base64')
|
fs.writeFileSync(path, data, 'base64')
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
@ -167,8 +167,13 @@ function Library (ronin) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.reduce = (fn, arr, acc = 0) => {
|
this.reduce = async (fn, arr, acc) => {
|
||||||
return arr.reduce(fn, acc)
|
const length = arr.length
|
||||||
|
let result = acc === undefined ? subject[0] : acc
|
||||||
|
for (let i = acc === undefined ? 1 : 0; i < length; i++) {
|
||||||
|
result = await fn(result, arr[i], i, arr)
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
this.len = (item) => { // Returns the length of a list.
|
this.len = (item) => { // Returns the length of a list.
|
||||||
@ -212,6 +217,12 @@ function Library (ronin) {
|
|||||||
return item[key]
|
return item[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.of = (h, ...keys) => {
|
||||||
|
return keys.reduce((acc, key) => {
|
||||||
|
return acc[key]
|
||||||
|
}, h)
|
||||||
|
}
|
||||||
|
|
||||||
// Frame
|
// Frame
|
||||||
|
|
||||||
this.frame = () => { // Returns a rect of the frame.
|
this.frame = () => { // Returns a rect of the frame.
|
||||||
@ -227,12 +238,22 @@ function Library (ronin) {
|
|||||||
return { x: rect.x, y: rect.y, w: rect.w * w, h: rect.h * h }
|
return { x: rect.x, y: rect.y, w: rect.w * w, h: rect.h * h }
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resize = async (w = 1, h = 1) => {
|
this.resize = async (w, h, fit = true) => { // Resizes the canvas to target w and h, returns the rect.
|
||||||
const rect = w <= 1 || h <= 1 ? { x: 0, y: 0, w: this.frame().w * w, h: this.frame().h * h } : { 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 = ronin.surface.el.toDataURL()
|
a.src = ronin.surface.el.toDataURL()
|
||||||
ronin.surface.resizeImage(a, b)
|
await ronin.surface.resizeImage(a, b)
|
||||||
|
ronin.surface.resize(rect, fit)
|
||||||
|
return ronin.surface.draw(b, rect)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rescale = async (w, h) => { // Rescales the canvas to target ratio of w and h, returns the rect.
|
||||||
|
const rect = { x: 0, y: 0, w: this.frame().w * w, h: this.frame().h * h }
|
||||||
|
const a = document.createElement('img')
|
||||||
|
const b = document.createElement('img')
|
||||||
|
a.src = ronin.surface.el.toDataURL()
|
||||||
|
await ronin.surface.resizeImage(a, b)
|
||||||
ronin.surface.resize(rect, true)
|
ronin.surface.resize(rect, true)
|
||||||
return ronin.surface.draw(b, rect)
|
return ronin.surface.draw(b, rect)
|
||||||
}
|
}
|
||||||
@ -241,21 +262,11 @@ function Library (ronin) {
|
|||||||
return ronin.surface.crop(rect)
|
return ronin.surface.crop(rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy/Paste
|
|
||||||
|
|
||||||
this.clone = (a, b) => {
|
this.clone = (a, b) => {
|
||||||
ronin.surface.clone(a, b)
|
ronin.surface.clone(a, b)
|
||||||
return [a, b]
|
return [a, b]
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should remove (of) for (get)?
|
|
||||||
|
|
||||||
this.of = (h, ...keys) => {
|
|
||||||
return keys.reduce((acc, key) => {
|
|
||||||
return acc[key]
|
|
||||||
}, h)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.theme = (variable, el = document.documentElement) => {
|
this.theme = (variable, el = document.documentElement) => {
|
||||||
// ex. (theme "f_main") -> :root { --f_main: "#fff" }
|
// ex. (theme "f_main") -> :root { --f_main: "#fff" }
|
||||||
return getComputedStyle(el).getPropertyValue(`--${variable}`)
|
return getComputedStyle(el).getPropertyValue(`--${variable}`)
|
||||||
@ -316,20 +327,17 @@ function Library (ronin) {
|
|||||||
ronin.source.quit(force)
|
ronin.source.quit(force)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client
|
|
||||||
this.ronin = ronin
|
|
||||||
|
|
||||||
// Livecoding
|
|
||||||
this.time = () => { // Returns timestamp in milliseconds.
|
this.time = () => { // Returns timestamp in milliseconds.
|
||||||
return Date.now
|
return Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.animate = (play = true) => { // Toggles animation.
|
this.animate = (play = true) => { // Toggles animation.
|
||||||
ronin.animate(play)
|
ronin.animate(play)
|
||||||
}
|
}
|
||||||
|
|
||||||
// javascript interop
|
this.js = () => { // Javascript interop.
|
||||||
this.js = window
|
return window
|
||||||
|
}
|
||||||
|
|
||||||
this.test = (name, a, b) => {
|
this.test = (name, a, b) => {
|
||||||
if (`${a}` !== `${b}`) {
|
if (`${a}` !== `${b}`) {
|
||||||
@ -339,4 +347,11 @@ function Library (ronin) {
|
|||||||
}
|
}
|
||||||
return a === b
|
return a === b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.benchmark = async (fn) => { // logs time taken to execute a function
|
||||||
|
const start = Date.now()
|
||||||
|
const result = await fn()
|
||||||
|
console.log(`time taken: ${Date.now() - start}ms`)
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,29 +33,21 @@ function Lisp (input, lib) {
|
|||||||
},
|
},
|
||||||
def: function (input, context) {
|
def: function (input, context) {
|
||||||
const identifier = input[1].value
|
const identifier = input[1].value
|
||||||
const value = (input[2].type === TYPES.string) ? input[3] : input[2]
|
const value = input[2].type === TYPES.string && input[3] ? input[3] : input[2]
|
||||||
if (input[2].type === TYPES.string) {
|
|
||||||
// docstring
|
|
||||||
console.log(input[2].value)
|
|
||||||
}
|
|
||||||
context.scope[identifier] = interpret(value, context)
|
context.scope[identifier] = interpret(value, context)
|
||||||
return value
|
return value
|
||||||
},
|
},
|
||||||
defn: function (input, context) {
|
defn: function (input, context) {
|
||||||
const identifier = input[1].value
|
const fnName = input[1].value
|
||||||
const argumentNames = (input[2].type === TYPES.string) ? input[3] : input[2]
|
const fnParams = input[2].type === TYPES.string && input[3] ? input[3] : input[2]
|
||||||
const functionBody = (input[2].type === TYPES.string) ? input[4] : input[3]
|
const fnBody = input[2].type === TYPES.string && input[4] ? input[4] : input[3]
|
||||||
if (input[2].type === TYPES.string) {
|
context.scope[fnName] = async function () {
|
||||||
// docstring
|
|
||||||
console.log(input[2].value)
|
|
||||||
}
|
|
||||||
context.scope[identifier] = async function () {
|
|
||||||
const lambdaArguments = arguments
|
const lambdaArguments = arguments
|
||||||
const lambdaScope = argumentNames.reduce(function (acc, x, i) {
|
const lambdaScope = fnParams.reduce(function (acc, x, i) {
|
||||||
acc[x.value] = lambdaArguments[i]
|
acc[x.value] = lambdaArguments[i]
|
||||||
return acc
|
return acc
|
||||||
}, {})
|
}, {})
|
||||||
return interpret(functionBody, new Context(lambdaScope, context))
|
return interpret(fnBody, new Context(lambdaScope, context))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
lambda: function (input, context) {
|
lambda: function (input, context) {
|
||||||
@ -80,7 +72,10 @@ function Lisp (input, lib) {
|
|||||||
if (input.length > 0 && input[0].value in special) {
|
if (input.length > 0 && input[0].value in special) {
|
||||||
return special[input[0].value](input, context)
|
return special[input[0].value](input, context)
|
||||||
}
|
}
|
||||||
const list = await Promise.all(input.map(function (x) { return interpret(x, context) }))
|
const list = []
|
||||||
|
for (let i = 0; i < input.length; i++) {
|
||||||
|
list.push(await interpret(input[i], context))
|
||||||
|
}
|
||||||
return list[0] instanceof Function ? list[0].apply(undefined, list.slice(1)) : list
|
return list[0] instanceof Function ? list[0].apply(undefined, list.slice(1)) : list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ function Ronin () {
|
|||||||
this.el.id = 'ronin'
|
this.el.id = 'ronin'
|
||||||
|
|
||||||
this.theme = new Theme(defaultTheme)
|
this.theme = new Theme(defaultTheme)
|
||||||
|
|
||||||
this.source = new Source(this)
|
this.source = new Source(this)
|
||||||
this.commander = new Commander(this)
|
this.commander = new Commander(this)
|
||||||
this.surface = new Surface(this)
|
this.surface = new Surface(this)
|
||||||
|
@ -15,6 +15,7 @@ function Surface (ronin) {
|
|||||||
this._guide.addEventListener('mousedown', ronin.commander.onMouseDown, false)
|
this._guide.addEventListener('mousedown', ronin.commander.onMouseDown, false)
|
||||||
this._guide.addEventListener('mousemove', ronin.commander.onMouseMove, false)
|
this._guide.addEventListener('mousemove', ronin.commander.onMouseMove, false)
|
||||||
this._guide.addEventListener('mouseup', ronin.commander.onMouseUp, false)
|
this._guide.addEventListener('mouseup', ronin.commander.onMouseUp, false)
|
||||||
|
// this.context.imageSmoothingEnabled = false
|
||||||
this.context.scale(this.ratio, this.ratio)
|
this.context.scale(this.ratio, this.ratio)
|
||||||
this.guide.scale(this.ratio, this.ratio)
|
this.guide.scale(this.ratio, this.ratio)
|
||||||
}
|
}
|
||||||
@ -159,28 +160,35 @@ function Surface (ronin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.resize = function (size, fit = false) {
|
this.resize = function (size, fit = false) {
|
||||||
|
const frame = this.getFrame()
|
||||||
|
if (frame.w === size.w && frame.h === size.h) { return }
|
||||||
console.log('Surface', `Resize: ${size.w}x${size.h}`)
|
console.log('Surface', `Resize: ${size.w}x${size.h}`)
|
||||||
this.el.width = size.w
|
this.el.width = size.w
|
||||||
this.el.height = size.h
|
this.el.height = size.h
|
||||||
this.el.style.width = size.w + 'px'
|
this.el.style.width = (size.w / this.ratio) + 'px'
|
||||||
this.el.style.height = size.h + 'px'
|
this.el.style.height = (size.h / this.ratio) + 'px'
|
||||||
this._guide.width = size.w
|
this._guide.width = size.w
|
||||||
this._guide.height = size.h
|
this._guide.height = size.h
|
||||||
this._guide.style.width = size.w + 'px'
|
this._guide.style.width = (size.w / this.ratio) + 'px'
|
||||||
this._guide.style.height = size.h + 'px'
|
this._guide.style.height = (size.h / this.ratio) + 'px'
|
||||||
if (fit === true) {
|
if (fit === true) {
|
||||||
this.fitWindow(size)
|
this.fitWindow(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.getFrame = function () {
|
||||||
|
return { x: 0, y: 0, w: this.el.width, h: this.el.height, t: 'rect' }
|
||||||
|
}
|
||||||
|
|
||||||
this.fitWindow = function (size) {
|
this.fitWindow = function (size) {
|
||||||
const win = require('electron').remote.getCurrentWindow()
|
const win = require('electron').remote.getCurrentWindow()
|
||||||
const pad = { w: ronin.commander.isVisible === true ? 400 : 60, h: 60 }
|
const pad = { w: ronin.commander.isVisible === true ? 400 : 60, h: 60 }
|
||||||
win.setSize(size.w + pad.w, size.h + pad.h, false)
|
if (size.w < 10 || size.h < 10) { return }
|
||||||
|
win.setSize(Math.floor((size.w / this.ratio) + pad.w), Math.floor((size.h / this.ratio) + pad.h), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.maximize = function () {
|
this.maximize = function () {
|
||||||
this.resize({ x: 0, y: 0, w: window.innerWidth - 60, h: window.innerHeight - 60, t: 'rect' })
|
this.resize({ x: 0, y: 0, w: (window.innerWidth * this.ratio) - 60, h: (window.innerHeight * this.ratio) - 60, t: 'rect' })
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onResize = function () {
|
this.onResize = function () {
|
||||||
@ -191,10 +199,6 @@ function Surface (ronin) {
|
|||||||
ronin.log(`resize ${f.w}x${f.h}`)
|
ronin.log(`resize ${f.w}x${f.h}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getFrame = function () {
|
|
||||||
return { x: 0, y: 0, w: this.el.width, h: this.el.height, t: 'rect' }
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getCrop = function (rect) {
|
this.getCrop = function (rect) {
|
||||||
const newCanvas = document.createElement('canvas')
|
const newCanvas = document.createElement('canvas')
|
||||||
newCanvas.width = rect.w
|
newCanvas.width = rect.w
|
||||||
@ -203,30 +207,34 @@ function Surface (ronin) {
|
|||||||
return newCanvas
|
return newCanvas
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resizeImage = function (src, dst, type = 'image/jpeg', quality = 0.92) {
|
this.resizeImage = function (src, dst, type = 'image/png', quality = 1.0) {
|
||||||
const tmp = new Image()
|
return new Promise(resolve => {
|
||||||
let canvas
|
const tmp = new Image()
|
||||||
let context
|
let canvas
|
||||||
let cW = src.naturalWidth
|
let context
|
||||||
let cH = src.naturalHeight
|
let cW = src.naturalWidth
|
||||||
tmp.src = src.src
|
let cH = src.naturalHeight
|
||||||
tmp.onload = function () {
|
tmp.src = src.src
|
||||||
canvas = document.createElement('canvas')
|
// resolve()
|
||||||
cW /= 2
|
tmp.onload = () => {
|
||||||
cH /= 2
|
canvas = document.createElement('canvas')
|
||||||
if (cW < src.width) {
|
cW /= 2
|
||||||
cW = src.width
|
cH /= 2
|
||||||
|
if (cW < src.width) {
|
||||||
|
cW = src.width
|
||||||
|
}
|
||||||
|
if (cH < src.height) {
|
||||||
|
cH = src.height
|
||||||
|
}
|
||||||
|
canvas.width = cW
|
||||||
|
canvas.height = cH
|
||||||
|
context = canvas.getContext('2d')
|
||||||
|
context.drawImage(tmp, 0, 0, cW, cH)
|
||||||
|
dst.src = canvas.toDataURL(type, quality)
|
||||||
|
if (cW <= src.width || cH <= src.height) { return resolve() }
|
||||||
|
tmp.src = dst.src
|
||||||
|
return resolve()
|
||||||
}
|
}
|
||||||
if (cH < src.height) {
|
})
|
||||||
cH = src.height
|
|
||||||
}
|
|
||||||
canvas.width = cW
|
|
||||||
canvas.height = cH
|
|
||||||
context = canvas.getContext('2d')
|
|
||||||
context.drawImage(tmp, 0, 0, cW, cH)
|
|
||||||
dst.src = canvas.toDataURL(type, quality)
|
|
||||||
if (cW <= src.width || cH <= src.height) { return }
|
|
||||||
tmp.src = dst.src
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
; animate
|
; animate
|
||||||
|
|
||||||
(
|
(
|
||||||
|
(clear)
|
||||||
(def t (sin (div (time) 100)))
|
(def t (sin (div (time) 100)))
|
||||||
|
|
||||||
(def pos (add 200 (mul 30 t)))
|
(def pos (add 200 30 (mul 30 t)))
|
||||||
(defn square (a) (rect a a a a))
|
(defn square (a) (rect a a a a))
|
||||||
(stroke (square pos) 1 "red")
|
(stroke (square pos) 1 "red")
|
||||||
|
|
||||||
(animate)
|
; set false to stop
|
||||||
;(animate false) to stop animation
|
(animate true)
|
||||||
)
|
)
|
9
examples/basics.lisp
Normal file
9
examples/basics.lisp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
; basics
|
||||||
|
(
|
||||||
|
; define a variable
|
||||||
|
(def a 25)
|
||||||
|
(echo a)
|
||||||
|
|
||||||
|
; define a function
|
||||||
|
(defn add-two (a) (add 2 a))
|
||||||
|
(echo (add-two 4)))
|
@ -1,13 +1,15 @@
|
|||||||
; dejong attractor
|
; dejong attractor
|
||||||
|
|
||||||
(
|
(
|
||||||
(clear)
|
(clear)
|
||||||
(defn point (x y color) (fill (circle x y 0.1) color))
|
(defn point (x y color)
|
||||||
|
(fill (rect x y 1 1) color))
|
||||||
|
|
||||||
(defn _dejong (x y a b c d)
|
(defn _dejong (x y a b c d)
|
||||||
(rest ((point
|
(rest ((point
|
||||||
(add 300 (mul 100 x))
|
(add 300 (mul 100 x))
|
||||||
(add 400 (mul 100 y))
|
(add 400 (mul 100 y))
|
||||||
"rgba(255,0,0,0.5)")
|
"red")
|
||||||
(add (sin (mul a y)) (mul x (cos (mul b x))))
|
(add (sin (mul a y)) (mul x (cos (mul b x))))
|
||||||
(add (mul x (sin (mul x c))) (cos (mul d y)))
|
(add (mul x (sin (mul x c))) (cos (mul d y)))
|
||||||
))
|
))
|
||||||
@ -23,5 +25,11 @@
|
|||||||
(2 1)
|
(2 1)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(dejong 128000 1.4 -2.3 2.4 -2.1)
|
(benchmark (lambda ()
|
||||||
|
(dejong 12800
|
||||||
|
(random -2 2)
|
||||||
|
(random -2 2)
|
||||||
|
(random -2 2)
|
||||||
|
(random -2 2)
|
||||||
|
)))
|
||||||
)
|
)
|
||||||
|
5
examples/import.lisp
Normal file
5
examples/import.lisp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
(
|
||||||
|
(def a (import
|
||||||
|
"../static/crystal.jpg"
|
||||||
|
(rect 0 0 400 400)))
|
||||||
|
(echo a))
|
Loading…
x
Reference in New Issue
Block a user