diff options
28 files changed, 1335 insertions, 1170 deletions
@@ -11,11 +11,14 @@ # render stylesheet : scss/main.scss |> !sassc |> dist/main.css -preload app -preload app/tags -preload app/mmmfs preload lib preload lib/mmmfs +preload root +preload root/animations +preload root/articles +preload root/articles/mmmfs +preload root/experiments +preload root/experiments/tags # render static content and compile sources run moon tup.moon diff --git a/app/center_of_mass.moon b/app/center_of_mass.moon deleted file mode 100644 index ecfee2a..0000000 --- a/app/center_of_mass.moon +++ /dev/null @@ -1,165 +0,0 @@ -on_client -> - import CanvasApp from require 'lib.canvasapp' - import rgb from require 'lib.color' - import h1, p, div, span, input, button from require 'lib.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 - - 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 {} diff --git a/app/koch.moon b/app/koch.moon deleted file mode 100644 index 0fea944..0000000 --- a/app/koch.moon +++ /dev/null @@ -1,104 +0,0 @@ -on_client -> - Math = window.Math - - import CanvasApp from require 'lib.canvasapp' - import hsl from require 'lib.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! - - append KochDemo!.node diff --git a/app/mmmfs/gallery.moon b/app/mmmfs/gallery.moon deleted file mode 100644 index 98c9490..0000000 --- a/app/mmmfs/gallery.moon +++ /dev/null @@ -1,50 +0,0 @@ -import Fileder from require 'lib.mmmfs' -import div, h1, a, img, br from require 'lib.dom' - -children = for i=1,100 - id = math.floor math.random! * 200 - Fileder { - 'name: alpha': "image#{id}" - 'URL -> image/png': "https://picsum.photos/600/600/?image=#{id}" - 'preview: URL -> image/png': "https://picsum.photos/200/200/?image=#{id}" - } - -props = { - 'name: alpha': 'gallery', - 'title: text/plain': "A Gallery of 100 random pictures, come in!", - 'preview: moon -> mmm/dom': => div { - 'the first pic as a little taste:', - br!, - img src: @children[1]\get 'preview', 'URL -> image/png' - } - 'moon -> mmm/dom': => - link = (child) -> a { - href: '#', - onclick: -> BROWSER\navigate { 'gallery', (child\get 'name', 'alpha'), nil }, - img src: child\gett 'preview', 'URL -> image/png' - } - - content = [link child for child in *@children] - table.insert content, 1, h1 'gallery index' - div content - - 'slideshow: moon -> mmm/dom': => - import ReactiveVar, text, elements from require 'lib.component' - - index = ReactiveVar 1 - - prev = (i) -> math.max 1, i - 1 - next = (i) -> math.min #@children, i + 1 - - e = elements - e.div { - e.div { - e.a 'prev', href: '#', onclick: -> index\transform prev - index\map (i) -> text " image ##{i} " - e.a 'next', href: '#', onclick: -> index\transform next - }, - index\map (i) -> img src: @children[i]\gett nil, 'URL -> image/png' - } -} - -Fileder props, children diff --git a/app/mmmfs/init.moon b/app/mmmfs/init.moon deleted file mode 100644 index 0cf66a0..0000000 --- a/app/mmmfs/init.moon +++ /dev/null @@ -1,23 +0,0 @@ -require = relative ... - -render = (path) -> - import Browser from require 'lib.mmmfs.browser' - import tohtml from require 'lib.component' - root = require '.tree' - - export BROWSER - BROWSER = Browser root, path - append tohtml BROWSER - - if MODE == 'SERVER' - rehydrate = (path) -> - require = relative ... - - import Browser from require 'lib.mmmfs.browser' - root = require '.tree' - - export BROWSER - BROWSER = Browser root, path, true - window.hljs\initHighlightingOnLoad! - - on_client init, path diff --git a/app/mmmfs/koch.moon b/app/mmmfs/koch.moon deleted file mode 100644 index 0fea944..0000000 --- a/app/mmmfs/koch.moon +++ /dev/null @@ -1,104 +0,0 @@ -on_client -> - Math = window.Math - - import CanvasApp from require 'lib.canvasapp' - import hsl from require 'lib.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! - - append KochDemo!.node diff --git a/app/mmmfs/twisted.moon b/app/mmmfs/twisted.moon deleted file mode 100644 index a122df9..0000000 --- a/app/mmmfs/twisted.moon +++ /dev/null @@ -1,49 +0,0 @@ -import Fileder from require 'lib.mmmfs' -import CanvasApp from require 'lib.canvasapp' -import hsl from require 'lib.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 - -TwistedDemo! - -Fileder { - 'name: alpha': 'twisted', - 'title: text/plain': "canvas animation with static preview", - 'preview: moon -> mmm/component': => TwistedDemo true - 'moon -> mmm/component': => TwistedDemo! -} diff --git a/app/realities.moon b/app/realities.moon deleted file mode 100644 index 2e12eb8..0000000 --- a/app/realities.moon +++ /dev/null @@ -1,543 +0,0 @@ -import append, elements from require 'lib.component' -import h1, h2, p, a, i, div, ol, li, br, hr, span, button, section, article from elements - -if MODE == 'CLIENT' - require 'svg.js' -else - import compile from require 'lib.duct_tape' - - append '<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js"></script>' - - 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! - -on_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! diff --git a/app/twisted.moon b/app/twisted.moon deleted file mode 100644 index 0ab30b1..0000000 --- a/app/twisted.moon +++ /dev/null @@ -1,38 +0,0 @@ -on_client -> - Math = window.Math - - import CanvasApp from require 'lib.canvasapp' - import hsl from require 'lib.color' - - class TwistedDemo extends CanvasApp - width: 500 - height: 400 - length: math.pi * 4 - new: => - 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 - - document.body\appendChild TwistedDemo!.node diff --git a/lib/init.client.moon b/lib/init.client.moon index 981cd25..77ff0ee 100644 --- a/lib/init.client.moon +++ b/lib/init.client.moon @@ -1,4 +1,4 @@ -export MODE, print, warn, relative, append, on_client +export MODE, print, warn, relative, on_client export window, document window = js.global @@ -7,8 +7,9 @@ window = js.global MODE = 'CLIENT' deep_tostring = (tbl, space='') -> - buf = space .. tostring tbl + return tbl if 'userdata' == type tbl + buf = space .. tostring tbl return buf unless 'table' == type tbl buf = buf .. ' {\n' @@ -42,5 +43,4 @@ relative = do name = base .. name if '.' == name\sub 1, 1 _require name -append = document.body\appendChild on_client = (f, ...) -> f ... diff --git a/lib/init.server.moon b/lib/init.server.moon index f81a2dc..198c64e 100644 --- a/lib/init.server.moon +++ b/lib/init.server.moon @@ -1,4 +1,4 @@ -export MODE, print, warn, relative, append, on_client +export MODE, print, warn, relative, on_client MODE = 'SERVER' deep_tostring = (tbl, space='') -> @@ -38,18 +38,13 @@ relative = do name = base .. name if '.' == name\sub 1, 1 _require name --- shorthand to append elements to body -buffer = '' -append = (val) -> - buffer ..= val - import compile, insert_loader from require 'lib.duct_tape' insert_loader! on_client = (fn, ...) -> args = {...} -- warn code - append "<script type=\"application/lua\"> + "<script type=\"application/lua\"> local fn = #{compile fn} fn(#{table.concat [string.format '%q', v for v in *args ], ', '}) </script>" diff --git a/lib/mmmfs/browser.moon b/lib/mmmfs/browser.moon index a4080c2..5f70174 100644 --- a/lib/mmmfs/browser.moon +++ b/lib/mmmfs/browser.moon @@ -6,28 +6,47 @@ import div, span, a, select, option from elements limit = (list, num) -> [v for i,v in ipairs list when i <= num] -class Browser - new: (@root, @path={}, rehydrate=false) => - @path = ReactiveVar @path - -- @path\subscribe (path) -> window.location.hash = '/' .. table.concat path, '/' - @prop = ReactiveVar (@root\find 'mmm/dom') or next @root.props - @active = @path\map (path) -> - fileder = @root - for name in *path - local next - for child in *fileder.children - if name == child\get 'name', 'alpha' - next = child - break +path2tbl = (path) -> + switch type path + when 'string' + path + when 'table' + str = table.concat path, '/' + if '/' != str\sub 1, 1 + str = '/' .. str + str + else + error "path is of wrong type: #{type path}" - if not next - return - - fileder = next +class Browser + new: (@root, path={}, rehydrate=false) => + @path = ReactiveVar path2tbl path - fileder + assert @root, 'root fileder is nil' - @active\subscribe (fileder) -> @prop\set (fileder\find 'mmm/dom') or next fileder.props + -- @path\subscribe (path) -> window.location.hash = '/' .. table.concat path, '/' + @active = @path\map (path) -> @root\walk path + +-- fileder = @root +-- +-- for name in *path +-- local next +-- for child in *fileder.children +-- if name == child\get 'name', 'alpha' +-- next = child +-- break +-- +-- if not next +-- warn "couldn't find node '#{name}'" +-- return +-- +-- fileder = next +-- +-- fileder + + @prop = @active\map (fileder) -> + return unless fileder + (fileder\find 'mmm/dom') or next fileder.props -- retrieve or create the root root = 'div' @@ -72,8 +91,9 @@ class Browser onchange = (_, e) -> @prop\set Key e.target.value - current = @prop\get!\tostring! - with select :onchange + current = @prop\get! + current = current and current\tostring! + with select :onchange, disabled: not fileder if fileder for key, _ in pairs fileder.props value = key\tostring! @@ -83,46 +103,59 @@ class Browser -- append or patch #browser-content node = 'div' node = document\getElementById 'browser-content' if rehydrate - @dom\append ReactiveElement node, { - id: 'browser-content', - style: { - flex: '1 0 0', - overflow: 'auto', - padding: '1em 2em', - }, - @get_content rehydrate and node - } + @dom\append with ReactiveElement node, { + id: 'browser-content', + style: { + flex: '1 0 0', + overflow: 'auto', + padding: '1em 2em', + }, + } + \append @get_content rehydrate and node + + if rehydrate + -- force one update to update onclick handlers etc + @prop\set @prop\get! @node = @dom.node @render = @dom\render get_content: (wrapper) => + disp_error = (msg) -> span msg, style: { color: '#f00' } var = @prop\map (prop) -> active = @active\get! + if not active + return disp_error "fileder not found!" + + if not prop + return disp_error "property not found!" + ok, res = pcall -> - conversions = assert (get_conversions 'mmm/dom', prop.type), "no conversion path" + conversions = get_conversions 'mmm/dom', prop.type value = assert (active\get prop), "value went missing?" + return unless conversions + for i=#conversions,1,-1 { :inp, :out, :transform } = conversions[i] value = transform value, active value - if ok and res - res + if ok + res or disp_error "[no conversion path to mmm/dom]" else warn "error: ", res unless ok - span "cannot display!", style: { color: '#f00' } + disp_error "[unknown error displaying]" -- wrapper was built already so take over the old value if wrapper - var\set wrapper.lastElementChild + return var, wrapper.lastChild -- var\set wrapper.lastElementChild var - navigate: (new) => @path\set new + navigate: (new) => @path\set path2tbl new { :Browser, diff --git a/lib/mmmfs/fileder.moon b/lib/mmmfs/fileder.moon index 75659d4..a1f689e 100644 --- a/lib/mmmfs/fileder.moon +++ b/lib/mmmfs/fileder.moon @@ -37,17 +37,75 @@ class Fileder -- instantiate from props and children tables -- or mix in one table (numeric keys are children, remainder props) -- prop-keys are passed to Key constructor - new: (props, @children) => - if not @children - @children = for i, child in ipairs props + new: (props, children) => + if not children + children = for i, child in ipairs props props[i] = nil child - @props = { (Key k), v for k, v in pairs props } + -- automatically mount children on insert + @children = setmetatable {}, __newindex: (t, k, child) -> + rawset t, k, child + if @path == '/' + child\mount '/' + elseif @path + child\mount @path .. '/' + + -- copy children + for i, child in ipairs children + @children[i] = child + + -- automatically reify string keys on insert + @props = setmetatable {}, __newindex: (t, key, v) -> + rawset t, key, nil -- fix for fengari.io + rawset t, (Key key), v + + -- copy props + for k, v in pairs props + @props[k] = v + + -- recursively walk to and return the fileder with @path == path + walk: (path) => + -- early-out if we are outside of the path already + return unless @path\match '^' .. path + + -- gotcha + return @ if path == @path + + -- @TODO: obviously there is better ways + for child in *@children + result = child\walk path + return if result + + -- recursively mount fileder and children at path + -- * path - the path to mount at (default: '/') + -- * mount_as - dont append own name to path + mount: (path='/', mount_as=false) => + assert not @path, "mounted twice: #{@path} and now #{path}" + + if mount_as + @path = path + else + @path = path .. @gett 'name: alpha' + + if @path == '/' + for child in *@children + child\mount '/' + else + for child in *@children + child\mount @path .. '/' + + -- recursively iterate all children (coroutine) + -- * depth - depth to stop after; 1 = yield only self (default: infinite) + iterate: (depth=0) => + coroutine.yield @ + return if depth == 1 + + for child in *@children + child\iterate depth - 1 -- find property key according to criteria, nil if no value or conversion path - -- * name - property name (optional: defaults to main content) - -- * type - wanted result type + -- * ... - arguments like Key find: (...) => want = Key ... @@ -66,8 +124,7 @@ class Fileder error "couldn't find key after resolution?" -- get property according to criteria, nil if no value or conversion path - -- * name - property name (optional: defaults to main content) - -- * type - wanted result type + -- * ... - arguments like Key get: (...) => want = Key ... @@ -89,7 +146,7 @@ class Fileder want = Key ... value, key = @get want - assert value, "node doesn't have value for #{want\tostring!}" + assert value, "node doesn't have value for '#{want\tostring!}'" value, key { diff --git a/lib/mmmfs/init.moon b/lib/mmmfs/init.moon index bb26505..172f0ef 100644 --- a/lib/mmmfs/init.moon +++ b/lib/mmmfs/init.moon @@ -1,7 +1,35 @@ require = relative ... import Key, Fileder from require '.fileder' +import Browser from require '.browser' +import tohtml from require 'lib.component' + +define_fileders = (...) -> + source_module = ... + + (...) -> + with fileder = Fileder ... + .source_module = source_module + +rehydrate = (path) -> + import Browser from require 'lib.mmmfs.browser' + root = require 'root' + root\mount! + + export BROWSER + BROWSER = Browser root, path, true + +render = (root, path) -> + export BROWSER + BROWSER = Browser root, path + + str = tohtml BROWSER + str ..= on_client rehydrate, path + str { :Key :Fileder + :render + :define_fileders + :module_roots } diff --git a/render.moon b/render.moon index 7acf9a4..b144cce 100644 --- a/render.moon +++ b/render.moon @@ -1,12 +1,27 @@ package.moonpath = './?.server.moon;' .. package.moonpath import flush from require 'lib.init' +import render from require 'lib.mmmfs' -import indexed from require 'app' +-- usage: +-- moon render.moon <output> <fileder_path> [<prefix module> <prefix path>] -route_name = assert arg[1], "please specify the route name to build as an argument" -output_name = assert arg[2], "please specify the output filename as an argument" -route = assert indexed[route_name], "route not found: '#{route_name}'" -route\render! +{ output_name, path, prefix_mod, prefix_path } = arg +-- output_name = assert arg[1], "please specify the output filename as an argument" +-- path = assert arg[2], "please specify the path name to build as an argument" +assert output_name, "please specify the output filename as an argument" +assert path, "please specify the path name to build as an argument" + +root = if prefix_mod and prefix_path + -- prefix module and path are given, skip deeper into the tree + assert path\match '^' .. prefix_path + with require prefix_mod + \mount prefix_path, true +else + -- load full tree + with require 'root' + \mount! + +content = assert (render root, path), "no content" with io.open output_name, 'w' \write "<!DOCTYPE html> @@ -16,7 +31,9 @@ with io.open output_name, 'w' <title>MMM: lunar low-gravity scripting playground</title> <link rel=\"stylesheet\" type=\"text/css\" href=\"/main.css\" /> <link rel=\"preload\" as=\"fetch\" href=\"/lib/dom.lua\" /> - <link rel=\"preload\" as=\"fetch\" href=\"/lib/component.lua\" /> + <link rel=\"preload\" as=\"fetch\" href=\"/lib/mmmfs/init.lua\" /> + <link rel=\"preload\" as=\"fetch\" href=\"/lib/mmmfs/fileder.lua\" /> + <link rel=\"preload\" as=\"fetch\" href=\"/lib/mmmfs/browser.lua\" /> <script src=\"/fengari-web.js\"></script> <script src=\"/highlight.pack.js\"></script> <script src=\"//cdn.jsdelivr.net/npm/marked/marked.min.js\"></script> @@ -24,7 +41,7 @@ with io.open output_name, 'w' <body> <script type=\"application/lua\" src=\"/lib/init.lua\"></script> - #{flush!} + #{content} </body> </html>" \close! diff --git a/root/animations/init.moon b/root/animations/init.moon new file mode 100644 index 0000000..cb1f20a --- /dev/null +++ b/root/animations/init.moon @@ -0,0 +1,29 @@ +import div, h3, ul, li, a from require 'lib.dom' +import define_fileders from require 'lib.mmmfs' +Fileder = define_fileders ... +require = relative ... + +Fileder { + 'name: alpha': 'animations', + 'title: text/plain': 'canvas animations', + 'moon -> 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, ...) -> + print 'ASD', e, ... + window\alert 'YO WADDAFUQ' + e\preventDefault! + BROWSER\navigate "animations | #{name}", + }, + ': ', desc + } + } + + require '.twisted' + require '.koch' +} diff --git a/root/animations/koch.moon b/root/animations/koch.moon new file mode 100644 index 0000000..9b8217d --- /dev/null +++ b/root/animations/koch.moon @@ -0,0 +1,113 @@ +import define_fileders from require 'lib.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 'lib.canvasapp' + import hsl from require 'lib.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['preview: moon -> mmm/component'] = => TwistedDemo true + .props['moon -> mmm/component'] = => KochDemo! diff --git a/root/animations/twisted.moon b/root/animations/twisted.moon new file mode 100644 index 0000000..9e97738 --- /dev/null +++ b/root/animations/twisted.moon @@ -0,0 +1,51 @@ +import define_fileders from require 'lib.mmmfs' +Fileder = define_fileders ... + +with Fileder { + 'name: alpha': 'twisted', + 'description: text/plain': "pseudo 3d", + } + + if MODE == 'CLIENT' + import CanvasApp from require 'lib.canvasapp' + import hsl from require 'lib.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: moon -> mmm/component'] = => TwistedDemo true + .props['moon -> mmm/component'] = => TwistedDemo! diff --git a/root/articles/init.moon b/root/articles/init.moon new file mode 100644 index 0000000..b706f7c --- /dev/null +++ b/root/articles/init.moon @@ -0,0 +1,27 @@ +import div, h3, ul, li, a from require 'lib.dom' +import define_fileders from require 'lib.mmmfs' +Fileder = define_fileders ... +require = relative ... + +Fileder { + 'name: alpha': 'articles', + 'title: text/plain': 'articles and papers', + 'moon -> 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/gallery.moon b/root/articles/mmmfs/gallery.moon new file mode 100644 index 0000000..081865a --- /dev/null +++ b/root/articles/mmmfs/gallery.moon @@ -0,0 +1,49 @@ +import define_fileders from require 'lib.mmmfs' +import div, h1, a, img, br from require 'lib.dom' + +Fileder = define_fileders ... + +with Fileder { + 'name: alpha': 'gallery', + 'title: text/plain': "A Gallery of 25 random pictures, come in!", + 'preview: moon -> mmm/dom': => div { + 'the first pic as a little taste:', + br!, + img src: @children[1]\get 'preview', 'URL -> image/png' + } + 'moon -> mmm/dom': => + link = (child) -> a { + href: '#', + onclick: -> BROWSER\navigate { 'gallery', (child\get 'name', 'alpha'), nil }, + img src: child\gett 'preview', 'URL -> image/png' + } + + content = [link child for child in *@children] + table.insert content, 1, h1 'gallery index' + div content + + 'slideshow: moon -> mmm/dom': => + import ReactiveVar, text, elements from require 'lib.component' + + index = ReactiveVar 1 + + prev = (i) -> math.max 1, i - 1 + next = (i) -> math.min #@children, i + 1 + + e = elements + e.div { + e.div { + e.a 'prev', href: '#', onclick: -> index\transform prev + index\map (i) -> text " image ##{i} " + e.a 'next', href: '#', onclick: -> index\transform next + }, + index\map (i) -> img src: @children[i]\gett nil, 'URL -> image/png' + } + } + for i=1,25 + id = 120 + i + .children[i] = Fileder { + 'name: alpha': "image#{id}" + 'URL -> image/png': "https://picsum.photos/600/600/?image=#{id}" + 'preview: URL -> image/png': "https://picsum.photos/200/200/?image=#{id}" + } diff --git a/app/mmmfs/tree.moon b/root/articles/mmmfs/init.moon index 23e1a89..8193356 100644 --- a/app/mmmfs/tree.moon +++ b/root/articles/mmmfs/init.moon @@ -1,8 +1,11 @@ -require = relative ..., 1 - -import Fileder from require 'lib.mmmfs' +import define_fileders from require 'lib.mmmfs' +Fileder = define_fileders ... +require = relative ... Fileder { + 'name: alpha': 'mmmfs', + 'description: text/plain': 'a file and operating system to live in', + -- main content -- doesn't have a name prefix (e.g. preview: moon -> mmm/dom) -- uses the 'moon ->' conversion to execute the lua/pre moon function on get @@ -82,31 +85,30 @@ Fileder { append p "Sounds cool, no? Here's some examples of things a fileder can be or embed:" -- render a preview block - preview = (title, content, name) -> div { - h3 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate { name } - 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) -> -- 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' - -- get 'name' as a DOM description (nil if no value or conversion possible) - name = child\gett 'name', 'alpha' + 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', + }, + } - preview title, content, name + + append div for child in *@children + preview child append h2 "details" -- @TODO s/parts: dimensions, aspects? @@ -280,7 +282,4 @@ and some bold **text** and `code tags` with me.", } require '.gallery', - - -- if we are on client, throw in twisted as a child - if MODE == 'CLIENT' then require '.twisted' } diff --git a/root/articles/realities.moon b/root/articles/realities.moon new file mode 100644 index 0000000..f913842 --- /dev/null +++ b/root/articles/realities.moon @@ -0,0 +1,552 @@ +import define_fileders from require 'lib.mmmfs' +Fileder = define_fileders ... + +Fileder { + 'name: alpha': 'realities' + 'description: text/plain': 'exploring the nesting relationships of virtual and other realities' + 'moon -> mmm/component': => + import elements from require 'lib.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' + -- import compile from require 'lib.duct_tape' + + -- append '<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js"></script>' + + 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! +} diff --git a/root/experiments/center_of_mass.moon b/root/experiments/center_of_mass.moon new file mode 100644 index 0000000..e5eceab --- /dev/null +++ b/root/experiments/center_of_mass.moon @@ -0,0 +1,179 @@ +import define_fileders from require 'lib.mmmfs' +Fileder = define_fileders ... + +with Fileder { + 'name: alpha': 'center_of_mass', + 'description: text/plain': "Fonts sorted by Center-of-Mass", +} + + if MODE == 'CLIENT' + import CanvasApp from require 'lib.canvasapp' + import rgb from require 'lib.color' + import article, h1, p, div, span, input, button from require 'lib.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['moon -> 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/init.moon b/root/experiments/init.moon new file mode 100644 index 0000000..0beb78c --- /dev/null +++ b/root/experiments/init.moon @@ -0,0 +1,26 @@ +import div, h3, ul, li, a from require 'lib.dom' +import define_fileders from require 'lib.mmmfs' +Fileder = define_fileders ... +require = relative ... + +Fileder { + 'name: alpha': 'experiments', + 'title: text/plain': 'various experiments', + 'moon -> 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 "animations | #{name}", + }, + ': ', desc + } + } + + require '.center_of_mass' +} diff --git a/app/tags/init.moon b/root/experiments/tags/init.moon index e3198f8..e3198f8 100644 --- a/app/tags/init.moon +++ b/root/experiments/tags/init.moon diff --git a/app/tags/tags.moon b/root/experiments/tags/tags.moon index 198392e..198392e 100644 --- a/app/tags/tags.moon +++ b/root/experiments/tags/tags.moon diff --git a/root/init.moon b/root/init.moon new file mode 100644 index 0000000..a2eab3b --- /dev/null +++ b/root/init.moon @@ -0,0 +1,68 @@ +import define_fileders from require 'lib.mmmfs' +Fileder = define_fileders ... +require = relative ... + +Fileder { + 'name: alpha': '', + 'moon -> mmm/dom': => + import article, h1, h3, div, b, p, a, br, ul, tt, li, img from require 'lib.dom' + import opairs from require 'lib.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' +} @@ -19,7 +19,7 @@ enum_dir = do coroutine.wrap -> yieldtree dir -for file in enum_dir 'app' +for file in enum_dir 'root' basename = assert file\match '(.*)%.moon$' print ": #{file} |> ^ MOON %b > %o^ moonc -o %o %f |> dist/#{basename}.lua" @@ -29,8 +29,23 @@ for file in enum_dir 'lib' basename = (file\match '(.*)%.client') or basename print ": #{file} |> ^ MOON %b > %o^ moonc -o %o %f |> dist/#{basename}.lua" --- add rules for statically rendered routes -import routes from require 'app' +-- add rules for each fileder +import module_roots from require 'lib.mmmfs' -for { :name, :dest } in *routes - print ": |> ^ HTML #{name}^ moon render.moon #{name} %o |> dist/#{dest}" +root = require 'root' +root\mount! + +module_roots = {} +for fileder in coroutine.wrap root\iterate + name = fileder\gett 'name: alpha' + { :path, :source_module } = fileder + + module_roots[source_module] or= fileder.path + prefix_path = module_roots[source_module] + + path = '/' if path == '' + + if prefix_path + print ": |> ^ HTML #{name}^ moon render.moon %o '#{path}' #{source_module} '#{prefix_path}' |> dist#{path}/index.html" + else + print ": |> ^ HTML #{name}^ moon render.moon %o '#{path}' |> dist#{path}/index.html" |
