i18n: bilingual de/en, bundle js from assets via hugo pipes, css refresh

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 01:07:04 +02:00
parent 7932bc35e4
commit c46f9a48f7
44 changed files with 515 additions and 60 deletions
+31
View File
@@ -41,6 +41,9 @@
outline: none;
caret-color: transparent;
}
/* a command "typed" by the file browser on hover/freeze — dimmed so it reads
as a hint, not something you committed. any real keystroke discards it. */
.prompt__input.is-ghost { color: var(--color-text-muted); font-weight: 400; }
/* blinking terminal cursor, sits right after the typed text */
.caret {
@@ -363,3 +366,31 @@ img { filter: none; }
/* frozen/locked preview indicator */
.filebrowser.is-frozen .tui__status { color: var(--color-text-primary); }
.filebrowser.is-frozen .tui__status::after { content: " ● locked"; }
/* hide every scrollbar site-wide — content still scrolls (wheel/touch/keys),
just no native chrome. keeps the clean terminal surface everywhere. */
* {
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* old Edge/IE */
}
*::-webkit-scrollbar { /* WebKit/Blink */
display: none;
}
/* ─────────────────── LANGUAGE SWITCH ─────────────────── */
/* top-right toggle on the shell row: shows only the *other* language,
click to switch. you never see both at once. */
.topbar { position: relative; }
.lang-switch {
position: absolute;
top: 0;
right: 0;
margin-left: 0;
font-family: var(--font-family-mono);
color: var(--color-text-muted);
border-bottom: 1px dotted;
z-index: 2;
}
.lang-switch:hover { color: var(--color-text-primary); border-bottom: 1px solid; }
/* keep the prompt text clear of the toggle so long paths never slide under it */
.prompt { padding-right: 3.5ch; }
+1 -5
View File
@@ -38,11 +38,7 @@
["ok", "Loaded index.html", 70],
["ok", "Loaded css/bundle.css", 60],
["ok", "Loaded fonts/iosevka-curly-slab.woff2", 90],
["ok", "Loaded js/cursor.js", 55],
["ok", "Loaded js/shell.js", 55],
["ok", "Loaded js/filebrowser.js", 55],
["ok", "Loaded js/nav.js", 55],
["ok", "Loaded js/boot.js", 80],
["ok", "Loaded js/bundle.js", 80],
["ok", "Parsed DOM — 0 errors", 120],
["st", "Mounting routes...", 240],
["ok", "Mounted /", 50],
@@ -10,6 +10,17 @@
function hidePlayer() { if (player) { player.hidden = true; if (pv && !pv.paused) pv.pause(); } }
function showPlayer() { if (player) player.hidden = false; }
function setFrozen(v) { frozen = v; if (container) container.classList.toggle("is-frozen", v); }
// tell the shell to "type" the matching command. navigable rows (those with an
// href: ".." and the portfolio project folders) are directories → `cd`; the
// preview-only leaves inside a project (images, info.md, video) are files → `cat`.
function ghostCmd(a) {
if (!a) return;
var name = a.getAttribute("data-name") || "";
var isDir = a.hasAttribute("href");
document.dispatchEvent(new CustomEvent("shell:ghost", { detail: (isDir ? "cd " : "cat ") + name }));
}
function ghostClear() { document.dispatchEvent(new CustomEvent("shell:ghost-clear")); }
function showImg(src) {
if (!img) return;
img.hidden = false;
@@ -20,7 +31,7 @@
if (img.complete) img.style.opacity = "1"; // already cached → no fade
}
function select(i) {
function select(i, silent) {
if (!rows.length) return;
if (i < 0) i = 0;
if (i >= rows.length) i = rows.length - 1;
@@ -43,6 +54,8 @@
var y = a.querySelector(".tui__date");
cap.textContent = (n ? n.textContent.trim() : a.getAttribute("data-name")) + (y ? " " + y.textContent.trim() : "");
}
if (!silent) ghostCmd(a); // echo into the shell, except on the initial load
}
function bind() {
@@ -62,13 +75,13 @@
a.addEventListener("click", function (e) {
if (a.getAttribute("href")) return; // navigation rows behave normally
e.preventDefault();
if (frozen && cur === i) setFrozen(false);
if (frozen && cur === i) { setFrozen(false); ghostClear(); }
else { select(i); setFrozen(true); }
});
});
var start = rows.findIndex(function (a) { return a.classList.contains("is-selected"); });
select(start < 0 ? 0 : start);
select(start < 0 ? 0 : start, true); // initial selection: don't echo into the shell yet
// warm the cache so switching between gallery images is instant
var srcs = rows.map(function (a) { return a.getAttribute("data-img"); }).filter(Boolean);
@@ -81,7 +94,7 @@
// one-time document listeners (reference the current bound state)
document.addEventListener("click", function (e) {
if (e.target.closest && e.target.closest(".tui__ls a")) return;
if (frozen) setFrozen(false);
if (frozen) { setFrozen(false); ghostClear(); }
});
document.addEventListener("keydown", function (e) {
var t = e.target;
@@ -95,6 +108,15 @@
}
});
// the always-open home menu lives in the persistent header (outside the
// filebrowser and untouched by pjax). hovering a folder ghost-types `cd <name>`
// so the shell echoes where a click would take you, until you type for real.
Array.prototype.forEach.call(document.querySelectorAll(".menu .tui__ls a[data-name]"), function (a) {
a.addEventListener("mouseenter", function () {
document.dispatchEvent(new CustomEvent("shell:ghost", { detail: "cd " + (a.getAttribute("data-name") || "") }));
});
});
bind();
document.addEventListener("pjax:load", bind);
})();
+16
View File
@@ -30,6 +30,12 @@
// per-section typeable routes live in .topbar — replace them
var topbar = document.querySelector(".topbar");
// language switch (persistent header) — repoint it at THIS page's
// translation, otherwise it keeps the target of the first-loaded page
var nl = doc.querySelector(".lang-switch"), ol = document.querySelector(".lang-switch");
if (ol && ol.parentNode) ol.parentNode.removeChild(ol);
if (nl && topbar) topbar.insertBefore(document.importNode(nl, true), topbar.firstChild);
var oldR = document.querySelector(".routes");
if (oldR && oldR.parentNode) oldR.parentNode.removeChild(oldR);
var newR = doc.querySelector(".routes");
@@ -49,9 +55,19 @@
if (!cache[url]) cache[url] = fetchHTML(url).catch(function () { delete cache[url]; return null; });
}
// which language a URL belongs to (de lives under /de/, en is the default)
function langOf(u) {
var p;
try { p = new URL(u, location.origin).pathname; } catch (e) { p = u; }
return /^\/de(\/|$)/.test(p) ? "de" : "en";
}
var busy = false;
function go(url, push) {
if (busy) return;
// a language change rebuilds the whole chrome (menu, html lang, switch),
// so do a real reload instead of a partial content swap
if (langOf(url) !== (document.documentElement.lang || "en")) { location.href = url; return; }
busy = true;
(cache[url] || fetchHTML(url))
.then(function (html) {
+25 -2
View File
@@ -18,7 +18,7 @@
var routes = {};
function buildRoutes() {
routes = {};
Array.prototype.forEach.call(document.querySelectorAll(".menu a, .routes a, footer a[data-name]"), function (a) {
Array.prototype.forEach.call(document.querySelectorAll(".menu a, .routes a, footer a[data-name], .lang-switch"), function (a) {
var key = (a.getAttribute("data-name") || a.textContent).trim().toLowerCase().replace(/\/+$/, "");
if (key) routes[key] = a.getAttribute("href");
});
@@ -32,7 +32,27 @@
}
function say(msg) { if (out) out.textContent = msg; }
function navigate(u) { input.textContent = ""; if (window.pjax) window.pjax(u); else window.location.href = u; }
function navigate(u) { clearGhost(); input.textContent = ""; if (window.pjax) window.pjax(u); else window.location.href = u; }
// ghost command: the file browser "types" e.g. `cat 03.webp` into the prompt as
// you hover/freeze a file, so you always see where you are. it's only a hint —
// any real keystroke (or navigation) discards it and the line is yours again.
var ghostActive = false;
function setGhost(text) {
if (!ghostActive && input.textContent) return; // never clobber a real command in progress
input.textContent = text;
ghostActive = true;
input.classList.add("is-ghost");
caretToEnd();
}
function clearGhost() {
if (!ghostActive) return;
input.textContent = "";
ghostActive = false;
input.classList.remove("is-ghost");
}
document.addEventListener("shell:ghost", function (e) { setGhost(e.detail); });
document.addEventListener("shell:ghost-clear", clearGhost);
function pad(n) { return (n < 10 ? "0" : "") + n; }
function dateStr() {
@@ -271,6 +291,8 @@
}
input.addEventListener("keydown", function (e) {
// a real keystroke wins over the file-browser's ghost command
if (ghostActive && !/^(Shift|Control|Alt|Meta|CapsLock)$/.test(e.key)) clearGhost();
if (e.key === "Enter") { e.preventDefault(); run(input.textContent); return; }
if (e.key === "Tab") { e.preventDefault(); complete(); return; }
if (e.key === "ArrowUp" && hist.length) {
@@ -305,6 +327,7 @@
if (e.metaKey || e.ctrlKey || e.altKey) return;
if (e.key && e.key.length === 1) { // a printable character
e.preventDefault();
if (ghostActive) clearGhost(); // discard the ghost, type for real
input.focus();
input.textContent += e.key;
caretToEnd();
+5
View File
@@ -0,0 +1,5 @@
---
title: "startseite"
description: "architektur studio"
heroImage: "/img/Triest_Rozzol_Melara.webp"
---
+9
View File
@@ -0,0 +1,9 @@
---
title: "about"
description: "über karim gabriele varano"
layout: "about"
---
mein name ist karim gabriele varano. ich bin im rheintal im kanton st. gallen aufgewachsen. vor der architektur habe ich in der elektrotechnik gearbeitet, auf der baustelle und in der planung. ich bin durch die gestalterische vorbildung gegangen und von dort ins architekturstudium an der ost und der hslu. ich habe einen bachelor in architektur und arbeite zurzeit auf den master hin. was mich an der architektur fesselt, ist ihre tiefe. sie bewegt sich zwischen dem gewicht eines materials und dem gewicht einer gesellschaftlichen krise. sie borgt sich aus dem ingenieurwesen, der soziologie, der kunst, der politik. sie ist keine wissenschaft. sie ist der ort, an dem die wissenschaften sich treffen, und an dem dieses treffen in etwas realem und bewohnbarem enden muss.
ich bin offen für [zusammenarbeit](mailto:hi@karimgabrielevarano.xyz).
+17
View File
@@ -0,0 +1,17 @@
---
title: "colophon"
description: "wie diese seite gemacht ist"
dotfile: true
---
diese seite ist ein kleines terminal.
sie ist statisch. hugo verwandelt meinen text in einfache html-dateien, und mehr gibt der server nie heraus. keine datenbank, kein backend, nichts zum einloggen. sie läuft auf fast jedem host.
die leiste oben ist eine echte shell. du kannst darin tippen. portfolio, about, studio, openbureau bringen dich zu diesen seiten. help zeigt die grundlagen, tab vervollständigt ein wort, die pfeiltaste nach oben holt zurück, was du vorher getippt hast. nicht alles, was sie kennt, steht in der liste. jede seite ist auch eine dateiliste, du kannst die projekte und sogar das impressum wie verzeichnisse durchsehen und an ort und stelle lesen.
der rest sind kleinigkeiten. die schrift ist iosevka curly slab, hier gehostet und von niemandem nachgeladen. der cursor ist pixel für pixel gezeichnet. es gibt einen dunkelmodus, wenn du dark tippst. nichts wird verfolgt, keine cookies, kein tracking.
sie folgt derselben idee wie [openbureau](/de/openbureau/): besitze deine werkzeuge, halte deine formate lesbar. die inhalte stehen unter cc by-sa, hugo und das theme sind open source (das [impressum](/de/legal-notice/) hat die details), und die seite baut zu einem docker-image, sodass jeder seine eigene kopie betreiben kann.
geschrieben zwischen rheintal und luzern.
+33
View File
@@ -0,0 +1,33 @@
---
title: "cv"
description: "ausbildung, erfahrung, fähigkeiten"
---
**ausbildung**
<dl class="meta">
<dt>2025-heute</dt><dd>ma architektur · hslu luzern · laufend</dd>
<dt>2023-2025</dt><dd>ba architektur · hslu luzern · abgeschlossen</dd>
<dt>2022-2023</dt><dd>ba architektur · ost st. gallen · 2 semester</dd>
<dt>2021-2022</dt><dd>bms gestaltung · st. gallen</dd>
<dt>2019-2021</dt><dd>elektroplanung, installation &amp; sicherheit · 3 semester, unvollständig</dd>
<dt>2014-2016</dt><dd>lehre als elektroinstallateur</dd>
<dt>2011-2014</dt><dd>lehre als montage-elektriker</dd>
</dl>
**erfahrung**
<dl class="meta">
<dt>2025-heute</dt><dd>architektur</dd>
<dt>2018-2022</dt><dd>elektroplanung</dd>
<dt>2016-2018</dt><dd>tontechniker</dd>
</dl>
**fähigkeiten**
<dl class="meta">
<dt>gestaltung</dt><dd>architektur · grafik · editorial · web</dd>
<dt>open source</dt><dd>self-hosting · ict einrichtung &amp; support</dd>
</dl>
[hi@karimgabrielevarano.xyz](mailto:hi@karimgabrielevarano.xyz)
+6
View File
@@ -0,0 +1,6 @@
---
title: "impressum"
description: "impressum, datenschutz und lizenzen"
layout: "legal"
dotfile: true
---
+5
View File
@@ -0,0 +1,5 @@
---
build:
render: never
list: never
---
+12
View File
@@ -0,0 +1,12 @@
---
build:
render: never
list: never
---
**HAFTUNGSAUSSCHLUSS**
der autor übernimmt keine haftung für die richtigkeit, vollständigkeit oder aktualität der bereitgestellten inhalte. ansprüche auf schadenersatz aus der nutzung oder nichtnutzung der angebotenen informationen sind ausgeschlossen.
für den inhalt extern verlinkter seiten sind ausschliesslich deren betreiber verantwortlich. zum zeitpunkt der verlinkung waren keine rechtsverstösse erkennbar. wird ein verstoss bekannt, wird der entsprechende link umgehend entfernt.
architekturzeichnungen und projektdokumentationen, die auf dieser website veröffentlicht werden, dienen ausschliesslich der information und der präsentation von arbeiten. sie stellen keine baubewilligungen, keine statischen freigaben und keine fachliche beratung dar.
+16
View File
@@ -0,0 +1,16 @@
---
build:
render: never
list: never
---
**LIZENZEN**
**WEBSITE-INHALTE**\
alle texte, bilder und projektdokumentationen auf dieser website stehen, sofern nicht anders angegeben, unter der lizenz [creative commons namensnennung-weitergabe unter gleichen bedingungen 4.0 international (cc by-sa 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). du darfst das material teilen und bearbeiten, sofern du angemessen credit gibst und deine beiträge unter derselben lizenz weitergibst.
**FRAMEWORK — HUGO**\
diese website wurde mit [hugo](https://gohugo.io) gebaut, einem quelloffenen statischen website-generator, lizenziert unter der [apache license 2.0](https://github.com/gohugoio/hugo/blob/master/LICENSE).
**THEME — SHIBUI**\
das theme shibui von nguyen tuan khanh ist unter der [mit license](https://github.com/ntk148v/shibui/blob/master/LICENSE) lizenziert.
+26
View File
@@ -0,0 +1,26 @@
---
build:
render: never
list: never
---
**DATENSCHUTZERKLÄRUNG**
der schutz deiner personendaten ist mir wichtig. diese erklärung beschreibt, wie auf dieser website mit daten umgegangen wird, im einklang mit dem schweizerischen bundesgesetz über den datenschutz (revdsg, in kraft seit 1. september 2023).
**VERANTWORTLICHE STELLE**\
karim gabriele varano, fluhmühlerain 1, 6015 luzern. kontaktangaben wie oben.
**SERVER-LOG**\
der hosting-anbieter erfasst automatisch technische zugriffsdaten in server-logdateien. dazu gehören aufgerufene seiten, datum und uhrzeit, browsertyp, betriebssystem, referrer-url und ip-adresse. diese daten werden ausschliesslich zu technischen und statistischen zwecken verwendet und nicht mit anderen datenquellen zusammengeführt oder für marketing genutzt.
**KONTAKT PER E-MAIL**\
wenn du mich per e-mail kontaktierst, werden deine angaben zur bearbeitung der anfrage gespeichert. diese daten werden ohne deine zustimmung nicht an dritte weitergegeben und nach abschluss der korrespondenz gelöscht, sofern keine gesetzliche aufbewahrungspflicht besteht.
**DEINE RECHTE**\
nach dem revdsg hast du das recht, auskunft über deine gespeicherten personendaten zu verlangen sowie deren berichtigung, löschung oder die einschränkung der bearbeitung. wende dich dazu an die oben genannte adresse.
du hast zudem das recht, bei der zuständigen aufsichtsbehörde beschwerde zu führen, dem eidgenössischen datenschutz- und öffentlichkeitsbeauftragten (edöb): [www.edoeb.admin.ch](https://www.edoeb.admin.ch)
**ÄNDERUNGEN**\
diese datenschutzerklärung kann bei bedarf angepasst werden. die aktuelle fassung ist immer auf dieser seite verfügbar.
+11
View File
@@ -0,0 +1,11 @@
---
build:
render: never
list: never
---
**VERANTWORTLICH FÜR DEN INHALT**
karim gabriele varano\
fluhmühlerain 1, 6015 luzern, schweiz\
[hi@karimgabrielevarano.xyz](mailto:hi@karimgabrielevarano.xyz)
+5
View File
@@ -0,0 +1,5 @@
---
build:
render: never
list: never
---
+12
View File
@@ -0,0 +1,12 @@
---
build:
render: never
list: never
---
**DOSSIER**\
2026
ein rhino-plugin für die frühe phase des architektonischen entwurfs. wände, türen, fenster, decken, treppen, geschosse und eine 2d-zeichenebene, die sich wie eine 2d-zeichenebene anfühlt. native rhino-objekte, keine parallele datenbank zum abgleichen. was es gibt, ist entweder teure proprietäre software oder vollständige bim-systeme, gebaut für die dokumentationsphasen im büromassstab, die nicht dazu passen, wie man während einer skizze tatsächlich denkt. quelloffene bim-werkzeuge leben in blender oder freecad und folgen einer 3d-zuerst-logik, nützlich, aber nicht so, wie man einen plan in 2d zeichnet. studierende und kleine büros zahlen am ende, raubkopieren oder behelfen sich im blanken rhino. dossier ist das werkzeug, das ich während meines masters und meiner eigenen arbeit selbst nutzen wollte. warum rhino und nicht ein vollständig quelloffenes cad? rhino verkauft dauerlizenzen, die man wirklich besitzt, statt abonnements, die man mietet, und seine dateiformate (3dm, opennurbs) und apis (rhinocommon, eto.forms) sind gut dokumentiert und auch ausserhalb der anwendung lesbar. das ist keine freie software, aber eine gangbare position zu eigentum und offenen daten, und dort, wo manche architekten ohnehin schon arbeiten. freecad oder librecad wären philosophisch offener, aber ihre verbreitung in der architektur ist marginal. dossier trifft die disziplin dort, wo sie steht. offene daten, eine etablierte gemeinschaft, genug infrastruktur, um darauf aufzubauen.
[repo](https://dossier.openbureau.ch)
+12
View File
@@ -0,0 +1,12 @@
---
build:
render: never
list: never
---
**RAPPORT**\
2026
ein verwaltungswerkzeug für kleine architekturbüros. projektverwaltung, zeiterfassung, offerten und rechnungen, buchhaltung, personaldaten, lohn, sitzungsprotokolle. alles an einem ort statt fünf zusammengeflickter abonnements. was es gibt, ist entweder zu klein (einzweck-apps, die nicht miteinander reden) oder zu gross (unternehmenssuiten für büros mit hundert leuten, mit passendem budget dazu). kleine büros zahlen am ende für software, die für jemand anderen entworfen wurde, und füllen die lücken mit tabellen. rapport ist das werkzeug, das ich selbst nutzen wollte. freie software, selbst hostbar, keine lizenz pro arbeitsplatz. deine daten bleiben auf deinen geräten.
[repo](https://rapport.openbureau.ch)
+13
View File
@@ -0,0 +1,13 @@
---
title: "openbureau"
description: "offene und selbst besessene werkzeuge für die architektur"
layout: "openbureau"
---
architektur läuft auf werkzeugen. die werkzeuge formen, was gedacht, gezeichnet und gebaut wird. die meisten sind proprietär: abonnements, die gekündigt werden können, dateiformate, die nur ihre eigentümer lesen können, arbeit, die verschwindet, wenn eine lizenz ausläuft. in einem beruf, der ohnehin auf prekärer arbeit läuft, ist das mietabschöpfung.
freie und quelloffene software ist die sauberste antwort, aber nicht die einzige. worum es mir geht, ist eigentum und offenheit. werkzeuge, die du besitzt, statt sie zu mieten. dateiformate, die jeder lesen kann. daten, die nicht hinter einer bezahlschranke liegen. code als gemeingut, wo möglich. wo nicht, wenigstens offene daten.
openbureau ist der ort, an dem ich sammle, was ich in dieser richtung baue. kleine werkzeuge, für die eigene praxis geschrieben, veröffentlicht, damit andere sie nutzen oder forken können.
über das hinaus, was ich baue, ist openbureau auch eine dienstleistung: ich kuratiere quelloffene software, die keine fixkosten und keine abhängigkeit erzeugt, richte sie ein und betreue sie, damit ein studio oder ein kleines büro auf werkzeugen läuft, die es besitzt, statt auf abonnements, die es mietet.
+4
View File
@@ -0,0 +1,4 @@
---
title: "portfolio"
description: "ausgewählte projekte"
---
+19
View File
@@ -0,0 +1,19 @@
---
title: "dojo"
slug: "dojo"
date: 2023-01-10
thumbnail: "/img/sem02/thumbnail.webp"
studies: "/studies/ost/ba/semester_02"
schools: ["ost"]
degrees: ["ba"]
semesters: ["semester_02"]
images:
- { src: "/img/sem02/01.webp", name: "timber-model.webp" }
- { src: "/img/sem02/02.webp", name: "long-elevation.webp" }
- { src: "/img/sem02/03.webp", name: "section.webp" }
- { src: "/img/sem02/04.webp", name: "front-elevation.webp" }
- { src: "/img/sem02/05.webp", name: "side-elevation.webp" }
- { src: "/img/sem02/06.webp", name: "joint-axonometric.webp" }
---
im zentrum dieses studienprojekts steht die konstruktive auseinandersetzung mit dem holzknoten, nicht als statisches detail, sondern als räumlich wirksames system. ausgehend von einem grundknoten, der ohne diagonale aussteifung auskommt und allein auf horizontalen und vertikalen balken beruht, wurde ein räumliches prinzip entwickelt, das zugleich rational und atmosphärisch ist. die besonderheit liegt in seiner skalierbarkeit: derselbe knoten wird in unterschiedlichen massstäben angewendet, vom feinen raster der fassadenstruktur bis zur tragenden ordnung des zweigeschossigen baus. so entsteht ein durchgehendes konstruktives system, das den ganzen bau trägt und sich zugleich sichtbar macht. das dojo ist um einen offenen innenhof organisiert. die klare holzkonstruktion vermittelt zwischen offenheit und konzentration, zwischen leichtigkeit und strenge, eigenschaften, die sich aus den kampfkünsten ableiten. der entwurf versteht sich als architektonische reflexion über struktur, disziplin und räumliche wahrnehmung.
+21
View File
@@ -0,0 +1,21 @@
---
title: "museo"
slug: "museo"
date: 2022-01-10
thumbnail: "/img/sem01/thumbnail.webp"
studies: "/studies/ost/ba/semester_01"
schools: ["ost"]
degrees: ["ba"]
semesters: ["semester_01"]
images:
- { src: "/img/sem01/01.webp", name: "cutaway-model-front.webp" }
- { src: "/img/sem01/08.webp", name: "exploded-axonometric.webp" }
- { src: "/img/sem01/02.webp", name: "plan-ground-floor.webp" }
- { src: "/img/sem01/03.webp", name: "plan-upper-floor.webp" }
- { src: "/img/sem01/04.webp", name: "section.webp" }
- { src: "/img/sem01/05.webp", name: "cutaway-model-angle.webp" }
- { src: "/img/sem01/06.webp", name: "site-plan.webp" }
- { src: "/img/sem01/07.webp", name: "street-linocut.webp" }
---
tonhalle museo ist ein spekulatives studienprojekt an der schnittstelle von architektur, klang und theorie. zwei scheinbar widersprüchliche programme, konzertsaal und museum, treffen in einem einzigen gebäude zusammen. dieses zusammentreffen wird nicht harmonisiert, sondern bewusst verschärft: unterschiedliche räumliche logiken, nutzungsdynamiken und atmosphären prallen aufeinander und erzeugen ein spannungsfeld, das den architektonischen ausdruck prägt. der entwurf beruht auf einer auditiven analyse, eine fünfminütige klangsequenz diente als ausgangspunkt für die räumliche struktur. im fokus standen nicht funktion oder form, sondern die übersetzung von klang in räumliche dimensionen. lautstärke, rhythmus, dichte und stille wurden in proportionen, übergänge und materialität übersetzt. das ergebnis ist ein gebautes fragment, eine bewusst unvollständige idee, ein raumkörper, der nicht erklären, sondern erfahrbar werden will. tonhalle museo versteht sich als versuch, architektur durch das hören zu denken, als räumliche partitur zwischen konzentration und ablenkung, zwischen aufführung und betrachtung.
+29
View File
@@ -0,0 +1,29 @@
---
title: "studienreise nach triest"
slug: "studytrip-trieste"
date: 2024-09-27
thumbnail: "/img/studytrip-trieste/Triest_Canale_Grande_SantAntonio_Tramaturgo-01.webp"
studies: "/studies/hslu/ba/semester_05"
schools: ["hslu"]
degrees: ["ba"]
semesters: ["semester_05"]
images:
- { src: "/img/studytrip-trieste/Triest_Canale_Grande_SantAntonio_Tramaturgo-01.webp", name: "canale-grande-01.webp" }
- { src: "/img/studytrip-trieste/Triest_Canale_Grande_SantAntonio_Tramaturgo-02.webp", name: "canale-grande-02.webp" }
- { src: "/img/studytrip-trieste/Triest_Canale_Grande_SantAntonio_Tramaturgo-03.webp", name: "canale-grande-03.webp" }
- { src: "/img/studytrip-trieste/Triest_Canale_Grande_SantAntonio_Tramaturgo-04.webp", name: "canale-grande-04.webp" }
- { src: "/img/studytrip-trieste/Triest_Casa_Bartoli-02.webp", name: "casa-bartoli.webp" }
- { src: "/img/studytrip-trieste/Triest_Cpo_Androna_Campo_Marzio-01.webp", name: "campo-marzio.webp" }
- { src: "/img/studytrip-trieste/Triest_Kathedrale_San_Giusto-02.webp", name: "san-giusto.webp" }
- { src: "/img/studytrip-trieste/Triest_Liceo_Artistico-02.webp", name: "liceo-artistico-01.webp" }
- { src: "/img/studytrip-trieste/Triest_Liceo_Artistico-03.webp", name: "liceo-artistico-02.webp" }
- { src: "/img/studytrip-trieste/Triest_Liceo_Artistico-05.webp", name: "liceo-artistico-03.webp" }
- { src: "/img/studytrip-trieste/Triest_Liceo_Artistico-07.webp", name: "liceo-artistico-04.webp" }
- { src: "/img/studytrip-trieste/Triest_Palmanova-01.webp", name: "palmanova.webp" }
- { src: "/img/studytrip-trieste/Triest_Rozzol_Melara-01.webp", name: "rozzol-melara-01.webp" }
- { src: "/img/studytrip-trieste/Triest_Rozzol_Melara-02.webp", name: "rozzol-melara-02.webp" }
- { src: "/img/studytrip-trieste/Triest_Rozzol_Melara-03.webp", name: "rozzol-melara-03.webp" }
- { src: "/img/studytrip-trieste/Triest_Rozzol_Melara-04.webp", name: "rozzol-melara-04.webp" }
- { src: "/img/studytrip-trieste/Triest_Rozzol_Melara-05.webp", name: "rozzol-melara-05.webp" }
- { src: "/img/studytrip-trieste/Triest_Stanjel-01.webp", name: "stanjel.webp" }
---
+20
View File
@@ -0,0 +1,20 @@
---
title: "textilsteinwerk"
slug: "textilsteinwerk"
date: 2025-01-10T10:00:00
thumbnail: "/img/sem05/03.webp"
studies: "/studies/hslu/ba/semester_05"
schools: ["hslu"]
degrees: ["ba"]
semesters: ["semester_05"]
images:
- { src: "/img/sem05/01.webp", name: "context-model.webp" }
- { src: "/img/sem05/02.webp", name: "sectional-model.webp" }
- { src: "/img/sem05/03.webp", name: "hall-interior.webp" }
- { src: "/img/sem05/04.webp", name: "facade-model.webp" }
- { src: "/img/sem05/05.webp", name: "dwelling-interior.webp" }
- { src: "/img/sem05/section01.webp", name: "long-section.webp" }
- { src: "/img/sem05/section02.webp", name: "hall-section.webp" }
---
die séchoir-halle ist ein studienprojekt, das die themen handel, bestand und weiternutzung innerhalb ehemaliger industriearchitektur untersucht. ein ehemaliges industriegebäude, verwurzelt in der lokalen textilgeschichte, wird in seiner identität bewahrt und zugleich mit einem neuen programm versehen. wo einst viskosestoffe zum trocknen aufgehängt wurden, werden heute neue bausteine aus recycelten textilien produziert, tragende elemente, aus alten stoffen in einem stampfverfahren gefertigt, nach den prinzipien der kreislaufwirtschaft und der wiederverwendung von material. der bestand wird erhalten und über einer hälfte der halle um ein zusätzliches geschoss ergänzt, das seine rohe, funktionale atmosphäre fortführt, statt sie zu ersetzen. neue wohneinheiten in direkter nachbarschaft treten in dialog mit der industriearchitektur und schaffen ein gemischtes quartier mit produktiven, sozialen und wohnfunktionen.
@@ -0,0 +1,7 @@
---
title: "der schatten über emmen"
slug: "the-shadow-over-emmen"
date: 2025-01-10T09:00:00
thumbnail: "/img/shadowofemmen/thumbnail.webp"
video: "/media/shadow.mp4"
---
+26
View File
@@ -0,0 +1,26 @@
---
title: "studio"
description: "ruhige, typografisch präzise websites für architektur und gestaltung"
---
ich gestalte ruhige, typografisch präzise websites für menschen, die genug haben von überladenen baukasten-seiten. ich bin architekt. ich verstehe, wie man arbeit zeigt, bevor das gespräch anfängt.
**was ich mache**\
schlanke, schnelle websites, die dem gehören, der sie bezahlt. kein plugin-wildwuchs, keine monatlichen lizenzfallen, keine seite, die nach zwei jahren auseinanderfällt. gestaltung, die zurücktritt, damit die arbeit nach vorne kommt.
**warum so und nicht anders**\
die meisten kleinen websites laufen auf systemen, die mehr verwalten als gestalten. sie sind langsam, teuer im unterhalt und hängen an diensten, über die niemand mehr kontrolle hat. ich baue anders. statische seiten, die in fünf jahren noch laufen, im unterhalt fast nichts kosten und von keinem konzern abhängen. die gleiche haltung steckt hinter [openbureau](/de/openbureau/).
**für wen**\
architekturbüros, innenarchitekten, fotografen, werkstätten mit anspruch. menschen, die form ernst nehmen und eine website wollen, die das zeigt, statt es zu behaupten.
**arbeiten**\
<dl class="meta">
<dt>fund bureau</dt><dd>one-page-website für ein kollektiv von architekten in luzern · 2026 · <a href="https://fundbureau.xyz">fundbureau.xyz</a></dd>
</dl>
---
**kontakt**\
wenn das nach ihrer vorstellung klingt, schreiben sie mir. ein kurzer satz dazu, wer sie sind und was sie machen, reicht für den anfang.\
[hi@karimgabrielevarano.xyz](mailto:hi@karimgabrielevarano.xyz)
+10 -9
View File
@@ -1,18 +1,18 @@
---
title: "studio"
description: "design across scales, and the open tools underneath"
description: "calm, typographically precise websites for architecture and design"
---
i work independently across scales, from buildings to books to screens, and the open infrastructure underneath them. it sounds like several jobs, but it's one: design with a bias toward things you own rather than rent, toward formats anyone can read, toward work that outlives a licence. the same logic that runs [openbureau](/openbureau/).
i make calm, typographically precise websites for people who have had enough of bloated site builders. i'm an architect. i understand how to show work before the conversation starts.
**architecture**\
concept and design work, from early studies to drawings.
**what i do**\
lean, fast websites that belong to whoever pays for them. no plugin sprawl, no monthly licence traps, no site that falls apart in two years. design that steps back so the work comes forward.
**open-source ICT**, via [openbureau](/openbureau/)\
i curate, set up, and support open-source software that carries no fixed costs, so a studio runs on tools it owns instead of subscriptions it rents.
**why this way**\
most small websites run on systems that manage more than they design. they're slow, expensive to maintain, and tied to services no one really controls anymore. i build differently. static pages that still run in five years, cost almost nothing to keep, and depend on no corporation. the same stance behind [openbureau](/openbureau/).
**graphic, editorial & web**\
visual identity, graphic design, book and publication layout, and websites built to be fast, readable, and yours, like this one.
**who it's for**\
architecture practices, interior designers, photographers, workshops with standards. people who take form seriously and want a website that shows it instead of claiming it.
**work**\
<dl class="meta">
@@ -21,5 +21,6 @@ visual identity, graphic design, book and publication layout, and websites built
---
**available** for architecture collaborations, commissions, consulting, and open-source work.\
**contact**\
if that sounds like what you have in mind, write to me. a short line about who you are and what you do is enough to start.\
[hi@karimgabrielevarano.xyz](mailto:hi@karimgabrielevarano.xyz)
+41 -15
View File
@@ -9,11 +9,6 @@ enableRobotsTXT = true
degree = "degrees"
semester = "semesters"
[languages]
[languages.en]
locale = "en_US"
weight = 1
[params]
description = "architecture studio"
email = "hi@karimgabrielevarano.xyz"
@@ -23,22 +18,53 @@ enableRobotsTXT = true
shellUser = "karimgabrielevarano"
shellHost = "xyz"
[menu]
[[menu.main]]
name = "portfolio"
url = "/portfolio/"
[languages]
[languages.en]
locale = "en_US"
label = "en"
weight = 1
[[menu.main]]
[languages.en.params]
description = "architecture studio"
[languages.en.menu]
[[languages.en.menu.main]]
name = "portfolio"
pageRef = "/portfolio"
weight = 1
[[languages.en.menu.main]]
name = "about"
url = "/about/"
pageRef = "/about"
weight = 2
[[menu.main]]
[[languages.en.menu.main]]
name = "studio"
url = "/studio/"
pageRef = "/studio"
weight = 3
[[menu.main]]
[[languages.en.menu.main]]
name = "openbureau"
url = "/openbureau/"
pageRef = "/openbureau"
weight = 4
[languages.de]
locale = "de_CH"
label = "de"
weight = 2
[languages.de.params]
description = "architektur studio"
[languages.de.menu]
[[languages.de.menu.main]]
name = "portfolio"
pageRef = "/portfolio"
weight = 1
[[languages.de.menu.main]]
name = "about"
pageRef = "/about"
weight = 2
[[languages.de.menu.main]]
name = "studio"
pageRef = "/studio"
weight = 3
[[languages.de.menu.main]]
name = "openbureau"
pageRef = "/openbureau"
weight = 4
[markup]
+11
View File
@@ -0,0 +1,11 @@
[skip_to_content]
other = "Zum Inhalt springen"
[table_of_contents]
other = "INHALTSVERZEICHNIS"
[colophon]
other = "kolophon"
[legal_notice]
other = "impressum"
+11
View File
@@ -0,0 +1,11 @@
[skip_to_content]
other = "Skip to content"
[table_of_contents]
other = "TABLE OF CONTENTS"
[colophon]
other = "colophon"
[legal_notice]
other = "legal notice"
+1 -1
View File
@@ -4,7 +4,7 @@
<p class="tui__cmd"><span class="tui__sym">$</span> cd <span class="err404">.</span></p>
<p class="tui__total">cd: no such file or directory: <span class="err404">.</span></p>
<p>error 404 — nothing lives here.</p>
<p><a href="{{ "/" | relURL }}">cd ~</a></p>
<p><a href="{{ "/" | relLangURL }}">cd ~</a></p>
</div>
<script>
(function () {
+1 -1
View File
@@ -5,7 +5,7 @@
<p class="tui__cmd"><span class="tui__sym">$</span> ls</p>
<p class="tui__cmd tui__total">total {{ if $cv }}2{{ else }}1{{ end }}</p>
<ul class="tui__ls">
<li><a href="{{ "/" | relURL }}" data-name="..">
<li><a href="{{ "/" | relLangURL }}" data-name="..">
<span class="tui__perm">drwxr-xr-x</span><span class="tui__name">..</span>
</a></li>
<li><a data-name="info.md" data-text="info.md" class="is-selected">
+13 -7
View File
@@ -3,19 +3,25 @@
{{ partial "head.html" . }}
<body class="{{ block "bodyclass" . }}{{ end }}">
<div id="boot" aria-hidden="true"><pre class="boot__log"></pre></div>
<a href="#main-content" class="skip-link">Skip to content</a>
<a href="#main-content" class="skip-link">{{ i18n "skip_to_content" }}</a>
{{ partial "header.html" . }}
<main id="main-content" role="main">
{{ block "main" . }}{{ end }}
</main>
{{ partial "footer.html" . }}
<script src="{{ "js/cursor.js" | relURL }}" defer></script>
<script src="{{ "js/shell.js" | relURL }}" defer></script>
<script src="{{ "js/filebrowser.js" | relURL }}" defer></script>
<script src="{{ "js/player.js" | relURL }}" defer></script>
<script src="{{ "js/nav.js" | relURL }}" defer></script>
<script src="{{ "js/boot.js" | relURL }}" defer></script>
{{/* one fingerprinted bundle: the hash changes whenever any script changes,
so the long browser/proxy cache can never serve a stale build. order is
preserved (deferred IIFEs run in sequence). */}}
{{ $js := slice
(resources.Get "js/cursor.js")
(resources.Get "js/shell.js")
(resources.Get "js/filebrowser.js")
(resources.Get "js/player.js")
(resources.Get "js/nav.js")
(resources.Get "js/boot.js")
| resources.Concat "js/bundle.js" | minify | fingerprint }}
<script src="{{ $js.RelPermalink }}" defer></script>
<script>document.addEventListener('contextmenu',function(e){e.preventDefault();});</script>
</body>
</html>
+1 -1
View File
@@ -10,7 +10,7 @@
<p class="tui__cmd"><span class="tui__sym">$</span> ls</p>
<p class="tui__cmd tui__total">total {{ len $files }}</p>
<ul class="tui__ls">
<li><a href="{{ "/" | relURL }}" data-name="..">
<li><a href="{{ "/" | relLangURL }}" data-name="..">
<span class="tui__perm">drwxr-xr-x</span><span class="tui__name">..</span>
</a></li>
{{ range $i, $p := $files }}{{ if $p }}
+1 -1
View File
@@ -7,7 +7,7 @@
{{ $total := 1 }}{{ if $rapport }}{{ $total = add $total 1 }}{{ end }}{{ if $dossier }}{{ $total = add $total 1 }}{{ end }}
<p class="tui__cmd tui__total">total {{ $total }}</p>
<ul class="tui__ls">
<li><a href="{{ "/" | relURL }}" data-name="..">
<li><a href="{{ "/" | relLangURL }}" data-name="..">
<span class="tui__perm">drwxr-xr-x</span><span class="tui__name">..</span>
</a></li>
<li><a data-name="info.md" data-text="info.md" class="is-selected">
+2 -2
View File
@@ -1,7 +1,7 @@
{{ define "main" }}
{{ if .Params.toc }}
<nav class="toc"><strong>TABLE OF CONTENTS</strong><div class="toc-content">{{ .TableOfContents }}</div></nav>
<nav class="toc"><strong>{{ i18n "table_of_contents" }}</strong><div class="toc-content">{{ .TableOfContents }}</div></nav>
{{ end }}
{{ .Content }}
<div class="terminal-nav"><div class="back-nav"><a href="{{ "/" | relURL }}" class="back-link">../</a></div></div>
<div class="terminal-nav"><div class="back-nav"><a href="{{ "/" | relLangURL }}" class="back-link">../</a></div></div>
{{ end }}
+1 -1
View File
@@ -5,7 +5,7 @@
<p class="tui__cmd"><span class="tui__sym">$</span> ls</p>
<p class="tui__cmd tui__total">total {{ len .Pages }}</p>
<ul class="tui__ls">
<li><a href="{{ $up | relURL }}" data-name="..">
<li><a href="{{ $up | relLangURL }}" data-name="..">
<span class="tui__perm">drwxr-xr-x</span><span class="tui__name">..</span>
</a></li>
{{ range .Pages }}
+2 -2
View File
@@ -1,5 +1,5 @@
<footer role="contentinfo">
<p>© {{ now.Year }} karimgabrielevarano.xyz</p>
<p><a href="{{ "/colophon/" | relURL }}" data-name="colophon">colophon</a> · <a href="{{ "/legal-notice/" | relURL }}" data-name="legal-notice">legal notice</a></p>
<a href="{{ "/cv/" | relURL }}" data-name="cv" hidden>cv</a>
<p><a href="{{ "/colophon/" | relLangURL }}" data-name="colophon">{{ i18n "colophon" }}</a> · <a href="{{ "/legal-notice/" | relLangURL }}" data-name="legal-notice">{{ i18n "legal_notice" }}</a></p>
<a href="{{ "/cv/" | relLangURL }}" data-name="cv" hidden>cv</a>
</footer>
+3
View File
@@ -12,6 +12,9 @@
<meta name="description" content="{{ $desc }}">
<meta name="author" content="{{ .Site.Params.author }}">
<link rel="canonical" href="{{ .Permalink }}">
{{/* tell search engines about the other language version of this page */}}
{{ range .AllTranslations }}<link rel="alternate" hreflang="{{ .Language.Lang }}" href="{{ .Permalink }}">
{{ end }}
{{/* social card image: project thumbnail, else home hero, else site default */}}
{{ $ogimg := .Site.Params.ogImage }}
+3 -2
View File
@@ -1,7 +1,8 @@
<header role="banner">
<div class="topbar" data-home="{{ "/" | relURL }}" data-info="{{ .Site.Params.description }}" data-email="{{ .Site.Params.email }}">
<div class="topbar" data-home="{{ "/" | relLangURL }}" data-info="{{ .Site.Params.description }}" data-email="{{ .Site.Params.email }}">
{{ with .Translations }}{{ range . }}<a class="lang-switch" href="{{ .RelPermalink }}" hreflang="{{ .Language.Lang }}" data-name="{{ .Language.Lang }}">{{ .Language.Lang }}</a>{{ end }}{{ end }}
<div class="prompt" aria-label="shell">
<a class="prompt__seg prompt__user" href="{{ "/" | relURL }}">{{ .Site.Params.shellUser }}@{{ .Site.Params.shellHost }}</a><span class="prompt__path">:~{{ if not .IsHome }}{{ $rel := strings.TrimSuffix "/" .RelPermalink }}{{ $parts := after 1 (split $rel "/") }}{{ $last := sub (len $parts) 1 }}{{ $acc := "" }}{{ range $i, $seg := $parts }}{{ $acc = printf "%s/%s" $acc $seg }}{{ $disp := $seg }}{{ if and $.Params.dotfile (eq $i $last) }}{{ $disp = printf ".%s" $seg }}{{ end }}/<a class="prompt__seg" href="{{ (printf "%s/" $acc) | relURL }}">{{ $disp }}</a>{{ end }}{{ end }}$</span><span class="prompt__input" contenteditable="true" role="textbox" aria-label="type a command, then press enter" spellcheck="false"></span><span class="caret">_</span>
<a class="prompt__seg prompt__user" href="{{ "/" | relLangURL }}">{{ .Site.Params.shellUser }}@{{ .Site.Params.shellHost }}</a><span class="prompt__path">:~{{ if not .IsHome }}{{ $rel := strings.TrimSuffix "/" .RelPermalink }}{{ $rel = strings.TrimPrefix .Site.LanguagePrefix $rel }}{{ $parts := after 1 (split $rel "/") }}{{ $last := sub (len $parts) 1 }}{{ $acc := "" }}{{ range $i, $seg := $parts }}{{ $acc = printf "%s/%s" $acc $seg }}{{ $disp := $seg }}{{ if and $.Params.dotfile (eq $i $last) }}{{ $disp = printf ".%s" $seg }}{{ end }}/<a class="prompt__seg" href="{{ (printf "%s/" $acc) | relLangURL }}">{{ $disp }}</a>{{ end }}{{ end }}$</span><span class="prompt__input" contenteditable="true" role="textbox" aria-label="type a command, then press enter" spellcheck="false"></span><span class="caret">_</span>
</div>
<p class="prompt__out" aria-live="polite"></p>
<nav class="menu tui tui--files" aria-label="Main menu">
+1 -1
View File
@@ -6,7 +6,7 @@
<p class="tui__cmd"><span class="tui__sym">$</span> ls</p>
<p class="tui__cmd tui__total">total {{ len $sorted }}</p>
<ul class="tui__ls">
<li><a href="{{ "/" | relURL }}" data-name="..">
<li><a href="{{ "/" | relLangURL }}" data-name="..">
<span class="tui__perm">drwxr-xr-x</span><span class="tui__date"></span><span class="tui__name">..</span>
</a></li>
{{ range $i, $p := $sorted }}
+1 -1
View File
@@ -10,7 +10,7 @@
{{ $total := 0 }}{{ if $images }}{{ $total = len $images }}{{ end }}{{ if $hasText }}{{ $total = add $total 1 }}{{ end }}{{ if $video }}{{ $total = add $total 1 }}{{ end }}
<p class="tui__cmd tui__total">total {{ $total }}</p>
<ul class="tui__ls">
<li><a href="{{ "/portfolio/" | relURL }}" data-name="..">
<li><a href="{{ "/portfolio/" | relLangURL }}" data-name="..">
<span class="tui__perm">drwxr-xr-x</span><span class="tui__name">..</span>
</a></li>
{{ if $hasText }}