Spiega documentation
- Knowledge sharing
- Portfolio
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.
- 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. The main index is spiega tech.
org-files
We extensively use org files org files features to create the content which gets exported in many different media formats. We created org operations to ease complex processing of org files like use LLMs to update tags and descriptions in the metadata.
create animations
authors:- adminprojects: [project]categories: [tags]featured: falsecommentable: trueimage: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 blmcpuv --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:latestcontainer_name: blender-mcp-bridgenetwork_mode: "host"command: TCP-LISTEN:19191,fork,reuseaddr TCP:127.0.0.1:9191restart: 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.svgmv 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
animation js
We can do motion graphics using javascript demos
# npx -y skills@latest add remotion-dev/skills -g -y#pnpm i @remotion/player@4.0.535cd ~/lav/src/spiega/knowledgepnpm create video --yes --blank js_animcd js_animationpnpm approve-builds#npx remotion skills addpnpm run dev
Welcome to Remotion![?25l? Choose a template: › - Use arrow-keys. Return to submit.❯ Blank Nothing except an empty canvasHello World A playground with a simple animationNext.js SaaS template for video generation appsNext.js (Vercel Sandbox) Render videos on-demand using Vercel SandboxRecorder A video production tool built entirely in JavaScriptPrompt to Motion Graphics SaaS Starter Kit SaaS template for AI-powered animation generationRender Server An Express.js server for rendering videos with RemotionElectron Render Remotion videos from a desktop appReact Router SaaS template for video generation appsReact Three Fiber Remotion + React Three Fiber Starter TemplateStill images Dynamic PNG/JPEG template with built-in serverAudiogram Text and waveform visualization for podcastsMusic Visualization Text and waveform visualization for podcastsPrompt to Video Create a story with images and voiceover from a promptSkia React Native Skia starterOverlay Overlays for video editing softwareCode Hike Beautiful code animationsStargazer Celebrate your repo stars with a videoTikTok Generate animated word-by-word captionsEditor Starter (Paid) A boilerplate for starting a video editor
We can then batch render the video
npx remotion render <composition-id> out/video.mp4 --gl=angle --concurrency=1
voice
voice over
To speed up voice over we use some tools like
cd ~/VideoProd/in_prog/graph/#pip install auto-editorauto-editormv output.svg ~/VideoProd/in_prog/graph/arch_dia.svg
transcribe speech
cd ~/VideoProd/clippython ~/lav/src/kotoba/kotoba/transcribe_video.py /home/sabeiro/VideoProd/publicati/org_creator.mp4
Processing 1 video(s)...============================================================Processing file 1 of 1: org_creator.mp4------------------------------------------------------------Loading Whisper model 'base'...Model loaded successfully.Extracting audio from 'org_creator.mp4'...Audio extracted successfully.Transcribing audio with Whisper...Detected language: ItalianTranscription completed.Generating SRT file: org_creator.srtGenerating text file: org_creator.txt✓ Successfully transcribed 'org_creator.mp4'Output files:- /home/sabeiro/VideoProd/publicati/org_creator.srt- /home/sabeiro/VideoProd/publicati/org_creator.txt============================================================SUMMARY============================================================Total videos: 1Successful: 1Failed: 0
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
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 itemizeYou 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 exportnum: turn on/off section-numberstoc: 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. Ifyou write "^:{}", a_{b} will be interpreted, butthe 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 texttasks: turn on/off inclusion of tasks (TODO items), can be nil to removeall tasks, todo to remove DONE tasks, or list of kwds to keeppri: turn on/off priority cookiestags: 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 textLaTeX: configure export of LaTeX fragments. Default autoskip: turn on/off skipping the text before the first headingauthor: turn on/off inclusion of author name/email into exported fileemail: turn on/off inclusion of author email into exported filecreator: turn on/off inclusion of creator info into exported filetimestamp: turn on/off inclusion creation time into exported filed: 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
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_twinpython3 -m http.server
thumbnail
Copy default thumbnail if no other is provided
cd ~/lav/siti/f/f_stagefor i in ~/lav/src/spiega/article/* ;dotitN1=${i%.org}titN=${titN1##*/}thumbF=thumb_$titN.pngif [ ! -f $thumbF ]; thenecho $titNcp thumb_spiega.png $thumbFfidone
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;dotitN1=${i%.org}titN=${titN1##*/}cp module_library_small.png thumb_$titN.pngdone
references
There are multiple guides with many different outcomes:
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/spiegabash ./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 cioscd quickstartgit initgit submodule add https://github.com/gohugo-ananke/ananke themes/anankeecho "theme = 'ananke'" >> hugo.tomlhugo 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"> </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
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 nilorg-html-footnotes-in-header-file nilorg-html-footnotes-after-body nilorg-html-footnotes-as-uid torg-export-with-broken-links torg-export-with-toc nilorg-export-with-section-numbers nilorg-export-with-sub-superscripts nilorg-html-verbatim "verbatim"org-use-sub-superscripts nilorg-html-wrap-src-lines torg-html-prefer-user-labels torg-export-babel-evaluate nilorg-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 jslet index = 1#+end_src
Literal html
#+REVEAL_HTML
Speakers note
* Heading 1Some contents.#+BEGIN_NOTESEnter 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 ::
We use the template
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 torg-tree-slide-activate-message "presentation started"org-tree-slide-deactivate-message "presentation ended"org-tree-slide-header torg-tree-slide-breadcrumbs " // ")
We can show the images in the file: (org-toggle-inline-images)
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
We need to wrap the two columns into a div
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: compacttitle: Current Agenda Timeline from Clock Logsconfig:gantt:useWidth: 900rightPadding: 20topAxis: truenumberSectionStyles: 3---ganttdateFormat YYYY-MM-DDtitle Agenda Items Timeline from Clock Logsexcludes weekendssection in progressagenda_review :done, rev1, 2026-09-07, 3dvideo_prep_org :active, v1, 2026-09-06, 5dvideo_prep_animations :active, v2, 2026-09-09, 3dsoundtrack_finish :active, s1, 2026-09-16, 5dllm_chat :done, llm1, 2026-09-14, 1dllm_gptel :active, llm2, 2026-09-15, 3dllm_ellama :active, llm3, 2026-09-19, 2dllm_coding_assistant :active, llm4, 2026-09-20, 3dreporting_basic :active, rep1, 2026-09-15, 3dsection activeemacs_conf :active, e1, 2026-09-19, 3dsection recurrenthousekeeping :active, h1, 2026-09-18, 2dpublish_sync :active, p1, 2026-09-18, 1dsection knowledgeintegrate_llm_emacs :active, k1, 2026-09-14, 5dsection milestonevideo_production :milestone, m1, 2026-09-27, 1d
---config:kanban:ticketBaseUrl: 'https://mermaidchart.atlassian.net/browse/#TICKET#'---kanbanTodo[TODO-1] Parse agenda items[TODO-2] Extract clock logs[TODO-3] Generate gantt timeline[TODO-4] Create kanban board[TODO-5] Validate output formatIn 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 parsingReview[REV-1] Check gantt spacing[REV-2] Validate task names[REV-3] Test with sample agendaDone[DONE-1] Extract task headers[DONE-2] Parse clock entries[DONE-3] Generate mermaid syntax[DONE-4] Create visualizationpresent this documentation