commit
3d4268fce0
19
README.md
19
README.md
@ -2,7 +2,13 @@
|
||||
|
||||
_"All I wanted, was a quick way of resizing a few photos.."_
|
||||
|
||||
Ronin is a [LISP](https://en.wikipedia.org/wiki/Lisp_(programming_language)) repl to create generative graphics currently under development. You can follow the daily progress on [Mastodon](https://merveilles.town/@neauoire/).
|
||||
The application was created to automate basic graphical tasks using a dialect of [LISP](https://en.wikipedia.org/wiki/Lisp_(programming_language)), it all went south when we started adding animation tools. You can look at these [example files](https://github.com/hundredrabbits/Ronin/tree/master/examples) to better understand how this all works.
|
||||
|
||||
```lisp
|
||||
; draw a red square
|
||||
(stroke
|
||||
(rect 30 30 100 100) 2 "red")
|
||||
```
|
||||
|
||||
## Install & Run
|
||||
|
||||
@ -31,6 +37,7 @@ npm start
|
||||
- `(stroke ~shape)` Strokes a shape.
|
||||
- `(fill ~rect)` Fills a shape.
|
||||
- `(clear ~rect)` Clears a rect.
|
||||
- `(concat ...items)`
|
||||
- `(add ...args)` Adds values.
|
||||
- `(sub ...args)` Subtracts values.
|
||||
- `(mul ...args)` Multiplies values.
|
||||
@ -54,7 +61,7 @@ npm start
|
||||
- `(or a b ...rest)` Returns true if at least one condition is true.
|
||||
- `(map fn arr)`
|
||||
- `(filter fn arr)`
|
||||
- `(reduce fn arr ~acc)`
|
||||
- `(reduce fn arr acc)`
|
||||
- `(len item)` Returns the length of a list.
|
||||
- `(first arr)` Returns the first item of a list.
|
||||
- `(last arr)` Returns the last
|
||||
@ -66,7 +73,7 @@ npm start
|
||||
- `(frame)` Returns a rect of the frame.
|
||||
- `(center)` Returns a position of the center of the frame.
|
||||
- `(scale rect w h)`
|
||||
- `(resize w h)` Resizes the canvas to target w and h, returns the rect.
|
||||
- `(resize w h ~fit)` 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)`
|
||||
- `(clone a b)`
|
||||
@ -78,12 +85,16 @@ npm start
|
||||
- `(echo ...args)`
|
||||
- `(str ...args)`
|
||||
- `(open path)` Imports a graphic file and resizes the frame.
|
||||
- `(folder ~path)` Returns the content of a folder path.
|
||||
- `(dir ~path)` Returns the content of a directory.
|
||||
- `(file ~path)` Returns the content of a file
|
||||
- `(dirpath ~path)` Returns the path of a directory.
|
||||
- `(filepath ~path)` Returns the path of a file
|
||||
- `(exit ~force)` Exits Ronin.
|
||||
- `(time)` Returns timestamp in milliseconds.
|
||||
- `(animate ~play)` Toggles animation.
|
||||
- `(js)` Javascript interop.
|
||||
- `(test name a b)`
|
||||
- `(benchmark fn)` logs time taken to execute a function
|
||||
|
||||
## Extras
|
||||
|
||||
|
@ -23,7 +23,7 @@ app.on('ready', () => {
|
||||
})
|
||||
|
||||
app.win.loadURL(`file://${__dirname}/sources/index.html`)
|
||||
app.inspect()
|
||||
// app.inspect()
|
||||
|
||||
app.win.on('closed', () => {
|
||||
win = null
|
||||
|
@ -45,6 +45,7 @@
|
||||
ronin.controller.add("default","View","Zoom Out",() => { ronin.modZoom(-0.25) },"CmdOrCtrl+-")
|
||||
ronin.controller.add("default","View","Zoom Reset",() => { ronin.modZoom(1,true) },"CmdOrCtrl+0")
|
||||
ronin.controller.add("default","View","Toggle Commander",() => { ronin.commander.toggle(); },"CmdOrCtrl+K");
|
||||
ronin.controller.add("default","View","Expand Commander",() => { ronin.commander.toggle(true); },"CmdOrCtrl+Shift+K");
|
||||
ronin.controller.add("default","Project","Run",() => { ronin.commander.run(); },"CmdOrCtrl+R");
|
||||
ronin.controller.add("default","Project","Reload Run",() => { ronin.source.revert(); ronin.commander.run(); },"CmdOrCtrl+Shift+R");
|
||||
ronin.controller.add("default","Project", "Animate",() => { ronin.animate(!ronin.always); },"CmdOrCtrl+Shift+T");
|
||||
|
@ -7,6 +7,7 @@ body { margin:0px; padding:0px; overflow:hidden; font-family:"input_mono_regular
|
||||
#ronin #wrapper #commander { z-index: 9000;position: relative;width: 310px;height: calc(100vh - 60px);-webkit-app-region: no-drag;padding-right: 30px;transition: margin-left 250ms;}
|
||||
#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 div#status { position: absolute; bottom: 0px; text-transform: lowercase;}
|
||||
#ronin.expand #wrapper #commander { width:100%; }
|
||||
#ronin.hidden #wrapper #commander { margin-left:-331px; }
|
||||
|
||||
#ronin canvas#surface,#ronin canvas#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%; left:340px; transition: left 250ms}
|
||||
|
@ -105,37 +105,43 @@ function Commander (ronin) {
|
||||
|
||||
this.onMouseDown = (e) => {
|
||||
this.mouseDown = true
|
||||
this.mouseRect.x = e.offsetX
|
||||
this.mouseRect.y = e.offsetY
|
||||
this.mouseRect.a.x = e.offsetX
|
||||
this.mouseRect.a.y = e.offsetY
|
||||
const offset = this.makeMouseOffset({ x: e.offsetX, y: e.offsetY })
|
||||
this.mouseRect.x = offset.x
|
||||
this.mouseRect.y = offset.y
|
||||
this.mouseRect.a.x = offset.x
|
||||
this.mouseRect.a.y = offset.y
|
||||
this.mouseRect.t = 'pos'
|
||||
this.capture()
|
||||
this.show()
|
||||
}
|
||||
|
||||
this.onMouseMove = (e) => {
|
||||
if (this.mouseDown === true) {
|
||||
this.mouseRect.w = e.offsetX - this.mouseRect.x
|
||||
this.mouseRect.h = e.offsetY - this.mouseRect.y
|
||||
this.mouseRect.b.x = e.offsetX
|
||||
this.mouseRect.b.y = e.offsetY
|
||||
this.commit()
|
||||
}
|
||||
if (this.mouseDown !== true) { return }
|
||||
const offset = this.makeMouseOffset({ x: e.offsetX, y: e.offsetY })
|
||||
this.mouseRect.w = offset.x - this.mouseRect.x
|
||||
this.mouseRect.h = offset.y - this.mouseRect.y
|
||||
this.mouseRect.b.x = offset.x
|
||||
this.mouseRect.b.y = offset.y
|
||||
this.commit()
|
||||
}
|
||||
|
||||
this.onMouseUp = (e) => {
|
||||
this.mouseDown = false
|
||||
this.mouseRect.w = e.offsetX - this.mouseRect.x
|
||||
this.mouseRect.h = e.offsetY - this.mouseRect.y
|
||||
this.mouseRect.b.x = e.offsetX
|
||||
this.mouseRect.b.y = e.offsetY
|
||||
const offset = this.makeMouseOffset({ x: e.offsetX, y: e.offsetY })
|
||||
this.mouseRect.w = offset.x - this.mouseRect.x
|
||||
this.mouseRect.h = offset.y - this.mouseRect.y
|
||||
this.mouseRect.b.x = offset.x
|
||||
this.mouseRect.b.y = offset.y
|
||||
this.mouseRect.t = ''
|
||||
this.commit()
|
||||
this._input.focus()
|
||||
ronin.surface.clearGuide()
|
||||
}
|
||||
|
||||
this.makeMouseOffset = (pos) => {
|
||||
return { x: pos.x * ronin.surface.ratio, y: pos.y * ronin.surface.ratio }
|
||||
}
|
||||
|
||||
// Injection
|
||||
|
||||
this.cache = ''
|
||||
@ -188,9 +194,9 @@ function Commander (ronin) {
|
||||
|
||||
// Display
|
||||
|
||||
this.show = function () {
|
||||
this.show = function (expand = false) {
|
||||
if (this.isVisible === true) { return }
|
||||
ronin.el.className = ''
|
||||
ronin.el.className = expand ? 'expand' : ''
|
||||
this.isVisible = true
|
||||
}
|
||||
|
||||
@ -200,9 +206,9 @@ function Commander (ronin) {
|
||||
this.isVisible = false
|
||||
}
|
||||
|
||||
this.toggle = function () {
|
||||
this.toggle = function (expand = false) {
|
||||
if (this.isVisible !== true) {
|
||||
this.show()
|
||||
this.show(expand)
|
||||
} else {
|
||||
this.hide()
|
||||
}
|
||||
|
@ -60,6 +60,12 @@ function Library (ronin) {
|
||||
return rect
|
||||
}
|
||||
|
||||
// Strings
|
||||
|
||||
this.concat = function (...items) {
|
||||
return items.reduce((acc, item) => { return `${acc}${item}` }, '')
|
||||
}
|
||||
|
||||
// Math
|
||||
|
||||
this.add = (...args) => { // Adds values.
|
||||
@ -318,8 +324,22 @@ function Library (ronin) {
|
||||
this.open = async (path) => { // Imports a graphic file and resizes the frame.
|
||||
return ronin.surface.open(path)
|
||||
}
|
||||
|
||||
// File System
|
||||
|
||||
this.folder = (path = ronin.source.path) => { // Returns the content of a folder path.
|
||||
this.dir = (path = ronin.source.path) => { // Returns the content of a directory.
|
||||
return fs.existsSync(path) ? fs.readdirSync(path) : []
|
||||
}
|
||||
|
||||
this.file = (path = ronin.source.path) => { // Returns the content of a file
|
||||
return fs.existsSync(path) ? fs.readFileSync(p, 'utf8') : ''
|
||||
}
|
||||
|
||||
this.dirpath = (path = ronin.source.path) => { // Returns the path of a directory.
|
||||
return require('path').dirname(path)
|
||||
}
|
||||
|
||||
this.filepath = (path = ronin.source.path) => { // Returns the path of a file
|
||||
return fs.existsSync(path) ? fs.readdirSync(path) : []
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ function Surface (ronin) {
|
||||
this.ratio = window.devicePixelRatio
|
||||
// Contexts
|
||||
this.context = this.el.getContext('2d')
|
||||
this.guide = this.el.getContext('2d')
|
||||
this.guide = this._guide.getContext('2d')
|
||||
|
||||
this.install = function (host) {
|
||||
host.appendChild(this.el)
|
||||
@ -15,9 +15,6 @@ function Surface (ronin) {
|
||||
this._guide.addEventListener('mousedown', ronin.commander.onMouseDown, false)
|
||||
this._guide.addEventListener('mousemove', ronin.commander.onMouseMove, false)
|
||||
this._guide.addEventListener('mouseup', ronin.commander.onMouseUp, false)
|
||||
// this.context.imageSmoothingEnabled = false
|
||||
this.context.scale(this.ratio, this.ratio)
|
||||
this.guide.scale(this.ratio, this.ratio)
|
||||
}
|
||||
|
||||
this.start = function () {
|
||||
@ -151,8 +148,8 @@ function Surface (ronin) {
|
||||
context.clearRect(rect.x, rect.y, rect.w, rect.h)
|
||||
}
|
||||
|
||||
this.clearGuide = function () {
|
||||
this.clear(ronin.surface.getFrame(), ronin.surface.guide)
|
||||
this.clearGuide = function (rect = this.getFrame(), context = this.guide) {
|
||||
context.clearRect(rect.x, rect.y, rect.w, rect.h)
|
||||
}
|
||||
|
||||
this.clone = function (a, b) {
|
||||
|
159
documentation.md
159
documentation.md
@ -1,159 +0,0 @@
|
||||
# Functions
|
||||
|
||||
## IO
|
||||
|
||||
`(open path)`
|
||||
|
||||
`(export path type quality)`
|
||||
|
||||
`(draw path rect)`
|
||||
|
||||
`(resize width height)`
|
||||
|
||||
`(crop rect)`
|
||||
|
||||
`(folder path)`
|
||||
|
||||
`(exit)`
|
||||
|
||||
## Logic
|
||||
|
||||
`(gt a b)` check if `a` is greater than `b`
|
||||
|
||||
`(lt a b)` check if `a` is lower than `b`
|
||||
|
||||
`(eq a b)` check if `a` is equal to `b`
|
||||
|
||||
`(and a b <c d...>)` returns true if all conditions are true
|
||||
|
||||
`(or a b <cd...>)` returns true if at least one condition is true
|
||||
|
||||
## Arrays
|
||||
|
||||
`(map function array)`
|
||||
|
||||
`(filter function array)`
|
||||
|
||||
`(reduce function array accumulator)`
|
||||
|
||||
`(len array)`
|
||||
|
||||
`(first array)`
|
||||
|
||||
`(last array)`
|
||||
|
||||
`(rest array)`
|
||||
|
||||
`(range start end step)`
|
||||
|
||||
## Shapes
|
||||
|
||||
`(pos x y)`
|
||||
|
||||
`(size w h)`
|
||||
|
||||
`(rect x y w h t)`
|
||||
|
||||
`(circle x y r)`
|
||||
|
||||
`(line start end)`
|
||||
|
||||
`(text x y g string font)`
|
||||
|
||||
`(svg data)`
|
||||
|
||||
## Helpers
|
||||
|
||||
`(frame)`
|
||||
|
||||
`(center)`
|
||||
|
||||
`(scale rect width height)`
|
||||
|
||||
## Copy/Paste
|
||||
|
||||
`(clone start end)` clone start `rect` into end `rect`
|
||||
|
||||
`(stroke shape thickness color)`
|
||||
|
||||
`(fill shape color)`
|
||||
|
||||
`(clear shape)`
|
||||
|
||||
## Objects
|
||||
|
||||
`(get item key <keys>)`
|
||||
|
||||
`(set item key val)`
|
||||
|
||||
## Colors
|
||||
|
||||
`(theme variable)`
|
||||
|
||||
`(gradient (x1,y1,x2,y2) colors)`
|
||||
|
||||
`(pixels rect function q)`
|
||||
|
||||
`(saturation pixel q)`
|
||||
|
||||
`(contrast pixel q)`
|
||||
|
||||
## Math
|
||||
|
||||
`(add ...values)`
|
||||
|
||||
`(sub...values)`
|
||||
|
||||
`(mul ...values)`
|
||||
|
||||
`(div ...values)`
|
||||
|
||||
`(mod a b)`
|
||||
|
||||
`(clamp value min max)`
|
||||
|
||||
`(step value step)`
|
||||
|
||||
`(min a b)`
|
||||
|
||||
`(max a b)`
|
||||
|
||||
`(ceil value)`
|
||||
|
||||
`(floor value)`
|
||||
|
||||
`(sin a)`
|
||||
|
||||
`(cos a)`
|
||||
|
||||
`PI, TWO_PI`
|
||||
|
||||
`(random)`
|
||||
|
||||
`(random start end)`
|
||||
|
||||
`(random max)`
|
||||
|
||||
## Generics
|
||||
|
||||
`(echo args)`
|
||||
|
||||
`(str args)`
|
||||
|
||||
`(test name value expectedValue)`
|
||||
|
||||
## Livecoding
|
||||
|
||||
`(time)` returns timestamp in milliseconds
|
||||
|
||||
`(animate)` start animation
|
||||
|
||||
`(animate false)` stop animation
|
||||
|
||||
## Javascript interop
|
||||
|
||||
`js`
|
||||
|
||||
## Client
|
||||
|
||||
`ronin`
|
@ -1,13 +1,17 @@
|
||||
; animate
|
||||
|
||||
(
|
||||
(clear)
|
||||
(def t (sin (div (time) 100)))
|
||||
|
||||
(def pos (add 200 30 (mul 30 t)))
|
||||
(defn square (a) (rect a a a a))
|
||||
(stroke (square pos) 1 "red")
|
||||
|
||||
(clear)
|
||||
(def t
|
||||
(sin
|
||||
(div
|
||||
(time) 100)))
|
||||
(def pos
|
||||
(add 200 30
|
||||
(mul 30 t)))
|
||||
(defn square
|
||||
(a)
|
||||
(rect a a a a))
|
||||
(stroke
|
||||
(square pos) 1 "red")
|
||||
; set false to stop
|
||||
(animate true)
|
||||
)
|
||||
(animate true))
|
14
examples/fs.lisp
Normal file
14
examples/fs.lisp
Normal file
@ -0,0 +1,14 @@
|
||||
; filesystem
|
||||
(
|
||||
; get files
|
||||
(def files
|
||||
(dir
|
||||
(dirpath)))
|
||||
; pick a random file
|
||||
(def random-index
|
||||
(floor
|
||||
(random
|
||||
(len files))))
|
||||
; print random file name
|
||||
(echo
|
||||
(get files random-index)))
|
@ -1,29 +0,0 @@
|
||||
; animated recusive spiral
|
||||
; by @local_guru
|
||||
(
|
||||
(def start (get ronin "animate"))
|
||||
(clear)
|
||||
(defn rec
|
||||
(v)
|
||||
(if (gt v 0)
|
||||
((stroke
|
||||
(circle
|
||||
(add 300
|
||||
(mul (cos (add (div v 17) (div (time) 2000)))
|
||||
(div v 2)
|
||||
)
|
||||
)
|
||||
(add 300
|
||||
(mul (sin (div v 11))
|
||||
(div v 2)
|
||||
)
|
||||
)
|
||||
(div v 2))
|
||||
1 "rgba(255,255,255,0.1")
|
||||
(rec (sub v 0.3))
|
||||
)
|
||||
)
|
||||
)
|
||||
(start)
|
||||
(rec 300)
|
||||
)
|
30
examples/spiral.lisp
Normal file
30
examples/spiral.lisp
Normal file
@ -0,0 +1,30 @@
|
||||
; animated recusive spiral
|
||||
; by @local_guru
|
||||
(
|
||||
(clear)
|
||||
(defn rec
|
||||
(v)
|
||||
(if
|
||||
(gt v 0)
|
||||
(
|
||||
(stroke
|
||||
(circle
|
||||
(add 375
|
||||
(mul
|
||||
(cos
|
||||
(add
|
||||
(div v 17)
|
||||
(div
|
||||
(time) 2000)))
|
||||
(div v 2)))
|
||||
(add 300
|
||||
(mul
|
||||
(sin
|
||||
(div v 11))
|
||||
(div v 2)))
|
||||
(div v 2)) 1 "rgba(114,222, 194,0.1)")
|
||||
(rec
|
||||
(sub v 0.3)))))
|
||||
; set false to stop
|
||||
(animate true)
|
||||
(rec 300))
|
Loading…
x
Reference in New Issue
Block a user