Spiega documentation

present documentation
work with tech

documentation present

The documentation is made with mardown and .org files. We need to convert those files into a public documentation. For portfolio creation look at portfolio creation. First of all we need to include the header template in every file with the command [C-t h] which reads header_org.org header org header_md.

.org files are really versatile and can export to many other formats.

pdf
using LaTeX or postscript
html
with different exporting options
html reveal
mainly using reveal.js with reveal_custom.css
html slides
my custom scripts slide.js and slide.css

This file will be outputted as blog post or slides.

create animations

authors:
  - admin
projects: [project]
categories: [tags]
featured: false
commentable: true
image:
  caption:
  focal_point: 'center'

Blender has its own scripting tab but it doesn’t fit in my workflow where I use python REPL and LLMs to test the commands. Blender has an addon called blender-mcp which allows to access blender methods from outside.

connect blender-mcp

So I need to run the mcp server with transport http:

cd ~/lav/src/blender_twin/deploy/mcp_client/
#bash ./blender_local_client.sh &
cd $HOME/lav/src/blender_twin/deploy/mcp_client/blender_mcp_example_code/mcp/blmcp/ 
#python3 -m blmcp
uv --directory $HOME/lav/src/blender_twin/deploy/mcp_client/blender_mcp_example_code/mcp run blender-mcp --transport http --port 9191 &

I then need a container as defined in docker_compose.yml to create a bridge between the host and the containers within docker network.

blender-mcp-bridge:
  image: alpine/socat:latest
  container_name: blender-mcp-bridge
  network_mode: "host"
  command: TCP-LISTEN:19191,fork,reuseaddr TCP:127.0.0.1:9191
  restart: unless-stopped

create animations

I can then work on a script create_animation.py or let an LLM test the blender code without exiting the container.

Mermaid produces svg files which are loaded in blender apart from text which is not recognized. For that we created a script text2svg.py to load each text tag, load a font and create a path around that text. We apply as well some grouping logic so the import in blender is smoother.

cd ~/lav/src/spiega/script/
python3 text2svg.py ~/lav/siti/f/f_twin/arch_diagram.svg
mv output.svg ~/VideoProd/in_prog/graph/arch_dia.svg
File processed: /home/sabeiro/lav/siti/f/f_twin/arch_diagram.svgresults in output.svg

video

slideshow

Create a slideshow from folders of images galery_show.py.

python3 ~/lav/src/malastro/media/galery_show.py

voice over

To speed up voice over we use some tools like

cd ~/VideoProd/in_prog/graph/
#pip install auto-editor
auto-editor 
mv output.svg ~/VideoProd/in_prog/graph/arch_dia.svg

exporting

We started with many tools and we tried to minimize the dependencies so over time I removed the dependencies from tools like `markdown` and `pandoc`. I rather use my own header and footer templates In emacs.el we define most of the configurations and load the libraries. In reveal_config.org we have the additional configurations for export.

conversion scripts

Each website uses different scripts

spiega
technical blog
viudi
music website
blender_twin
project docs
foto
photography website
viaggi
travel website
scritti
personal blog

Where I built custom lisp and python files for tag manipulations.

export options

We can visualize the current export options with:

[C-c C-e t]

#+TITLE:       the title to be shown (default is the buffer name)
#+AUTHOR:      the author (default taken from user-full-name)
#+DATE:        a date, an Org timestamp120, or a format string for format-time-string
#+EMAIL:       his/her email address (default from user-mail-address)
#+DESCRIPTION: the page description, e.g. for the XHTML meta tag
#+KEYWORDS:    the page keywords, e.g. for the XHTML meta tag
#+LANGUAGE:    language for HTML, e.g. ‘en’ (org-export-default-language)
#+TEXT:        Some descriptive text to be inserted at the beginning.
#+TEXT:        Several lines may be given.
#+OPTIONS:     H:2 num:t toc:t \n:nil @:t ::t |:t ^:t f:t TeX:t ...
#+BIND:        lisp-var lisp-val, e.g.: org-export-latex-low-levels itemize
               You need to confirm using these, or configure org-export-allow-BIND
