aboutsummaryrefslogtreecommitdiffstats
path: root/root
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2018-11-06 07:19:59 +0000
committers-ol <s-ol@users.noreply.github.com>2018-11-06 07:19:59 +0000
commita7e539c272ffcd9e14fb58f8c24714cdff8e7c17 (patch)
tree404f92906bd402b1c394f7b521508b5138e76d98 /root
parentinspect mode wip (diff)
parentadd metadata for compilation (diff)
downloadmmm-a7e539c272ffcd9e14fb58f8c24714cdff8e7c17.tar.gz
mmm-a7e539c272ffcd9e14fb58f8c24714cdff8e7c17.zip
Merge branch 'tru-fs' into inspect-mode
Diffstat (limited to 'root')
-rw-r--r--root/animations/init.moon27
-rw-r--r--root/animations/koch.moon112
-rw-r--r--root/animations/koch/description: text$plain1
-rw-r--r--root/animations/koch/text$moonscript -> mmm$component.moon104
-rw-r--r--root/animations/text$moonscript -> fn -> mmm$dom.moon18
-rw-r--r--root/animations/title: text$plain1
-rw-r--r--root/animations/twisted.moon51
-rw-r--r--root/animations/twisted/description: text$plain1
-rw-r--r--root/animations/twisted/text$moonscript -> mmm$component.moon43
-rw-r--r--root/articles/init.moon27
-rw-r--r--root/articles/mmmfs/description: text$plain1
-rw-r--r--root/articles/mmmfs/empty/title: text$plain1
-rw-r--r--root/articles/mmmfs/image/URL -> image$png1
-rw-r--r--root/articles/mmmfs/image/preview: text$moonscript -> fn -> mmm$dom.moon5
-rw-r--r--root/articles/mmmfs/image/title: text$plain1
-rw-r--r--root/articles/mmmfs/init.moon285
-rw-r--r--root/articles/mmmfs/markdown/text$markdown.md6
-rw-r--r--root/articles/mmmfs/markdown/title: text$plain1
-rw-r--r--root/articles/mmmfs/text$markdown.md7
-rw-r--r--root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon235
-rw-r--r--root/articles/realities.moon550
-rw-r--r--root/articles/realities/description: text$plain1
-rw-r--r--root/articles/realities/text$moonscript -> mmm$dom.moon542
-rw-r--r--root/articles/text$moonscript -> fn -> mmm$dom18
-rw-r--r--root/articles/title: text$plain1
-rw-r--r--root/experiments/center_of_mass.moon179
-rw-r--r--root/experiments/center_of_mass/description: text$plain1
-rw-r--r--root/experiments/center_of_mass/text$moonscript -> mmm$dom.moon171
-rw-r--r--root/experiments/init.moon27
-rw-r--r--root/experiments/tags/description: text$plain1
-rw-r--r--root/experiments/tags/init.moon99
-rw-r--r--root/experiments/tags/tags: text$moonscript -> table.moon (renamed from root/experiments/tags/tags.moon)0
-rw-r--r--root/experiments/tags/text$moonscript -> fn -> mmm$component.moon92
-rw-r--r--root/experiments/text$moonscript -> fn -> mmm$dom.moon18
-rw-r--r--root/experiments/title: text$plain1
-rw-r--r--root/init.moon69
-rw-r--r--root/meta/init.moon36
-rw-r--r--root/meta/mmm.dom/description: text$plain1
-rw-r--r--root/meta/mmm.dom/text$moonscript -> mmm$dom.moon172
-rw-r--r--root/meta/mmm_dom.moon179
-rw-r--r--root/meta/test_component.moon254
-rw-r--r--root/meta/test_mmm.component/description: text$plain1
-rw-r--r--root/meta/test_mmm.component/text$moonscript -> mmm$dom.moon246
-rw-r--r--root/meta/text$moonscript -> fn -> mmm$dom.moon25
-rw-r--r--root/meta/title: text$plain1
-rw-r--r--root/meta/todo.moon42
-rw-r--r--root/meta/todo/description: text$plain1
-rw-r--r--root/meta/todo/text$moonscript -> mmm$component.moon34
-rw-r--r--root/text$moonscript -> fn -> mmm$dom.moon57
49 files changed, 1810 insertions, 1937 deletions
diff --git a/root/animations/init.moon b/root/animations/init.moon
deleted file mode 100644
index ff8ef4b..0000000
--- a/root/animations/init.moon
+++ /dev/null
@@ -1,27 +0,0 @@
-import div, h3, ul, li, a from require 'mmm.dom'
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-require = relative ...
-
-Fileder {
- 'name: alpha': 'animations',
- 'title: text/plain': 'canvas animations',
- 'fn -> mmm/dom': (path) => div {
- h3 @gett 'title: text/plain', style: { 'margin-bottom': '-.5em' },
- ul for child in *@children
- name = child\gett 'name: alpha'
- desc = child\gett 'description: text/plain'
- li {
- a name, {
- href: child.path,
- onclick: (e) =>
- e\preventDefault!
- BROWSER\navigate child.path
- },
- ': ', desc
- }
- }
-
- require '.twisted'
- require '.koch'
-}
diff --git a/root/animations/koch.moon b/root/animations/koch.moon
deleted file mode 100644
index f7927d4..0000000
--- a/root/animations/koch.moon
+++ /dev/null
@@ -1,112 +0,0 @@
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-
-with Fileder {
- 'name: alpha': 'koch',
- 'description: text/plain': "lil' fractal thing",
- }
-
- if MODE == 'CLIENT'
- Math = window.Math
-
- import CanvasApp from require 'mmm.canvasapp'
- import hsl from require 'mmm.color'
-
- class KochDemo extends CanvasApp
- width: 600
- height: 600
- length: math.pi * 2
-
- new: (@iterations=3) =>
- super true
- hue = Math.random!
- @background = {1 - hue, .3, .3}
-
- @shades = setmetatable {}, __index: (tbl, key) ->
- with val = hsl { hue, .7, .9 - .5 * (key / @iterations)} do rawset tbl, key, val
-
- a_sixth = math.pi / 3
- a_third = 2 * a_sixth
- cossin = (a) -> (math.cos a), math.sin a
- triangle: (color) =>
- @ctx.fillStyle = color
- @ctx\beginPath!
- @ctx\moveTo cossin 0
- @ctx\lineTo cossin a_third
- @ctx\lineTo cossin 2*a_third
- @ctx\fill!
-
- update: (dt) =>
- super dt * 1.6
-
- draw: =>
- @ctx.fillStyle = hsl @background
- @ctx\fillRect 0, 0, @width, @height
-
- @ctx\translate @width/2, @height/2
- s = .3 * math.min @width, @height
- @ctx\scale s, s
-
- _scale = 0.8 + 0.2 * math.sin math.pi + @time
-
- ttime = @time - math.pi/2
- transfer, flipped = 0
- if ttime > 0 and ttime < math.pi
- transfer = .5 - .5 * math.cos ttime
- flipped = true
-
- draw = (i, pop) ->
- @triangle @shades[i]
-
- extra = not pop and flipped
- return unless i > (if extra then -1 else 0)
-
- scale = _scale
- if (pop and i < 1) or (not pop and i < 0)
- scale = transfer
-
- @ctx\save!
- @ctx\rotate -(a_sixth + a_third)
- @ctx\scale scale, scale
-
- for o=1,2
- @ctx\rotate a_third
- @ctx\save!
- @ctx\translate .5 + .5/scale, 0
- draw i - 1, pop
- @ctx\restore!
-
- @ctx\restore!
-
- @ctx\rotate a_sixth/2
- @ctx\translate -transfer, 0
- @ctx\rotate a_sixth * transfer
-
- @triangle @shades[3 - transfer]
-
- @ctx\save!
- @ctx\rotate a_sixth
- @ctx\scale _scale, _scale
-
- @ctx\save!
- @ctx\translate .5 + .5/_scale, 0
- draw 2 - transfer
- @ctx\restore!
-
- @ctx\rotate a_third
-
- @ctx\save!
- @ctx\translate .5 + .5/_scale, 0
- draw 2 - transfer
- @ctx\restore!
-
- @ctx\rotate a_third
-
- @ctx\save!
- @ctx\translate .5 + .5/_scale, 0
- draw 2 + transfer, true
- @ctx\restore!
-
- @ctx\restore!
-
- .props['fn -> mmm/component'] = => KochDemo!
diff --git a/root/animations/koch/description: text$plain b/root/animations/koch/description: text$plain
new file mode 100644
index 0000000..a0b96e7
--- /dev/null
+++ b/root/animations/koch/description: text$plain
@@ -0,0 +1 @@
+lil' fractal thing
diff --git a/root/animations/koch/text$moonscript -> mmm$component.moon b/root/animations/koch/text$moonscript -> mmm$component.moon
new file mode 100644
index 0000000..4f97329
--- /dev/null
+++ b/root/animations/koch/text$moonscript -> mmm$component.moon
@@ -0,0 +1,104 @@
+assert MODE == 'CLIENT', '[nossr]'
+Math = window.Math
+
+import CanvasApp from require 'mmm.canvasapp'
+import hsl from require 'mmm.color'
+
+class KochDemo extends CanvasApp
+ width: 600
+ height: 600
+ length: math.pi * 2
+
+ new: (@iterations=3) =>
+ super true
+ hue = Math.random!
+ @background = {1 - hue, .3, .3}
+
+ @shades = setmetatable {}, __index: (tbl, key) ->
+ with val = hsl { hue, .7, .9 - .5 * (key / @iterations)} do rawset tbl, key, val
+
+ a_sixth = math.pi / 3
+ a_third = 2 * a_sixth
+ cossin = (a) -> (math.cos a), math.sin a
+ triangle: (color) =>
+ @ctx.fillStyle = color
+ @ctx\beginPath!
+ @ctx\moveTo cossin 0
+ @ctx\lineTo cossin a_third
+ @ctx\lineTo cossin 2*a_third
+ @ctx\fill!
+
+ update: (dt) =>
+ super dt * 1.6
+
+ draw: =>
+ @ctx.fillStyle = hsl @background
+ @ctx\fillRect 0, 0, @width, @height
+
+ @ctx\translate @width/2, @height/2
+ s = .3 * math.min @width, @height
+ @ctx\scale s, s
+
+ _scale = 0.8 + 0.2 * math.sin math.pi + @time
+
+ ttime = @time - math.pi/2
+ transfer, flipped = 0
+ if ttime > 0 and ttime < math.pi
+ transfer = .5 - .5 * math.cos ttime
+ flipped = true
+
+ draw = (i, pop) ->
+ @triangle @shades[i]
+
+ extra = not pop and flipped
+ return unless i > (if extra then -1 else 0)
+
+ scale = _scale
+ if (pop and i < 1) or (not pop and i < 0)
+ scale = transfer
+
+ @ctx\save!
+ @ctx\rotate -(a_sixth + a_third)
+ @ctx\scale scale, scale
+
+ for o=1,2
+ @ctx\rotate a_third
+ @ctx\save!
+ @ctx\translate .5 + .5/scale, 0
+ draw i - 1, pop
+ @ctx\restore!
+
+ @ctx\restore!
+
+ @ctx\rotate a_sixth/2
+ @ctx\translate -transfer, 0
+ @ctx\rotate a_sixth * transfer
+
+ @triangle @shades[3 - transfer]
+
+ @ctx\save!
+ @ctx\rotate a_sixth
+ @ctx\scale _scale, _scale
+
+ @ctx\save!
+ @ctx\translate .5 + .5/_scale, 0
+ draw 2 - transfer
+ @ctx\restore!
+
+ @ctx\rotate a_third
+
+ @ctx\save!
+ @ctx\translate .5 + .5/_scale, 0
+ draw 2 - transfer
+ @ctx\restore!
+
+ @ctx\rotate a_third
+
+ @ctx\save!
+ @ctx\translate .5 + .5/_scale, 0
+ draw 2 + transfer, true
+ @ctx\restore!
+
+ @ctx\restore!
+
+KochDemo!
diff --git a/root/animations/text$moonscript -> fn -> mmm$dom.moon b/root/animations/text$moonscript -> fn -> mmm$dom.moon
new file mode 100644
index 0000000..1c04309
--- /dev/null
+++ b/root/animations/text$moonscript -> fn -> mmm$dom.moon
@@ -0,0 +1,18 @@
+import div, h3, ul, li, a from require 'mmm.dom'
+
+=>
+ div {
+ h3 @gett 'title: text/plain', style: { 'margin-bottom': '-.5em' },
+ ul for child in *@children
+ name = child\gett 'name: alpha'
+ desc = child\gett 'description: text/plain'
+ li {
+ a name, {
+ href: child.path,
+ onclick: (e) =>
+ e\preventDefault!
+ BROWSER\navigate child.path
+ },
+ ': ', desc
+ }
+ }
diff --git a/root/animations/title: text$plain b/root/animations/title: text$plain
new file mode 100644
index 0000000..4732b34
--- /dev/null
+++ b/root/animations/title: text$plain
@@ -0,0 +1 @@
+canvas animations
diff --git a/root/animations/twisted.moon b/root/animations/twisted.moon
deleted file mode 100644
index 00b11c5..0000000
--- a/root/animations/twisted.moon
+++ /dev/null
@@ -1,51 +0,0 @@
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-
-with Fileder {
- 'name: alpha': 'twisted',
- 'description: text/plain': "pseudo 3d",
- }
-
- if MODE == 'CLIENT'
- import CanvasApp from require 'mmm.canvasapp'
- import hsl from require 'mmm.color'
-
- Math = window.Math
-
- class TwistedDemo extends CanvasApp
- width: 500
- height: 400
- length: math.pi * 4
- new: (preview) =>
- if preview
- @width, @height = 120, 120
- super false, true
- else
- super true
- @background = {Math.random!, Math.random!/3+.2, Math.random!/4}
- hue = Math.random!
- @shades = setmetatable {}, __index: (key) =>
- with val = { hue, .7, key * .3 + .1} do rawset @, key, val
-
- draw: =>
- @ctx.fillStyle = hsl @background
- @ctx\fillRect 0, 0, @width, @height
- @ctx\translate @width/2, @height/2 + 70
-
- draw = (i) ->
- @ctx\save!
- @ctx\translate 0, -120*i
- s = 1 - 0.1 * math.sin @time + i*2
- s *= 0.8 - i * .4 * math.cos @time
- @ctx\scale s, s/2
- @ctx\rotate @time/4 + i * .6 * math.cos @time
- @ctx.fillStyle = hsl table.unpack @shades[i]
- @ctx\fillRect -80, -80, 160, 160
- @ctx\restore!
-
- for i=0,1,1/(20 + 19 * math.sin(@time / 2))
- draw i
- draw 1
-
- .props['preview: fn -> mmm/component'] = => TwistedDemo true
- .props['fn -> mmm/component'] = => TwistedDemo!
diff --git a/root/animations/twisted/description: text$plain b/root/animations/twisted/description: text$plain
new file mode 100644
index 0000000..bbd63be
--- /dev/null
+++ b/root/animations/twisted/description: text$plain
@@ -0,0 +1 @@
+pseudo-3d twisting pyramid
diff --git a/root/animations/twisted/text$moonscript -> mmm$component.moon b/root/animations/twisted/text$moonscript -> mmm$component.moon
new file mode 100644
index 0000000..3fd11b0
--- /dev/null
+++ b/root/animations/twisted/text$moonscript -> mmm$component.moon
@@ -0,0 +1,43 @@
+assert MODE == 'CLIENT', '[nossr]'
+import CanvasApp from require 'mmm.canvasapp'
+import hsl from require 'mmm.color'
+
+Math = window.Math
+
+class TwistedDemo extends CanvasApp
+ width: 500
+ height: 400
+ length: math.pi * 4
+ new: (preview) =>
+ if preview
+ @width, @height = 120, 120
+ super false, true
+ else
+ super true
+ @background = {Math.random!, Math.random!/3+.2, Math.random!/4}
+ hue = Math.random!
+ @shades = setmetatable {}, __index: (key) =>
+ with val = { hue, .7, key * .3 + .1} do rawset @, key, val
+
+ draw: =>
+ @ctx.fillStyle = hsl @background
+ @ctx\fillRect 0, 0, @width, @height
+ @ctx\translate @width/2, @height/2 + 70
+
+ draw = (i) ->
+ @ctx\save!
+ @ctx\translate 0, -120*i
+ s = 1 - 0.1 * math.sin @time + i*2
+ s *= 0.8 - i * .4 * math.cos @time
+ @ctx\scale s, s/2
+ @ctx\rotate @time/4 + i * .6 * math.cos @time
+ @ctx.fillStyle = hsl table.unpack @shades[i]
+ @ctx\fillRect -80, -80, 160, 160
+ @ctx\restore!
+
+ for i=0,1,1/(20 + 19 * math.sin(@time / 2))
+ draw i
+ draw 1
+
+-- .props['preview: fn -> mmm/component'] = => TwistedDemo true
+TwistedDemo!
diff --git a/root/articles/init.moon b/root/articles/init.moon
deleted file mode 100644
index 4cab81b..0000000
--- a/root/articles/init.moon
+++ /dev/null
@@ -1,27 +0,0 @@
-import div, h3, ul, li, a from require 'mmm.dom'
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-require = relative ...
-
-Fileder {
- 'name: alpha': 'articles',
- 'title: text/plain': 'articles and papers',
- 'fn -> mmm/dom': (path) => div {
- h3 @gett 'title: text/plain', style: { 'margin-bottom': '-.5em' },
- ul for child in *@children
- name = child\gett 'name: alpha'
- desc = child\gett 'description: text/plain'
- li {
- a name, {
- href: child.path,
- onclick: (e) =>
- e\preventDefault!
- BROWSER\navigate child.path
- },
- ': ', desc
- }
- }
-
- require '.mmmfs'
- require '.realities'
-}
diff --git a/root/articles/mmmfs/description: text$plain b/root/articles/mmmfs/description: text$plain
new file mode 100644
index 0000000..1322f1d
--- /dev/null
+++ b/root/articles/mmmfs/description: text$plain
@@ -0,0 +1 @@
+a file, operating and content-management system to live in (powers this site)
diff --git a/root/articles/mmmfs/empty/title: text$plain b/root/articles/mmmfs/empty/title: text$plain
new file mode 100644
index 0000000..911f98b
--- /dev/null
+++ b/root/articles/mmmfs/empty/title: text$plain
@@ -0,0 +1 @@
+Hey I'm an almost empty Fileder.
diff --git a/root/articles/mmmfs/image/URL -> image$png b/root/articles/mmmfs/image/URL -> image$png
new file mode 100644
index 0000000..c586722
--- /dev/null
+++ b/root/articles/mmmfs/image/URL -> image$png
@@ -0,0 +1 @@
+https://picsum.photos/200?random
diff --git a/root/articles/mmmfs/image/preview: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/image/preview: text$moonscript -> fn -> mmm$dom.moon
new file mode 100644
index 0000000..6c431d0
--- /dev/null
+++ b/root/articles/mmmfs/image/preview: text$moonscript -> fn -> mmm$dom.moon
@@ -0,0 +1,5 @@
+import img from require 'mmm.dom'
+
+-- look for main content with 'URL to png' type
+-- and wrap in an mmm/dom image tag
+=> img src: @gett 'URL -> image/png'
diff --git a/root/articles/mmmfs/image/title: text$plain b/root/articles/mmmfs/image/title: text$plain
new file mode 100644
index 0000000..60a556f
--- /dev/null
+++ b/root/articles/mmmfs/image/title: text$plain
@@ -0,0 +1 @@
+Hey I'm like a link to a picture or smth
diff --git a/root/articles/mmmfs/init.moon b/root/articles/mmmfs/init.moon
deleted file mode 100644
index 8227a70..0000000
--- a/root/articles/mmmfs/init.moon
+++ /dev/null
@@ -1,285 +0,0 @@
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-require = relative ...
-
-Fileder {
- 'name: alpha': 'mmmfs',
- 'description: text/plain': 'a file, operating and content-management system to live in (powers this site)',
-
- -- main content
- -- doesn't have a name prefix (e.g. preview: fn -> mmm/dom)
- -- uses the 'fn ->' conversion to execute the lua function on @get
- -- resolves to a value of type mmm/dom
- 'fn -> mmm/dom': () =>
- html = require 'mmm.dom'
- import article, h1, h2, h3, p, div, a, sup, ol, li, span, code, pre, br from html
-
- moon = if MODE == 'SERVER'
- (str) -> code (str\match '^ *(..-) *$'), class: 'hljs'
- else
- (str) ->
- result = window.hljs\highlight 'moonscript', (str\match '^ *(..-) *$'), true
- with code class: 'hljs'
- .innerHTML = result.value
-
- article with _this = {}
- append = (a) -> table.insert _this, a
-
- footnote, getnotes = do
- local *
- notes = {}
-
- id = (i) -> "footnote-#{i}"
-
- footnote = (stuff) ->
- i = #notes + 1
- notes[i] = stuff
- sup a "[#{i}]", style: { 'text-decoration': 'none' }, href: '#' .. id i
-
- footnote, ->
- args = for i, note in ipairs notes
- li (span (tostring i), id: id i), ': ', note
- notes = {}
- table.insert args, style: { 'list-style': 'none', 'font-size': '0.8em' }
- ol table.unpack args
-
- append h1 'mmmfs', style: { 'margin-bottom': 0 }
- -- @TODO: s/filesystem/a way of organizing files/g
- append p "a file and operating system to live in", style: { 'margin-top': 0, 'margin-bottom': '1em' }
-
- -- @TODO: motivation / outline problem + need
- -- @TODO: quote http://pchiusano.github.io/2013-05-22/future-of-software.html on Applications
-
- append p do
- fileder = footnote "fileder: file + folder. 'node', 'table' etc. are too general to be used all over."
-
- -- @TODO: mention:
- -- can store anything - text, an image, a link to a website or video,
- -- a program and anything else you can think of.
- "in mmmfs, directories, files and applications are all kind of the same thing, or something like that.
- Listen, I don't really know yet either. The idea is that there is only one type of 'thing' -
- a fileder", fileder, ". A fileder can store multiple variants and metadata of its content,
- such as a markdown text and a rendered HTML version of the same document.
- It could also store a script that transforms the markdown version into HTML and is executed on demand,
- automatically."
-
- append p "Fileders can also have other fileders as their children (just like directories do in a normal
- filesystem). You can make a fileder view query these children and display them however you want.
- A 'Pictures' fileder, for example, could contain a script within itself that renders all the picture files
- you put into it as little previews and lets you click on them to view the full image."
-
- append p "This means the 'Pictures' fileder can also have an alternate slideshow mode, with fullscreen view and
- everything (some of this is built, check out the gallery example below), or one that displays geotagged images
- on a world map, if you really want that. Maybe you could build a music folder that contains links to youtube
- videos, spotify tracks and just plain mp3 files, and the folder knows how to play them all.", br!, "
- In this way fileders fulfil the purpose of 'Applications' too."
-
- -- @TODO: BUT doesn't have to be only for one type of file:
- -- @TODO: rework
- -- making a multi-media collage representing your thoughts and mental organization of a topic
- append p "A fileder is also responsible for how it's children are sorted, filtered and interacted with.
- For example you should be able to create a fileder that is essentially a 'word document' equivalent: it can
- contain images, websites, links and of course text as children and let you reorder, layout and edit them
- whenever you open the fileder."
-
- append p "Sounds cool, no? Here's some examples of things a fileder can be or embed:"
-
- -- render a preview block
- preview = (child) ->
- -- get 'title' as 'text/plain' (error if no value or conversion possible)
- title = child\gett 'title', 'text/plain'
-
- -- get 'preview' as a DOM description (nil if no value or conversion possible)
- content = child\get 'preview', 'mmm/dom'
-
- div {
- h3 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate child.path
- content or span '(no renderable content)', style: { color: 'red' },
- style: {
- display: 'inline-block',
- width: '300px',
- height: '200px',
- padding: '4px',
- margin: '8px',
- border: '4px solid #eeeeee',
- overflow: 'hidden',
- },
- }
-
-
- append div for child in *@children
- preview child
-
- append h2 "details"
- -- @TODO s/parts: dimensions, aspects?
- -- @TODO: first mention both properties & children; then go into detail
- -- @TODO: main content
- append do
- name = html.i 'name'
- type = html.i 'type'
-
- p "Fileders are made up of two main parts. The first is the list of ", (html.i 'properties'), ",
- which are values identified by a ", name, " and ", type, ". These values are queried using strings like ",
- (code 'title: text/plain'), " or ", (code 'mmm/dom'), ", which describe both the ", name,
- " of a property (", (moon '"title"'), " and ", (moon '""'), ", the unnamed/main property) and the ", type,
- " of a property. Property types can be something resembling a MIME-type or a more complex structure
- (see ", (html.i "type chains"), " below). A fileder can have multiple properties of different types
- set that share a ", name, ". In this case the overlapping properties are considered equivalent and the one
- with the most appropriate ", type, " is selected, depending on the query.
- The unnamed property is considered a fileder's 'main content', i.e. what you are interested in when viewing it."
-
- append p "The second part of a fileder is the list of it's children, which are fileders itself.
- The children are stored in an ordered list and currently identified by their ", (code 'name: alpha'),
- " property for UI and navigation purposes only (not sure if this is a good idea tbh)."
-
--- append do
--- github = footnote a 's-ol/mmm', href: 'https://github.com/s-ol/mmm/tree/master/app/mmmfs'
--- "Oh and also everything is on github and stuff", github,
--- " if you care about that."
-
- append do
- mmmdom = code ('mmm/dom'), footnote span (code 'mmm/dom'), " is a polymorphic content type;
- on the server it is just an HTML string (like ", (code 'text/html'), "),
- but on the client it is a JS DOM Element instance."
-
- p "What you are viewing right now is the main property of the root fileder.
- The property is queried as ", mmmdom, ", a website fragment (DOM node). This website fragment
- is then added to the page in the main content area, where you are most likely reading it right now."
-
- p "Anyway, this node is set up as a very generic sort of index thing and just lists its children-fileders'
- alongside this text part you are reading.", br!, "For each child it displays the ", (code 'title: text/plain'),
- " and shows the ", (code 'preview: mmm/dom'), " property (if set)."
-
- append h3 "converts"
- append p "So far I have always listed properties as they are being queried, but a main feature of mmmfs is
- type conversion. This means that you generally ask for content in whichever format suits your application,
- and rely on the type resolution mechanism to make that happen."
-
- append pre moon [[
--- render a preview block
-preview = (title, content) -> div {
- h3 title, style: { ... },
- content or span '(no renderable content)', style: { ... },
- style: { ... }
-}
-
-append div for child in *@children
- -- get 'title' as 'text/plain' (error if no value or conversion possible)
- title = child\gett 'title', 'text/plain'
-
- -- get 'preview' as a DOM description (nil if no value or conversion possible)
- content = child\get 'preview', 'mmm/dom'
-
- preview title, content
- ]]
-
- append p "Here the code that renders these previews. You can see it ", (html.i "asks"), " for the
- properties ", (code 'title: text/plain'), ' and ', (code 'preview: mmm/dom'), "), but the values don't actually have to
- be ", (html.i "defined"), " as these types.
- For example, the markdown child below only provides ", (code 'preview'), " as ", (code 'text/markdown'), ":"
-
- append pre moon [[
-Fileder {
- 'title: text/plain': "I'm not even five lines of markdown but i render myself!",
- 'preview: text/markdown': "See I have like
-
-- a list of things
-- (two things)
-
-and some bold **text** and `code tags` with me.",
-}
- ]]
-
- append p "Then, globally, there are some conversion paths specified; such as one that maps from ",
- (code 'text/markdown'), " to ", (code 'mmm/dom'), ":"
-
- append pre moon [[
-{
- inp: 'text/markdown',
- out: 'mmm/dom',
- transform: (md) ->
- -- polymorphic client/serverside implementation here,
- -- uses lua-discount on the server, marked.js on the client
-}
- ]]
-
- append h3 "type chains"
- append p "In addition, a property type can be encoded using multiple types in a ", (code 'type chain'), ".
- For example the root node you are viewing currently is actually defined as ", (code 'fn -> mmm/dom'), ",
- meaning it's value is a pre moon function returing a regular ", (code 'mmm/dom'), " value."
-
- append p "Both value chains and 'sideways' converts are resolved using the same mechanism,
- so this page is being rendered just using ", (moon "append root\\get 'mmm/dom'"), " as well.
- The convert that resolves the moon type is defined as follows:"
-
- append pre moon [[
-{
- inp: 'fn -> (.+)',
- out: '%1',
- transform: (val, fileder) -> val fileder
-}
- ]]
-
- append p "The example with the image is curious as well. In mmmfs, you might want to save a link to an image,
- without ever saving the actual image on your hard drive (or wherever the data may ever be stored - it is
- quite transient currently). The image Fileder below has it's main (unnamed) value tagged as ",
- (code 'URL -> image/png'), " - a png image, encoded as an URL. When accessed as ", (code 'image/png'), "
- the URL should be resolved, and the binary data provided in it's place (yeah right - I haven't build that yet)."
-
- append p "However, if a script is aware of URLs and knows a better way to handle them, then it can ask for and
- use the URL directly instead.
- This is what the image demo does in order to pass the URL to an ", (code 'img'), " tag's ", (code 'src'), " attribute:"
-
- append pre moon [[
-Fileder {
- 'title: text/plain': "Hey I'm like a link to picture or smth",
- 'URL -> image/png': 'https://picsum.photos/200?random',
- 'preview: fn -> mmm/dom': =>
- import img from require 'mmm.dom'
- img src: @gett 'URL -> image/png' -- look for main content with 'URL to png' type
-}
- ]]
-
- append getnotes!
-
- 'text/markdown': "this is a markdown version or something.
-
-There's no content here so switch back to the real one!
-(Assuming there is a switching UI by the time you are reading this, which I assume since you are reading this at all.
-If you are reading this in the source, then c'mon, just scroll past and give me a break.)
-
-(the switching UI has now been built.)"
-
- Fileder {
- 'name: alpha': 'empty',
- 'title: text/plain': "Hey I'm an ad-hoc child with no content at all",
- }
-
- Fileder {
- 'name: alpha': 'image',
- 'title: text/plain': "Hey I'm like a link to picture or smth",
-
- -- main content is image/png, to be interpreted by URL to access
- 'URL -> image/png': 'https://picsum.photos/200?random',
-
- -- preview is a lua/moonscript function that neturns an mmm/dom value
- 'preview: fn -> mmm/dom': =>
- import img from require 'mmm.dom'
- img src: @gett 'URL -> image/png' -- look for main content with 'URL to png' type
- }
-
- Fileder {
- 'name: alpha': 'markdown',
- 'title: text/plain': "I'm not even five lines of markdown but i render myself!",
-
- -- preview can be rendered using global convert
- 'preview: text/markdown': "See I have like
-
-- a list of things
-- (two things)
-
-and some bold **text** and `code tags` with me.",
- }
-
- require '.gallery',
-}
diff --git a/root/articles/mmmfs/markdown/text$markdown.md b/root/articles/mmmfs/markdown/text$markdown.md
new file mode 100644
index 0000000..4b38ef2
--- /dev/null
+++ b/root/articles/mmmfs/markdown/text$markdown.md
@@ -0,0 +1,6 @@
+See I have like
+
+- a list of things
+- (two things)
+
+and some bold **text** and `code tags` with me.
diff --git a/root/articles/mmmfs/markdown/title: text$plain b/root/articles/mmmfs/markdown/title: text$plain
new file mode 100644
index 0000000..319068d
--- /dev/null
+++ b/root/articles/mmmfs/markdown/title: text$plain
@@ -0,0 +1 @@
+ I'm not even five lines of markdown but i render myself!
diff --git a/root/articles/mmmfs/text$markdown.md b/root/articles/mmmfs/text$markdown.md
new file mode 100644
index 0000000..1c1b4f9
--- /dev/null
+++ b/root/articles/mmmfs/text$markdown.md
@@ -0,0 +1,7 @@
+## this is a markdown version or something.
+
+There's no content here so switch back to the real one!
+(Assuming there is a switching UI by the time you are reading this, which I assume since you are reading this at all.
+If you are reading this in the source, then c'mon, just scroll past and give me a break.)
+
+(the switching UI has now been built.)
diff --git a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon
new file mode 100644
index 0000000..5d454a1
--- /dev/null
+++ b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon
@@ -0,0 +1,235 @@
+-- main content
+-- doesn't have a name prefix (e.g. preview: fn -> mmm/dom)
+-- uses the 'fn ->' conversion to execute the lua function on @get
+-- resolves to a value of type mmm/dom
+=>
+ html = require 'mmm.dom'
+ import article, h1, h2, h3, p, div, a, sup, ol, li, span, code, pre, br from html
+
+ moon = if MODE == 'SERVER'
+ (str) -> code (str\match '^ *(..-) *$'), class: 'hljs'
+ else
+ (str) ->
+ result = window.hljs\highlight 'moonscript', (str\match '^ *(..-) *$'), true
+ with code class: 'hljs'
+ .innerHTML = result.value
+
+ article with _this = {}
+ append = (a) -> table.insert _this, a
+
+ footnote, getnotes = do
+ local *
+ notes = {}
+
+ id = (i) -> "footnote-#{i}"
+
+ footnote = (stuff) ->
+ i = #notes + 1
+ notes[i] = stuff
+ sup a "[#{i}]", style: { 'text-decoration': 'none' }, href: '#' .. id i
+
+ footnote, ->
+ args = for i, note in ipairs notes
+ li (span (tostring i), id: id i), ': ', note
+ notes = {}
+ table.insert args, style: { 'list-style': 'none', 'font-size': '0.8em' }
+ ol table.unpack args
+
+ append h1 'mmmfs', style: { 'margin-bottom': 0 }
+ -- @TODO: s/filesystem/a way of organizing files/g
+ append p "a file and operating system to live in", style: { 'margin-top': 0, 'margin-bottom': '1em' }
+
+ -- @TODO: motivation / outline problem + need
+ -- @TODO: quote http://pchiusano.github.io/2013-05-22/future-of-software.html on Applications
+
+ append p do
+ fileder = footnote "fileder: file + folder. 'node', 'table' etc. are too general to be used all over."
+
+ -- @TODO: mention:
+ -- can store anything - text, an image, a link to a website or video,
+ -- a program and anything else you can think of.
+ "in mmmfs, directories, files and applications are all kind of the same thing, or something like that.
+ Listen, I don't really know yet either. The idea is that there is only one type of 'thing' -
+ a fileder", fileder, ". A fileder can store multiple variants and metadata of its content,
+ such as a markdown text and a rendered HTML version of the same document.
+ It could also store a script that transforms the markdown version into HTML and is executed on demand,
+ automatically."
+
+ append p "Fileders can also have other fileders as their children (just like directories do in a normal
+ filesystem). You can make a fileder view query these children and display them however you want.
+ A 'Pictures' fileder, for example, could contain a script within itself that renders all the picture files
+ you put into it as little previews and lets you click on them to view the full image."
+
+ append p "This means the 'Pictures' fileder can also have an alternate slideshow mode, with fullscreen view and
+ everything (some of this is built, check out the gallery example below), or one that displays geotagged images
+ on a world map, if you really want that. Maybe you could build a music folder that contains links to youtube
+ videos, spotify tracks and just plain mp3 files, and the folder knows how to play them all.", br!, "
+ In this way fileders fulfil the purpose of 'Applications' too."
+
+ -- @TODO: BUT doesn't have to be only for one type of file:
+ -- @TODO: rework
+ -- making a multi-media collage representing your thoughts and mental organization of a topic
+ append p "A fileder is also responsible for how it's children are sorted, filtered and interacted with.
+ For example you should be able to create a fileder that is essentially a 'word document' equivalent: it can
+ contain images, websites, links and of course text as children and let you reorder, layout and edit them
+ whenever you open the fileder."
+
+ append p "Sounds cool, no? Here's some examples of things a fileder can be or embed:"
+
+ -- render a preview block
+ preview = (child) ->
+ -- get 'title' as 'text/plain' (error if no value or conversion possible)
+ title = child\gett 'title', 'text/plain'
+
+ -- get 'preview' as a DOM description (nil if no value or conversion possible)
+ content = child\get 'preview', 'mmm/dom'
+
+ div {
+ h3 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate child.path
+ content or span '(no renderable content)', style: { color: 'red' },
+ style: {
+ display: 'inline-block',
+ width: '300px',
+ height: '200px',
+ padding: '4px',
+ margin: '8px',
+ border: '4px solid #eeeeee',
+ overflow: 'hidden',
+ },
+ }
+
+
+ append div for child in *@children
+ preview child
+
+ append h2 "details"
+ -- @TODO s/parts: dimensions, aspects?
+ -- @TODO: first mention both properties & children; then go into detail
+ -- @TODO: main content
+ append do
+ name = html.i 'name'
+ type = html.i 'type'
+
+ p "Fileders are made up of two main parts. The first is the list of ", (html.i 'properties'), ",
+ which are values identified by a ", name, " and ", type, ". These values are queried using strings like ",
+ (code 'title: text/plain'), " or ", (code 'mmm/dom'), ", which describe both the ", name,
+ " of a property (", (moon '"title"'), " and ", (moon '""'), ", the unnamed/main property) and the ", type,
+ " of a property. Property types can be something resembling a MIME-type or a more complex structure
+ (see ", (html.i "type chains"), " below). A fileder can have multiple properties of different types
+ set that share a ", name, ". In this case the overlapping properties are considered equivalent and the one
+ with the most appropriate ", type, " is selected, depending on the query.
+ The unnamed property is considered a fileder's 'main content', i.e. what you are interested in when viewing it."
+
+ append p "The second part of a fileder is the list of it's children, which are fileders itself.
+ The children are stored in an ordered list and currently identified by their ", (code 'name: alpha'),
+ " property for UI and navigation purposes only (not sure if this is a good idea tbh)."
+
+-- append do
+-- github = footnote a 's-ol/mmm', href: 'https://github.com/s-ol/mmm/tree/master/app/mmmfs'
+-- "Oh and also everything is on github and stuff", github,
+-- " if you care about that."
+
+ append do
+ mmmdom = code ('mmm/dom'), footnote span (code 'mmm/dom'), " is a polymorphic content type;
+ on the server it is just an HTML string (like ", (code 'text/html'), "),
+ but on the client it is a JS DOM Element instance."
+
+ p "What you are viewing right now is the main property of the root fileder.
+ The property is queried as ", mmmdom, ", a website fragment (DOM node). This website fragment
+ is then added to the page in the main content area, where you are most likely reading it right now."
+
+ p "Anyway, this node is set up as a very generic sort of index thing and just lists its children-fileders'
+ alongside this text part you are reading.", br!, "For each child it displays the ", (code 'title: text/plain'),
+ " and shows the ", (code 'preview: mmm/dom'), " property (if set)."
+
+ append h3 "converts"
+ append p "So far I have always listed properties as they are being queried, but a main feature of mmmfs is
+ type conversion. This means that you generally ask for content in whichever format suits your application,
+ and rely on the type resolution mechanism to make that happen."
+
+ append pre moon [[
+-- render a preview block
+preview = (title, content) -> div {
+h3 title, style: { ... },
+content or span '(no renderable content)', style: { ... },
+style: { ... }
+}
+
+append div for child in *@children
+-- get 'title' as 'text/plain' (error if no value or conversion possible)
+title = child\gett 'title', 'text/plain'
+
+-- get 'preview' as a DOM description (nil if no value or conversion possible)
+content = child\get 'preview', 'mmm/dom'
+
+preview title, content
+ ]]
+
+ append p "Here the code that renders these previews. You can see it ", (html.i "asks"), " for the
+ properties ", (code 'title: text/plain'), ' and ', (code 'preview: mmm/dom'), "), but the values don't actually have to
+ be ", (html.i "defined"), " as these types.
+ For example, the markdown child below only provides ", (code 'preview'), " as ", (code 'text/markdown'), ":"
+
+ append pre moon [[
+Fileder {
+'title: text/plain': "I'm not even five lines of markdown but i render myself!",
+'preview: text/markdown': "See I have like
+
+- a list of things
+- (two things)
+
+and some bold **text** and `code tags` with me.",
+}
+ ]]
+
+ append p "Then, globally, there are some conversion paths specified; such as one that maps from ",
+ (code 'text/markdown'), " to ", (code 'mmm/dom'), ":"
+
+ append pre moon [[
+{
+inp: 'text/markdown',
+out: 'mmm/dom',
+transform: (md) ->
+ -- polymorphic client/serverside implementation here,
+ -- uses lua-discount on the server, marked.js on the client
+}
+ ]]
+
+ append h3 "type chains"
+ append p "In addition, a property type can be encoded using multiple types in a ", (code 'type chain'), ".
+ For example the root node you are viewing currently is actually defined as ", (code 'fn -> mmm/dom'), ",
+ meaning it's value is a pre moon function returing a regular ", (code 'mmm/dom'), " value."
+
+ append p "Both value chains and 'sideways' converts are resolved using the same mechanism,
+ so this page is being rendered just using ", (moon "append root\\get 'mmm/dom'"), " as well.
+ The convert that resolves the moon type is defined as follows:"
+
+ append pre moon [[
+{
+inp: 'fn -> (.+)',
+out: '%1',
+transform: (val, fileder) -> val fileder
+}
+ ]]
+
+ append p "The example with the image is curious as well. In mmmfs, you might want to save a link to an image,
+ without ever saving the actual image on your hard drive (or wherever the data may ever be stored - it is
+ quite transient currently). The image Fileder below has it's main (unnamed) value tagged as ",
+ (code 'URL -> image/png'), " - a png image, encoded as an URL. When accessed as ", (code 'image/png'), "
+ the URL should be resolved, and the binary data provided in it's place (yeah right - I haven't build that yet)."
+
+ append p "However, if a script is aware of URLs and knows a better way to handle them, then it can ask for and
+ use the URL directly instead.
+ This is what the image demo does in order to pass the URL to an ", (code 'img'), " tag's ", (code 'src'), " attribute:"
+
+ append pre moon [[
+Fileder {
+'title: text/plain': "Hey I'm like a link to picture or smth",
+'URL -> image/png': 'https://picsum.photos/200?random',
+'preview: fn -> mmm/dom': =>
+ import img from require 'mmm.dom'
+ img src: @gett 'URL -> image/png' -- look for main content with 'URL to png' type
+}
+ ]]
+
+ append getnotes!
diff --git a/root/articles/realities.moon b/root/articles/realities.moon
deleted file mode 100644
index 1d8c9fa..0000000
--- a/root/articles/realities.moon
+++ /dev/null
@@ -1,550 +0,0 @@
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-
-Fileder {
- 'name: alpha': 'realities'
- 'description: text/plain': 'exploring the nesting relationships of virtual and other realities'
- 'fn -> mmm/component': =>
- import elements from require 'mmm.component'
- import h1, h2, p, a, i, div, ol, li, br, hr, span, button, section, article from elements
-
- _content = div!
- append = _content\append
-
- if MODE == 'SERVER'
- export ^
- class Diagram
- style = {
- display: 'inline-block',
- width: '150px',
- height: '80px',
- 'line-height': '80px',
- color: '#fff',
- background: '#666',
- }
-
- @id = 1
- new: (@func) =>
- @id = "diagram-#{@@id}"
- @@id += 1
-
- render: =>
- rplc = with div id: @id, :style
- \append '(diagram goes here)'
- -- \append "<script type=\"application/lua\">
- -- local rplc = js.global.document:getElementById('#{@id}');
- -- local fn = #{compile @func}
- -- diag = Diagram(fn)
- -- rplc.parentNode:replaceChild(diag.node, rplc)
- -- </script>"
- rplc\render!
-
- if MODE == 'CLIENT'
- export ^
- export o
- eval = js.global\eval
- GRID_W = 50
- GRID_H = 40
-
- SVG =
- doc: eval "(function() { return SVG(document.createElement('svg')); })",
- G: eval "(function() { return new SVG.G(); })",
- setmetatable SVG, __call: => @doc!
-
- o = do
- mkobj = eval "(function () { return {}; })"
- (tbl) ->
- with obj = mkobj!
- for k,v in pairs(tbl)
- obj[k] = v
-
- class Diagram
- new: (f) =>
- @svg = SVG!
- @arrows = SVG.G!
- @width, @height = 0, 0
- @y = 0
-
- f @
-
- txtattr = o {
- fill: 'white',
- 'font-size': '14px',
- 'text-anchor': 'middle',
- }
- block: (color, label, h=1) =>
- @svg\add with SVG.G!
- with \rect GRID_W, h * GRID_H
- \attr o fill: color
- if label
- with \plain label
- \move GRID_W/2, 0
- \attr txtattr
-
- \move @width * GRID_W, (@y + h) * -GRID_H
- @y += h
- if @y > @height
- @height = @y
-
- arrattr = o {
- fill: 'white',
- 'font-size': '18px',
- 'text-anchor': 'middle',
- }
- arrow: (char, x, y) =>
- with @arrows\plain char
- \attr arrattr
- \move (x + 1) * GRID_W, (y - 0.5) * -GRID_H - 11
-
- -- inout: (x=@width, y=@y) => @arrow '⇋', x, y -- U+21CB
- -- inn: (x=@width, y=@y) => @arrow '↼', x, y+0.25 -- U+21BC
- -- out: (x=@width, y=@y) => @arrow '⇁', x, y-0.25 -- U+21C1
- inout: (x=@width, y=@y) => @arrow '⇆', x, y -- U+21C6
- inn: (x=@width, y=@y) => @arrow '←', x, y+0.25 -- U+2190
- out: (x=@width, y=@y) => @arrow '→', x, y-0.25 -- U+2192
-
- mind: (label='mind', ...) => @block '#fac710', label, ...
- phys: (label='phys', ...) => @block '#8fd13f', label, ...
- digi: (label='digi', ...) => @block '#9510ac', label, ...
-
- next: =>
- @y = 0
- @width += 1
-
- finish: =>
- return if @node
- @svg\add @arrows
-
- @width += 1
- w, h = @width * GRID_W, @height * GRID_H
-
- l = GRID_W / 6.5
- @svg\add with @svg\line 0, -GRID_H, w, -GRID_H
- \stroke o width: 2, color: '#ffffff', dasharray: "#{l}, #{l}"
-
- @svg\size w, h
- @svg\viewbox 0, -h, w, h
- @node = @svg.node
-
- addlabel = (label, diagram) ->
- with div style: { display: 'inline-block', margin: '20px', 'text-align': 'center' }
- \append diagram
- \append div label
-
- figures = do
- style =
- display: 'flex'
- 'align-items': 'flex-end'
- 'justify-content': 'space-evenly'
- (...) -> div { :style, ... }
-
- sources = do
- short = => "#{@id} #{@year}"
- long = => @names, " (#{@year}): ", (i @title), ", #{@published}"
- {
- {
- id: 'Milgram',
- title: 'Augmented Reality: A class of displays on the reality-virtuality continuum',
- published: 'in SPIE Vol. 2351',
- names: 'P. Milgram, H. Takemura, A. Utsumi, F. Kishino',
- year: 1994
- :long, :short,
- },
- {
- id: 'Marsh',
- title: 'Nested Immersion: Describing and Classifying Augmented Virtual Reality',
- published: 'IEEE Virtual Reality Conference 2015',
- names: 'W. Marsh, F. Mérienne',
- year: 2015
- :long, :short,
- },
- {
- id: 'Billinghurst',
- title: 'The MagicBook: a transitional AR interface',
- published: 'in Computer & Graphics 25',
- names: 'M. Billinghurst, H. Kato, I. Poupyrev',
- year: 2001,
- :long, :short,
- },
- {
- id: 'Matrix',
- title: 'The Matrix',
- year: 1999,
- names: 'L. Wachowski, A. Wachowski',
- long: => @names, " (#{@year}): ", (i @title), " (movie)"
- short: => tostring @year
- },
- {
- id: 'Naam',
- title: 'Nexus',
- published: 'Angry Robot (novel)',
- names: 'R. Naam',
- year: 2012,
- :long, :short,
- }
- }
-
- ref = do
- fmt = (id) ->
-
- local src
- for _src in *sources
- if _src.id == id
- src = _src
- break
-
- if src
- a { src\short!, href: "##{src.id}" }
- else
- span id
-
- ref = (...) ->
- refs = { ... }
- with span "(", fmt refs[1]
- for i=2, #refs
- \append ", "
- \append fmt refs[i]
- \append ")"
-
- references = ->
- with ol!
- for src in *sources
- \append li { id: src.id, src\long! }
-
- sect = (label) ->
- with section style: 'page-break-inside': 'avoid'
- \append h2 label
-
- append with article style: { margin: 'auto', 'max-width': '750px' }
- \append div 'Sol Bekic', style: 'text-align': 'right'
-
- \append h1 {
- style: { 'text-align': 'center', 'font-size': '2em' },
- "Reality Stacks",
- div "a Taxonomy for Multi-Reality Experiences", style: 'font-size': '0.6em'
- }
-
- \append with sect "Abstract"
- \append p "With the development of mixed-reality experiences and the corresponding interface devices
- multiple frameworks for classification of these experiences have been proposed. However these past
- attempts have mostly been developed alongside and with the intent of capturing specific projects ",
- (ref 'Marsh', 'Billinghurst'), " or are nevertheless very focused on existing methods and technologies ",
- (ref 'Milgram'), ". The existing taxonomies also all assume physical reality as a fixpoint and constant and are
- thereby not suited to describe many fictional mixed-reality environments and altered states of consciousness.
- In this paper we describe a new model for describing such experiences and examplify it's use with currently
- existing as well as idealized technologies from popular culture."
-
- \append with sect "Terminology"
- \append p "We propose the following terms and definitions that will be used extensively for the remainder of the paper:"
- for definition in *{
- { "layer of reality": "a closed system consisting of a world model and a set of rules or dynamics operating on and
- constraining said model." },
- { "world model": "describes a world state containing objects, agents and/or concepts on an arbitrary abstraction level." },
- '------',
- { "reality stack": "structure consisting of all layers of reality encoding an agent's interaction with his environment
- in their world model at a given moment, as well as all layers supporting these respectively." },
- '------',
- { "physical reality": "layer of reality defined by physical matter and the physical laws acting upon it.
- While the emergent phenomena of micro- and macro physics as well as layers of social existence etc. may be seen
- as separate layers, for the purpose of this paper we will group these together under the term of physical reality." },
- { "mental reality": "layer of reality perceived and processed by the brain of a human agent." },
- { "digital reality": "layer of reality created and simulated by a digital system, e.g. a virtual reality game." },
- { "phys, mind, digi": "abbreviations for physical, mental and digital reality respectively." },
- }
- if 'string' == type definition
- \append hr!
- continue
- \append with div style: { 'margin-left': '2rem' }
- term = next definition
- \append span term, style: {
- display: 'inline-block',
- 'margin-left': '-2rem',
- 'font-weight': 'bold',
- 'min-width': '140px'
- }
- \append span definition[term]
-
- \append with sect "Introduction"
- \append p "We identify two different types of relationships between layers in multi-reality environments.
- The first is layer nesting. Layer nesting describes how some layers are contained in other layers; i.e. they exist
- within and can be represented fully by the parent layer's world model and the child layer's rules emerge natively from
- the parent layer's dynamics. Layer nesting is visualized on the vertical axis in the following diagrams.
- For each layer of reality on the bottom of the diagram the nested parent layers can be found by tracing a line upwards
- to the top of the diagram. Following a materialistic point of view, physical reality therefore must completely encompass
- the top of each diagram."
-
- \append p "The second type of relationship describes the information flow between a subject and the layers of reality
- the subject is immersed in. In a multi-reality experience the subject has access to multiple layers of reality and
- their corresponding world models simultaneously.", br!,
- "Depending on the specific experience, different types of and directions for information exchange
- can exist between these layers and the subject's internal representation of the experience.
- For the sake of this paper we distinguish only between ", (i "input"), " and ", (i "output"), " data flow (from the
- perspective of the subject); categorized loosely as information the subject receives from the environment
- (", (i "input"), ", e.g. visual stimuli) and actions the subject can take to influence the state of the world model
- (", (i "output"), ", e.g. motor actions) respectively."
-
- \append p "In the following diagrams, information flow is visualized horizontally, in the region below the dashed line
- at the bottom of the diagram. The subject's internal mental model and layer of reality are placed on the bottom left
- side of the diagram.
- The layers of reality that the subject experiences directly and that mirror it's internal representations are placed
- on the far right. There may be multiple layers of reality sharing this space, visualized as a vertical stack of
- layers. Since the subject must necessarily have a complete internal model of the multi-reality experience around
- him to feel immersed, the subject's mental layer of reality must span the full height of all the layers visible
- on the right side of the diagram.", br!,
- "Information flow itself is now visualized concretely using arrows that cross layer boundaries in the lower part of
- the diagram as described above. Arrows pointing leftwards denote ", (i "input"), " flow, whilst arrows pointing
- rightwards denote ", (i "output"), "-directed information flow. In some cases information doesn't flow directly
- between the layers the subject is directly aware of and the subject's internal representation and instead
- traverses ", (i "intermediate layers"), " first."
-
- \append p "Before we take a look at some reality stacks corresponding to current VR and AR technology,
- we can take a look at waking life as a baseline stack. To illustrate the format of the diagram we will compare it
- to the stack corresponding to a dreaming state:"
-
- \append with figures!
- \append addlabel "Waking Life", Diagram =>
- @mind!
- @inout!
- @phys!
-
- @next!
- @phys '', 2
- @finish!
-
- \append addlabel "Dreaming", Diagram =>
- @mind!
- @phys!
- @finish!
-
- \append p "In both cases, the top of the diagram is fully occupied by the physical layer of reality, colored in green.
- This is due to the fact that, according to the materialistic theory of mind, human consciousness owes its existance
- to the physical and chemical dynamics of neurons in our brains. Therefore our mental reality must be considered
- fully embedded in the physical reality, and consequently it may only appear underneath it in the diagram."
-
- \append p "During waking life, we concern ourselves mostly with the physical reality surrounding us.
- For this reason the physical reality is placed in the lower right corner of the diagram as the layer holding the
- external world model relevant to the subject. Information flows in both directions between the physical world model
- and the subject's mental model, as denoted by the two white arrows: Information about the state of the world model
- enter the subjects mind via the senses (top arrow, pointing leftwards), and choices the subject makes inside of and
- based on his mental model can feed back into the physical layer through movements (lower arrow, pointing rightwards)."
-
- \append p "In the dreaming state on the other hand, the subject is unaware of the physical layer of reality, though
- the mind remains embedded inside it. When dreaming, subjects' mental models don't depend on external models, hence
- the mental layer of reality must be the only layer along the bottom of the diagram."
-
- \append with sect "Current Technologies"
- \append p "Since recent technological advancements have enabled the development of VR and AR consumer devices,
- AR and VR have been established as the potential next frontier of digital entertainment.", br!,
- "As the names imply, the notion of reality is at the core of both technologies.
- In the following section we will take a look at the respective stacks of both experience types:"
-
- \append with figures!
- \append addlabel "VR", Diagram =>
- @mind!
- @phys!
- @inout nil, 1
-
- @next!
- @phys '', 2
- @inout nil, 1
-
- @next!
- @digi!
- @phys ''
- @finish!
-
-
- \append addlabel "AR", Diagram =>
- @mind!
- @inout nil, 1.25
- @inn nil, 0.5
- @phys!
-
- @next!
- @phys '', 2
- @inn nil, .5
-
- @next!
- @digi nil, .5
- @phys '', 1.5
- @finish!
-
- \append p "In both cases we find the physical layer of reality as an ", (i "intermediate layer"), " between the mental
- and digital layers. Actions taken by the subject have to be acted out physically (corresponding to the
- information traversing the barrier between mental and physical reality) before they can be again digitized using
- the various tracking and input technologies (which in turn carry the information across the boundary of the physical
- and digital spaces)."
-
- \append p "The difference between AR and VR lies in the fact that in AR the subject experiences a mixture of the
- digital and physical world models. This can be seen in the diagram, where we find that right of the diagram origin
- and the mental model, the diagram splits and terminates in both layers: while information reaches the subject both
- from the digital reality through the physical one, as well as directly from the physical reality, the subject only
- directly manipulates state in the physical reality."
-
- \append p "The data conversions necessary at layer boundaries incur at the least losses in quality and accuracy of
- information for purely technical reasons. However ", (i "intermediate layers"), " come at a cost larger than just
- an additional step of conversion:
- For information to flow through a layer, it must be encodable within that layer’s world model.
- This means that the 'weakest link' in a given reality stack determines the upper bound of information possible to
- encode within said stack and thereby limits the overall expressivity of the stack.", br!,
- "As a practical example we can consider creating an hypothetical VR application that allows users to traverse a
- large virtual space by flying. While the human mind is perfectly capable of imagining to fly and control the motion
- appropriately, it is extremely hard to devise and implement a satisfying setup and control scheme because the
- physical body of the user needs to be taken into account and it, unlike the corresponding representations in the
- mental and digital world models, cannot float around freely."
-
- \append with sect "Future Developments"
- \append p "In the previous section we found that the presence of the physical layer in the information path of
- VR and AR stacks limits the experience as a whole. It follows that the removal of that indirection should be
- an obvious goal for future developments:"
-
- \append figures addlabel "holy grail of VR: 'The Matrix'", Diagram =>
- @mind!
- @inout!
- @phys!
-
- @next!
- @digi!
- @phys ''
- @finish!
-
- \append p "In the action movie 'The Matrix' ", (ref 'Matrix'), ", users of the titular VR environment interface with it
- by plugging cables into implanted sockets that connect the simulation directly to their central nervous system.", br!,
- "While these cables and implanted devices are physical devices, they don't constitute the presence of the
- physical layer of reality in the information path because while they do transmit information, the information
- remains in either the encoding of the mental model (neural firing patterns) or the encoding of the digital model
- (e.g. a numeric encoding of a player character's movement in digital space) and the conversion is made directly
- between those two - the data never assumes the native encoding of the physical layer (e.g. as a physical motion)."
-
- \append p "While we are currently far from being able to read arbitrary high-level information from the brain
- or to synthesize sensual input in human perception by bypassing the sensory organs, brain-computer interfaces (BCI)
- are a very active area of research with high hopes for comparable achievements in the near future."
-
- \append p "Applying this same step of removing the physical layer of reality from AR, we end up with something similar
- to the nano-particle drug in ", (i "Nexus"), " ", (ref 'Naam'), ". However this does not grant the user a similar
- amount of control over his experience as the holy grail of VR does, since the user and the physical part of the
- environment remain bound by the physical layer of reality's laws.", br!,
- "Instead the holy grail of AR is reached with the creation of a god machine that can manipulate the state of the
- physical world according to the user's wishes. In this way the digital and physical realities become unified and
- fully 'augmented'."
-
- \append with figures!
- \append addlabel "'Nexus'", Diagram =>
- @mind!
- @inout nil, 0.75
- @inout nil, 1.25
- @phys!
-
- @next!
- @digi nil, .5
- @phys '', 1.5
- @finish!
-
- \append addlabel "holy grail of AR: 'Deus Machina'", Diagram =>
- col = '#92807c'
-
- @mind!
- @inout!
- @block col, ''
-
- @next!
- @block col, '', 2
- @svg\plain('phys + digi')\attr(o fill: 'white', 'font-size': '14px')\move 6, -2 * GRID_H
- @finish!
-
- \append p "Despite the similarities of VR and AR, the two can be considered polar opposites, as becomes evident when
- we compare their respective utopian implementations: they share the goal of allowing us to experience realities
- different from the one we naturally inhabit, but while VR seeks to accomplish this by creating a new, nested reality
- inside ours, thus giving us full control over it.
- AR, on the other hand, is instead an attempt to retrofit our specific needs directly into the very reality we exist
- in.", br!,
- "This is in direct contrast with the popular notion of the 'reality-virtuality continuum' ", (ref 'Milgram'), ":
- the reality-virtuality continuum places common reality and VR (virtuality) as the two extreme poles, while AR
- is represented as an intermediate state between the two. Here however we propose to view instead AR and VR as the
- respective poles and find instead reality at the centerpoint, where the two opposing influences 'cancel out'."
-
- \append with sect "Conclusion and Further Work"
- \append p "In this paper we have proposed a taxonomy and visualization style for multi-reality experiences, as well
- as demonstrated it's flexibility by applying them as examples. Through the application of the proposed theory,
- we have also gained a new and contrasting view on preceding work such as the reality-virtuality-continuum.
- We have also found that the taxonomy can be used outside the research field of media studies and its use may extend
- as far as philosophy of consciousness (see Appendix below)."
-
- \append p "Further research could enhance the proposed theory with better and more concrete definitions.
- In the future, the proposed taxonomy might be used to create a more extensive and complete classification
- of reality stacks and to analyse the relationships between them."
-
- \append with sect 'References'
- \append references!
-
- \append with sect "Appendix: Relation to Theories of Mind"
- \append p "This paper starts from a deeply materialistic point of view that borders on microphysicalism.
- However it should be noted that the diagram style introduced above lends itself also to display other
- philosophical theories of mind. As an example, the following graphics show a typical VR stack as interpreted by
- Materialism, Cartesian Dualism and Solipsism respectively:"
-
- \append with figures!
- \append addlabel "VR in Materialism", Diagram =>
- @mind!
- @inout nil, 1
- @phys!
-
- @next!
- @phys '', 2
- @inout nil, 1
-
- @next!
- @digi!
- @phys ''
-
- @finish!
-
- \append addlabel "VR in Solipsism", Diagram =>
- @mind nil, 2
- @inout nil, 1
-
- @next!
- @digi!
- @mind ''
- @finish!
-
- \append addlabel "VR in Cartesian Dualism", Diagram =>
- @mind nil, 2
- @inout nil, 1
- @next!
-
- @phys nil, 2
- @inout nil, 1
- @next!
-
- @digi!
- @phys ''
- @finish!
-
- \append p "However these philosophical theories of minds also constitute reality stacks by themselves and as such can
- be compared directly:"
-
- \append with figures!
- \append addlabel "Materialism", Diagram =>
- @mind!
- @inout!
- @phys!
-
- @next!
- @phys '', 2
- @finish!
-
- \append addlabel "Solipsism", Diagram =>
- @mind!
- @finish!
-
- \append addlabel "Cartesian Dualism", Diagram =>
- @mind!
- @inout!
- @next!
-
- @phys!
- @finish!
-
- _content
-}
diff --git a/root/articles/realities/description: text$plain b/root/articles/realities/description: text$plain
new file mode 100644
index 0000000..c7a0891
--- /dev/null
+++ b/root/articles/realities/description: text$plain
@@ -0,0 +1 @@
+exploring the nesting relationships of virtual and other realities
diff --git a/root/articles/realities/text$moonscript -> mmm$dom.moon b/root/articles/realities/text$moonscript -> mmm$dom.moon
new file mode 100644
index 0000000..7689dbb
--- /dev/null
+++ b/root/articles/realities/text$moonscript -> mmm$dom.moon
@@ -0,0 +1,542 @@
+import elements from require 'mmm.component'
+import h1, h2, p, a, i, div, ol, li, br, hr, span, button, section, article from elements
+
+_content = div!
+append = _content\append
+
+if MODE == 'SERVER'
+ export ^
+ class Diagram
+ style = {
+ display: 'inline-block',
+ width: '150px',
+ height: '80px',
+ 'line-height': '80px',
+ color: '#fff',
+ background: '#666',
+ }
+
+ @id = 1
+ new: (@func) =>
+ @id = "diagram-#{@@id}"
+ @@id += 1
+
+ render: =>
+ rplc = with div id: @id, :style
+ \append '(diagram goes here)'
+ -- \append "<script type=\"application/lua\">
+ -- local rplc = js.global.document:getElementById('#{@id}');
+ -- local fn = #{compile @func}
+ -- diag = Diagram(fn)
+ -- rplc.parentNode:replaceChild(diag.node, rplc)
+ -- </script>"
+ rplc\render!
+
+if MODE == 'CLIENT'
+ export ^
+ export o
+ eval = js.global\eval
+ GRID_W = 50
+ GRID_H = 40
+
+ SVG =
+ doc: eval "(function() { return SVG(document.createElement('svg')); })",
+ G: eval "(function() { return new SVG.G(); })",
+ setmetatable SVG, __call: => @doc!
+
+ o = do
+ mkobj = eval "(function () { return {}; })"
+ (tbl) ->
+ with obj = mkobj!
+ for k,v in pairs(tbl)
+ obj[k] = v
+
+ class Diagram
+ new: (f) =>
+ @svg = SVG!
+ @arrows = SVG.G!
+ @width, @height = 0, 0
+ @y = 0
+
+ f @
+
+ txtattr = o {
+ fill: 'white',
+ 'font-size': '14px',
+ 'text-anchor': 'middle',
+ }
+ block: (color, label, h=1) =>
+ @svg\add with SVG.G!
+ with \rect GRID_W, h * GRID_H
+ \attr o fill: color
+ if label
+ with \plain label
+ \move GRID_W/2, 0
+ \attr txtattr
+
+ \move @width * GRID_W, (@y + h) * -GRID_H
+ @y += h
+ if @y > @height
+ @height = @y
+
+ arrattr = o {
+ fill: 'white',
+ 'font-size': '18px',
+ 'text-anchor': 'middle',
+ }
+ arrow: (char, x, y) =>
+ with @arrows\plain char
+ \attr arrattr
+ \move (x + 1) * GRID_W, (y - 0.5) * -GRID_H - 11
+
+ -- inout: (x=@width, y=@y) => @arrow '⇋', x, y -- U+21CB
+ -- inn: (x=@width, y=@y) => @arrow '↼', x, y+0.25 -- U+21BC
+ -- out: (x=@width, y=@y) => @arrow '⇁', x, y-0.25 -- U+21C1
+ inout: (x=@width, y=@y) => @arrow '⇆', x, y -- U+21C6
+ inn: (x=@width, y=@y) => @arrow '←', x, y+0.25 -- U+2190
+ out: (x=@width, y=@y) => @arrow '→', x, y-0.25 -- U+2192
+
+ mind: (label='mind', ...) => @block '#fac710', label, ...
+ phys: (label='phys', ...) => @block '#8fd13f', label, ...
+ digi: (label='digi', ...) => @block '#9510ac', label, ...
+
+ next: =>
+ @y = 0
+ @width += 1
+
+ finish: =>
+ return if @node
+ @svg\add @arrows
+
+ @width += 1
+ w, h = @width * GRID_W, @height * GRID_H
+
+ l = GRID_W / 6.5
+ @svg\add with @svg\line 0, -GRID_H, w, -GRID_H
+ \stroke o width: 2, color: '#ffffff', dasharray: "#{l}, #{l}"
+
+ @svg\size w, h
+ @svg\viewbox 0, -h, w, h
+ @node = @svg.node
+
+addlabel = (label, diagram) ->
+ with div style: { display: 'inline-block', margin: '20px', 'text-align': 'center' }
+ \append diagram
+ \append div label
+
+figures = do
+ style =
+ display: 'flex'
+ 'align-items': 'flex-end'
+ 'justify-content': 'space-evenly'
+ (...) -> div { :style, ... }
+
+sources = do
+ short = => "#{@id} #{@year}"
+ long = => @names, " (#{@year}): ", (i @title), ", #{@published}"
+ {
+ {
+ id: 'Milgram',
+ title: 'Augmented Reality: A class of displays on the reality-virtuality continuum',
+ published: 'in SPIE Vol. 2351',
+ names: 'P. Milgram, H. Takemura, A. Utsumi, F. Kishino',
+ year: 1994
+ :long, :short,
+ },
+ {
+ id: 'Marsh',
+ title: 'Nested Immersion: Describing and Classifying Augmented Virtual Reality',
+ published: 'IEEE Virtual Reality Conference 2015',
+ names: 'W. Marsh, F. Mérienne',
+ year: 2015
+ :long, :short,
+ },
+ {
+ id: 'Billinghurst',
+ title: 'The MagicBook: a transitional AR interface',
+ published: 'in Computer & Graphics 25',
+ names: 'M. Billinghurst, H. Kato, I. Poupyrev',
+ year: 2001,
+ :long, :short,
+ },
+ {
+ id: 'Matrix',
+ title: 'The Matrix',
+ year: 1999,
+ names: 'L. Wachowski, A. Wachowski',
+ long: => @names, " (#{@year}): ", (i @title), " (movie)"
+ short: => tostring @year
+ },
+ {
+ id: 'Naam',
+ title: 'Nexus',
+ published: 'Angry Robot (novel)',
+ names: 'R. Naam',
+ year: 2012,
+ :long, :short,
+ }
+ }
+
+ref = do
+ fmt = (id) ->
+
+ local src
+ for _src in *sources
+ if _src.id == id
+ src = _src
+ break
+
+ if src
+ a { src\short!, href: "##{src.id}" }
+ else
+ span id
+
+ ref = (...) ->
+ refs = { ... }
+ with span "(", fmt refs[1]
+ for i=2, #refs
+ \append ", "
+ \append fmt refs[i]
+ \append ")"
+
+references = ->
+ with ol!
+ for src in *sources
+ \append li { id: src.id, src\long! }
+
+sect = (label) ->
+ with section style: 'page-break-inside': 'avoid'
+ \append h2 label
+
+append with article style: { margin: 'auto', 'max-width': '750px' }
+ \append div 'Sol Bekic', style: 'text-align': 'right'
+
+ \append h1 {
+ style: { 'text-align': 'center', 'font-size': '2em' },
+ "Reality Stacks",
+ div "a Taxonomy for Multi-Reality Experiences", style: 'font-size': '0.6em'
+ }
+
+ \append with sect "Abstract"
+ \append p "With the development of mixed-reality experiences and the corresponding interface devices
+ multiple frameworks for classification of these experiences have been proposed. However these past
+ attempts have mostly been developed alongside and with the intent of capturing specific projects ",
+ (ref 'Marsh', 'Billinghurst'), " or are nevertheless very focused on existing methods and technologies ",
+ (ref 'Milgram'), ". The existing taxonomies also all assume physical reality as a fixpoint and constant and are
+ thereby not suited to describe many fictional mixed-reality environments and altered states of consciousness.
+ In this paper we describe a new model for describing such experiences and examplify it's use with currently
+ existing as well as idealized technologies from popular culture."
+
+ \append with sect "Terminology"
+ \append p "We propose the following terms and definitions that will be used extensively for the remainder of the paper:"
+ for definition in *{
+ { "layer of reality": "a closed system consisting of a world model and a set of rules or dynamics operating on and
+ constraining said model." },
+ { "world model": "describes a world state containing objects, agents and/or concepts on an arbitrary abstraction level." },
+ '------',
+ { "reality stack": "structure consisting of all layers of reality encoding an agent's interaction with his environment
+ in their world model at a given moment, as well as all layers supporting these respectively." },
+ '------',
+ { "physical reality": "layer of reality defined by physical matter and the physical laws acting upon it.
+ While the emergent phenomena of micro- and macro physics as well as layers of social existence etc. may be seen
+ as separate layers, for the purpose of this paper we will group these together under the term of physical reality." },
+ { "mental reality": "layer of reality perceived and processed by the brain of a human agent." },
+ { "digital reality": "layer of reality created and simulated by a digital system, e.g. a virtual reality game." },
+ { "phys, mind, digi": "abbreviations for physical, mental and digital reality respectively." },
+ }
+ if 'string' == type definition
+ \append hr!
+ continue
+ \append with div style: { 'margin-left': '2rem' }
+ term = next definition
+ \append span term, style: {
+ display: 'inline-block',
+ 'margin-left': '-2rem',
+ 'font-weight': 'bold',
+ 'min-width': '140px'
+ }
+ \append span definition[term]
+
+ \append with sect "Introduction"
+ \append p "We identify two different types of relationships between layers in multi-reality environments.
+ The first is layer nesting. Layer nesting describes how some layers are contained in other layers; i.e. they exist
+ within and can be represented fully by the parent layer's world model and the child layer's rules emerge natively from
+ the parent layer's dynamics. Layer nesting is visualized on the vertical axis in the following diagrams.
+ For each layer of reality on the bottom of the diagram the nested parent layers can be found by tracing a line upwards
+ to the top of the diagram. Following a materialistic point of view, physical reality therefore must completely encompass
+ the top of each diagram."
+
+ \append p "The second type of relationship describes the information flow between a subject and the layers of reality
+ the subject is immersed in. In a multi-reality experience the subject has access to multiple layers of reality and
+ their corresponding world models simultaneously.", br!,
+ "Depending on the specific experience, different types of and directions for information exchange
+ can exist between these layers and the subject's internal representation of the experience.
+ For the sake of this paper we distinguish only between ", (i "input"), " and ", (i "output"), " data flow (from the
+ perspective of the subject); categorized loosely as information the subject receives from the environment
+ (", (i "input"), ", e.g. visual stimuli) and actions the subject can take to influence the state of the world model
+ (", (i "output"), ", e.g. motor actions) respectively."
+
+ \append p "In the following diagrams, information flow is visualized horizontally, in the region below the dashed line
+ at the bottom of the diagram. The subject's internal mental model and layer of reality are placed on the bottom left
+ side of the diagram.
+ The layers of reality that the subject experiences directly and that mirror it's internal representations are placed
+ on the far right. There may be multiple layers of reality sharing this space, visualized as a vertical stack of
+ layers. Since the subject must necessarily have a complete internal model of the multi-reality experience around
+ him to feel immersed, the subject's mental layer of reality must span the full height of all the layers visible
+ on the right side of the diagram.", br!,
+ "Information flow itself is now visualized concretely using arrows that cross layer boundaries in the lower part of
+ the diagram as described above. Arrows pointing leftwards denote ", (i "input"), " flow, whilst arrows pointing
+ rightwards denote ", (i "output"), "-directed information flow. In some cases information doesn't flow directly
+ between the layers the subject is directly aware of and the subject's internal representation and instead
+ traverses ", (i "intermediate layers"), " first."
+
+ \append p "Before we take a look at some reality stacks corresponding to current VR and AR technology,
+ we can take a look at waking life as a baseline stack. To illustrate the format of the diagram we will compare it
+ to the stack corresponding to a dreaming state:"
+
+ \append with figures!
+ \append addlabel "Waking Life", Diagram =>
+ @mind!
+ @inout!
+ @phys!
+
+ @next!
+ @phys '', 2
+ @finish!
+
+ \append addlabel "Dreaming", Diagram =>
+ @mind!
+ @phys!
+ @finish!
+
+ \append p "In both cases, the top of the diagram is fully occupied by the physical layer of reality, colored in green.
+ This is due to the fact that, according to the materialistic theory of mind, human consciousness owes its existance
+ to the physical and chemical dynamics of neurons in our brains. Therefore our mental reality must be considered
+ fully embedded in the physical reality, and consequently it may only appear underneath it in the diagram."
+
+ \append p "During waking life, we concern ourselves mostly with the physical reality surrounding us.
+ For this reason the physical reality is placed in the lower right corner of the diagram as the layer holding the
+ external world model relevant to the subject. Information flows in both directions between the physical world model
+ and the subject's mental model, as denoted by the two white arrows: Information about the state of the world model
+ enter the subjects mind via the senses (top arrow, pointing leftwards), and choices the subject makes inside of and
+ based on his mental model can feed back into the physical layer through movements (lower arrow, pointing rightwards)."
+
+ \append p "In the dreaming state on the other hand, the subject is unaware of the physical layer of reality, though
+ the mind remains embedded inside it. When dreaming, subjects' mental models don't depend on external models, hence
+ the mental layer of reality must be the only layer along the bottom of the diagram."
+
+ \append with sect "Current Technologies"
+ \append p "Since recent technological advancements have enabled the development of VR and AR consumer devices,
+ AR and VR have been established as the potential next frontier of digital entertainment.", br!,
+ "As the names imply, the notion of reality is at the core of both technologies.
+ In the following section we will take a look at the respective stacks of both experience types:"
+
+ \append with figures!
+ \append addlabel "VR", Diagram =>
+ @mind!
+ @phys!
+ @inout nil, 1
+
+ @next!
+ @phys '', 2
+ @inout nil, 1
+
+ @next!
+ @digi!
+ @phys ''
+ @finish!
+
+
+ \append addlabel "AR", Diagram =>
+ @mind!
+ @inout nil, 1.25
+ @inn nil, 0.5
+ @phys!
+
+ @next!
+ @phys '', 2
+ @inn nil, .5
+
+ @next!
+ @digi nil, .5
+ @phys '', 1.5
+ @finish!
+
+ \append p "In both cases we find the physical layer of reality as an ", (i "intermediate layer"), " between the mental
+ and digital layers. Actions taken by the subject have to be acted out physically (corresponding to the
+ information traversing the barrier between mental and physical reality) before they can be again digitized using
+ the various tracking and input technologies (which in turn carry the information across the boundary of the physical
+ and digital spaces)."
+
+ \append p "The difference between AR and VR lies in the fact that in AR the subject experiences a mixture of the
+ digital and physical world models. This can be seen in the diagram, where we find that right of the diagram origin
+ and the mental model, the diagram splits and terminates in both layers: while information reaches the subject both
+ from the digital reality through the physical one, as well as directly from the physical reality, the subject only
+ directly manipulates state in the physical reality."
+
+ \append p "The data conversions necessary at layer boundaries incur at the least losses in quality and accuracy of
+ information for purely technical reasons. However ", (i "intermediate layers"), " come at a cost larger than just
+ an additional step of conversion:
+ For information to flow through a layer, it must be encodable within that layer’s world model.
+ This means that the 'weakest link' in a given reality stack determines the upper bound of information possible to
+ encode within said stack and thereby limits the overall expressivity of the stack.", br!,
+ "As a practical example we can consider creating an hypothetical VR application that allows users to traverse a
+ large virtual space by flying. While the human mind is perfectly capable of imagining to fly and control the motion
+ appropriately, it is extremely hard to devise and implement a satisfying setup and control scheme because the
+ physical body of the user needs to be taken into account and it, unlike the corresponding representations in the
+ mental and digital world models, cannot float around freely."
+
+ \append with sect "Future Developments"
+ \append p "In the previous section we found that the presence of the physical layer in the information path of
+ VR and AR stacks limits the experience as a whole. It follows that the removal of that indirection should be
+ an obvious goal for future developments:"
+
+ \append figures addlabel "holy grail of VR: 'The Matrix'", Diagram =>
+ @mind!
+ @inout!
+ @phys!
+
+ @next!
+ @digi!
+ @phys ''
+ @finish!
+
+ \append p "In the action movie 'The Matrix' ", (ref 'Matrix'), ", users of the titular VR environment interface with it
+ by plugging cables into implanted sockets that connect the simulation directly to their central nervous system.", br!,
+ "While these cables and implanted devices are physical devices, they don't constitute the presence of the
+ physical layer of reality in the information path because while they do transmit information, the information
+ remains in either the encoding of the mental model (neural firing patterns) or the encoding of the digital model
+ (e.g. a numeric encoding of a player character's movement in digital space) and the conversion is made directly
+ between those two - the data never assumes the native encoding of the physical layer (e.g. as a physical motion)."
+
+ \append p "While we are currently far from being able to read arbitrary high-level information from the brain
+ or to synthesize sensual input in human perception by bypassing the sensory organs, brain-computer interfaces (BCI)
+ are a very active area of research with high hopes for comparable achievements in the near future."
+
+ \append p "Applying this same step of removing the physical layer of reality from AR, we end up with something similar
+ to the nano-particle drug in ", (i "Nexus"), " ", (ref 'Naam'), ". However this does not grant the user a similar
+ amount of control over his experience as the holy grail of VR does, since the user and the physical part of the
+ environment remain bound by the physical layer of reality's laws.", br!,
+ "Instead the holy grail of AR is reached with the creation of a god machine that can manipulate the state of the
+ physical world according to the user's wishes. In this way the digital and physical realities become unified and
+ fully 'augmented'."
+
+ \append with figures!
+ \append addlabel "'Nexus'", Diagram =>
+ @mind!
+ @inout nil, 0.75
+ @inout nil, 1.25
+ @phys!
+
+ @next!
+ @digi nil, .5
+ @phys '', 1.5
+ @finish!
+
+ \append addlabel "holy grail of AR: 'Deus Machina'", Diagram =>
+ col = '#92807c'
+
+ @mind!
+ @inout!
+ @block col, ''
+
+ @next!
+ @block col, '', 2
+ @svg\plain('phys + digi')\attr(o fill: 'white', 'font-size': '14px')\move 6, -2 * GRID_H
+ @finish!
+
+ \append p "Despite the similarities of VR and AR, the two can be considered polar opposites, as becomes evident when
+ we compare their respective utopian implementations: they share the goal of allowing us to experience realities
+ different from the one we naturally inhabit, but while VR seeks to accomplish this by creating a new, nested reality
+ inside ours, thus giving us full control over it.
+ AR, on the other hand, is instead an attempt to retrofit our specific needs directly into the very reality we exist
+ in.", br!,
+ "This is in direct contrast with the popular notion of the 'reality-virtuality continuum' ", (ref 'Milgram'), ":
+ the reality-virtuality continuum places common reality and VR (virtuality) as the two extreme poles, while AR
+ is represented as an intermediate state between the two. Here however we propose to view instead AR and VR as the
+ respective poles and find instead reality at the centerpoint, where the two opposing influences 'cancel out'."
+
+ \append with sect "Conclusion and Further Work"
+ \append p "In this paper we have proposed a taxonomy and visualization style for multi-reality experiences, as well
+ as demonstrated it's flexibility by applying them as examples. Through the application of the proposed theory,
+ we have also gained a new and contrasting view on preceding work such as the reality-virtuality-continuum.
+ We have also found that the taxonomy can be used outside the research field of media studies and its use may extend
+ as far as philosophy of consciousness (see Appendix below)."
+
+ \append p "Further research could enhance the proposed theory with better and more concrete definitions.
+ In the future, the proposed taxonomy might be used to create a more extensive and complete classification
+ of reality stacks and to analyse the relationships between them."
+
+ \append with sect 'References'
+ \append references!
+
+ \append with sect "Appendix: Relation to Theories of Mind"
+ \append p "This paper starts from a deeply materialistic point of view that borders on microphysicalism.
+ However it should be noted that the diagram style introduced above lends itself also to display other
+ philosophical theories of mind. As an example, the following graphics show a typical VR stack as interpreted by
+ Materialism, Cartesian Dualism and Solipsism respectively:"
+
+ \append with figures!
+ \append addlabel "VR in Materialism", Diagram =>
+ @mind!
+ @inout nil, 1
+ @phys!
+
+ @next!
+ @phys '', 2
+ @inout nil, 1
+
+ @next!
+ @digi!
+ @phys ''
+
+ @finish!
+
+ \append addlabel "VR in Solipsism", Diagram =>
+ @mind nil, 2
+ @inout nil, 1
+
+ @next!
+ @digi!
+ @mind ''
+ @finish!
+
+ \append addlabel "VR in Cartesian Dualism", Diagram =>
+ @mind nil, 2
+ @inout nil, 1
+ @next!
+
+ @phys nil, 2
+ @inout nil, 1
+ @next!
+
+ @digi!
+ @phys ''
+ @finish!
+
+ \append p "However these philosophical theories of minds also constitute reality stacks by themselves and as such can
+ be compared directly:"
+
+ \append with figures!
+ \append addlabel "Materialism", Diagram =>
+ @mind!
+ @inout!
+ @phys!
+
+ @next!
+ @phys '', 2
+ @finish!
+
+ \append addlabel "Solipsism", Diagram =>
+ @mind!
+ @finish!
+
+ \append addlabel "Cartesian Dualism", Diagram =>
+ @mind!
+ @inout!
+ @next!
+
+ @phys!
+ @finish!
+
+_content
diff --git a/root/articles/text$moonscript -> fn -> mmm$dom b/root/articles/text$moonscript -> fn -> mmm$dom
new file mode 100644
index 0000000..1c04309
--- /dev/null
+++ b/root/articles/text$moonscript -> fn -> mmm$dom
@@ -0,0 +1,18 @@
+import div, h3, ul, li, a from require 'mmm.dom'
+
+=>
+ div {
+ h3 @gett 'title: text/plain', style: { 'margin-bottom': '-.5em' },
+ ul for child in *@children
+ name = child\gett 'name: alpha'
+ desc = child\gett 'description: text/plain'
+ li {
+ a name, {
+ href: child.path,
+ onclick: (e) =>
+ e\preventDefault!
+ BROWSER\navigate child.path
+ },
+ ': ', desc
+ }
+ }
diff --git a/root/articles/title: text$plain b/root/articles/title: text$plain
new file mode 100644
index 0000000..c45a444
--- /dev/null
+++ b/root/articles/title: text$plain
@@ -0,0 +1 @@
+articles and papers
diff --git a/root/experiments/center_of_mass.moon b/root/experiments/center_of_mass.moon
deleted file mode 100644
index 41cf8a4..0000000
--- a/root/experiments/center_of_mass.moon
+++ /dev/null
@@ -1,179 +0,0 @@
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-
-with Fileder {
- 'name: alpha': 'center_of_mass',
- 'description: text/plain': "Fonts aligned by Center-of-Mass",
-}
-
- if MODE == 'CLIENT'
- import CanvasApp from require 'mmm.canvasapp'
- import rgb from require 'mmm.color'
- import article, h1, p, div, span, input, button from require 'mmm.dom'
-
- fast = true
- center = true
- center_char = do
- canvas = document\createElement 'canvas'
- ctx = canvas\getContext '2d'
-
- cache = {}
-
- (char, font, height) ->
- name = "#{char} #{height} #{font}"
- return table.unpack cache[name] if cache[name]
-
- ctx\resetTransform!
- ctx.font = "#{height}px #{font}"
- width = (ctx\measureText char).width
- canvas.width, canvas.height = width, height * 1.2
-
- ctx.font = "#{height}px #{font}"
- ctx.textBaseline = 'top'
- ctx.fillStyle = rgb 0, 0, 0
- ctx\fillText char, 0, 0
-
- data = ctx\getImageData 0, 0, width, height * 1.2
-
- local xx, yy
- if fast
- loop = window\eval '(function(data) {
- var xx = 0, yy = 0, n = 0;
- for (var x = 0; x < data.width - 1; x++) {
- for (var y = 0; y < data.height - 1; y++) {
- var i = y * (data.width * 4) + x * 4;
- var alpha = data.data[i + 3] / 255;
- xx += x * alpha;
- yy += y * alpha;
- n += alpha;
- }
- }
-
- xx /= n;
- yy /= n;
- return [xx, yy];
- })'
- res = loop nil, data
- xx, yy = res[0], res[1]
- else
- xx, yy, n = 0, 0, 0
- for x = 0, data.width - 1
- for y = 0, data.height - 1
- i = y * (data.width * 4) + x * 4
- alpha = data.data[i + 3] / 255
- xx += x * alpha
- yy += y * alpha
- n += alpha
-
- xx /= n
- yy /= n
- cache[name] = { xx, yy, width }
- xx, yy, width
-
- class CenterOfMass extends CanvasApp
- width: window.innerWidth - 20
- height: 300
- new: (text, @font, @size) =>
- super!
- @text = {}
- for i = 1,#text
- @add text\sub i, i
-
- add: (char) =>
- rcx, rcy, w = center_char char, @font, @size
- cx, cy = w/2, @size/2
- vx, vy = 0, 0
- table.insert @text, {
- :char, :rcx, :rcy, :w
- :cx, :cy, :vx, :vy
- }
-
- refresh: =>
- for char in *@text
- char.rcx, char.rcy, char.w = center_char char.char, @font, @size
-
- keydown: (key) =>
- if key == "Backspace" or key == "Delete"
- table.remove @text
- elseif string.len(key) == 1
- @add key
-
- update: (dt) =>
- super dt
-
- ACCEL = 4 * dt
- DAMPING = 8 * dt
-
- for char in *@text
- { :rcx, :rcy, :cx, :cy, :w } = char
- if not center
- rcx, rcy = w/2, @size/2
- dx, dy = rcx - cx, rcy - cy
- char.vx += dx * ACCEL
- char.vy += dy * ACCEL
- char.cx += char.vx
- char.cy += char.vy
- char.vx *= DAMPING
- char.vy *= DAMPING
-
- draw: =>
- @ctx\clearRect 0, 0, @width, @height
-
- @ctx.font = "#{@size}px #{@font}"
- @ctx.textBaseline = 'top'
-
- x, y = @size * .1, @size
- for { :char, :cx, :cy, :w } in *@text
- if x + w > @width
- x = 0
- y += @size * 1.2
-
- @ctx\fillText char, x + w/2 - cx, y - cy
- x += w
-
- .props['fn -> mmm/dom'] = ->
- _content = {}
- append = (x) -> table.insert _content, x
-
- append h1 'Fonts aligned by Center-of-Mass'
- app = CenterOfMass "Click here and type Away!", "Times New Roman", 40
- append app.canvas
- app.canvas.style.backgroundColor = '#eee'
-
- add = =>
- append div {
- span 'font: ',
- with @font_input = input!
- .type = 'text'
- .value = 'Times New Roman'
- with button 'set'
- .onclick = (_, e) ->
- app.font = @font_input.value
- app\refresh!
- }
-
- append div {
- span 'size: ',
- input type: 'range', min: 2, max: 120, value: 40, onchange: (_, e) ->
- size = e.target.value
- @size_label.innerText = size
- app.size = size
- app\refresh!
- with @size_label = span '40'
- ''
- }
-
- append div {
- span 'center characters by weight: ',
- input type: 'checkbox', checked: center, onchange: (_, e) ->
- center = e.target.checked
- }
-
- append div {
- span 'optimize inner loop: ',
- input type: 'checkbox', checked: fast, onchange: (_, e) ->
- fast = e.target.checked
- }
- add {}
-
- article _content
diff --git a/root/experiments/center_of_mass/description: text$plain b/root/experiments/center_of_mass/description: text$plain
new file mode 100644
index 0000000..256df66
--- /dev/null
+++ b/root/experiments/center_of_mass/description: text$plain
@@ -0,0 +1 @@
+Fonts aligned by Center-of-Mass
diff --git a/root/experiments/center_of_mass/text$moonscript -> mmm$dom.moon b/root/experiments/center_of_mass/text$moonscript -> mmm$dom.moon
new file mode 100644
index 0000000..a43ea69
--- /dev/null
+++ b/root/experiments/center_of_mass/text$moonscript -> mmm$dom.moon
@@ -0,0 +1,171 @@
+assert MODE == 'CLIENT', '[nossr]'
+
+import CanvasApp from require 'mmm.canvasapp'
+import rgb from require 'mmm.color'
+import article, h1, p, div, span, input, button from require 'mmm.dom'
+
+fast = true
+center = true
+center_char = do
+ canvas = document\createElement 'canvas'
+ ctx = canvas\getContext '2d'
+
+ cache = {}
+
+ (char, font, height) ->
+ name = "#{char} #{height} #{font}"
+ return table.unpack cache[name] if cache[name]
+
+ ctx\resetTransform!
+ ctx.font = "#{height}px #{font}"
+ width = (ctx\measureText char).width
+ canvas.width, canvas.height = width, height * 1.2
+
+ ctx.font = "#{height}px #{font}"
+ ctx.textBaseline = 'top'
+ ctx.fillStyle = rgb 0, 0, 0
+ ctx\fillText char, 0, 0
+
+ data = ctx\getImageData 0, 0, width, height * 1.2
+
+ local xx, yy
+ if fast
+ loop = window\eval '(function(data) {
+ var xx = 0, yy = 0, n = 0;
+ for (var x = 0; x < data.width - 1; x++) {
+ for (var y = 0; y < data.height - 1; y++) {
+ var i = y * (data.width * 4) + x * 4;
+ var alpha = data.data[i + 3] / 255;
+ xx += x * alpha;
+ yy += y * alpha;
+ n += alpha;
+ }
+ }
+
+ xx /= n;
+ yy /= n;
+ return [xx, yy];
+ })'
+ res = loop nil, data
+ xx, yy = res[0], res[1]
+ else
+ xx, yy, n = 0, 0, 0
+ for x = 0, data.width - 1
+ for y = 0, data.height - 1
+ i = y * (data.width * 4) + x * 4
+ alpha = data.data[i + 3] / 255
+ xx += x * alpha
+ yy += y * alpha
+ n += alpha
+
+ xx /= n
+ yy /= n
+ cache[name] = { xx, yy, width }
+ xx, yy, width
+
+class CenterOfMass extends CanvasApp
+ width: window.innerWidth - 20
+ height: 300
+ new: (text, @font, @size) =>
+ super!
+ @text = {}
+ for i = 1,#text
+ @add text\sub i, i
+
+ add: (char) =>
+ rcx, rcy, w = center_char char, @font, @size
+ cx, cy = w/2, @size/2
+ vx, vy = 0, 0
+ table.insert @text, {
+ :char, :rcx, :rcy, :w
+ :cx, :cy, :vx, :vy
+ }
+
+ refresh: =>
+ for char in *@text
+ char.rcx, char.rcy, char.w = center_char char.char, @font, @size
+
+ keydown: (key) =>
+ if key == "Backspace" or key == "Delete"
+ table.remove @text
+ elseif string.len(key) == 1
+ @add key
+
+ update: (dt) =>
+ super dt
+
+ ACCEL = 4 * dt
+ DAMPING = 8 * dt
+
+ for char in *@text
+ { :rcx, :rcy, :cx, :cy, :w } = char
+ if not center
+ rcx, rcy = w/2, @size/2
+ dx, dy = rcx - cx, rcy - cy
+ char.vx += dx * ACCEL
+ char.vy += dy * ACCEL
+ char.cx += char.vx
+ char.cy += char.vy
+ char.vx *= DAMPING
+ char.vy *= DAMPING
+
+ draw: =>
+ @ctx\clearRect 0, 0, @width, @height
+
+ @ctx.font = "#{@size}px #{@font}"
+ @ctx.textBaseline = 'top'
+
+ x, y = @size * .1, @size
+ for { :char, :cx, :cy, :w } in *@text
+ if x + w > @width
+ x = 0
+ y += @size * 1.2
+
+ @ctx\fillText char, x + w/2 - cx, y - cy
+ x += w
+
+_content = {}
+append = (x) -> table.insert _content, x
+
+append h1 'Fonts aligned by Center-of-Mass'
+app = CenterOfMass "Click here and type Away!", "Times New Roman", 40
+append app.canvas
+app.canvas.style.backgroundColor = '#eee'
+
+add = =>
+ append div {
+ span 'font: ',
+ with @font_input = input!
+ .type = 'text'
+ .value = 'Times New Roman'
+ with button 'set'
+ .onclick = (_, e) ->
+ app.font = @font_input.value
+ app\refresh!
+ }
+
+ append div {
+ span 'size: ',
+ input type: 'range', min: 2, max: 120, value: 40, onchange: (_, e) ->
+ size = e.target.value
+ @size_label.innerText = size
+ app.size = size
+ app\refresh!
+ with @size_label = span '40'
+ ''
+ }
+
+ append div {
+ span 'center characters by weight: ',
+ input type: 'checkbox', checked: center, onchange: (_, e) ->
+ center = e.target.checked
+ }
+
+ append div {
+ span 'optimize inner loop: ',
+ input type: 'checkbox', checked: fast, onchange: (_, e) ->
+ fast = e.target.checked
+ }
+add {}
+
+article _content
diff --git a/root/experiments/init.moon b/root/experiments/init.moon
deleted file mode 100644
index ad3e06a..0000000
--- a/root/experiments/init.moon
+++ /dev/null
@@ -1,27 +0,0 @@
-import div, h3, ul, li, a from require 'mmm.dom'
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-require = relative ...
-
-Fileder {
- 'name: alpha': 'experiments',
- 'title: text/plain': 'various experiments',
- 'fn -> mmm/dom': (path) => div {
- h3 @gett 'title: text/plain', style: { 'margin-bottom': '-.5em' },
- ul for child in *@children
- name = child\gett 'name: alpha'
- desc = child\gett 'description: text/plain'
- li {
- a name, {
- href: child.path,
- onclick: (e) =>
- e\preventDefault!
- BROWSER\navigate child.path
- },
- ': ', desc
- }
- }
-
- require '.center_of_mass'
- require '.tags'
-}
diff --git a/root/experiments/tags/description: text$plain b/root/experiments/tags/description: text$plain
new file mode 100644
index 0000000..e585bb8
--- /dev/null
+++ b/root/experiments/tags/description: text$plain
@@ -0,0 +1 @@
+defining toggles, categories etc. with tags and functional hooks
diff --git a/root/experiments/tags/init.moon b/root/experiments/tags/init.moon
deleted file mode 100644
index 6b7945b..0000000
--- a/root/experiments/tags/init.moon
+++ /dev/null
@@ -1,99 +0,0 @@
-import div, h3, ul, li, a from require 'mmm.dom'
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-require = relative ...
-
-Fileder {
- 'name: alpha': 'tags',
- 'description: text/plain': 'defining toggles, categories etc. with only tags and functional hooks',
- 'fn -> mmm/component': if MODE == 'CLIENT' then =>
- import add_tag, rmv_tag, Node, Hierarchy, Toggle, NamespacedToggle from require '.tags'
- import ReactiveVar, tohtml, text, elements from require 'mmm.component'
- import article, div, form, span, h3, a, input, textarea, button from elements
-
- clone = (set) ->
- assert set and 'table' == (type set), 'not a set'
- { k,v for k,v in pairs set }
-
- set_append = (val) -> (set) ->
- with copy = clone set
- copy[val] = val
-
- set_remove = (val) -> (set) ->
- with copy = clone set
- copy[val] = nil
-
- set_join = (tbl, sep=' ') ->
- ret = ''
- for tag in pairs tbl
- ret ..= (tostring tag) .. sep
- ret
-
- entries = div!
-
- class ReactiveNode extends Node
- new: (...) =>
- super ...
- @tags = ReactiveVar @tags
- @_node = div {
- span @name, style: { 'font-weight': 'bold' },
- @tags\map (tags) -> with div!
- for tag,_ in pairs tags
- \append a (text tag), href: '#', style: {
- display: 'inline-block',
- margin: '0 5px',
- }
- }
-
- @node = tohtml @_node
-
- has: (tag) => @tags\get![tag]
- add: (tag) => @tags\transform set_append tag
- rmv: (tag) => @tags\transform set_remove tag
-
- rules = {
- Hierarchy 'home', 'sol'
- Hierarchy 'sol', 'desktop'
- Hierarchy 'desktop', 'vacation'
- Hierarchy 'desktop', 'documents'
- NamespacedToggle 'documents', 'work', 'personal'
- -- Toggle 'work', 'personal'
- -- Hierarchy 'documents', 'work'
- -- Hierarchy 'documents', 'personal'
- }
-
- pictures = for i=1,10
- with node = ReactiveNode "picture#{i}.jpg"
- entries\append node
- add_tag node, 'vacation'
-
- pers = ReactiveNode 'mypersonalfile.doc'
- entries\append pers
-
- article entries, div do
- yield = coroutine.yield
- step = coroutine.wrap ->
- yield "mark document"
- add_tag pers, 'documents'
-
- yield "mark personal"
- add_tag pers, 'personal'
-
- yield "mark work"
- add_tag pers, 'work'
-
- yield "unmark work"
- rmv_tag pers, 'work'
-
- yield "remove from documents"
- rmv_tag pers, 'documents'
-
- yield false
-
- next_step = ReactiveVar step!
- next_step\map (desc) ->
- if desc
- button (text desc), onclick: (e) => next_step\set step!
- else
- text ''
-}
diff --git a/root/experiments/tags/tags.moon b/root/experiments/tags/tags: text$moonscript -> table.moon
index 198392e..198392e 100644
--- a/root/experiments/tags/tags.moon
+++ b/root/experiments/tags/tags: text$moonscript -> table.moon
diff --git a/root/experiments/tags/text$moonscript -> fn -> mmm$component.moon b/root/experiments/tags/text$moonscript -> fn -> mmm$component.moon
new file mode 100644
index 0000000..24972ac
--- /dev/null
+++ b/root/experiments/tags/text$moonscript -> fn -> mmm$component.moon
@@ -0,0 +1,92 @@
+=>
+ assert MODE == 'CLIENT', '[nossr]'
+
+ import add_tag, rmv_tag, Node, Hierarchy, Toggle, NamespacedToggle from @get 'tags: table'
+ import ReactiveVar, tohtml, text, elements from require 'mmm.component'
+ import article, div, form, span, h3, a, input, textarea, button from elements
+
+ clone = (set) ->
+ assert set and 'table' == (type set), 'not a set'
+ { k,v for k,v in pairs set }
+
+ set_append = (val) -> (set) ->
+ with copy = clone set
+ copy[val] = val
+
+ set_remove = (val) -> (set) ->
+ with copy = clone set
+ copy[val] = nil
+
+ set_join = (tbl, sep=' ') ->
+ ret = ''
+ for tag in pairs tbl
+ ret ..= (tostring tag) .. sep
+ ret
+
+ entries = div!
+
+ class ReactiveNode extends Node
+ new: (...) =>
+ super ...
+ @tags = ReactiveVar @tags
+ @_node = div {
+ span @name, style: { 'font-weight': 'bold' },
+ @tags\map (tags) -> with div!
+ for tag,_ in pairs tags
+ \append a (text tag), href: '#', style: {
+ display: 'inline-block',
+ margin: '0 5px',
+ }
+ }
+
+ @node = tohtml @_node
+
+ has: (tag) => @tags\get![tag]
+ add: (tag) => @tags\transform set_append tag
+ rmv: (tag) => @tags\transform set_remove tag
+
+ rules = {
+ Hierarchy 'home', 'sol'
+ Hierarchy 'sol', 'desktop'
+ Hierarchy 'desktop', 'vacation'
+ Hierarchy 'desktop', 'documents'
+ NamespacedToggle 'documents', 'work', 'personal'
+ -- Toggle 'work', 'personal'
+ -- Hierarchy 'documents', 'work'
+ -- Hierarchy 'documents', 'personal'
+ }
+
+ pictures = for i=1,10
+ with node = ReactiveNode "picture#{i}.jpg"
+ entries\append node
+ add_tag node, 'vacation'
+
+ pers = ReactiveNode 'mypersonalfile.doc'
+ entries\append pers
+
+ article entries, div do
+ yield = coroutine.yield
+ step = coroutine.wrap ->
+ yield "mark document"
+ add_tag pers, 'documents'
+
+ yield "mark personal"
+ add_tag pers, 'personal'
+
+ yield "mark work"
+ add_tag pers, 'work'
+
+ yield "unmark work"
+ rmv_tag pers, 'work'
+
+ yield "remove from documents"
+ rmv_tag pers, 'documents'
+
+ yield false
+
+ next_step = ReactiveVar step!
+ next_step\map (desc) ->
+ if desc
+ button (text desc), onclick: (e) => next_step\set step!
+ else
+ text ''
diff --git a/root/experiments/text$moonscript -> fn -> mmm$dom.moon b/root/experiments/text$moonscript -> fn -> mmm$dom.moon
new file mode 100644
index 0000000..1c04309
--- /dev/null
+++ b/root/experiments/text$moonscript -> fn -> mmm$dom.moon
@@ -0,0 +1,18 @@
+import div, h3, ul, li, a from require 'mmm.dom'
+
+=>
+ div {
+ h3 @gett 'title: text/plain', style: { 'margin-bottom': '-.5em' },
+ ul for child in *@children
+ name = child\gett 'name: alpha'
+ desc = child\gett 'description: text/plain'
+ li {
+ a name, {
+ href: child.path,
+ onclick: (e) =>
+ e\preventDefault!
+ BROWSER\navigate child.path
+ },
+ ': ', desc
+ }
+ }
diff --git a/root/experiments/title: text$plain b/root/experiments/title: text$plain
new file mode 100644
index 0000000..0487531
--- /dev/null
+++ b/root/experiments/title: text$plain
@@ -0,0 +1 @@
+various experiments
diff --git a/root/init.moon b/root/init.moon
deleted file mode 100644
index 41be710..0000000
--- a/root/init.moon
+++ /dev/null
@@ -1,69 +0,0 @@
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-require = relative ...
-
-Fileder {
- 'name: alpha': '',
- 'fn -> mmm/dom': =>
- import article, h1, h3, div, b, p, a, br, ul, tt, li, img from require 'mmm.dom'
- import opairs from require 'mmm.ordered'
-
- append, finish = do
- content = {}
-
- append = (stuff) -> table.insert content, stuff
- append, -> article content
-
- moon = '\xe2\x98\xbd'
-
- iconlink = (href, src, alt, style) -> a {
- class: 'iconlink',
- :href,
- target: '_blank',
- img :src, :alt, :style
- }
-
- -- menu
- append h1 {
- style: {
- position: 'relative',
- 'border-bottom': '1px solid #000'
- },
- 'mmm',
- div {
- class: 'icons',
- iconlink 'https://github.com/s-ol/mmm', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg',
- iconlink 'https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg',
- iconlink 'https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring',
- { height: '0.9em', 'margin-left': '.04em' }
- }
- }
-
- append p {
- tt 'mmm'
- ' is not the '
- tt 'www'
- ', because it runs on '
- a { 'MoonScript', href: 'https://moonscript.org' }
- '.'
- br!
- 'You can find the source code of everything '
- a { 'here', href: 'https://github.com/s-ol/mmm' }
- '.'
- }
-
- for child in *@children
- append (child\get 'preview: mmm/dom') or child\get 'mmm/dom'
-
- append p {
- "made with #{moon} by "
- a { 's-ol', href: 'https://twitter.com/S0lll0s' }
- }
-
- finish!
-
- require '.articles'
- require '.animations'
- require '.experiments'
- require '.meta'
-}
diff --git a/root/meta/init.moon b/root/meta/init.moon
deleted file mode 100644
index 4c2fc15..0000000
--- a/root/meta/init.moon
+++ /dev/null
@@ -1,36 +0,0 @@
-import div, h3, p, br, ul, li, b, a from require 'mmm.dom'
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-require = relative ...
-
-Fileder {
- 'name: alpha': 'meta',
- 'title: text/plain': 'about mmm',
- 'fn -> mmm/dom': (path) => div {
- style: { 'max-width': '700px' },
- h3 @gett 'title: text/plain', style: { 'margin-bottom': '-.5em' },
- p "mmm is a collection of Lua/Moonscript modules for web development.",
- "All modules are 'polymorphic' - they can run in the ", (b 'browser'),
- ", using the native browser API for creating and interacting with DOM content, as well as on the ",
- (b 'server'), ", where they operate on and produce equivalent HTML strings."
- p "As the two implementations of each module are designed to be compatible,
- mmm facilitates code and content sharing between server and client
- and enables serverside rendering and rehydration."
- ul for child in *@children
- name = child\gett 'name: alpha'
- desc = child\gett 'description: mmm/dom'
- li {
- a name, {
- href: child.path,
- onclick: (e) =>
- e\preventDefault!
- BROWSER\navigate child.path
- },
- ': ', desc
- }
- }
-
- require '.mmm_dom'
- require '.todo'
- require '.test_component'
-}
diff --git a/root/meta/mmm.dom/description: text$plain b/root/meta/mmm.dom/description: text$plain
new file mode 100644
index 0000000..5f4f965
--- /dev/null
+++ b/root/meta/mmm.dom/description: text$plain
@@ -0,0 +1 @@
+a lightweight DSL for creating HTML documents
diff --git a/root/meta/mmm.dom/text$moonscript -> mmm$dom.moon b/root/meta/mmm.dom/text$moonscript -> mmm$dom.moon
new file mode 100644
index 0000000..07dab49
--- /dev/null
+++ b/root/meta/mmm.dom/text$moonscript -> mmm$dom.moon
@@ -0,0 +1,172 @@
+import article, h1, h2, p, a, span, div, pre, code from require 'mmm.dom'
+
+mmmdom = -> code 'mmm.dom'
+
+source = do
+ build = (lang) -> if MODE == 'SERVER'
+ (str) -> code (str\match '^ *(..-) *$'), class: "hljs lang-#{lang}"
+ else
+ (str) ->
+ result = window.hljs\highlight lang, (str\match '^ *(..-) *$'), true
+ with code class: 'hljs'
+ .innerHTML = result.value
+
+ mklua, mkmoon = (build 'lua'), build 'moonscript'
+
+ (moon, lua, demo=true) ->
+ the_code = pre (mkmoon moon), (mklua lua), class: 'dual-code'
+
+ return the_code unless demo
+
+ example = assert load lua
+ div the_code, div example!, class: 'example'
+
+article {
+ h1 mmmdom!
+ p mmmdom!, " is a lightweight DSL for creating HTML documents in Lua and Moonscript."
+
+ p do
+ fengari = a "fengari.io", href: '//fengari.io'
+
+ "The same API is supported both on the server / in native Lua, where it outputs an HTML string,
+ as well as on the client (using ", fengari, "), where it dynamically creates DOM Nodes that can
+ be further manipulated using Lua or JavaScript. The API behaves exactly the same way in both modes
+ so that you can write code once that works both for rendering offline/serverside and in the browser.
+ This enables you to build websites and applications with dynamic content as well as perfect static
+ views for clients with JS disabled and SEO."
+
+ h2 "API"
+ p "Begin by requiring ", mmmdom!, ". The module returns a 'magic table' that allows you to instantiate
+ HTML elements of any type. Compare the usage in Lua and Moonscript:"
+
+ source [[
+import div, h1, p, a from require 'mmm.dom'
+
+-- or just use dom.div etc. if you want to keep your
+-- namespace clean, they are cached automatically
+
+dom = require 'mmm.dom'
+ ]], [[
+local dom = require 'mmm.dom'
+
+local div, h1, p, a = dom.div, dom.h1, dom.p, dom.a
+
+-- or just use dom.div etc. if you want to keep your
+-- namespace clean, they are cached automatically
+ ]], false
+
+ p "Each of these constructor functions can now be used to instantiate elements of the specified type.
+ In the simplest case, you may want to a simple element with no attributes or children, for example a ",
+ (code '<br />'), " line break tag:"
+
+ source [[
+import br from require 'mmm.dom'
+
+br!
+ ]], [[
+local dom = require 'mmm.dom'
+
+return dom.br()
+ ]], false
+
+ p "You can pass any number of children as arguments when you create an element. They will be joined without spaces:"
+
+ source [[
+import h3, i, code from require 'mmm.dom'
+
+h3 "this is a ",
+(i 'headline'),
+" with some ",
+code 'rich text'
+]], [[
+local d = require 'mmm.dom'
+
+return d.h3(
+"this is a ",
+d.i 'headline',
+" with some ",
+d.code 'rich text'
+)
+ ]]
+
+ p "As you can see, ", mmmdom!, " can be used quite comfortably both in Lua and Moonscript."
+ p "As you build bigger structures, you may find that constructing HTML trees via argument lists can get a bit
+ confusing (especially with Moonscript and indentation rules).
+ Because of this ", mmmdom!, " also supports passing a table with children in the integer keys 1, 2, ...
+ This is particularily useful when you make use of Lua's shorthand for calling functions with single arguments:"
+
+ source [[
+import article, h3, span, div, i, p from require 'mmm.dom'
+
+article {
+h3 "This is a headline with ", i "cursive text"
+p {
+ "The content goes ",
+ i "here."
+}
+p "more paragraphs can be added as well, of course."
+}
+ ]], [[
+local dom = require 'mmm.dom'
+local article, h3, span, div, i, p = dom.article, dom.h3, dom.span, dom.div, dom.i, dom.p
+
+return article{
+h3{ "This is a headline with ", i "cursive text" },
+p{
+ "The content goes ",
+ i"here."
+},
+p"more paragraphs can be added as well, of course."
+}
+ ]]
+
+ p "Of course ", mmmdom!, " also allows you to set attributes on elements."
+ p "When you are using a constructor using the single-table approach,
+ all string keys set on the table are considered attributes and set on the element:"
+
+ source [[
+import div from require 'mmm.dom'
+
+div {
+id: 'my_div',
+class: 'shadow',
+"This is div matches the CSS selector `div#my_div.shadow`"
+}
+ ]], [[
+local div = require('mmm.dom').div
+
+return div{
+id = 'my_div',
+class = 'shadow',
+"This is div matches the CSS selector `div#my_div.shadow`"
+}
+ ]]
+
+ p "When you are passing multiple arguments, you can attach the attributes in a table
+ as the last argument. This works very well with Moonscript syntax."
+
+ p "In general attribute values need to be strings or numbers to be rendered correctly both
+ on client on server. The only exception is the ", (code 'style'), " attribute, which,
+ if it is passed as a table, will be expanded into a valid CSS string:"
+
+ source [[
+import div from require 'mmm.dom'
+
+div "red div with white text", style: {
+background: 'red',
+color: '#ffffff',
+}
+ ]], [[
+local div = require('mmm.dom').div
+
+return div(
+"red div with white text",
+{
+ style = {
+ background = 'red',
+ color = '#ffffff',
+ }
+}
+)
+ ]]
+}
diff --git a/root/meta/mmm_dom.moon b/root/meta/mmm_dom.moon
deleted file mode 100644
index 35d60c0..0000000
--- a/root/meta/mmm_dom.moon
+++ /dev/null
@@ -1,179 +0,0 @@
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-
-import article, h1, h2, p, a, span, div, pre, code from require 'mmm.dom'
-
-mmmdom = -> code 'mmm.dom'
-
-source = do
- build = (lang) -> if MODE == 'SERVER'
- (str) -> code (str\match '^ *(..-) *$'), class: "hljs lang-#{lang}"
- else
- (str) ->
- result = window.hljs\highlight lang, (str\match '^ *(..-) *$'), true
- with code class: 'hljs'
- .innerHTML = result.value
-
- mklua, mkmoon = (build 'lua'), build 'moonscript'
-
- (moon, lua, demo=true) ->
- the_code = pre (mkmoon moon), (mklua lua), class: 'dual-code'
-
- return the_code unless demo
-
- example = assert load lua
- div the_code, div example!, class: 'example'
-
-Fileder {
- 'name: alpha': 'mmm.dom'
- 'description: mmm/dom': 'a lightweight DSL for creating HTML documents',
- 'mmm/dom': article {
- h1 mmmdom!
- p mmmdom!, " is a lightweight DSL for creating HTML documents in Lua and Moonscript."
-
- p do
- fengari = a "fengari.io", href: '//fengari.io'
-
- "The same API is supported both on the server / in native Lua, where it outputs an HTML string,
- as well as on the client (using ", fengari, "), where it dynamically creates DOM Nodes that can
- be further manipulated using Lua or JavaScript. The API behaves exactly the same way in both modes
- so that you can write code once that works both for rendering offline/serverside and in the browser.
- This enables you to build websites and applications with dynamic content as well as perfect static
- views for clients with JS disabled and SEO."
-
- h2 "API"
- p "Begin by requiring ", mmmdom!, ". The module returns a 'magic table' that allows you to instantiate
- HTML elements of any type. Compare the usage in Lua and Moonscript:"
-
- source [[
-import div, h1, p, a from require 'mmm.dom'
-
--- or just use dom.div etc. if you want to keep your
--- namespace clean, they are cached automatically
-
-dom = require 'mmm.dom'
- ]], [[
-local dom = require 'mmm.dom'
-
-local div, h1, p, a = dom.div, dom.h1, dom.p, dom.a
-
--- or just use dom.div etc. if you want to keep your
--- namespace clean, they are cached automatically
- ]], false
-
- p "Each of these constructor functions can now be used to instantiate elements of the specified type.
- In the simplest case, you may want to a simple element with no attributes or children, for example a ",
- (code '<br />'), " line break tag:"
-
- source [[
-import br from require 'mmm.dom'
-
-br!
- ]], [[
-local dom = require 'mmm.dom'
-
-return dom.br()
- ]], false
-
- p "You can pass any number of children as arguments when you create an element. They will be joined without spaces:"
-
- source [[
-import h3, i, code from require 'mmm.dom'
-
-h3 "this is a ",
- (i 'headline'),
- " with some ",
- code 'rich text'
- ]], [[
-local d = require 'mmm.dom'
-
-return d.h3(
- "this is a ",
- d.i 'headline',
- " with some ",
- d.code 'rich text'
-)
- ]]
-
- p "As you can see, ", mmmdom!, " can be used quite comfortably both in Lua and Moonscript."
- p "As you build bigger structures, you may find that constructing HTML trees via argument lists can get a bit
- confusing (especially with Moonscript and indentation rules).
- Because of this ", mmmdom!, " also supports passing a table with children in the integer keys 1, 2, ...
- This is particularily useful when you make use of Lua's shorthand for calling functions with single arguments:"
-
- source [[
-import article, h3, span, div, i, p from require 'mmm.dom'
-
-article {
- h3 "This is a headline with ", i "cursive text"
- p {
- "The content goes ",
- i "here."
- }
- p "more paragraphs can be added as well, of course."
-}
- ]], [[
-local dom = require 'mmm.dom'
-local article, h3, span, div, i, p = dom.article, dom.h3, dom.span, dom.div, dom.i, dom.p
-
-return article{
- h3{ "This is a headline with ", i "cursive text" },
- p{
- "The content goes ",
- i"here."
- },
- p"more paragraphs can be added as well, of course."
-}
- ]]
-
- p "Of course ", mmmdom!, " also allows you to set attributes on elements."
- p "When you are using a constructor using the single-table approach,
- all string keys set on the table are considered attributes and set on the element:"
-
- source [[
-import div from require 'mmm.dom'
-
-div {
- id: 'my_div',
- class: 'shadow',
- "This is div matches the CSS selector `div#my_div.shadow`"
-}
- ]], [[
-local div = require('mmm.dom').div
-
-return div{
- id = 'my_div',
- class = 'shadow',
- "This is div matches the CSS selector `div#my_div.shadow`"
-}
- ]]
-
- p "When you are passing multiple arguments, you can attach the attributes in a table
- as the last argument. This works very well with Moonscript syntax."
-
- p "In general attribute values need to be strings or numbers to be rendered correctly both
- on client on server. The only exception is the ", (code 'style'), " attribute, which,
- if it is passed as a table, will be expanded into a valid CSS string:"
-
- source [[
-import div from require 'mmm.dom'
-
-div "red div with white text", style: {
- background: 'red',
- color: '#ffffff',
-}
- ]], [[
-local div = require('mmm.dom').div
-
-return div(
- "red div with white text",
- {
- style = {
- background = 'red',
- color = '#ffffff',
- }
- }
-)
- ]]
- }
-}
diff --git a/root/meta/test_component.moon b/root/meta/test_component.moon
deleted file mode 100644
index d5fb6f1..0000000
--- a/root/meta/test_component.moon
+++ /dev/null
@@ -1,254 +0,0 @@
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-
-Fileder {
- 'name: alpha': 'test_mmm.component'
- 'description: text/plain': 'Tests for mmm.component'
- 'fn -> mmm/dom': =>
- import article, div, h1, ul, li, pre from require 'mmm.dom'
-
- _content = {}
- append = (stuff) -> table.insert _content, stuff
-
- last = nil
- test_group = (name) ->
- if last
- append div (h1 last.name), ul last
-
- last = { :name }
- (name, test) ->
- ok, err = pcall test
- table.insert last, li if ok
- "passed '#{name}'"
- else
- "failed '#{name}'", pre err
-
- expect = (expected, note, ...) ->
- ok, msg = pcall ...
- if ok or not msg\find expected
- error note
-
- run_test = test_group 'component.moon'
-
- local ReactiveVar, ReactiveElement
- run_test "exports ReactiveVar, ReactiveElement", ->
- import ReactiveVar, ReactiveElement from require 'mmm.component'
- assert ReactiveVar, "ReactiveVar not exported"
- assert ReactiveElement, "ReactiveElement not exported"
-
- run_test "exports tohtml helper", ->
- import tohtml from require 'mmm.component'
- assert 'function' == (type tohtml), "tohtml not exported"
-
- -- @TODO: get_or_create
-
- run_test "exports text helper", ->
- import text from require 'mmm.component'
- assert 'function' == (type text), "text not exported"
-
- node = text 'a test string'
-
- data = if MODE == 'CLIENT'
- assert (js.instanceof node, js.global.Node), "expected text to generate a Node"
- node.data
- else
- node
-
- assert data == 'a test string', "expected text to store the string"
-
- run_test "text joins multiple arguments", ->
- import text from require 'mmm.component'
-
- node = text 'a', 'test', 'string'
-
- data = if MODE == 'CLIENT' then node.data else node
- assert data == 'a test string', "expected text to join arguments with spaces"
-
- run_test "exports elements table", ->
- import elements from require 'mmm.component'
-
- assert (type elements.div!) == 'table', "expected to build element with elements.div!"
- assert (type elements.madeup!) == 'table', "expected to build element with elements.madeup!"
-
- run_test = test_group 'ReactiveVar'
-
- run_test "stores a value", ->
- reactive = ReactiveVar 'test'
- assert 'test' == reactive\get!, "expected x to be 'test'"
-
- run_test "provides #map shorthand", ->
- local done
-
- original = ReactiveVar 1
- mapped = original\map (a) -> a + 10
-
- assert mapped\get! == 11, "expected mapped to be 11"
- return if MODE == 'SERVER'
-
- original\set 4
- assert mapped\get! == 14, "expected mapped to update"
-
- mapped\subscribe coroutine.wrap (next, last) ->
- assert next == 26, "expected next to be 26"
- assert last == 14, "expected last to be 14"
- done = true
-
- original\set 16
- assert done, "expected to reach the end"
-
- if MODE == 'CLIENT'
- run_test "propagates updates", ->
- local done
-
- reactive = ReactiveVar 'test'
- reactive\subscribe coroutine.wrap (next) ->
- assert next == 'toast', "expected next to be 'toast'"
- assert coroutine.yield! == 'cheese', "expected next to be 'cheese'"
- done = true
-
- reactive\set 'toast'
- assert 'toast' == reactive\get!, "expected #get to return 'toast'"
- reactive\set 'cheese'
- assert done, "expected to reach the end"
-
- run_test "passes old value as well", ->
- local done
-
- reactive = ReactiveVar 1
- reactive\subscribe coroutine.wrap (next, last) ->
- assert last == 1, "expected last:1 to be 1"
- next, last = coroutine.yield!
- assert last == 2, "expected last:2 to be 2"
- done = true
-
- reactive\set 2
- reactive\set 3
- assert done, "expected to reach the end"
-
- run_test "provides #transform shorthand", ->
- local done
-
- reactive = ReactiveVar 1
- reactive\subscribe coroutine.wrap (next, last) ->
- assert last == 1, "expected last:1 to be 1"
- next, last = coroutine.yield!
- assert last == 2, "expected last:2 to be 2"
- done = true
-
- add_one = (a) -> a + 1
- reactive\transform add_one
- reactive\transform add_one
- assert done, "expected to reach the end"
-
- run_test "#subscribe returns function to unsubscribe", ->
- calls = 0
-
- reactive = ReactiveVar 1
- unsub = reactive\subscribe coroutine.wrap () ->
- calls += 1
- coroutine.yield!
- calls += 1
- coroutine.yield!
- calls += 1
-
- assert 'function' == (type unsub), "expected to receive a function"
-
- reactive\set 2
- reactive\set 3
- assert calls == 2, "wat"
-
- unsub!
- reactive\set 4
- assert calls == 2, "expected to stop receiving updates"
-
- run_test "tracks multiple subscriptions at once", ->
- reactive = ReactiveVar 'test'
- unsub = reactive\subscribe coroutine.wrap (next) ->
- assert next == 'toast', "expected next to be toast"
- next = coroutine.yield!
- assert next == 'cheese', "expected next to be cheese"
- coroutine.yield!
- error "expected not to get here"
-
- reactive\set 'toast'
-
- local done
- reactive\subscribe coroutine.wrap (next) ->
- assert next == 'cheese', "expected next to be cheese"
- next = coroutine.yield!
- assert next == 'test', "expected next to be test"
- done = true
-
- reactive\set 'cheese'
- unsub!
- reactive\set 'test'
- assert done, "expected to reach the end"
-
- run_test = test_group 'ReactiveElement'
-
- run_test "creates a HTML element", ->
- elem = ReactiveElement 'span'
- assert elem.node and elem.node.localName == 'span', "expected Node to be a <span>"
-
- -- @TODO: can take over a DOM Node
-
- run_test "sets attributes from a table arg", ->
- elem = ReactiveElement 'span', class: 'never'
- assert elem.node.className == 'never', "expected class to be 'never'"
-
- run_test "appends Nodes from arguments", ->
- e_div, e_pre = div!, pre!
- elem = ReactiveElement 'span', e_div, e_pre
- assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem"
- assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem"
-
- run_test "can append ReactiveElements and text", ->
- e_div = ReactiveElement 'div'
- elem = ReactiveElement 'div', e_div, 'testtext'
- assert elem.node.firstElementChild == e_div.node, "expected div to be the first child of elem"
- assert elem.node.lastChild.data == 'testtext', "expected last child of elem to be 'testtext'"
-
- run_test "accepts attributes after children", ->
- e_div = div!
- elem = ReactiveElement 'div', e_div, class: 'test'
- assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem"
- assert elem.node.className == 'test', "expected class to be 'test'"
-
- run_test "allows mixing attributes and children in a single table", ->
- e_div, e_pre = div!, pre!
- elem = ReactiveElement 'div', { class: 'test', e_div, e_pre }
- assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem"
- assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem"
- assert elem.node.className == 'test', "expected class to be 'test'"
-
- run_test "can unwrap and track attributes from ReactiveVars", ->
- klass = ReactiveVar 'test'
- elem = ReactiveElement 'div', class: klass
- assert elem.node.className == 'test', "expected class to be 'test'"
- klass\set 'toast'
- assert elem.node.className == 'toast', "expected class to be 'toast'"
-
- run_test "can unwrap and track children from ReactiveVars", ->
- child = ReactiveVar h1 'test'
- elem = ReactiveElement 'div', child, pre 'fixed'
- assert elem.node.firstElementChild.localName == 'h1', "expected first child to be h1"
- assert elem.node.childElementCount == 2, "expected node to have two children"
- child\set div 'toast'
- assert elem.node.firstElementChild.localName == 'div', "expected first child to be div"
- assert elem.node.childElementCount == 2, "expected node to have two children"
-
- run_test "warns when appending a string from a ReactiveVar", ->
- import text from require 'mmm.component'
-
- str = ReactiveVar 'test'
- elem = ReactiveElement 'div', str
- expect 'cannot replace string node', 'expected error', str\set, 'string too'
- elem\destroy!
-
- elem = ReactiveElement 'div', str\map text
- str\set 'this is text'
-
- test_group!
-
- article _content
-}
diff --git a/root/meta/test_mmm.component/description: text$plain b/root/meta/test_mmm.component/description: text$plain
new file mode 100644
index 0000000..691fea5
--- /dev/null
+++ b/root/meta/test_mmm.component/description: text$plain
@@ -0,0 +1 @@
+Tests for mmm.component
diff --git a/root/meta/test_mmm.component/text$moonscript -> mmm$dom.moon b/root/meta/test_mmm.component/text$moonscript -> mmm$dom.moon
new file mode 100644
index 0000000..547b030
--- /dev/null
+++ b/root/meta/test_mmm.component/text$moonscript -> mmm$dom.moon
@@ -0,0 +1,246 @@
+import article, div, h1, ul, li, pre from require 'mmm.dom'
+
+_content = {}
+append = (stuff) -> table.insert _content, stuff
+
+last = nil
+test_group = (name) ->
+ if last
+ append div (h1 last.name), ul last
+
+ last = { :name }
+ (name, test) ->
+ ok, err = pcall test
+ table.insert last, li if ok
+ "passed '#{name}'"
+ else
+ "failed '#{name}'", pre err
+
+expect = (expected, note, ...) ->
+ ok, msg = pcall ...
+ if ok or not msg\find expected
+ error note
+
+run_test = test_group 'component.moon'
+
+local ReactiveVar, ReactiveElement
+run_test "exports ReactiveVar, ReactiveElement", ->
+ import ReactiveVar, ReactiveElement from require 'mmm.component'
+ assert ReactiveVar, "ReactiveVar not exported"
+ assert ReactiveElement, "ReactiveElement not exported"
+
+run_test "exports tohtml helper", ->
+ import tohtml from require 'mmm.component'
+ assert 'function' == (type tohtml), "tohtml not exported"
+
+-- @TODO: get_or_create
+
+run_test "exports text helper", ->
+ import text from require 'mmm.component'
+ assert 'function' == (type text), "text not exported"
+
+ node = text 'a test string'
+
+ data = if MODE == 'CLIENT'
+ assert (js.instanceof node, js.global.Node), "expected text to generate a Node"
+ node.data
+ else
+ node
+
+ assert data == 'a test string', "expected text to store the string"
+
+run_test "text joins multiple arguments", ->
+ import text from require 'mmm.component'
+
+ node = text 'a', 'test', 'string'
+
+ data = if MODE == 'CLIENT' then node.data else node
+ assert data == 'a test string', "expected text to join arguments with spaces"
+
+run_test "exports elements table", ->
+ import elements from require 'mmm.component'
+
+ assert (type elements.div!) == 'table', "expected to build element with elements.div!"
+ assert (type elements.madeup!) == 'table', "expected to build element with elements.madeup!"
+
+run_test = test_group 'ReactiveVar'
+
+run_test "stores a value", ->
+ reactive = ReactiveVar 'test'
+ assert 'test' == reactive\get!, "expected x to be 'test'"
+
+run_test "provides #map shorthand", ->
+ local done
+
+ original = ReactiveVar 1
+ mapped = original\map (a) -> a + 10
+
+ assert mapped\get! == 11, "expected mapped to be 11"
+ return if MODE == 'SERVER'
+
+ original\set 4
+ assert mapped\get! == 14, "expected mapped to update"
+
+ mapped\subscribe coroutine.wrap (next, last) ->
+ assert next == 26, "expected next to be 26"
+ assert last == 14, "expected last to be 14"
+ done = true
+
+ original\set 16
+ assert done, "expected to reach the end"
+
+if MODE == 'CLIENT'
+ run_test "propagates updates", ->
+ local done
+
+ reactive = ReactiveVar 'test'
+ reactive\subscribe coroutine.wrap (next) ->
+ assert next == 'toast', "expected next to be 'toast'"
+ assert coroutine.yield! == 'cheese', "expected next to be 'cheese'"
+ done = true
+
+ reactive\set 'toast'
+ assert 'toast' == reactive\get!, "expected #get to return 'toast'"
+ reactive\set 'cheese'
+ assert done, "expected to reach the end"
+
+ run_test "passes old value as well", ->
+ local done
+
+ reactive = ReactiveVar 1
+ reactive\subscribe coroutine.wrap (next, last) ->
+ assert last == 1, "expected last:1 to be 1"
+ next, last = coroutine.yield!
+ assert last == 2, "expected last:2 to be 2"
+ done = true
+
+ reactive\set 2
+ reactive\set 3
+ assert done, "expected to reach the end"
+
+ run_test "provides #transform shorthand", ->
+ local done
+
+ reactive = ReactiveVar 1
+ reactive\subscribe coroutine.wrap (next, last) ->
+ assert last == 1, "expected last:1 to be 1"
+ next, last = coroutine.yield!
+ assert last == 2, "expected last:2 to be 2"
+ done = true
+
+ add_one = (a) -> a + 1
+ reactive\transform add_one
+ reactive\transform add_one
+ assert done, "expected to reach the end"
+
+ run_test "#subscribe returns function to unsubscribe", ->
+ calls = 0
+
+ reactive = ReactiveVar 1
+ unsub = reactive\subscribe coroutine.wrap () ->
+ calls += 1
+ coroutine.yield!
+ calls += 1
+ coroutine.yield!
+ calls += 1
+
+ assert 'function' == (type unsub), "expected to receive a function"
+
+ reactive\set 2
+ reactive\set 3
+ assert calls == 2, "wat"
+
+ unsub!
+ reactive\set 4
+ assert calls == 2, "expected to stop receiving updates"
+
+ run_test "tracks multiple subscriptions at once", ->
+ reactive = ReactiveVar 'test'
+ unsub = reactive\subscribe coroutine.wrap (next) ->
+ assert next == 'toast', "expected next to be toast"
+ next = coroutine.yield!
+ assert next == 'cheese', "expected next to be cheese"
+ coroutine.yield!
+ error "expected not to get here"
+
+ reactive\set 'toast'
+
+ local done
+ reactive\subscribe coroutine.wrap (next) ->
+ assert next == 'cheese', "expected next to be cheese"
+ next = coroutine.yield!
+ assert next == 'test', "expected next to be test"
+ done = true
+
+ reactive\set 'cheese'
+ unsub!
+ reactive\set 'test'
+ assert done, "expected to reach the end"
+
+run_test = test_group 'ReactiveElement'
+
+run_test "creates a HTML element", ->
+ elem = ReactiveElement 'span'
+ assert elem.node and elem.node.localName == 'span', "expected Node to be a <span>"
+
+-- @TODO: can take over a DOM Node
+
+run_test "sets attributes from a table arg", ->
+ elem = ReactiveElement 'span', class: 'never'
+ assert elem.node.className == 'never', "expected class to be 'never'"
+
+run_test "appends Nodes from arguments", ->
+ e_div, e_pre = div!, pre!
+ elem = ReactiveElement 'span', e_div, e_pre
+ assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem"
+ assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem"
+
+run_test "can append ReactiveElements and text", ->
+ e_div = ReactiveElement 'div'
+ elem = ReactiveElement 'div', e_div, 'testtext'
+ assert elem.node.firstElementChild == e_div.node, "expected div to be the first child of elem"
+ assert elem.node.lastChild.data == 'testtext', "expected last child of elem to be 'testtext'"
+
+run_test "accepts attributes after children", ->
+ e_div = div!
+ elem = ReactiveElement 'div', e_div, class: 'test'
+ assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem"
+ assert elem.node.className == 'test', "expected class to be 'test'"
+
+run_test "allows mixing attributes and children in a single table", ->
+ e_div, e_pre = div!, pre!
+ elem = ReactiveElement 'div', { class: 'test', e_div, e_pre }
+ assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem"
+ assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem"
+ assert elem.node.className == 'test', "expected class to be 'test'"
+
+run_test "can unwrap and track attributes from ReactiveVars", ->
+ klass = ReactiveVar 'test'
+ elem = ReactiveElement 'div', class: klass
+ assert elem.node.className == 'test', "expected class to be 'test'"
+ klass\set 'toast'
+ assert elem.node.className == 'toast', "expected class to be 'toast'"
+
+run_test "can unwrap and track children from ReactiveVars", ->
+ child = ReactiveVar h1 'test'
+ elem = ReactiveElement 'div', child, pre 'fixed'
+ assert elem.node.firstElementChild.localName == 'h1', "expected first child to be h1"
+ assert elem.node.childElementCount == 2, "expected node to have two children"
+ child\set div 'toast'
+ assert elem.node.firstElementChild.localName == 'div', "expected first child to be div"
+ assert elem.node.childElementCount == 2, "expected node to have two children"
+
+run_test "warns when appending a string from a ReactiveVar", ->
+ import text from require 'mmm.component'
+
+ str = ReactiveVar 'test'
+ elem = ReactiveElement 'div', str
+ expect 'cannot replace string node', 'expected error', str\set, 'string too'
+ elem\destroy!
+
+ elem = ReactiveElement 'div', str\map text
+ str\set 'this is text'
+
+test_group!
+
+article _content
diff --git a/root/meta/text$moonscript -> fn -> mmm$dom.moon b/root/meta/text$moonscript -> fn -> mmm$dom.moon
new file mode 100644
index 0000000..bff47be
--- /dev/null
+++ b/root/meta/text$moonscript -> fn -> mmm$dom.moon
@@ -0,0 +1,25 @@
+import div, h3, p, br, ul, li, b, a from require 'mmm.dom'
+
+=> div {
+ style: { 'max-width': '700px' },
+ h3 @gett 'title: text/plain', style: { 'margin-bottom': '-.5em' },
+ p "mmm is a collection of Lua/Moonscript modules for web development.",
+ "All modules are 'polymorphic' - they can run in the ", (b 'browser'),
+ ", using the native browser API for creating and interacting with DOM content, as well as on the ",
+ (b 'server'), ", where they operate on and produce equivalent HTML strings."
+ p "As the two implementations of each module are designed to be compatible,
+ mmm facilitates code and content sharing between server and client
+ and enables serverside rendering and rehydration."
+ ul for child in *@children
+ name = child\gett 'name: alpha'
+ desc = child\gett 'description: mmm/dom'
+ li {
+ a name, {
+ href: child.path,
+ onclick: (e) =>
+ e\preventDefault!
+ BROWSER\navigate child.path
+ },
+ ': ', desc
+ }
+ }
diff --git a/root/meta/title: text$plain b/root/meta/title: text$plain
new file mode 100644
index 0000000..ac2dbb1
--- /dev/null
+++ b/root/meta/title: text$plain
@@ -0,0 +1 @@
+about mmm
diff --git a/root/meta/todo.moon b/root/meta/todo.moon
deleted file mode 100644
index a568a74..0000000
--- a/root/meta/todo.moon
+++ /dev/null
@@ -1,42 +0,0 @@
-import define_fileders from require 'mmm.mmmfs'
-Fileder = define_fileders ...
-
-Fileder {
- 'name: alpha': 'todo'
- 'description: text/plain': 'TodoMVC using mmm.component'
- 'fn -> mmm/component': =>
- import ReactiveVar, text, elements from require 'mmm.component'
- import article, div, form, span, h3, a, input from elements
-
- parent = div!
- todoItem = (desc, done) ->
- -- convert into reactive data sources
- desc, done = (ReactiveVar desc), ReactiveVar done
- with me = div style:
- margin: '8px'
- padding: '8px'
- background: '#eeeeee'
- \append h3 (desc\map text), style: 'margin: 0;'
- \append span done\map (done) -> text if done then 'done' else 'not done yet'
- \append input type: 'checkbox', checked: done, onchange: (e) => done\set e.target.checked
- \append a (text 'delete'), href: '#', onclick: (e) => parent\remove me
-
- parent\append todoItem 'write a Component System', true
- parent\append todoItem 'eat Lasagna', true
- parent\append todoItem 'do other things'
-
- desc = ReactiveVar 'start'
- form = with form {
- action: ''
- style:
- margin: '2px'
- onsubmit: (e) =>
- e\preventDefault!
- parent\append todoItem desc\get!
- desc\set ''
- }
- \append input type: 'text', value: desc, onchange: (e) => desc\set e.target.value
- \append input type: 'submit', value: 'add'
-
- article parent, form
-}
diff --git a/root/meta/todo/description: text$plain b/root/meta/todo/description: text$plain
new file mode 100644
index 0000000..baaf6fc
--- /dev/null
+++ b/root/meta/todo/description: text$plain
@@ -0,0 +1 @@
+TodoMVC using mmm.component
diff --git a/root/meta/todo/text$moonscript -> mmm$component.moon b/root/meta/todo/text$moonscript -> mmm$component.moon
new file mode 100644
index 0000000..dc4e5e1
--- /dev/null
+++ b/root/meta/todo/text$moonscript -> mmm$component.moon
@@ -0,0 +1,34 @@
+import ReactiveVar, text, elements from require 'mmm.component'
+import article, div, form, span, h3, a, input from elements
+
+parent = div!
+todoItem = (desc, done) ->
+ -- convert into reactive data sources
+ desc, done = (ReactiveVar desc), ReactiveVar done
+ with me = div style:
+ margin: '8px'
+ padding: '8px'
+ background: '#eeeeee'
+ \append h3 (desc\map text), style: 'margin: 0;'
+ \append span done\map (done) -> text if done then 'done' else 'not done yet'
+ \append input type: 'checkbox', checked: done, onchange: (e) => done\set e.target.checked
+ \append a (text 'delete'), href: '#', onclick: (e) => parent\remove me
+
+parent\append todoItem 'write a Component System', true
+parent\append todoItem 'eat Lasagna', true
+parent\append todoItem 'do other things'
+
+desc = ReactiveVar 'start'
+form = with form {
+ action: ''
+ style:
+ margin: '2px'
+ onsubmit: (e) =>
+ e\preventDefault!
+ parent\append todoItem desc\get!
+ desc\set ''
+ }
+ \append input type: 'text', value: desc, onchange: (e) => desc\set e.target.value
+ \append input type: 'submit', value: 'add'
+
+article parent, form
diff --git a/root/text$moonscript -> fn -> mmm$dom.moon b/root/text$moonscript -> fn -> mmm$dom.moon
new file mode 100644
index 0000000..158bc48
--- /dev/null
+++ b/root/text$moonscript -> fn -> mmm$dom.moon
@@ -0,0 +1,57 @@
+import article, h1, h3, div, b, p, a, br, ul, tt, li, img from require 'mmm.dom'
+import opairs from require 'mmm.ordered'
+
+=>
+ append, finish = do
+ content = {}
+
+ append = (stuff) -> table.insert content, stuff
+ append, -> article content
+
+ moon = '\xe2\x98\xbd'
+
+ iconlink = (href, src, alt, style) -> a {
+ class: 'iconlink',
+ :href,
+ target: '_blank',
+ img :src, :alt, :style
+ }
+
+ -- menu
+ append h1 {
+ style: {
+ position: 'relative',
+ 'border-bottom': '1px solid #000'
+ },
+ 'mmm',
+ div {
+ class: 'icons',
+ iconlink 'https://github.com/s-ol/mmm', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg',
+ iconlink 'https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg',
+ iconlink 'https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring',
+ { height: '0.9em', 'margin-left': '.04em' }
+ }
+ }
+
+ append p {
+ tt 'mmm'
+ ' is not the '
+ tt 'www'
+ ', because it runs on '
+ a { 'MoonScript', href: 'https://moonscript.org' }
+ '.'
+ br!
+ 'You can find the source code of everything '
+ a { 'here', href: 'https://github.com/s-ol/mmm' }
+ '.'
+ }
+
+ for child in *@children
+ append (child\get 'preview: mmm/dom') or child\get 'mmm/dom'
+
+ append p {
+ "made with #{moon} by "
+ a { 's-ol', href: 'https://twitter.com/S0lll0s' }
+ }
+
+ finish!