diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2018-11-06 07:19:59 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2018-11-06 07:19:59 +0000 |
| commit | a7e539c272ffcd9e14fb58f8c24714cdff8e7c17 (patch) | |
| tree | 404f92906bd402b1c394f7b521508b5138e76d98 /root | |
| parent | inspect mode wip (diff) | |
| parent | add metadata for compilation (diff) | |
| download | mmm-a7e539c272ffcd9e14fb58f8c24714cdff8e7c17.tar.gz mmm-a7e539c272ffcd9e14fb58f8c24714cdff8e7c17.zip | |
Merge branch 'tru-fs' into inspect-mode
Diffstat (limited to 'root')
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! |