#+LINK_UP:     the ``up'' link of an exported page
#+LINK_HOME:   the ``home'' link of an exported page
#+LATEX_HEADER: extra line(s) for the LaTeX header, like \usepackage{xyz}
#+EXPORT_SELECT_TAGS:   Tags that select a tree for export
#+EXPORT_EXCLUDE_TAGS:  Tags that exclude a tree from export
#+XSLT:        the XSLT stylesheet used by DocBook exporter to generate FO file

The options we have are:

H:         set the number of headline levels for export
num:       turn on/off section-numbers
toc:       turn on/off table of contents, or set level limit (integer)
\n:        turn on/off line-break-preservation (DOES NOT WORK)
@:         turn on/off quoted HTML tags
::         turn on/off fixed-width sections
|:         turn on/off tables
^:         turn on/off TeX-like syntax for sub- and superscripts.  If
you write "^:{}", a_{b} will be interpreted, but
the simple a_b will be left as it is.
-:         turn on/off conversion of special strings.
f:         turn on/off footnotes like this[1].
todo:      turn on/off inclusion of TODO keywords into exported text
tasks:     turn on/off inclusion of tasks (TODO items), can be nil to remove
all tasks, todo to remove DONE tasks, or list of kwds to keep
pri:       turn on/off priority cookies
tags:      turn on/off inclusion of tags, may also be not-in-toc
<:         turn on/off inclusion of any time/date stamps like DEADLINES
*:         turn on/off emphasized text (bold, italic, underlined)
TeX:       turn on/off simple TeX macros in plain text
LaTeX:     configure export of LaTeX fragments.  Default auto
skip:      turn on/off skipping the text before the first heading
author:    turn on/off inclusion of author name/email into exported file
email:     turn on/off inclusion of author email into exported file
creator:   turn on/off inclusion of creator info into exported file
timestamp: turn on/off inclusion creation time into exported file
d:         turn on/off inclusion of drawers

A typical syntax:

#+OPTIONS:     H:2 num:t toc:t \n:nil @:t ::t |:t ^:t f:t TeX:t ...
(org-insert-export-options-template)

export scripts

We use multiple scripts to export, convert and publish the org files into slides, blog articles and pages: org-export.

html compatibility

An exhaustive guide.

> export iframe

html css

We can add css style in the page

publish

References ref1, ref2, ref3, ref4, ref5, ref6, ref7

.org files allow the publishing option as defined in emacs.el where I can set a project and the publishing directory. All the .org files in the `base-directory` will be converted into the `publishing-directory` and the pictures will be copied.

