In der hintersten Ecke unseres Wohnzimmerschrankes lagerten die Einzelteile meines alten Teufelsknotens, bis ich sie vor ein paar Tagen wieder entdeckte. Es war ein Spaß, den Knoten mit unseren Kindern wieder zusammenzusetzen. Was uns jedoch so schnell nicht gelang.
Diese Anleitung soll das in Zukunft erleichtern:
Bei der Erstellung habe ich -wie sollte es anders sein- Blender und A-Frame genutzt.
Ja, das ist jetzt schon der 10. Entwurf für unsere „Smart Cabaña Sajoma“. Unabhängig von der Hangsituation steht das eigentliche Haus nun auf einem Tisch, durch welchen die Geländeanpassung erledigt wird. Ausserdem ist die Gesamterscheinung ein wenig mehr in Richtung „Tradition“ gerückt.
Das letzte Mal hab ich eine „einfache“ Orbit-Navigation mit three.js gebaut. Hier wollte ich nun gerne eine First-Person-Navigation mit Anpassung an das Gelände und Collision detection realisieren. Die Wahl für die Umsetzung fiel auf das 3D-Web-Framework A-Frame, welches intern auf three.js aufbaut.
Im Fokus stand diesmal auch die Innenraumgestaltung. Da konnte ich ein wenig Panorama-Anzeige ausprobieren: zuerst mit Blender Equirektangulare erstellen und dann im Panorama-Viewer (hier Pannellum) anzeigen lassen.
Letztes Jahr hatte ich eine Fahrrad-Rallye zum Braunschweiger Ringgleis veranstaltet. Da ich der Meinung bin, dass sich solch eine Veranstaltung geradezu anbietet, per Software unterstützt zu werden, schrieb ich die R-Rallye:
R-Rallye mobile view
Die Web-App ist eine Browser-Anwendung und für mobile Nutzung optimiert. Ein großer Teil der Aufgaben ist jedoch leider inzwischen veraltet, da sich die lokalen Gegebenheiten (z.B. Graffitis) geändert haben. Wenn ich mal wieder Zeit habe, werde ich die Aufgaben aktualisieren. Dabei unterstützt mich der Task-Editor. (Bei aktualisierten Aufgaben und Antworten wird der Task-Editor von hier natürlich nicht mehr erreichbar sein)
Hier eine kleine Übersicht über die Funktionsweise und die Bestandteile des ‚Webhostings‘. Also: wie veröffentliche ich eine eigene Website? Und zwar ohne mich bei Webbaukasten-Anbietern registrieren zu müssen und damit in den meisten Fällen im Netz eines Anbieters gefangen zu sein. Guckstu:
Wenn du eine Website erstellen willst, brauchst du einen Webhoster. Bei diesem bestellst du ein (kostenpflichtiges) Hostingpaket mit Wunschdomain („irgendeinentollenseitennamen.de“) und bekommst damit als Eigentümer Zugang zur Domain-Verwaltung und zum Webspace. Mithilfe eines FTP-Programms (z.B. FileZilla) und den vom Webhoster mitgeteilten Zugangsdaten machst du den Datei-Upload in deinen Webspace. Wenn du WordPress verwenden willst, lädst du dir die zip-Datei von wordpress.org herunter und packst den Inhalt des Unterordners ‚wordpress‘ auf den Webspace. Mittels der Domain-Verwaltung sagst du dem System, welcher Ordner des Webspace der Domain zugeordnet werden soll. Für WordPress (und andere CMS) benötigst du eine Datenbank, die über die Domain-Verwaltung eingerichtet werden kann. Nun kann die Designverwaltung aufgerufen werden (bei WordPress initial aufzurufen mit der domain und im Folgenden mit domain/wp-login) und der Spaß beginnt.
Die vorangegangenen Schritte sind im Allgemeinen nur einmalig auszuführen. Alles Folgende passiert innerhalb der Designverwaltung (z.B. innerhalb von WordPress).
Zu WordPress:
Worpress ist historisch gesehen eine Software , um Web-Blogs zu erstellen. Aus diesem Grunde unterscheidet die Admin-Oberfläche zwischen ‚Beiträgen‘ und ‚Seiten‘. Standardmäßig gibt es immer eine Blogseite, auf der die Beiträge gesammelt werden, und alle anderen Seiten, die üblicherweise auch im Menü zu finden sind. Ausgangspunkt für das Layout sind die ‚Themes‘. Einige sind bereits in der Installationsversion mitgeliefert, andere lassen sich (oftmals kostenpflichtig) nachinstallieren. Die Themes haben spezifische Einstellungsmöglichkeiten, die über den ‚Design -> Customizer‘ aufzurufen sind. Du solltest dir auf jeden Fall Zeit nehmen, um ein wenig rumzuexperimentieren. Das englischsprachige Manual https://codex.wordpress.org hilft auf jeden Fall.
Hier noch ein Hinweis zu den Sternchen * in der Grafik: alle Zugangsdaten sollten in deinem Passwortcontainer hinterlegt werden, z.B. KeePass.
Mein Freund Peter hat sich ein großes, schönes Projekt für 2018 vorgenommen. Ich freue mich, ein wenig dabei helfen zu dürfen mit Logoentwurf und Homepage.
Für Hutträger Werner habe ich eine neue Homepage erstellt. Ich glaube, das wird die letzte handgemachte Seite von mir sein, denn die ist leider nicht responsiv, also nicht handygeeignet. Es hat aber viel Spaß gemacht, das Hutthema zu verarbeiten. (existiert nicht mehr)
Die Familienmitglieder müssen zum Testen herhalten: Für meine Schwester Birgit und ihren Mann Thomas, beide sehr erfahrene und ideenreiche Garten- und Landschaftsbauer, hab ich einen Entwurf mithilfe meines one-file-cms gemacht.
An den großen Contentmanagement-Systemen hat mich immer der enorme Umfang genervt. Da werden Unmengen an MBs auf den Webserver geladen und diejenigen, die im Alltag die Inhaltspflege übernehmen sollen, müssen aufwendig angelernt werden. Mal ehrlich: es ist fast einfacher, HTML, CSS und JavaScript von der Pike auf zu erlernen als die Redaktionsoberfäche von Typo3 (oder WordPress 😉 ) zu bedienen. Das hat mich dazu animiert, das onefile_cms zu schreiben. Eine einzige kleine PHP-Script-Datei und ein HTML-Template mit nur 5 Variablen sind die Zutaten. Natürlich kann damit kein Enterprise-Portal entwickelt werden, aber für eine mehrseitige kleine Homepage mit 1-stufigem Menü reicht’s.
<?php
// onefile_cms by G. Drinkmann Ver 0.12 (29.05.2013)
// Contentmanagement-System mit Wiki-Dialekt zur Contentbearbeitung
// Dieser Quelltext kann völlig frei verwendet werden
error_reporting(E_ALL);
// ############################ HTML-Template ##########################################
// das Template sollte folgendes enthalten:
// Variablen im Template:
// <!-- {sitetitle} -->
// wird ersetzt durch Homepage-Titel
// <!-- {menutitle} -->
// der Menüname der angezeigten Seite
// <!-- {ul-menu} -->
// Menü als automatisch erzeugte ul-Liste (CSS s.u.)
// <!-- {content-width} -->
// wird ersetzt durch Content-Breite
// <!-- {content} -->
// der eigentliche Seiteninhalt aus der Redaktionsseite
// CSS:
// #menu id des ul-Elements
// #menu li z.B.{display:inline; list-style:none;}
// #menu a.menunormal class-Attribut des a-Elements im Menü
// #menu a.menucurrent class-Attribut des aktiven a-Elements im Menü
// img.Lfloat class-Attribut von linksbündig formatierten Bildern mit Text-Umlauf
// img.Rfloat class-Attribut von rechtsbündig formatierten Bildern mit Text-Umlauf
// Konvention:
// Namen der Bilder des Templates sollten mit "ONEFILECMS_" beginnen
// ------- HTML-Template-Datei ---------------------
$ggtplfile = "tpl1.html";
// ############################ Script-Variablen #######################################
// ------- Homepage-Titel --------------------------------------------------------------
$ggsitetitel = "Kiosk JOJO";
// ------- md5-Passwort (zu erstellen bei z.B. http://www.functions-online.com/md5.html)
$ggpass = "e6b3cd51a7afb493493d0c4a0bb0c8b2"; // jo33jo (bitte comment löschen)
// ------- Edit-URL-Parameter (m=) zum Aufruf der Redaktionsseite ----------------------
$ggeditpara = "edit"; // ohne Leer- oder Sonderzeichen !
// ------- Template ist XHTML ----------------------------------------------------------
$ggisxhtml = false;
// ------- Content-Breite --------------------------------------------------------------
$ggcontwidth = "750px";
// ############################ ab hier Chefsache !! ###################################
$ggcontfile = "content1file.txt";
$ggxsl = ($ggisxhtml) ? " /" : "";
function ggerror($ggmsg) {
global $ggcontent, $ggsitetitel, $ggxsl;
$ggcontent[0]['mtitle'] = "FEHLER";
$ggcontent[0]['read'] = "<i>".$ggmsg."</i><br".$ggxsl."><br".$ggxsl.">Die Seite \"".$ggsitetitel."\" ist momentan nicht verfügbar.<br".$ggxsl.">Versuchen Sie es bitte später nocheinmal.<br".$ggxsl.">Danke !";
}
if (isset($_GET['m'])) { // Check des GET-Parameter
if ($_GET['m'] === $ggeditpara) $ggpar = "e";
else $ggpar = intval($_GET['m']);
} else $ggpar = 0;
if ($ggpar === "e") { // Seite editieren
if (md5($_POST['pass']) === $ggpass && isset($_POST['content'])) {
file_put_contents("./".$ggcontfile, urldecode($_POST['content']));
if (isset($_FILES['pic'])) {
if (preg_match("/\.(jpg|gif|png)$/i", $_FILES['pic']['name']) || ($ggtplfile === $_FILES['pic']['name'])) {
move_uploaded_file($_FILES['pic']['tmp_name'], "./".$_FILES['pic']['name']);
}
}
if (isset($_POST['delimg'])) {
for ($i=0; $i<count($_POST['delimg']); $i++) {
@unlink("./".urldecode($_POST['delimg'][$i]));
}
}
}
if (file_exists("./".$ggcontfile)) {
$ggfstr = file_get_contents("./".$ggcontfile);
} else $ggfstr = utf8_encode("; Bitte mit Inhalt füllen");
$ggpiclis = ""; // vorhandene Bilder listen
if ($gghandle = opendir('.')) {
while (false !== ($ggfile = readdir($gghandle))) {
if (preg_match("/\.(jpg|gif|png)$/i", $ggfile) && (!preg_match("/^ONEFILECMS_/", $ggfile))) {
$ggpiclis .= "{{".$ggfile."}}<input type='checkbox' name='delimg[]' value='".$ggfile."' title='Bild löschen'><img onmouseover='document.getElementById(\"preview\").src = this.src; document.getElementById(\"preview\").className=\"gvisible\"' onmouseout='document.getElementById(\"preview\").className=\"ghidden\"' class='pici' src='".$ggfile."'> ";
}
}
closedir($gghandle);
}
if (!$ggpiclis) $ggpiclis = "<i>Keine</i>";
$ggaction = $_SERVER['PHP_SELF']."?m=".$ggeditpara;
$ggeditsite = <<<EOTE
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>{$ggsitetitel} editieren</title>
<style type="text/css">
* {font-family:arial}
img.pici {border:0;padding:0;margin:0;height:18px}
img.gvisible {visibility:visible}
img.ghidden {visibility:hidden}
</style>
</head>
<body style="background-color:#ebebeb">
<h2>Website <a href="{$_SERVER['PHP_SELF']}" style="color:red" target="_blank"><i>{$ggsitetitel}</i></a> editieren (Inhalts-Breite <span style="color:red">{$ggcontwidth}</span>):</h2>
<p style="font-size:10px">Zeile mit ; am Anfang = Kommentar<br>
M--- am Anfang der Zeile = neuer Menütitel<br>
HTML-Tags werden ausgeführt<br>
== am Anfang der Zeile = große Überschrift<br>
=== am Anfang der Zeile = kleinere Überschrift<br>
| am Anfang der Zeile = Tabelle (weitere Zellen mit | trennen)<br>
* am Anfang der Zeile = Liste<br>
{{*.jpg oder gif oder png}} = Bild in Originalgröße<br>
{{*.jpg oder gif oder png|L oder R}} = Bild links bzw. rechts mit Text-Umlauf<br>
[[Menüindex|Linktext oder -bild]] = interner Link (Index beginnt bei 0)<br>
[[Linkadresse|Linktext oder -bild]] = externer Link<br>
**Wörter** = Fett<br>
//Wörter// = Kursiv<br>
---- = horizontale Linie<br>
((x)) am Anfang = Text-Umlauf (Float) beenden</p>
<form name="f1" action="{$ggaction}" method="post" enctype="multipart/form-data">
<p><b>Inhalt</b><br>
<textarea name="content" style="width: 600px; height: 300px; font-size: 12pt">{$ggfstr}</textarea></p>
<p id="piclist"><b>Hochgeladene Bilder:</b><br>
{$ggpiclis}</p>
<p><b>Datei hochladen:</b> jpg, gif, png oder Template <i>{$ggtplfile}</i><br>
<input type="file" name="pic" size="61"></p>
<p>Passwort <input type="password" onkeydown="document.getElementsByName('OK')[0].disabled=false" name="pass" style="width: 200px;">
<input style="font-weight:bold" type="submit" name="OK" value="Seite speichern" disabled="disabled"></p>
</form>
<img class="ghidden" id="preview" src="nixda" style="position:absolute; left:3px; top:3px; border:solid #808080 30px;">
</body>
</html>
EOTE;
echo $ggeditsite;
} else { // normaler Seitenaufruf
if (file_exists("./".$ggtplfile)) {
$ggsitestr = file_get_contents("./".$ggtplfile);
} else die("TEMPLATE NICHT VORHANDEN !");
$ggcontent = array(); // Initialisierung des Content-Array
$ggcount=-1;
if (file_exists("./".$ggcontfile)) { // Steuerdatei ins Content-Array einlesen
$ggf = fopen("./".$ggcontfile, 'rb');
while (!feof($ggf)) {
$ggtmp = rtrim(fgets($ggf));
if (substr(ltrim($ggtmp),0,4)==="M---") {
$ggcount++;
$ggcontent[$ggcount]['mtitle'] = ltrim(substr(ltrim($ggtmp),4));
$ggcontent[$ggcount]['mtitleclass'] = "menunormal";
$ggcontent[$ggcount]['read'] = "";
} elseif (substr(ltrim($ggtmp),0,1)!==";") {
$ggcontent[$ggcount]['read'] .= $ggtmp."<brbr>";
}
}
fclose($ggf);
if ($ggcount === -1) ggerror("Fehler: Kein Menü in Steuer-Datei eingetragen");
} else ggerror("Fehler: Steuer-Datei nicht vorhanden");
if ($ggpar>$ggcount) $ggpar = 0;
$ggcontent[$ggpar]['mtitleclass'] = "menucurrent";
$ggsitestr = str_replace("<!-- {sitetitle} -->", $ggsitetitel, $ggsitestr);
$ggsitestr = str_replace("<!-- {menutitle} -->", $ggcontent[$ggpar]['mtitle'], $ggsitestr);
$ggsitestr = str_replace("<!-- {content-width} -->", $ggcontwidth, $ggsitestr);
// --- Menü zusammenbauen ---
$ggmenustr = "<ul id=\"menu\">\n";
for ($i=0; $i<count($ggcontent); $i++) {
$ggmenustr .= "<li><a href=\"".$_SERVER['PHP_SELF']."?m=".$i."\" class=\"".$ggcontent[$i]['mtitleclass']."\" target=\"_self\">".$ggcontent[$i]['mtitle']."</a></li>\n";
}
$ggmenustr .= "</ul>\n";
$ggsitestr = str_replace("<!-- {ul-menu} -->", $ggmenustr, $ggsitestr);
// --- Content zusammenbauen ---
$ggcont = $ggcontent[$ggpar]['read'];
$ggcont = explode("<brbr>",$ggcont);
$ggcontstr = "";
$istab = 0; // Tabelle
$isul = false; // Bullet-Liste
$ggcleardiv = "<div style='clear:both;visibility:hidden;width:0;height:0;margin:0;padding:0;border:0;'></div>\n";
for ($i=0; $i<count($ggcont); $i++) {
if (substr(ltrim($ggcont[$i]),0,5)==="((x))") {
$ggisclear = " style='clear:both'";
$ggcont[$i] = substr(ltrim($ggcont[$i]),5);
} else $ggisclear = "";
if (substr(ltrim($ggcont[$i]),0,1)==="|") {
$ggtra = explode("|",substr(ltrim($ggcont[$i]),1));
if (!$istab) {
$ggcontstr .= "<table".$ggisclear.">\n";
} elseif ($istab !== count($ggtra)) {
$ggcontstr .= "</table>\n<table".$ggisclear.">\n";
}
$istab = count($ggtra);
$ggcontstr .= "<tr>";
for ($j=0; $j<$istab; $j++) {
$ggcontstr .= "<td>".trim($ggtra[$j])."</td>";
}
$ggcontstr .= "</tr>";
} else {
if ($istab) $ggcontstr .= "</table>\n";
$istab = 0;
if ((substr(ltrim($ggcont[$i]),0,1)==="*") && (substr(ltrim($ggcont[$i]),1,1)!=="*")) {
if (!$isul) $ggcontstr .= "<ul".$ggisclear.">\n";
$isul = true;
$ggcontstr .= "<li>".trim(substr(ltrim($ggcont[$i]),1))."</li>";
} else {
if ($isul) $ggcontstr .= "</ul>\n";
$isul = false;
if (substr(ltrim($ggcont[$i]),0,3)==="===") {
$ggcontstr .= "<h2".$ggisclear.">".substr(ltrim($ggcont[$i]),3)."</h2>";
} elseif (substr(ltrim($ggcont[$i]),0,2)==="==") {
$ggcontstr .= "<h1".$ggisclear.">".substr(ltrim($ggcont[$i]),2)."</h1>";
} elseif (trim($ggcont[$i])==="----") {
$ggcontstr .= "<hr".$ggisclear.">";
} elseif ($ggisclear) {
$ggcontstr .= $ggcleardiv.$ggcont[$i]."<br".$ggxsl.">";
} else $ggcontstr .= $ggcont[$i]."<br".$ggxsl.">";
}
}
$ggcontstr .= "\n";
}
$ggcontstr = preg_replace("/{{(\S.*\.(jpg|JPG|gif|GIF|png|PNG))\|L}}/", "<img src=\"$1\" style=\"float:left\" class=\"Lfloat\"".$ggx.">", $ggcontstr); // Bilder mit float links
$ggcontstr = preg_replace("/{{(\S.*\.(jpg|JPG|gif|GIF|png|PNG))\|R}}/", "<img src=\"$1\" style=\"float:right\" class=\"Rfloat\"".$ggx.">", $ggcontstr); // Bilder mit float rechts
$ggcontstr = preg_replace("/{{(\S.*\.(jpg|gif|png))}}/i", "<img src=\"$1\"".$ggx.">", $ggcontstr); // Bilder
$ggcontstr = preg_replace("/\[\[(\d+)\|(\S.*\S|\S)]]/", "<a href=\"".$_SERVER['PHP_SELF']."?m=$1\" target=\"_self\">$2</a>", $ggcontstr); // interne Links
$ggcontstr = preg_replace("/\[\[(\S+)\|(\S.*\S|\S)]]/", "<a href=\"$1\" target=\"_blank\" title=\"Link in neuem Fenster\">$2</a>", $ggcontstr); // externe Links
$ggcontstr = preg_replace("/ /", " ", $ggcontstr); // Leerzeichen
$ggcontstr = preg_replace("/ (\S)/", " $1", $ggcontstr);
$ggcontstr = preg_replace("/\*\*(\S.*\S|\S)\*\*/", "<strong>$1</strong>", $ggcontstr); // Fett
$ggcontstr = preg_replace("#//(\S.*\S|\S)//#", "<em>$1</em>", $ggcontstr); // Kursiv
$ggsitestr = str_replace("<!-- {content} -->", $ggcontstr, $ggsitestr);
$ggsitestr .= $ggcleardiv;
echo $ggsitestr;
}
?>
Also, man nehme den Quelltext, erstelle daraus eine Datei names index.php, fülle die Variablen aus, erstelle eine Template-Datei (mit dem Namen wie bei den Variablen angegeben) und lade beide Dateien (inklusive der zum Template gehörigen Bilder) auf den Webserver. Die index.php-Datei beinhaltet beides: die Maschinerie der eigentlichen Website für den Betrachter und die der Redaktion. Die Redaktionsseite wird über den Link <DeineURL>/index.php?m=<Variable URL-Parameter> aufgerufen. Ok, es sind mehr als nur eine Datei im Spiel, doch das eigentliche Programm besteht in der Tat nur aus dieser einen PHP-Datei.
Das Template sollte eine ganz normale HTML-Seite sein. Die Namen der Templatebilder sollten mit „ONEFILECMS_“ beginnen. Folgende Variablen können in diesem Template plaziert sein:
<!– {sitetitle} –> der Homepagetitel
<!– {menutitle} –> der Menüname der angezeigten Seite
<!– {ul-menu} –> Seiten-Menü als automatisch erzeugte ul-Liste
<!– {content-width} –> Breite des Inhaltbereichs
<!– {content} –> der eigentliche Seiteninhalt
Hier ist eine kleine Testseite zur Anschauung: der Kiosk des fiktiven Jojo
Das zugehörige Template ist die Datei tpl1.html. Im Quelltext dieser Seite sind die Variablen sichtbar.
Jojo’s Kiosk kann mit der Edit-Seite bearbeitet werden.
Dabei wird zur leicht erlernbaren Bearbeitung ein Wiki-Dialekt angewendet. Hat Ähnlichkeit mit Creole. Zum Speichern wird JEDESMAL das Paßwort abgefragt. Das ist ein wenig lästig, aber sicher.
Ich weiß nicht mehr, wie ich auf Jill Brittons Homepage (leider inzwischen inaktiv) gestoßen bin, aber ich weiß, dass sie bei meinen Lesezeichen sehr weit oben steht, weil es dort viele interessante Dinge zu stöbern gibt. Dort gibt es ein Kapitel über Flexagone (unter R-U-B-B-E-R Topic4).
Ein Flexagon ist ein faszinierendes Gebilde: annähernd 2-dimenional wie ein Blatt Papier (ist ja auch aus Papier gebaut, s. Bild oben), aber du kannst es in einer bestimmten Art entfalten, bzw. auffalten, so dass eine andere verborgene Oberfläche sichtbar wird. Das hier vorgestellte Flexagon heißt Tetra-Tetra-Flexagon und kann als nettes Giveaway dienen. Im fertigen Zustand hat es eine Vorderseite (1.Bild) und eine Rückseite (2.Bild) . Dann kann es zweimal so umgefaltet werden, dass nacheinander zwei zusätzliche Bilder erscheinen (also insgesamt 4 Bilder). Ich habe Jills Fexifier ein wenig getuned (hope you’ll forgive me, Jill):