v18
BIN
01_3D-Druck/blender/raci-board.blend
Normal file
|
|
@ -34,9 +34,15 @@ LET_SIZE, LET_DEP = 11.0, 1.0
|
||||||
WORD_SIZE, WORD_DEP = 5.0, 0.8
|
WORD_SIZE, WORD_DEP = 5.0, 0.8
|
||||||
TOP = BASE_H
|
TOP = BASE_H
|
||||||
|
|
||||||
HERE = os.path.dirname(bpy.data.filepath) or os.path.dirname(os.path.abspath(__file__))
|
def _outdir():
|
||||||
|
d = os.path.dirname(bpy.data.filepath) # gesetzt, wenn .blend gespeichert
|
||||||
|
if d: return d
|
||||||
|
try: return os.path.dirname(os.path.abspath(__file__))
|
||||||
|
except NameError: return os.path.expanduser("~") # Fallback: Benutzerordner
|
||||||
|
HERE = _outdir()
|
||||||
STL_OUT = os.path.join(HERE, "raci-board.stl")
|
STL_OUT = os.path.join(HERE, "raci-board.stl")
|
||||||
PNG_OUT = os.path.join(HERE, "raci_preview.png")
|
PNG_OUT = os.path.join(HERE, "raci_preview.png")
|
||||||
|
print("Ausgabe-Ordner:", HERE)
|
||||||
|
|
||||||
# ----------------------------- Helfer -----------------------------
|
# ----------------------------- Helfer -----------------------------
|
||||||
def clear_scene():
|
def clear_scene():
|
||||||
|
|
@ -149,27 +155,44 @@ cut_text(base, "INFORMED", DIAL_CX, DIAL_CY-(RING_R+30), 0, WORD_SIZE, WORD_DEP)
|
||||||
cut_text(base, "ACCOUNTABLE", DIAL_CX, CARD_CY - CARD_BD/2 - 8, 0, WORD_SIZE, WORD_DEP)
|
cut_text(base, "ACCOUNTABLE", DIAL_CX, CARD_CY - CARD_BD/2 - 8, 0, WORD_SIZE, WORD_DEP)
|
||||||
|
|
||||||
base.name = "RACI-Board"
|
base.name = "RACI-Board"
|
||||||
bpy.ops.object.shade_smooth()
|
# Auto-Smooth: flache Flaechen scharf, gefaste Kanten glatt
|
||||||
|
try:
|
||||||
|
bpy.ops.object.shade_auto_smooth(angle=math.radians(30)) # Blender >= 4.1
|
||||||
|
except Exception:
|
||||||
|
try: bpy.ops.object.shade_flat()
|
||||||
|
except Exception: pass
|
||||||
|
|
||||||
# ----------------------------- Material -----------------------------
|
# ----------------------------- Material -----------------------------
|
||||||
mat = bpy.data.materials.new("BoardBlue"); mat.use_nodes = True
|
mat = bpy.data.materials.new("BoardBlue"); mat.use_nodes = True
|
||||||
bsdf = mat.node_tree.nodes.get("Principled BSDF")
|
bsdf = next((n for n in mat.node_tree.nodes if n.type == 'BSDF_PRINCIPLED'), None)
|
||||||
if bsdf:
|
if bsdf:
|
||||||
bsdf.inputs["Base Color"].default_value = (0.10, 0.16, 0.30, 1)
|
bsdf.inputs["Base Color"].default_value = (0.09, 0.15, 0.30, 1) # dunkelblau
|
||||||
try: bsdf.inputs["Roughness"].default_value = 0.55
|
try: bsdf.inputs["Roughness"].default_value = 0.5
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
base.data.materials.append(mat)
|
base.data.materials.clear(); base.data.materials.append(mat)
|
||||||
|
|
||||||
# ----------------------------- Vorschau-Render (guarded) -----------------------------
|
# ----------------------------- Vorschau-Render (guarded) -----------------------------
|
||||||
try:
|
try:
|
||||||
bpy.ops.object.light_add(type='SUN', location=(120, -160, 220))
|
|
||||||
bpy.context.object.data.energy = 3.0
|
|
||||||
bpy.ops.object.camera_add(location=(150, -190, 210))
|
|
||||||
cam = bpy.context.object
|
|
||||||
cam.rotation_euler = (math.radians(58), 0, math.radians(38))
|
|
||||||
bpy.context.scene.camera = cam
|
|
||||||
sc = bpy.context.scene
|
sc = bpy.context.scene
|
||||||
sc.render.resolution_x, sc.render.resolution_y = 1400, 1000
|
# Welt etwas aufhellen
|
||||||
|
try:
|
||||||
|
wn = sc.world.node_tree.nodes
|
||||||
|
bg = next((n for n in wn if n.type == 'BACKGROUND'), None)
|
||||||
|
if bg: bg.inputs[1].default_value = 1.2
|
||||||
|
except Exception: pass
|
||||||
|
# Licht
|
||||||
|
bpy.ops.object.light_add(type='SUN', location=(120, -160, 240))
|
||||||
|
bpy.context.object.data.energy = 3.5
|
||||||
|
bpy.ops.object.light_add(type='AREA', location=(-120, -60, 160))
|
||||||
|
bpy.context.object.data.energy = 4000; bpy.context.object.data.size = 200
|
||||||
|
# Kamera blickt aufs Board-Zentrum (Track-To), rahmt das ganze Board
|
||||||
|
bpy.ops.object.empty_add(location=(0, 0, 4)); tgt = bpy.context.object
|
||||||
|
bpy.ops.object.camera_add(location=(175, -220, 210)); cam = bpy.context.object
|
||||||
|
cam.data.lens = 52
|
||||||
|
con = cam.constraints.new('TRACK_TO'); con.target = tgt
|
||||||
|
con.track_axis = 'TRACK_NEGATIVE_Z'; con.up_axis = 'UP_Y'
|
||||||
|
sc.camera = cam
|
||||||
|
sc.render.resolution_x, sc.render.resolution_y = 1500, 1050
|
||||||
sc.render.filepath = PNG_OUT
|
sc.render.filepath = PNG_OUT
|
||||||
try: sc.render.engine = 'BLENDER_EEVEE_NEXT'
|
try: sc.render.engine = 'BLENDER_EEVEE_NEXT'
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
||||||
BIN
01_3D-Druck/blender/raci_preview.png
Normal file
|
After Width: | Height: | Size: 813 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 201 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 179 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 188 KiB |
|
|
@ -407,7 +407,7 @@ const PHASEN = {
|
||||||
support:{label:"Support", color:"var(--support)"},
|
support:{label:"Support", color:"var(--support)"},
|
||||||
review:{label:"Review", color:"var(--review)"}
|
review:{label:"Review", color:"var(--review)"}
|
||||||
};
|
};
|
||||||
/* Action Cards: 6 Services × 5 Change-Typen (aus „Use Cases mit möglichen Changes"). */
|
/* Action Cards: 6 Services × 4 Change-Arten (aus „Use Cases mit möglichen Changes"). */
|
||||||
const CHANGE_TYPES = [
|
const CHANGE_TYPES = [
|
||||||
"Major Change",
|
"Major Change",
|
||||||
"Normal Change",
|
"Normal Change",
|
||||||
|
|
@ -499,7 +499,7 @@ const USE_CASES = [
|
||||||
desc:"Zentrales Web-Portal, über das Bürger*innen Meldungen (z. B. Straßenreparatur, Lärm) und Anträge (z. B. Baugenehmigung, Personalausweis) digital einreichen und den Status verfolgen.",
|
desc:"Zentrales Web-Portal, über das Bürger*innen Meldungen (z. B. Straßenreparatur, Lärm) und Anträge (z. B. Baugenehmigung, Personalausweis) digital einreichen und den Status verfolgen.",
|
||||||
changes:[
|
changes:[
|
||||||
{titel:"Mitreden, Pflicht!", text:"Ein neues Landesgesetz schreibt digitale Bürgerbeteiligung vor — das Portal muss um komplette Beteiligungs-Module erweitert werden."},
|
{titel:"Mitreden, Pflicht!", text:"Ein neues Landesgesetz schreibt digitale Bürgerbeteiligung vor — das Portal muss um komplette Beteiligungs-Module erweitert werden."},
|
||||||
{titel:"Rotstift gefragt", text:"Der Bürgerservice meldet einen Rechtschreibfehler in einem statischen Hinweistext, der korrigiert werden muss."},
|
{titel:"Licht an!", text:"Das Amt für öffentliche Ordnung möchte eine neue Mängel-Kategorie „Beleuchtung und Strom“ zu den bestehenden Kategorien hinzufügen."},
|
||||||
{titel:"Patchday", text:"Das monatliche Sicherheits-Patch des Webservers (Apache/Nginx) steht an."},
|
{titel:"Patchday", text:"Das monatliche Sicherheits-Patch des Webservers (Apache/Nginx) steht an."},
|
||||||
{titel:"Lücke im Formular!", text:"In einem Eingabe-Formular wird eine kritische XSS-Schwachstelle entdeckt — ein Hotfix muss sofort raus."}
|
{titel:"Lücke im Formular!", text:"In einem Eingabe-Formular wird eine kritische XSS-Schwachstelle entdeckt — ein Hotfix muss sofort raus."}
|
||||||
]},
|
]},
|
||||||
|
|
@ -515,7 +515,7 @@ const USE_CASES = [
|
||||||
desc:"Web-basiertes Karten- und Analyse-Portal, das Fachämtern (Bau, Umwelt, Verkehr) räumliche Daten (Flurstücke, Infrastruktur, Umweltzonen) und bearbeitbare Layer bereitstellt.",
|
desc:"Web-basiertes Karten- und Analyse-Portal, das Fachämtern (Bau, Umwelt, Verkehr) räumliche Daten (Flurstücke, Infrastruktur, Umweltzonen) und bearbeitbare Layer bereitstellt.",
|
||||||
changes:[
|
changes:[
|
||||||
{titel:"Norm-Zwang", text:"Eine bundesweite Vorgabe zu EU-Standards erzwingt die komplette Migration des GIS-Stacks auf konforme Services und Datenmodelle."},
|
{titel:"Norm-Zwang", text:"Eine bundesweite Vorgabe zu EU-Standards erzwingt die komplette Migration des GIS-Stacks auf konforme Services und Datenmodelle."},
|
||||||
{titel:"Falsch beschriftet", text:"Das Bauamt meldet eine falsche Beschriftung eines Karten-Layers, die korrigiert werden muss."},
|
{titel:"Grün dazu!", text:"Das Umweltamt möchte im Analyse-Modul „Klimarisiko-Analyse“ eine weitere Datenquelle zu städtischen Grünflächen anbinden."},
|
||||||
{titel:"GeoServer-Update", text:"Das monatliche Update der GIS-Software (GeoServer 2.23 → 2.24) steht an."},
|
{titel:"GeoServer-Update", text:"Das monatliche Update der GIS-Software (GeoServer 2.23 → 2.24) steht an."},
|
||||||
{titel:"Schnittstelle offen!", text:"An einer Schnittstelle wird eine kritische Schwachstelle entdeckt, die unautorisierten Datenzugriff erlaubt — Dienst sofort abschalten und patchen."}
|
{titel:"Schnittstelle offen!", text:"An einer Schnittstelle wird eine kritische Schwachstelle entdeckt, die unautorisierten Datenzugriff erlaubt — Dienst sofort abschalten und patchen."}
|
||||||
]},
|
]},
|
||||||
|
|
@ -523,7 +523,7 @@ const USE_CASES = [
|
||||||
desc:"Web-Applikation, über die Fachämter interne Beschaffungen (Material, Dienstleistungen) anlegen, prüfen und Verträge digital verwalten.",
|
desc:"Web-Applikation, über die Fachämter interne Beschaffungen (Material, Dienstleistungen) anlegen, prüfen und Verträge digital verwalten.",
|
||||||
changes:[
|
changes:[
|
||||||
{titel:"Vergabe neu!", text:"Eine neue EU-Vergaberichtlinie zwingt zur Einführung von E-Invoicing und erweiterten Transparenz-Reports."},
|
{titel:"Vergabe neu!", text:"Eine neue EU-Vergaberichtlinie zwingt zur Einführung von E-Invoicing und erweiterten Transparenz-Reports."},
|
||||||
{titel:"Vierstellig, bitte", text:"Das Finanzamt wünscht eine kleine Anpassung: aus dem Label „Kostenstelle“ wird „Kostenstelle (4-stellig)“."},
|
{titel:"Format-Wechsel", text:"Die Verträge der Fachämter liegen wegen aktualisierter Sicherheitsrichtlinien in einem neuen Dateiformat vor — die Schnittstellen der Web-Applikation müssen entsprechend angepasst werden."},
|
||||||
{titel:"Patch-Quartal", text:"Das quartalsweise Sicherheits-Patch des Anwendungsservers steht an."},
|
{titel:"Patch-Quartal", text:"Das quartalsweise Sicherheits-Patch des Anwendungsservers steht an."},
|
||||||
{titel:"Upload-Falle!", text:"Im Vertrags-Upload wird eine kritische Lücke entdeckt, über die sich Schadcode hochladen lässt — Endpoint sofort sperren, Hotfix einspielen."}
|
{titel:"Upload-Falle!", text:"Im Vertrags-Upload wird eine kritische Lücke entdeckt, über die sich Schadcode hochladen lässt — Endpoint sofort sperren, Hotfix einspielen."}
|
||||||
]}
|
]}
|
||||||
|
|
@ -1119,7 +1119,7 @@ function cardHtml(si, ci){ const c = acard(si, ci);
|
||||||
return `<div style="font-weight:800;font-size:18px;color:var(--ink);margin-bottom:6px">${c.titel}</div>`
|
return `<div style="font-weight:800;font-size:18px;color:var(--ink);margin-bottom:6px">${c.titel}</div>`
|
||||||
+ `<div>${c.text}</div>`
|
+ `<div>${c.text}</div>`
|
||||||
+ `<div style="color:var(--muted);font-style:italic;margin-top:8px">Was passiert an welchen Stellen?</div>`; }
|
+ `<div style="color:var(--muted);font-style:italic;margin-top:8px">Was passiert an welchen Stellen?</div>`; }
|
||||||
// Finale Action-Card-Grafik (cards/s<service>-c<change>.png) — alle 30 vorhanden.
|
// Finale Action-Card-Grafik (cards/s<service>-c<change>.png) — alle 24 vorhanden.
|
||||||
function cardImg(si, ci){ return `cards/s${si}-c${ci}.png`; }
|
function cardImg(si, ci){ return `cards/s${si}-c${ci}.png`; }
|
||||||
function cardMedia(si, ci){ const f = cardImg(si, ci);
|
function cardMedia(si, ci){ const f = cardImg(si, ci);
|
||||||
return f ? `<img class="acImg" src="${f}" alt="Action Card: ${acard(si,ci).titel}"
|
return f ? `<img class="acImg" src="${f}" alt="Action Card: ${acard(si,ci).titel}"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/* Service Worker — SLC-Workshop Companion (App-Shell, offline-first) */
|
/* Service Worker — SLC-Workshop Companion (App-Shell, offline-first) */
|
||||||
const CACHE = "slc-companion-v21";
|
const CACHE = "slc-companion-v23";
|
||||||
const SHELL = ["./", "index.html", "manifest.webmanifest", "icon.svg"];
|
const SHELL = ["./", "index.html", "manifest.webmanifest", "icon.svg"];
|
||||||
// Action-Card-Grafiken (cards/s<service>-c<change>.png) fuer Offline vorab cachen (alle 30).
|
// Action-Card-Grafiken (cards/s<service>-c<change>.png) fuer Offline vorab cachen (alle 24).
|
||||||
const CARDS = [];
|
const CARDS = [];
|
||||||
for (let s = 0; s <= 5; s++) for (let c = 0; c <= 3; c++) {
|
for (let s = 0; s <= 5; s++) for (let c = 0; c <= 3; c++) {
|
||||||
CARDS.push(`cards/s${s}-c${c}.png`);
|
CARDS.push(`cards/s${s}-c${c}.png`);
|
||||||
|
|
|
||||||
|
|
@ -115,8 +115,16 @@ Konzept (`00_Konzept/README_konzept.md`), bis Rückkopplung mit Michael:**
|
||||||
- [x] **„Verräter"-Sätze** aus 5 Standard-Karten raus (Quartalspflege, Monatsroutine, Patchday,
|
- [x] **„Verräter"-Sätze** aus 5 Standard-Karten raus (Quartalspflege, Monatsroutine, Patchday,
|
||||||
GeoServer-Update, Patch-Quartal).
|
GeoServer-Update, Patch-Quartal).
|
||||||
- [x] **Einstiegs-Frage** umformuliert: „Wo würde die Umsetzung starten (nach Freigabe)?".
|
- [x] **Einstiegs-Frage** umformuliert: „Wo würde die Umsetzung starten (nach Freigabe)?".
|
||||||
- [ ] **Wartet auf Frank:** 3 „Normal"-Karten (Rotstift gefragt · Vierstellig, bitte · Falsch
|
- [x] **3 „Normal"-Karten neu** (aus Franks Word v2, ehemals fälschlich Standard): `s2-c1`
|
||||||
beschriftet) sind eigentlich **Standard** → neue **Normal**-Texte aus Franks Word übernehmen.
|
**„Licht an!"** (neue Mängel-Kategorie Beleuchtung/Strom) · `s4-c1` **„Grün dazu!"**
|
||||||
|
(Grünflächen-Datenquelle im Klimarisiko-Modul) · `s5-c1` **„Format-Wechsel"** (neues
|
||||||
|
Vertrags-Dateiformat → Schnittstellen anpassen). **Texte in `index.html` ersetzt.**
|
||||||
|
- [x] **Alle 24 Karten-Grafiken** durch das finale Canva-Set ersetzt (`SLC Actioncards`,
|
||||||
|
30 Karten → die 24 richtigen übernommen). Neue Normals (Licht an!/Grün dazu!/Format-Wechsel)
|
||||||
|
und bereinigte Standards (ohne „Katalog"-Satz) sind jetzt auch grafisch korrekt. Bild = Text.
|
||||||
|
**Nicht verwendet:** 6 „Major – Low Level"-Extras (Bauamt will mehr! · Schlüsselpflicht ·
|
||||||
|
Ratsbeschluss! · Akten-Zuwachs · Klimarisiko im Blick · Portal für Partner) — App nutzt nur
|
||||||
|
einen Major (Top-Level) je Service. Liegen im Download-Ordner, falls später gewünscht.
|
||||||
- [ ] **Wartet auf Frank:** Service-Steckbrief-Beiblatt (6 Services: Was ist der Service, was der
|
- [ ] **Wartet auf Frank:** Service-Steckbrief-Beiblatt (6 Services: Was ist der Service, was der
|
||||||
IT-Provider-Anteil) aus Franks Inhalten.
|
IT-Provider-Anteil) aus Franks Inhalten.
|
||||||
- [ ] **Klären (Frank + Patrick):** **Problem-Manager**-Rolle — in App vorhanden (`sp_09/sp_10`),
|
- [ ] **Klären (Frank + Patrick):** **Problem-Manager**-Rolle — in App vorhanden (`sp_09/sp_10`),
|
||||||
|
|
|
||||||