(setq org-publish-project-alist
      `(("pages"
         :base-directory "~/lav/src/spiega/blender_twin/"
         :publishing-directory "~/lav/siti/blender_twin/a/"
         :publishing-function roam-publication-wrapper
         :recursive t
         :html-head "<link rel=\"stylesheet\" href=\"static_html//css/org.css\" type=\"text/css\"/>\n"
         )
        ("static"
         :base-directory "~/lav/src/spiega/static/blender_twin/"
         :base-extension "jpg\\|gif\\|png\\|svg\\|css\\|js"
         :recursive t
         :publishing-directory "~/lav/siti/blender_twin/"
         :publishing-function org-publish-attachment)
      ("blender_twin" :components ("pages" "static"))))
(org-publish "blender_twin" t)

In case run a webserver

cd ~/lav/siti/blender_twin
python3 -m http.server

thumbnail

Copy default thumbnail if no other is provided

cd ~/lav/siti/f/f_stage
for i in ~/lav/src/spiega/article/* ;
do
    titN1=${i%.org}
    titN=${titN1##*/}
    thumbF=thumb_$titN.png
    if [ ! -f $thumbF ]; then
        echo $titN
        cp thumb_spiega.png $thumbF
    fi
done

emacs reveal slides

Emacs has many packages to convert .org into html + reveal.js, the most common is org-reveal but I tested org-re-reveal, emacs-reveal, oer-reveal, ox-reveal and they all cause headaches.

I had to pick manually select files from reveal.js and put them in the same order in the folder reveal/ with the same relative paths.

I tend to prefer `org-reveal` which has least dependencies.

export file

I need to figure out how to change filename (add _slide) and how to move it to another directory

script

We use one command to export this file to reveal.js and move it to the final folder.

(org-reveal-export-to-html)
;;(org-re-reveal-export-to-html)
mv documentation_present.html ~/lav/siti/spiega/a/documentation_present_slide.html
#firefox http://localhost/spiega/a/documentation_present_slide.html

oer package

Here we test the oer package

(use-package oer-reveal-publish)
(oer-reveal-setup-submodules t)
(oer-reveal-generate-include-files t)
(oer-reveal-publish-setq-defaults)
(setq oer-reveal-publish-babel-languages '((dot . t) (emacs-lisp . t))
      org-publish-project-alist
      (list (list "img"
                  :base-directory "~/lav/siti/blender_twin/"
                  :base-extension "png"
                  :publishing-function 'org-publish-attachment
                  :publishing-directory "~/lav/siti/f/f_twin/")))
img :base-directory ~/lav/siti/blender_twin/ :base-extension png :publishing-function org-publish-attachment :publishing-directory ~/lav/siti/f/f_twin/

wrap in tags

(use-package wrap-region)
(wrap-region-add-wrapper "<div class=\"r-stack\">" "</div>")

(lambda (arg) (interactive p) (wrap-region-trigger arg <div class=“r-stack”>))

open graph

We want to create open graph descriptions and

	<!-- Open Graph -->
<meta property="og:title" content="technical blog">
<meta property="og:description" content="technical blog, a collection of articles/post written during 17y of career spanning over 3k3 source code files and 2k images">
<meta property="og:url" content="https://intertino.it/spiega/a/spiega.html">
<meta property="og:image" content="https://intertino.it/f/f_stage/module_library_small.png">
cd ~/lav/siti/f/f_stage/
for i in ~/lav/src/spiega/markdown/*.org;
do
    titN1=${i%.org}
    titN=${titN1##*/}
    cp module_library_small.png thumb_$titN.png
done

references

There are multiple guides with many different outcomes:

systemcrafters

convert folder

We mainly use following script to convert the documentation.

(org-publish-current-project)
#rm ~/lav/siti/spiega/a/*
#rm ~/lav/siti/scritti/p/*
cd $HOME/lav/src/spiega
bash ./script/convert.sh
elogio noia
/home/sabeiro/lav/siti/scritti//a/elogio_noia.html

hugo

Here we test hugo which is nicely integrated with emacs and org-mode.

(use-package ox-hugo) (setq org-hugo-base-dir “~/lav/src/spiega/hugo”) (setq org-hugo-default-section-directory “post”)

#+hugo_base_dir:
export HUGO_BASE_DIR="~/lav/src/spiega/hugo/"
cd ~/lav/src/spiega/
hugo new project cios
cd quickstart
git init
git submodule add https://github.com/gohugo-ananke/ananke themes/ananke
echo "theme = 'ananke'" >> hugo.toml
hugo server

hugo templates

Hugo works with templating:

hugo.toml
config file
content/
where to put the .html files
data/
data files (like for maps)
assets/
theme assets
layouts/
layout of partial snippets
static/
css, js
themes/
pre-made themes

Hugo uses macros to read the content from folders and replace variables:

<meta charset="utf-8">
<title>{{ print .Page.Title }}</title>
{{ $style := resources.Get "assets/sass/main.scss" | css.Sass }}
<link rel="stylesheet" href="{{ $style.Permalink }}">

hugo examples

A typical layout of index.html

{{ define "main" }}
<section class="intro">
  <p class="intro__eyebrow">visitor@{{ .Site.Params.prompt.host | default "blog" }} $ cat about.txt<span class="cursor">&nbsp;</span></p>
  <h1>{{ .Site.Params.tagline | default .Site.Title }}</h1>
  {{ with .Site.Params.description }}<p>{{ . }}</p>{{ end }}
</section>

{{ $sectionPages := where .Site.RegularPages "Type" "posts" }}
{{ if eq (len $sectionPages) 0 }}{{ $sectionPages = .Site.RegularPages }}{{ end }}
{{ $paginator := .Paginate $sectionPages }}

<p class="section-label">Recent posts</p>
<ul class="post-list">
  {{ range $i, $p := $paginator.Pages }}
    {{ partial "post-card.html" (dict "page" $p "index" $i) }}
  {{ else }}
    <li style="color: var(--overlay1); font-family: 'IBM Plex Mono', monospace;">No posts yet — create one with <code>hugo new posts/my-first-post.html</code>.</li>
  {{ end }}
</ul>

{{ partial "pagination.html" $paginator }}
{{ end }}

blog

Let’s find a way to create a blog out of a folder of org files.

References: ref1, ref2, ref3, ref4, ref5 The idea is to come closer to the style of adhdecode, markaicode, solariz

content management system

A wordpress approach:

(use-package org2blog) ;;uses wordpress

table of content

We want to create an index file from table of content

(defun org-toc ()
  (interactive)
  (let ((files (f-entries "." (lambda (f) (f-ext? f "org")) t))
    (headlines '())
    choice) 
    (loop for file in files do
      (with-temp-buffer 
        (insert-file-contents file) 
        (goto-char (point-min))
        (while (re-search-forward org-heading-regexp nil t)
          (cl-pushnew (list
               (format "%-80s (%s)"
                   (match-string 0)
                   (file-name-nondirectory file))
               :file file
               :position (match-beginning 0))
              headlines))))
    (setq choice
      (completing-read "Headline: " (reverse headlines)))
    (find-file (plist-get (cdr (assoc choice headlines)) :file))
    (goto-char (plist-get (cdr (assoc choice headlines)) :position))))

slides

slides

Here we use two main libraries

reveal
reveal.js example org to reveal
custom
org-export-reveal.el for batch processes run in convert.sh

reveal_slide.png

reveal

There are multiple options to turn org files into reveal slides

custom
org-export-reveal.el and reveal_config for batch processes run in convert.sh
(require 'ox-publish)
(use-package ox-reveal)
(setq org-reveal-root "../reveal/")
(setq org-re-reveal-root "../reveal/")
(setq org-reveal-hlevel 1) 
(use-package oer-reveal)
(setq oer-reveal-publish-org-publishing-functions
      '(oer-reveal-publish-to-reveal))
(setq org-html-toc nil
      org-html-footnotes-in-header-file nil
      org-html-footnotes-after-body nil
      org-html-footnotes-as-uid t
      org-export-with-broken-links t
      org-export-with-toc nil
      org-export-with-section-numbers nil
      org-export-with-sub-superscripts nil
      org-html-verbatim "verbatim"
      org-use-sub-superscripts nil
      org-html-wrap-src-lines t
      org-html-prefer-user-labels t
      org-export-babel-evaluate nil 
      org-html-footer nil
      )

reveal customization

The current setup is reveal_config where the main features are ref:

#+REVEAL_THEME:league
#+REVEAL_TITLE_SLIDE: title.html
#+REVEAL_INIT_OPTIONS: slideNumber:true
#+REVEAL_SLIDE_HEADER:
#+REVEAL_SLIDE_FOOTER:
#+REVEAL_EXTRA_CSS: url-to-custom-stylesheet.css
#+REVEAL_EXTRA_SCRIPT_SRC: url-to-custom-script

Multiplexing (users can change slides in presentation mode)

#+REVEAL_MULTIPLEX_ID: [Obtained from the socket.io server. ]
#+REVEAL_MULTIPLEX_SECRET: [Obtained from socket.io server. Gives the master control of the presentation.]
#+REVEAL_MULTIPLEX_URL:  https://reveal-multiplex.glitch.me [Location of socket.io server]

reveal usage

Some inline commands while writing org

Split a slide if the section is too long

#+REVEAL: split:t

change the section background

:PROPERTIES:
:reveal_background: #123456
:END:

change the image background

:PROPERTIES:
:reveal_background: ./images/whale.jpg
:reveal_background_trans: slide
:END:

iframe background

:PROPERTIES:
:reveal_background_iframe: https://hakim.se
:reveal_background: rgb(0,0,0)
:reveal_background_opacity: 0.8
:END:

fragment (transition) lists

#+ATTR_REVEAL: :frag (grow shrink roll-in fade-out none) :frag_idx (4 3 2 1 -)
   - I will grow.
   - I will shrink.
   - I rolled in.
   - I will fade out.
   - I don't fragment.

auto animate

* Heading 1
  :PROPERTIES:
  :REVEAL_EXTRA_ATTR: data-auto-animate
  :END:
  #+ATTR_REVEAL: :data_id foo
  #+begin_src js
    let index = 1
  #+end_src

Literal html

#+REVEAL_HTML

Speakers note

 * Heading 1
   Some contents.
#+BEGIN_NOTES
  Enter speaker notes here.
#+END_NOTES

Global properties

#+REVEAL_HLEVEL: 2
#+REVEAL_INIT_OPTIONS: transition: 'cube'
#+REVEAL_THEME: moon

Sub-heading properties

:PROPERTIES:
:EXPORT_REVEAL_HLEVEL: 2
:EXPORT_INIT_OPTIONS: transition: 'cube'
:EXPORT_REVEAL_THEME: moon
:END:

reveal export

Here it gets a bit confusing with all packages:

ox-reveal :: org-reveal :: org-re-reveal :: for of oer oer-reveal ::

org-tree-slide

Here we use (org-tree-slide-mode) which basically displays and org file as slides. Navigation:

change section
[C-<] [C->]
show content
[C-x s c]
presets
simple
(org-tree-slide-simple-profile)
presentation
(org-tree-slide-presentation-profile)
narrow
no todos (org-tree-slide-narrowing-control-profile)
timer
(org-tree-slide-play-with-timer)
(use-package org-tree-slide
  :custom (org-image-actual-with nil))
(global-set-key (kbd "<f8>") 'org-tree-slide-mode)
(global-set-key (kbd "S-<f8>") 'org-tree-slide-skip-done-toggle)
(setq org-tree-slide-in-effect t
      org-tree-slide-activate-message "presentation started"
      org-tree-slide-deactivate-message "presentation ended"
      org-tree-slide-header t
      org-tree-slide-breadcrumbs " // "
)           

We can show the images in the file: (org-toggle-inline-images)

nil

slide generation from .org and .html

emacs has a lot of publishing options but in some cases I need a really custom design and therefore I strip header and footer from the html and append my own. We have a bash file for that convert_slide.sh. I need as well to convert the mermaid svg graph into a format blender can import which means first of all to convert the plain text into path which is accomplished by text2svg. This script tries as well to rename path ids to allow easier grouping into blender.

cd $HOME/lav/src/spiega/script/
bash ./convert.sh 
#bash ./text2svg.sh
###        /home/sabeiro/lav/src/spiega/article//documentation_present.org

two columns

scale architecture

This is a design sketch on how to scale this workflow for multi-user system

org
keeps track of agendas, tasks, project notes, deadlines, and authored knowledge
hugo
can publish curated pages such as project documentation, procedures, decisions, and reference material
tags
a rule for what is publishable, how links, attachments, tags map to site structure
knowledge graph
structured meaning and relationships: people, projects, tasks, documents, headings, tags, deadlines, links, permissions, and their connections. It answer relationship-oriented questions
search layer
finding relevant content quickly, typically using text and semantic matching.
parser
extract headings, properties, tags, IDs, links, timestamps, TODO states, schedules, deadlines, drawers, and selected planning metadata
linter
a special util inside the editor should check per user-group what changes make sense before committing

org processing

We need to build an org-processor and a non-tech-user UI for editing some labels

map
into a defined semantic model or knowledge graph. Hugo could remain the employee-facing interface, while the graph and retrieval layer support relationships and semantic search.
sync
decide how changes are synchronized
access
tech users to access org-repository. UI users for curated documentation, project views, task summaries, and semantic search.
labels
sensitive content should be filtered out or enforced through query-time permissions
pipeline
Org repo → parser and validation → knowledge graph → role-aware internal web UI
semantic search
current task views, relationship navigation, and role-aware results
permissions
a narrowly scoped update API for employee-editable fields such as task status or approved labels
validation
updates would be validated, written back to Org, and then re-indexed into the knowledge graph and search layer
collision
server-authoritative document model, real-time synchronization, user presence, version history, and conflict handling—often through operational transformation or CRDT-style techniques
change review
submit changes only to approved properties or tags through the UI; the service validates the change, records the user and timestamp, applies it to Org through one write path, and re-indexes the graph and search projections

architecture design

A draft of architecture would be:

repo
where all the org-files are stored
linter
a consistency check on information (end-date > start-date…)
commit
a series of allowed changes and permissions
sensitivity
sensitivity labels (inherit)

mermaid

---
displayMode: compact
title: Current Agenda Timeline from Clock Logs
config:
  gantt:
      useWidth: 900
      rightPadding: 20
      topAxis: true
      numberSectionStyles: 3
---
gantt
    dateFormat  YYYY-MM-DD
    title  Agenda Items Timeline from Clock Logs
    excludes  weekends

    section in progress
        agenda_review          :done,   rev1, 2026-09-07, 3d
        video_prep_org         :active,  v1, 2026-09-06, 5d
        video_prep_animations  :active,  v2, 2026-09-09, 3d

        soundtrack_finish      :active,  s1, 2026-09-16, 5d

        llm_chat               :done,   llm1, 2026-09-14, 1d
        llm_gptel              :active,  llm2, 2026-09-15, 3d
        llm_ellama            :active,  llm3, 2026-09-19, 2d
        llm_coding_assistant  :active,  llm4, 2026-09-20, 3d

        reporting_basic        :active,  rep1, 2026-09-15, 3d

    section active
        emacs_conf             :active,  e1, 2026-09-19, 3d

    section recurrent
        housekeeping           :active,  h1, 2026-09-18, 2d
        publish_sync           :active,  p1, 2026-09-18, 1d

    section knowledge
        integrate_llm_emacs    :active,  k1, 2026-09-14, 5d

    section milestone
        video_production       :milestone, m1, 2026-09-27, 1d
---
config:
  kanban:
    ticketBaseUrl: 'https://mermaidchart.atlassian.net/browse/#TICKET#'
---
kanban
  Todo
    [TODO-1] Parse agenda items
    [TODO-2] Extract clock logs
    [TODO-3] Generate gantt timeline
    [TODO-4] Create kanban board
    [TODO-5] Validate output format
  In Progress
    [PROG-1] Convert org headers to tasks
    [PROG-2] Map TODO states to kanban columns
    [PROG-3] Schedule date extraction
    [PROG-4] Effort estimation parsing
  Review
    [REV-1] Check gantt spacing
    [REV-2] Validate task names
    [REV-3] Test with sample agenda
  Done
    [DONE-1] Extract task headers
    [DONE-2] Parse clock entries
    [DONE-3] Generate mermaid syntax
    [DONE-4] Create visualization
     present this documentation

Date: 2026-09-07 Mon 00:00

Author: sabeiro

Created: 2026-10-09 Fri 17:15

Validate