{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# nbpresent\n",
    "nbslides is the evolution of the work by the Jupyter community to make notebooks into authorable, presentable, designed assets for communicating."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "source": [
    "> 1. The problem that this enhancement addresses. If possible include code or anecdotes to describe this problem to readers."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Problem\n",
    "Creating conference-quality presentations with the Notebook requires a good understanding of the limitations of the notebook, nbconvert, reveal.js, RISE and the publishing platform (nbconvert and hosting, or nbviewer). The user is forced into a particular mindset about how slides are structured and authored, based on the these limitations, and at the end is still left with a potentially fragile artifact that doesn't reflect the amount of effort that goes into its creation."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### User Story: Jill\n",
    "Jill is presenting in support of her journal paper at a conference. While performing her work in Jupyter notebooks, she has prepared some beautiful visualizations and meaningful code snippets, as well a number of content pieces which are included in the draft and final versions of her journal paper.\n",
    "\n",
    "She has seen some example slide decks on nbviewer that use reveal.js, and they look pretty neat, so she decides to turn on the _Slides_ cell metadata and starts a brand new document, copy-and-pasting the content from her notebooks, making some screenshots.\n",
    "\n",
    "Going back and forth between some command line scripts, her local web server and her notebook, she finally has something she can present. The resulting presentation looks pretty ho-hum, and has some formatting issues, but gets the point across. Right before the presentation, the organizers tell her they need a ppt or pdf of her slides, as there are A/V issues, and she won't be able to connect her laptop directly or use the internet during her talk.\n",
    "\n",
    "She decides to just use LibreOffice next time. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### User Story: John\n",
    "John maintains a family of presentations, which are frequently updated for customer courses. While the content is light, the format represents his corporate and personal brand, and is a selling tool for his organization. In addition to wanting to create printed take-home materials, he has slides that contain interactive features.\n",
    "\n",
    "Jack has experimented with [showoff](https://github.com/puppetlabs/showoff), [beamer](https://en.wikipedia.org/wiki/Beamer_(LaTeX), but keeps ending up with LibreOffice. He evaluates using the notebook for his presentations, but finds that it lacks a number of key features: reuse of slides, repeatable PDF output, slide numbering, branding for his company and others.\n",
    "\n",
    "He tries using showoff, but still finds it requires a lot of knowledge of CSS and html, and even has to learn some ruby. He decides to just use LibreOffice. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "source": [
    "> A brief (1-2 sentences) overview of the enhancement you are proposing. If possible include hypothetical code sample to describe how the solution would work to readers."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Proposed Enhancement\n",
    "We propse unifying a number of features in different parts of the ecosystem into a single installable package which contains authoring, conversion, and management of presentation-related features. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "source": [
    "> A detailed explanation covering relevant algorithms, data structures, an API spec, and any other relevant technical information"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Logical Architecture"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> ## _Using `nbpresent`, a user can seamlessly author, present and publish notebooks as fixed-viewport, regioned, themed, layered, composable, hierarchically-stated experiences._"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## ...user\n",
    "The key user is the author/presenter of technical findings and opinions involving code, prose and data. While we must assume a fair degree of technical competence, they should not need to learn many skills outside their area of interest."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## ...seamlessly\n",
    "After deciding to author slides and getting `npresent` installed on their server, a user should not have to leave their area of comfort, whether that's the JS Notebook environment, a `hydrogen` session or the command line, to be able to see their presentation. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### ...author, present\n",
    "The authoring and live presenting experience should dominate nbpresent design choices. A significant shortcoming of reveal, showoff, and beamer are required knowledge of some form of esoteric language(s) to get your presentaton to Look Good. LibreOffice has mostly succeeded here with its drag-and-drop UI, but makes it more difficult to achieve a designed, consistent layout, as you are given free reign to make pixel-level corrections, sapping productivity.\n",
    "\n",
    "Somewhere in between is a system that achieves separation of content, composition, layout and style which allows the user (and eventually a team) to concentrate on the appropriate task at hand, evolving an outline into a delivered, polished, and rehearsed presentation.\n",
    "\n",
    "For rapid authoring, an author needs to be able to drop in and out of the logical model of the traditional notebook view, the tooled slide authoring view, and a full-on presentation view, suitable for delivering presentations which include rich widgets and require execution."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### ...publish\n",
    "At the end of the process, a user will need to be able to hit \"publish\", initially to some simple choices like PDF, a standalone HTML file, or a zip of their file ready to be hosted on a plain-old-host (github/google pages). Jupyter Notebook Viewer represents a specific publishing target, and will have to be able to provide a out-of-the-box compatibility."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### ....notebooks\n",
    "At a granular level, cell inputs and outputs, and to an extent, widgets, will be the content that make up presentations, but there is seldom a one-to-one mapping of cell to slide, cell to part-of-slide, or part-of-cell to part-of-slide. Furthermore, presentations frequently represent the unification of a number of sources, and need to be remixable, suggesting there is not a one-to-one mapping between notebook and presentation.\n",
    "\n",
    "We propose allow using per-cell metadata to allow mapping each cell's input (and outputs, for code cells) to a specific region of a slide. Since cross-notebook cell transclusion must be possible, we will need to be able to assign stable identifiers to cells, and by extension their inputs and outputs."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### ...fixed-viewport\n",
    "One key aspect of presentations (as opposed the the incubating dashboards) is working within the boundaries of the presented screen... whichever screen: desktop, mobile, hi-res presentation. Pixel-based approaches to this are significantly limiting.\n",
    "\n",
    "To work within this, a constraint-based system, built on a cassowary-derived engine such as [kiwi.js](https://github.com/nucleic/kiwi/tree/feature-js) is proposed."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### ...regioned\n",
    "Within the confines of a particular slide, instead of a pure stream of slides, subslides and fragments as  in the current slideshow mechanism, we need to be able to add cell (inputs and outputs) to different parts of a slide layout: even to multiple regions of multiple slides."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## ...themed\n",
    "Today, it takes heroic effort to view a notebook-as-slides in anything other than the stock default. Unlike the notebook, where consistent UI is a feature, presentations need to represent the brand of the author and/or their organization.\n",
    "\n",
    "Intertwined with regioned layouts is CSS, fonts, images (and potentially JS, such as typographic effects) that enables a specific branding of a presentation. These theme assets need to be referenced/embedded along with presentations, with effective fallback to a default brand (such as on nbviewer)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## ...layered\n",
    "Backgrounds, headers and footers are important to presentations, but without a full z-index stack, managing these becomes very static.\n",
    "\n",
    "Layers, a la inkscape, provide a useful solution to this design problem."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## ...composable\n",
    "A huge advantage of showoff and beamer is the (technically adept) user's ability to reuse content.\n",
    "\n",
    "A presentation notebook needs to be able to bring in one or more cells (inputs and outputs) from other slides. These guest cells would *not* be editable within the host notebook, and refreshing of guest cells should be as painless as possible (automatic on save, if possible, on keystroke, eventually)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## ...hierarchically-stated\n",
    "Slides should participate in both a layout hierarchy, as well as a state hierarchy. This is a generalization of the reveal sub-slide and fragment constructs.\n",
    "\n",
    "Additional dimensions of state include scroll position"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Repo Architecture\n",
    "- `setup.py`\n",
    "- `nbpresent`\n",
    "  - `static`\n",
    "    - `nbpresent`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Web-Based Presentation\n",
    "The most challenging part is the presentation system itself. The current choice, [`reveal.js`](http://lab.hakim.se/reveal-js), has gotten us very far, but is turning out to be challening to support: its CSS, build chain, and opinions make it a poor match for the kinds of complex HTML that come out of notebooks, as well as the design goals of many of our users.\n",
    "\n",
    "The initial implementation would continue to use reveal, but would not try to directly translate cells to `<section>` content."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Web-based Presentation: Future\n",
    "This feature would be packaged as a number of `npm` modules, using current Jupyter front-end development practices: \n",
    "- es6/typescript\n",
    "- browserify\n",
    "\n",
    "PhosphorJS is a strong contender for the underlying layout engine, specifically the proposed [constraint-based layout](https://github.com/phosphorjs/phosphor/issues/35), and will be generally available in the notebook in a roadmapped version.\n",
    "\n",
    "In addition to the core rendering functions, specific components would be packaged as plugin modules that carry their own JS and CSS:\n",
    "\n",
    "- layouts\n",
    "- themes\n",
    "\n",
    "Several of these plugins would be packaged with the `pip`/`conda`-installable Jupyter package, but these could be added/upgraded by the user."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Notebook Authoring\n",
    "The authoring environment"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "source": [
    "> A list of pros that this implementation has over other potential implementations."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Pros"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "source": [
    "> A list of cons that this implementation has."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Cons"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "source": [
    "> A list of individuals who would be interested in contributing to this enhancement should it be accepted."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Interested Contributors\n",
    "- [@bollwyvl]((https://github.com/bollwyvl) _Continuum Analytics_\n",
    "- [@damianavila]((https://github.com/damianavila) _Continuum Analytics_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Data Model\n",
    "\n",
    "<div class=\"mermaid\">\n",
    "graph LR\n",
    "nb[notebook] --> md[metadata]\n",
    "md --> nbp[present]\n",
    "nbp --> slide\n",
    "nbp --> layer\n",
    "slide --> region\n",
    "\n",
    "nb -- * --> cells\n",
    "cells --> c[cell]\n",
    "cp[cell part]\n",
    "c --> input\n",
    "c -- 0,1 --> outputs\n",
    "c -- 0,1 --> widgets\n",
    "input --- cp\n",
    "outputs --- cp\n",
    "widgets --- cp\n",
    "c --> cmd[cell metadata]\n",
    "cmd --> cnbp[cell present]\n",
    "\n",
    "cnbp -- 0,* --> cpm\n",
    "cp --> cpm\n",
    "layer --> cpm\n",
    "region --> cpm\n",
    "effect --> cpm\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Mockups"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## UI won't change much vs RISE\n",
    "![](./design/screens.svg#layers=bg|cells.content|cells.bg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## _New Slide_ should default to something useful\n",
    "![](./design/screens.svg#layers=bg|cells.content|cells.bg|present.none)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "require.config({\n",
       "  paths: {\n",
       "    \"d3\": [\n",
       "      // use locally if possible\n",
       "      \"/nbextensions/inkscapelayers/lib/d3/d3.min\",\n",
       "      // fall back to cdn\n",
       "      \"https://cdn.jsdelivr.net/g/d3js#\",\n",
       "    ],\n",
       "    \"underscore\": [\n",
       "      \"underscore\",\n",
       "      \"/static/components/underscore/underscore-min\",\n",
       "      \"https://cdn.jsdelivr.net/g/underscorejs#\"\n",
       "    ]\n",
       "  }\n",
       "});\n",
       "\n",
       "require(\n",
       "[\n",
       "  \"underscore\",\n",
       "  \"d3\"\n",
       "],\n",
       "function(_, d3){\n",
       "  var serializer = new XMLSerializer(),\n",
       "    namespaces =  {\n",
       "      inkscape: \"http://www.inkscape.org/namespaces/inkscape\",\n",
       "      sodipodi: \"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n",
       "    };\n",
       "\n",
       "  _.extend(d3.ns.prefix, namespaces);\n",
       "\n",
       "  function urlize(xml){\n",
       "    return 'data:image/svg+xml;base64,' + btoa(xml);\n",
       "  }\n",
       "\n",
       "  function layerize(cell){\n",
       "    cell.selectAll(\"img[src*='.svg#layers=']:not([src^='data:'])\")\n",
       "      .each(makeLayer);\n",
       "  }\n",
       "\n",
       "  function makeLayer(){\n",
       "    var el = d3.select(this),\n",
       "      layers = this.src.split(\"#layers=\")[1].split(\"|\");\n",
       "\n",
       "    // load the source document\n",
       "    d3.xml(this.src, \"image/svg+xml\", function(err, doc){\n",
       "      // ensure righteous namespacing\n",
       "      var svg = d3.select(doc).select(\"svg\")\n",
       "          .attr({version: 1.1, xmlns: \"http://www.w3.org/2000/svg\"}),\n",
       "        layer = svg.selectAll(\"[*|groupmode = 'layer']\"),\n",
       "        named = layer.filter(function(){\n",
       "          return layers.indexOf(d3.select(this).attr(\"inkscape:label\")) !== -1;\n",
       "        });\n",
       "\n",
       "      // show all named (and parents of named) layers\n",
       "      layer.style({\n",
       "        display: function(){\n",
       "          var layer = this;\n",
       "          return named[0].indexOf(layer) > -1 ||\n",
       "            _.any(named[0], function(child){\n",
       "              return layer.contains(child);\n",
       "            }) ? \"inline\" : \"none\";\n",
       "        }\n",
       "      });\n",
       "\n",
       "      // set src to a shiny data url\n",
       "      el.attr({src: urlize(serializer.serializeToString(svg.node()))});\n",
       "    });\n",
       "  }\n",
       "\n",
       "  function init(){\n",
       "    require([\n",
       "      \"base/js/namespace\",\n",
       "      \"base/js/events\"\n",
       "    ], function(IPython, events){\n",
       "      events\n",
       "        .on(\"rendered.MarkdownCell\", function(event, data){\n",
       "          layerize(d3.select(data.cell.element[0]));\n",
       "        });\n",
       "\n",
       "      IPython.notebook.get_cells()\n",
       "        .filter(function(cell){ return cell.cell_type === \"markdown\"; })\n",
       "        .map(function(cell){ layerize(d3.select(cell.element[0])); });\n",
       "    }, function(err){\n",
       "      d3.selectAll(\".rendered_html.text_cell_render\")\n",
       "        .call(layerize);\n",
       "    });\n",
       "\n",
       "    return init;\n",
       "  }\n",
       "\n",
       "  // pun for IPython.load_extensions\n",
       "  init.load_ipython_extension = init;\n",
       "\n",
       "  return init();\n",
       "});\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/javascript": [
       "// Generated by CoffeeScript 1.9.3\n",
       "(function() {\n",
       "  require({\n",
       "    paths: {\n",
       "      \"nb-mermaid\": [\"/nbextensions/nb-mermaid/nb-mermaid\", \"https://bollwyvl.github.io/nb-mermaid/nb-mermaid\"]\n",
       "    }\n",
       "  }, [\"nb-mermaid\"], function(nbmermaid) {\n",
       "    return nbmermaid();\n",
       "  });\n",
       "\n",
       "}).call(this);\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# these customize the environment \n",
    "from IPython.display import Javascript, display\n",
    "foo = [display(Javascript(url=url)) for url in [\n",
    "    \"https://bollwyvl.github.io/nb-inkscapelayers/main.js\",\n",
    "    \"https://bollwyvl.github.io/nb-mermaid/init.js\"\n",
    "]],"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
