Autor: Mario Breskic

  • Update 6: Change Notes 18.10.2025

    Update 6: Change Notes 18.10.2025

    Layout verbessert

    • Sidebar und Paginierung eingeführt
    • Paginierung ist jetzt menschen­lesbar, und damit auch maschinen­lesbar
    • Paginierungs-Bug beseitigt
    • Vereinheitlichte Darstellung

    Links auf der Website

    • Sidebar verlinkt jetzt zu allen Seiten meiner Website
    • Sidebar beinhaltet jetzt eine Webroll (ersetzt damit die Blogroll)
    • Relationale Links nach XFN für Webroll und Social Links
    • Sidebar beinhaltet jetzt Links zu meinen Socials

    Artikel

    Shortform‑Artikel sind jetzt einfach ein normaler Bestand­teil des Feeds

  • Persisting Context: Kontext erhalten mit Index-Posts

    Ich beschäftige mich seit einigen Wochen mit einem der größten Probleme von Social Media: dass selbst Threads ihren Kontext über die Zeit verlieren.

    Wenn ich mehrere Posts verfasse, entstehen diese meist aus einer bestimmten Stimmung oder Absicht heraus. Wer in dem Moment live dabei ist, kann diesen Zusammenhang noch „hören“, fast wie den Tonfall meiner Stimme. Doch Social Media funktioniert überwiegend asynchron: ich schreibe jetzt, andere lesen irgendwann.

    Das Problem: Kontextverlust in Social Media

    Das Problem: Algorithmen zeigen Posts nicht in der ursprünglichen Reihenfolge, sondern nach vermuteter Aufmerksamkeit. So kann es passieren, dass jemand Monate später nur einen einzelnen Post von mir sieht – etwa über den Nutzen von Dokumentenscannern für Grafikdesigner mit einem Faible für Texturen – ohne zu wissen, warum ich ihn geschrieben habe oder ob das Thema für mich noch aktuell ist. Der Kontext ist verloren. Und auch ich gehe in den seltensten Fällen einfach mal irgendwessen Timeline durchsuchen, um zu rekonstruieren, um was es ging und ob es noch mehr gibt.

    Social Media wird dadurch zu einer Aneinanderreihung von Einzelpostings, die so chaotisch wirken können wie die Launen eines Glücksspielautomaten, sogar dann wenn sie von nur einem einzelnen Account stammen.

    “By treating a pinned post as a living index, Mario turns the most rigid feature of social media into its most flexible one — a single anchor that can grow, branch, and even hand off gracefully to the next index when it’s time to move on.”

    ChatGPT

    Die Lösung: Kontext erhalten mit Index-Posts

    Meine Lösung? Persisting Context – also Kontext erhalten. Dafür nutze ich einen gepinnten Beitrag als Index, an den ich thematische Threads anhänge. Jeder neue Thread verknüpft sich mit diesem Index, kann aber wiederum eigene Unterthemen entfalten. Auch experimentiere ich mich Randnotizen und Anmerkungen, im Moment mit den Hashtags #aside und #notes, falls ich zu einem bestimmten Post etwas anmerken möchte.

    Es entsteht eine Art Fächer: alle Threads gehen von einem gemeinsamen Index-Post aus, stellen aber ihre jedoch ihre eigenen Inhalte dar. So bleiben Themen klar voneinander getrennt, aber gleichzeitig im größeren Zusammenhang erkennbar.

    Zwei willkommene Nebeneffekte hat diese Methode auch: erstens bleibt durch den Erhalt des Kontextes auch die Sichtbarkeit der Posts erhalten, nichts geht mehr irgendwo verloren (außer man will es), und zweitens steigt die Anzahl der Views der eigenen Posts im Thread.

    Besonderer Dank an arianekonzepte auf Bluesky: durch den Hinweis darauf, dass mein Buildinpublic-Thread auf Bluesky über eine Lösung in huginn nicht nur übersichtlich war, sondern auch von einem kleinen Themenbot geboostet wurde, kam ich erst wieder auf diese Möglichkeit der Ordnung auf Social Media.

  • Happy Birthday, ASCA! Mein Social-Wall-Projekt wird ein Jahr alt

    Heute vor einem Jahr habe ich das damals noch unter https://social.mariobreskic.de/ erreichbare Projekt namens ASCA, Automated Social Content Archiver, gestartet: um eine Idee von mir umzusetzen, die es ermöglicht, dass man meine Posts auf meinen zur Zeit aktiveren Social-Media-Accounts auch dann lesen (und per RSS abonnieren, crawlen, weiterverarbeiten, mit AIs durchsuchen, usw.) kann, wenn man weder einen Account auf diesen Seiten hat, noch einen Account haben will.

    Liberate the Post! sozusagen.

    Und jetzt, nach einem Jahr, finde ich zwischen Familientreffen, der fortlaufenden Bedrohung durch Hornissen und Wespen, kurz Zeit, um mir die ersten Beiträge anzuschauen, die auf meiner Social Wall veröffentlicht wurden. Ich erwarte einige Posts, die wenig mehr aussagen, als „Test“, „Noch ein Test“ und „Dieser Test muss jetzt auch noch sein“.

    Partyhüte aufgesetzt? Cool, aber so spannend wird das nicht.

    Die ersten drei Posts

    Tag 0, einen Tag vor dem offiziellen Launch:

    This is a test without a title, but with a single tag.
    For a thing I am doing.

    Ursprünglich gepostet auf meinem Sideblog auf Tumblr, war dies schlicht der erste gelungene Test der Übertragung von Inhalten aus einer Social-Media-Plattform nach WordPress. Und welchen Tag hat es einfach nicht mitgenommen? Beim Blick auf die Quelle auf Tumblr, steht er da: #strength is performance.
    Was ich mit diesem Tag gemeint habe? Keine Ahnung mehr, der Kontext erschließt sich mir nicht mehr.1

    Und so folgt dann auch schon der erste richtige Beitrag, der auch mit Hashtags übertragen wurde, schon am nächsten Tag, mit dem Launch am 24. August 2024:

    I am currently working on a sort of a public facing backbone archive for my social media, using WordPress.
    The main idea is to collect all of my social media posts from now on in one single place, so that we can have a social wall of basically everything.
    I think that each social media website provides a certain tone, which can add to our work.
    It basically works like this:
    my own posts on Tumblr (and maybe soon Instagram and Twitter, too) are being copied as native WordPress posts.
    Stay tuned, I think I will bash this one out in the next few hours.
    If all works out properly, you can watch things pop up on https://social.­mariobreskic.­de/ over the next few months.
    I have a need to build and learn in public. Always have. So I will do just that.
    Next on the list: my own website, and making a tumblr theme which works for me (I need a sidebar to just add tags to).
    I expect a lot of tweaking, in general, since what I want and need is usually something I can build with what I have.

    https://codeandcanvas.tumblr.com/post/759711141568102401/i-am-currently-working-on-a-sort-of-a-public

    Interessant, zu diesem Zeitpunkt waren Twitter und Instagram noch gar nicht eingebunden, aber ich dachte schon daran, wie ich sie einbinden würde. Wusste ich gar nicht mehr! Cool, ich lese meine eigenen öffentlichen Aufzeichnungen von vor einem Jahr.

    Und am gleichen Tag folgte dann auch schon der erste Tweet, der in meiner Social Wall zugänglich gemacht wurde. Und damals war noch ein anderer Hashtag der Trigger für das selektive Speichern? ACAS und nicht, wie später, ASCA. Könnte aber auch ein Fehlerteufel gewesen sein.

    I am currently building a public archive of my social media posts using #automation.
    You can watch the progress here https://social.­mariobreskic.­de/ #acas #buildinpublic #LearnInPublic

    https://x.com/MarioBreskic/status/1827384913391129073

    Auch damals lag mir diese Art des öffentlich dokumentierten Arbeitens, die Tags #buildinpublic und #learninpublic sind mir so vertraut wie #gläsernewerkstatt und #gläserneslabor, aber #learninpublic hab ich in letzter Zeit eher selten verwendet (was ich übrigens auch einfach auf meiner Social Wall selber nachschlagen kann).

    Wie es weiterging

    So kamen dann auch mit der Zeit Instagram, Threads, Mastodon und auch Bluesky hinzu, und mir wurde klar, dass ich bei meinen eigenen Posts langsam in Richtung steigender Ansprüche ging, damit es wirklich wert ist, dass jemand seine Zeit hergibt, um von mir etwas zu sehen, zu lesen.

    Auch gab es dann noch ein paar Umstellungen und Veränderungen, und auch die Subdomain wanderte von social.mariobreskic.de zu socialwall.mariobreskic.de, aber das waren noch die kleineren Veränderungen. Und jetzt, ein Jahr nach Launch, bin ich froh darüber, dass dieses Projekt einfach existiert. Es ist da. Es selbst persistiert Social Media und darum ging es mir: wenn jemand einfach keinen Bock auf Social Media hat (und ich kann es so gut verstehen), aber trotzdem einfach und dass ohne sich irgendwo einzuloggen nötig ist, sehen will, was ich da so treibe, kann er das seit einem Jahr ganz einfach auf meiner Social Wall auch tun.

    Wohin es geht

    Das steht noch in den Sternen für ASCA. Und für mich auch. Danke fürs Mitfeiern und danke für so manch gutes Wort an passender Stell’.

    Jetzt auf „Veröffentlichen“ klicken und feiern gehen.

    1. Ab morgen, den 25. August 2025 um 7:59 Uhr kann man unter dieser URL https://www.mariobreskic.de/blog/persisting-context-kontext-erhalten-mit-index-posts/ zu dem Thema des Kontextes auf Social Media mehr lesen, oder aber auf ein paar meiner Social-Media-Accounts schon schauen, wozu ich die Möglichkeit eines gepinnten Beitrages verwende. ↩︎
  • Update 5: Change Notes 11.08.2025

    Update 5: Change Notes 11.08.2025

    Change Notes beziehen sich auf Arbeiten seit den letzten Change Notes. Ich war um Vollständigkeit bemüht, kann aber aus Gründen der Sicherheit nicht ins Detail gehen.

    AEO/SEO1

    Datenschutzerklärung überarbeitet

    Design

    Informationsergonomie, menschorientiertes Design und Signaletik

    • Linkwarden als Speicher für Links aus Artikeln aktiviert, doppelte Archivierung in Linkwarden (nicht öffentlich) und archive.org (öffentlich) beugt Link rot vor (siehe Snippet hier)
    • Redirects für alle Veränderungen implementiert
    • Maschinenlesbar bedeutet für Menschen lesbar (fortlaufende Arbeit, die Schnittstellen unter AEO/SEO erleichtern beide Lese-Arten)
    • Verschiedene Scripts hinzugefügt, die informationsdichten Inhalt von optionalem/ornamentalem Inhalt trennen (beispielsweise werden in der Sitemap nur die Inhalte berücksichtigt, die nicht durch Automatisierung und Integration entstehen)
    • Code-Snippets haben jetzt einen Button, mit dem man den ganzen Code mit nur einem Klick kopieren kann
    • Artikel und Seiten zeigen an, wann sie als letztes Mal nach der Veröffentlichung bearbeitet wurden

    Kategorien und Seiten, Navigation

    • Neue Kategorien: Macht (ehemals Baut), Baukasten (ehemals eine einzelne Seite namens Toolbox), Kategorie Status wurde zum Zweck der Übersichtlichkeit aufgelöst
    • Breadcrumb-Navigation hinzugefügt
    • Suche verbessert: Suchergebnisse werden hervorgehoben und ihre Anzahl angezeigt
    • Weniger Kurznachrichten-Kategorien auf der Landing Page (experimentell)

    Projekte

    Design-Informationsdienst (auch bekannt als Grafikdesignfeed 2.0)

    Momentaner Umfang des Netzwerks: auf Bluesky, Mastodon, Threads und Twitter werden dreimal täglich die interessantesten Artikel gepostet

    Mastodon

    • Anbindung an das Fediverse verbessert4
    • Suche mittels Elasticsearch optimiert

    Social Wall


    1. Zu AEO „Answer Engine Optimization“ siehe auch dieser Thread ↩︎
    2. Über humans.txt: About humans.txt ↩︎
    3. Siehe mehr dazu hier: Getting Started with llms.txt ↩︎
    4. Durch Anpassung der nginx-Direktiven wurden sowohl die Reichweite meiner Instanz daramtisch erhöht, als auch fehlerhafte Anfragen mittels .well-known beseitigt. Aktuelle Direktiven teile ich gerne auf Anfrage auf meiner Website hier ↩︎
  • Change Notes 005

  • Dateiumbenennung nach Velsz in Bridge

    Wir machen das in zwei Stufen: zuerst bereinigen wir alle üblichen Datumsangaben in dem Ordner, in dem wir die Umbenennung vornehmen wollen, dann machen wir die Umbenennung in Bridge.

    Vorbereitungsskript zur Bereinigung von Dateinamen (vor der Umbenennung in Adobe Bridge)

    Mein Python-Skript dient dazu, Datumseinträge aus Dateinamen zu entfernen, bevor die eigentliche Umbenennung mit Adobe Bridge erfolgt. Es hilft mir dabei, doppelte oder inkonsistente Datumsangaben zu vermeiden, wenn Bridge später ein neues Datum hinzufügt.

    Was mein Skript macht

    • Durchsucht den Ordner, in dem sich das Skript befindet
    • Erkennt typische Datumsformate im Dateinamen:
      • YYYY-MM-DD (z. B. 2023-08-07)
      • DD-MM-YYYY (z. B. 07-08-2023)
      • YYYYMMDD oder DDMMYYYY (z. B. 20230807)
      • YYMMDD oder DDMMYY (z. B. 230807)
    • Entfernt diese Datumsbestandteile aus dem Dateinamen
    • Lässt die Dateiendung unverändert
    • Gibt eine Rückmeldung, ob eine Datei umbenannt wurde oder nicht (aber nur, wenn man über Commandline/Konsole aufruft)

    Anwendung

    1. Ich speichere das Skript im gleichen Ordner wie die zu bereinigenden Dateien.
    2. Dann führe ich das Skript aus (z. B. mit Python über die Konsole) und dann
    3. Starte ich Adobe Bridge und wende meine Umbenennungsvorlage an.

    Nachfolgend das Python-Script, das ich verwende. Einfach markieren und kopieren, dann beispielsweise als rename_cleaner.py speichern.

    import os
    import re

    # 📍 Get the folder where the script is located
    folder_path = os.path.dirname(os.path.abspath(__file__))

    # 🧠 Regex pattern to match common date formats in filenames
    date_pattern = re.compile(
    r'(\d{4}-\d{2}-\d{2})|' # YYYY-MM-DD
    r'(\d{2}-\d{2}-\d{4})|' # DD-MM-YYYY
    r'(\d{8})|' # YYYYMMDD or DDMMYYYY
    r'(\d{6})' # YYMMDD or DDMMYY
    )

    # 🚀 Loop through files in the folder
    for filename in os.listdir(folder_path):
    file_path = os.path.join(folder_path, filename)

    # Skip folders
    if not os.path.isfile(file_path):
    continue

    name, ext = os.path.splitext(filename)

    # 🧹 Remove date patterns from filename
    cleaned_name = date_pattern.sub('', name).strip('-_ ')

    # 🏷️ Build new filename
    new_filename = f"{cleaned_name}{ext}"
    new_path = os.path.join(folder_path, new_filename)

    # 🔁 Rename file if name changed
    if filename != new_filename:
    os.rename(file_path, new_path)
    print(f"✅ Renamed: {filename} → {new_filename}")
    else:
    print(f"⏩ Skipped (no change): {filename}")

    Anleitung zur Verwendung der Batch-Umbenennungsvorlage in Adobe Bridge

    Dateiname der Vorlage: standard-nach-velsz.setting
    Kompatibel mit: Adobe Bridge 2022, 2023, 2024

    So verwendest du meine Vorlage nach Velsz1

    1. Datei kopieren: Kopiere die Datei standard-nach-velsz.setting in folgenden Ordner auf deinem Computer:

    Windows:

    C:\Users\<USERNAME>\AppData\Roaming\Adobe\Bridge <version>\Batch Rename Settings\

    macOS:

    /Users/<USERNAME>/Library/Application Support/Adobe/Bridge <version>/Batch Rename Settings2

    1. Starte Adobe Bridge.
    2. Markiere alle Dateien, die umbenannt werden sollen.
    3. Gehe zu Werkzeuge > Stapelumbenennung
    4. Lade die heruntergeladene Vorlage standard-nach-velsz, oder:
    5. Wähle folgende Einstellungen
      • Zielordner: Gleicher Ordner (oder ein neuer)
      • Neuer Dateiname:
        • Datum/Uhrzeit. Erstellungsdatum. JJJJMMTT (YYYMMDD)
        • Text: –
        • Beibehaltener Dateiname. Name. Kleinbuchstaben.
    6. Klicke auf Umbenennen, um die Änderungen anzuwenden.
    1. Vergleiche dazu u.a. „Lightroom Classic und CC: das umfassende Handbuch“ von István Velsz ↩︎
    2. Dank für den richtigen Pfad an wckdtalls Kommentar hier: https://community.adobe.com/t5/bridge-discussions/batch-rename-presets/m-p/13085459#M35134 ↩︎
  • Umbenennungen, und gute Redirects. Willkommen zur neuen Kategorie „Macht”

  • Artikellinks aus WordPress in Linkwarden speichern

    Ein kurzer Snippet zum Ausprobieren. Benötigt WordPress und Linkwarden.1 Damit werden alle Links, die sich in einem Artikel bestimmter Kategorien befinden, beim Veröffentlichen zum Speichern an Linkwarden geschickt. Linkwarden schickt diese dann auch an archive.org, damit sie auch öffentlich verfügbar bleiben.

    Kontext dazu: Mein Mastodon‑Post hier, und dieser Bluesky‑Post.

    // Hooks into the WordPress publish_post action.
    // When a post is published, it triggers the send_post_links_to_linkwarden function.
    add_action('publish_post', 'send_post_links_to_linkwarden', 10, 2);

    function send_post_links_to_linkwarden($post_ID, $post) {
    // Only proceed if the post is in one of these categories.
    $preferred_categories = ['CHANGE_ME', 'CHANGE_ME_TOO'];

    // Set post_title
    $post_title = sanitize_text_field($post->post_title);


    // Get the category slugs of the published post.
    $post_categories = wp_get_post_categories($post_ID, ['fields' => 'slugs']);

    // Skip processing if the post doesn't belong to one of the preferred categories.
    if (empty(array_intersect($preferred_categories, $post_categories))) {
    error_log("[Linkwarden] Skipping post ID $post_ID because it is not in preferred categories.");
    return;
    }

    // Define the Linkwarden API base URL and access token.
    $api_base_url = ' https://YOUR_LINKWARDEN_URL/api/v1';
    $api_token = 'YOUR_API_TOKEN';

    // Extract all URLs from the post content.
    $content = $post->post_content;
    $urls = wp_extract_urls($content);

    // Exit if no URLs were found in the post.
    if (empty($urls)) {
    error_log("[Linkwarden] No URLs found in post ID $post_ID");
    return;
    }

    // Remove duplicate URLs.
    $urls = array_unique($urls);

    // Send each URL found in the post to the Linkwarden API.
    foreach ($urls as $url) {
    // Create the body of the request with the URL, post title as title and tag.
    $body = [
    'url' => $url,
    'title' => $post->post_title,
    'tags' => [ ['name'=> $post_title] ],
    'collectionId' => [
    'id' => COLLECTION_ID_NUMBER_NO_QUOTES_FOR_ME_PLEASE
    ],
    ];

    // Make a POST request to the Linkwarden /links endpoint.
    $response = wp_remote_post("{$api_base_url}/links", [
    'headers' => [
    'Authorization' => 'Bearer ' . $api_token,
    'Content-Type' => 'application/json',
    ],
    'body' => wp_json_encode($body),
    'timeout' => 10,
    ]);

    // Log an error if the HTTP request fails.
    if (is_wp_error($response)) {
    error_log("[Linkwarden] HTTP request error for URL $url: " . $response->get_error_message());
    continue;
    }

    // Check the response code to confirm successful addition.
    $code = wp_remote_retrieve_response_code($response);
    if ($code !== 201 && $code !== 200) {
    error_log("[Linkwarden] Unexpected response code $code for URL $url. Response: " . wp_remote_retrieve_body($response));
    } else {
    error_log("[Linkwarden] Successfully added URL $url from post ID $post_ID");
    }
    }
    }
    1. Getestet mit selbst-gehostetem Linkwarden als Docker-Volume. ↩︎
  • Satzspiegelrechner

    Was macht der Satzspiegelrechner?

    Der Satzspiegel­rechner ist ein Tool zur Visualisierung und Berechnung des Satzspiegels für ein Buchformat, hier exemplarisch für A5‑Seiten.
    Er zeigt, wie viele Zeilen bei einer vorgegebenen Buchstaben­höhe und einem fest­gelegten Zeilen­abstand auf die Seite passen, und stellt den Satz­spiegel (den be­druckbaren Bereich) mit typischen Seiten­rändern dar. So kann man Layout‑Parameter wie Buchstaben­höhe und Zeilen­abstand experimentell anpassen und direkt sehen, wie sich der Satzspiegel verändert.

    Wichtig: Dieses Tool ist aktuell noch ein Work in Progress – es befindet sich in einer sehr frühen Entwicklungsphase.

    Danke an Andreas Maxbauer für die Inspiration.