diff --git a/README.md b/README.md
index c953b45..1f1aa21 100644
--- a/README.md
+++ b/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
diff --git a/desktop/main.js b/desktop/main.js
index 5201349..33934bd 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -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
diff --git a/desktop/sources/index.html b/desktop/sources/index.html
index d3a5353..955ce4b 100644
--- a/desktop/sources/index.html
+++ b/desktop/sources/index.html
@@ -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");
diff --git a/desktop/sources/links/main.css b/desktop/sources/links/main.css
index 8abe5c2..4a9d7de 100644
--- a/desktop/sources/links/main.css
+++ b/desktop/sources/links/main.css
@@ -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,"); background-size: 10px 10px; background-position: -4px -4px; width:100%; height:100%; left:340px; transition: left 250ms}
diff --git a/desktop/sources/scripts/commander.js b/desktop/sources/scripts/commander.js
index b7aae9b..95892a5 100644
--- a/desktop/sources/scripts/commander.js
+++ b/desktop/sources/scripts/commander.js
@@ -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()
}
diff --git a/desktop/sources/scripts/library.js b/desktop/sources/scripts/library.js
index 7bd7b3e..ea3483a 100644
--- a/desktop/sources/scripts/library.js
+++ b/desktop/sources/scripts/library.js
@@ -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) : []
}
diff --git a/desktop/sources/scripts/surface.js b/desktop/sources/scripts/surface.js
index 36ab155..b2ee463 100644
--- a/desktop/sources/scripts/surface.js
+++ b/desktop/sources/scripts/surface.js
@@ -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) {
diff --git a/documentation.md b/documentation.md
deleted file mode 100644
index 706fee5..0000000
--- a/documentation.md
+++ /dev/null
@@ -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 )` returns true if all conditions are true
-
-`(or a b )` 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 )`
-
-`(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`
diff --git a/examples/animate.lisp b/examples/animate.lisp
index ed3eadf..4adaf64 100644
--- a/examples/animate.lisp
+++ b/examples/animate.lisp
@@ -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)
-)
\ No newline at end of file
+ (animate true))
\ No newline at end of file
diff --git a/examples/fs.lisp b/examples/fs.lisp
new file mode 100644
index 0000000..b63101e
--- /dev/null
+++ b/examples/fs.lisp
@@ -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)))
\ No newline at end of file
diff --git a/examples/g_spiral1.lisp b/examples/g_spiral1.lisp
deleted file mode 100644
index 0fc82e6..0000000
--- a/examples/g_spiral1.lisp
+++ /dev/null
@@ -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)
-)
diff --git a/examples/spiral.lisp b/examples/spiral.lisp
new file mode 100644
index 0000000..6ca0c55
--- /dev/null
+++ b/examples/spiral.lisp
@@ -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))
\ No newline at end of file