active tabs and small upgrades

This commit is contained in:
Doriane 2024-05-16 13:12:26 +02:00
parent 41ee3159d8
commit a6f78efcc1
14 changed files with 578 additions and 436 deletions

31
README.md Normal file
View File

@ -0,0 +1,31 @@
# cobbled paths
from figlet2svgbob, creating contextual stroke font ready to plot.
this is called _cobbled paths_ as a reminder of the permeability between the discrete and the continuous.
smooth connected paths are made out of an extremely restrictive grid, like multiple blocky stones form a tortuous path.
## dependencies
## font database
* figlet offical ftp at <ftp://ftp.figlet.org>
* `ours` the original default font made by the developper and given with the program, in early 1993
* `contributed` fonts made by figlet amateur and submitted to the official figlet ftp, from before 1993 to 2005
* `c64` are fonts that are only made of the `#` character, the most black ascii char, is if it was a pixel
* `bdffont` are fonts automatically made using bdf2figlet, converting [Glyph Bitmap Distribution Format](https://en.wikipedia.org/wiki/Glyph_Bitmap_Distribution_Format), often from adobe to `c64` like font.
* figlet font library of JavE (a free Ascii Editor), <http://www.jave.de/figlet/fonts.html>. those also include the figlet ftp native, they where sorted in order to keep only the uniques ones.
## todo
* redo catalogue!
* iframe per category for less computing time
* left and right reload in draw & font
* input listen when opening page (for browser history remember)
* factorise JS
* factorise CSS
* show font-info file
* option to save as hpgl

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

167
app.py
View File

@ -75,15 +75,28 @@ autofix = [
def most_common(lst):
return max(set(lst), key=lst.count)
def text2figlet(input, figfont):
figlet = subprocess.run(["figlet", input, "-f", figfont, "-w", "160"], stdout = subprocess.PIPE, text=True)
return figlet.stdout
def text2figlet(text, figfont):
print('--- FIGLET SUBPROCESS')
figlet = subprocess.run(["figlet", text, "-f", figfont, "-w", "160"], stdout = subprocess.PIPE, stderr = subprocess.PIPE, text=True)
print(figlet.stdout)
if figlet.returncode == 0:
answer = (True, figlet.stdout)
else:
answer = (False, figlet.stderr)
return answer
def ascii2svg(ascii_input, weight):
svgbob = subprocess.run(["svgbob_cli", '--stroke-width', weight], input = ascii_input, stdout = subprocess.PIPE, text=True)
return svgbob.stdout
def ascii2svg(ascii, weight):
if ascii:
print('--- SVGBOB SUBPROCESS')
svgbob = subprocess.run(["svgbob_cli", '--stroke-width', weight], input = ascii, stdout = subprocess.PIPE, text=True)
return svgbob.stdout
else:
return "ERROR: etherpad request failed"
def ascii_autofix(ascii):
print('--- REGEX AUTOFIX')
for regex, replace in autofix:
ascii = re.sub(regex, replace, ascii)
return ascii
@ -92,11 +105,29 @@ def autofix_indication(ascii):
for regex, replace in autofix:
# the two markers have to not appear in any regex
ascii = re.sub(regex, "$" + replace + "", ascii)
ascii = re.sub("[\$]", "<span class='fix'>", ascii)
ascii = re.sub("[\€]", "</span>", ascii)
return ascii
def get_pad(url):
# get pad content
print('--- ETHERPAD REQUEST')
print(url)
pad_export = requests.get(url + '/export/txt')
if pad_export.status_code == requests.codes.ok:
answer = (True, pad_export.text)
else:
answer = (False, "ERROR: etherpad request failed")
return answer
def make_figfont(ascii):
print('--- MAKE TEMP FIGFONT')
(figfont_file, figfont_path) = tempfile.mkstemp(suffix='.flf')
print(figfont_path)
with open(figfont_path, 'w') as figfont_file:
figfont_file.write(ascii)
return figfont_path
# ROUTES
# ------------------------------
@ -151,13 +182,12 @@ def drawing(id):
}
params['pad-full'] = etherpad + prefix + params['pad']
# get pad content
print(' getting ' + params['pad-full'])
pad_export = requests.get(params['pad-full'] + '/export/txt')
ascii_input = pad_export.text
# to SVG
svg = ascii2svg(ascii_input, params['weight'])
pad_answer = get_pad(params['pad-full'])
if pad_answer[0]:
ascii = pad_answer[1]
svg = ascii2svg(ascii, params['weight'])
else:
svg = pad_answer[1]
return render_template(
'drawing.html',
@ -178,7 +208,7 @@ def drawing(id):
def font():
params = {
'text': request.args.get('t') or 'Cobbled Paths',
'text': request.args.get('t') or 'the quick brown fox jumps over the lazy dog',
'pad': request.args.get('p') or 'standard',
'weight': request.args.get('w') or '3',
}
@ -193,30 +223,29 @@ def font():
def writing(id):
params = {
'text': request.args.get('t') or 'Cobbled Paths',
'text': request.args.get('t') or 'the quick brown fox jumps over the lazy dog',
'pad': id or 'standard',
'weight': request.args.get('w') or '3',
}
params['pad-full'] = etherpad + prefix + params['pad']
# get pad content
print(' getting ' + params['pad-full'])
pad_export = requests.get(params['pad-full'] + '/export/txt')
ascii_input = pad_export.text
pad_answer = get_pad(params['pad-full'])
# TODO: only create new file if content of pad changed
# store as a temporary file
print('--- saving figfont as temp ---')
(figfont_file, figfont_path) = tempfile.mkstemp(suffix='.flf')
print(figfont_path)
with open(figfont_path, 'w') as figfont_file:
figfont_file.write(ascii_input)
print('--- opening the figfont ---')
ascii = text2figlet(params['text'], figfont_path)
print(ascii)
print('--- rendering to svg ---')
svg = ascii2svg(ascii, params['weight'])
if pad_answer[0]:
ascii = pad_answer[1]
figfont = make_figfont(ascii)
figlet_answer = text2figlet(params['text'], figfont)
if figlet_answer[0]:
ascii = figlet_answer[1]
svg = ascii2svg(figlet_answer[1], params['weight'])
else:
ascii = svg = figlet_answer[1]
else:
ascii = svg = pad_answer[1]
return render_template(
'writing.html',
@ -234,51 +263,51 @@ def writing(id):
#
# FIGLET 2 SVGBOB INTERACTIVE CATALOGUE
@app.route("/catalogue.html")
def catalogue():
# @app.route("/catalogue.html")
# def catalogue():
# text and weight as get parameter
params = {
'text': request.args.get('t') or 'Echoes',
'weight': request.args.get('w') or '3',
}
# # text and weight as get parameter
# params = {
# 'text': request.args.get('t') or 'Echoes',
# 'weight': request.args.get('w') or '3',
# }
# walk in the figlet font directory
for root, dirs, files in os.walk(fonts_directory):
for name in files:
# # walk in the figlet font directory
# for root, dirs, files in os.walk(fonts_directory):
# for name in files:
(basename, ext) = os.path.splitext(name)
if ext in possible_extensions:
# (basename, ext) = os.path.splitext(name)
# if ext in possible_extensions:
figfont = os.path.join(root, name)
print(figfont)
# figfont = os.path.join(root, name)
# print(figfont)
# get font category out of last folder
catalogue = root.split('/')[-2]
type = root.split('/')[-1]
if type in output:
# # get font category out of last folder
# catalogue = root.split('/')[-2]
# type = root.split('/')[-1]
# if type in output:
f = {}
output[type]['fonts'].append(f)
f['name'] = name
f['catalogue'] = catalogue
f['ascii'] = text2figlet(params['text'], figfont)
f['svg'] = ascii2svg(f['ascii'], params['weight'])
# f = {}
# output[type]['fonts'].append(f)
# f['name'] = name
# f['catalogue'] = catalogue
# f['ascii'] = text2figlet(params['text'], figfont)
# f['svg'] = ascii2svg(f['ascii'], params['weight'])
# regex auto_fix
f['ascii_fix'] = ascii_autofix(f['ascii'])
# # regex auto_fix
# f['ascii_fix'] = ascii_autofix(f['ascii'])
if f['ascii'] != f['ascii_fix']:
f['autofix'] = True
f['ascii_fix_indication'] = autofix_indication(f['ascii_fix'])
f['svg_fix'] = ascii2svg(f['ascii_fix'], params['weight'])
# if f['ascii'] != f['ascii_fix']:
# f['autofix'] = True
# f['ascii_fix_indication'] = autofix_indication(f['ascii_fix'])
# f['svg_fix'] = ascii2svg(f['ascii_fix'], params['weight'])
return render_template(
'catalogue.html',
title = title,
databases = databases,
output = output,
params = params)
# return render_template(
# 'catalogue.html',
# title = title,
# databases = databases,
# output = output,
# params = params)
# _ _ _
@ -302,10 +331,10 @@ def hpgl (id):
# get pad content
print(' getting ' + params['pad-full'])
pad_export = requests.get(params['pad-full'] + '/export/txt')
ascii_input = pad_export.text
ascii = pad_export.text
# to SVG
svg = ascii2svg(ascii_input, params['weight'])
svg = ascii2svg(ascii, params['weight'])
# store as a temporary file
(svg_file, svg_path) = tempfile.mkstemp()

View File

@ -19,8 +19,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from __future__ import print_function
import sys
sys.path.append('/usr/share/inkscape/extensions')
sys.path.append('/snap/inkscape/10555/share/inkscape/extensions')
import inkex
from inkex.localization import inkex_gettext as _
@ -70,6 +72,7 @@ class HpglOutputAdapted(inkex.OutputExtension):
)
def save(self, stream):
print('start')
self.options.debug = False
# get hpgl data
if len(self.svg.xpath("//svg:use|//svg:flowRoot|//svg:text")) > 0:
@ -79,6 +82,9 @@ class HpglOutputAdapted(inkex.OutputExtension):
hpgl = encoder.getHpgl()
except hpgl_encoder.NoPathError:
raise inkex.AbortExtension(_("No convertible objects were found"))
print('middle')
# convert raw HPGL to HPGL
hpgl_init = "IN"
# if self.options.force > 0:
@ -88,7 +94,9 @@ class HpglOutputAdapted(inkex.OutputExtension):
hpgl = hpgl_init + hpgl + ";SP0;PU0,0;IN; "
# Make it available externally
self.hpgl = hpgl
stream.write(hpgl.encode("utf-8"))
# stream.write(hpgl.encode("utf-8"))
print('end')
if __name__ == "__main__":

View File

@ -1,11 +1,13 @@
:root{
--bar-h: 3rem;
--c-link: blue;
--c-back: whitesmoke;
--c-default: black;
--c-contributed: palegreen;
--c-jave: mediumpurple;
--c-back: whitesmoke;
}
.default{
--c: var(--c-default);
@ -24,28 +26,13 @@ body{
line-height: 1.45;
}
a{
color: currentColor;
color: var(--c-link);
}
a:hover{
font-weight: bold;
}
ul.special{
display: flex;
gap: 1rem;
justify-content: center;
align-items: baseline;
}
.special a{
display: block;
border: 1px solid black;
padding: 2rem 3rem;
border-radius: 2rem;
text-decoration: none;
}
ul.classic{
list-style: initial;
padding: 0 1rem;
p{
margin: 0.5rem 0;
}
/* BAR
@ -62,25 +49,14 @@ body.draw{
nav ul,
.controls{
box-sizing: border-box;
height: var(--bar-h);
position: fixed;
width: 100%;
z-index: 999;
gap: 1rem;
display: flex;
align-items: center;
border-bottom: 1px solid black;
}
nav ul{
top: 0;
background: black;
color: white;
}
.controls{
top: var(--bar-h);
background-color: var(--c-back);
border-bottom: 1px solid black;
padding: 1rem 2rem;
}
nav ul li{
flex-grow: 1;
@ -89,16 +65,32 @@ nav ul li:not(:last-child){
border-right: 1px solid var(--c-back);
}
nav ul a{
padding: 1rem 2rem;
color: white;
padding: 0 2rem;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
height: var(--bar-h);
background-color: black;
box-sizing: border-box;
}
nav ul a.active{
background-color: var(--c-link);
}
/* CONTROLS
================================================= */
.controls{
gap: 0.5rem;
top: var(--bar-h);
background-color: var(--c-back);
border-bottom: 1px solid black;
padding: 0rem 2rem;
height: var(--bar-h);
}
h1,h2{
font-weight: bold;
}
@ -127,6 +119,14 @@ label{
padding: 1rem 2rem;
border-bottom: 1px solid black;
}
.two-columns{
display: flex;
flex-wrap: wrap;
gap: var(--bar-h);
}
.two-columns > *{
flex: 1 1 0%;
}
.legend::before{
content: '';
@ -267,13 +267,7 @@ span.fix{
fill: red !important;
}
/* font info */
.info-label{
border-bottom: solid mediumblue 3px;
}
/* body class checkboxes */
.font div.fix{
visibility: hidden;
}
@ -286,30 +280,53 @@ body.check-fix .font div.fix{
body.check-text .svgbob text{
visibility: visible;
}
/* .fix{
visibility: hidden;
}
body.check-fix .fix{
visibility: visible;
} */
/* TITLE
================================================= */
.title.font{
padding: 1rem 2rem;
padding: 3rem 2rem;
gap: 1rem var(--bar-h);
grid-template-columns: repeat(2, calc(50% - calc(var(--bar-h) / 2)));
}
.title .f-ascii{
margin-left: auto;
padding: 0;
background: initial;
grid-row: auto;
}
.title .f-svg{
grid-row: auto;
margin-right: auto;
padding: 0;
background: initial;
}
.title .special{
grid-column: 1 / -1;
grid-row: 2 / span 1;
}
ul.special{
display: flex;
gap: 1rem;
justify-content: center;
align-items: baseline;
}
.special a{
display: block;
border: 1px solid currentColor;
padding: 2rem 3rem;
border-radius: 2rem;
text-decoration: none;
}
ul.classic{
list-style: initial;
padding: 0 1rem;
margin: 0.5rem 0;
}
/* DRAW
================================================= */
.draw .font{
height: calc(100vh - var(--bar-h) * 2);
@ -336,4 +353,23 @@ body.check-fix .fix{
width: 100%;
height: 100%;
display: block;
}
.figfont{
grid-template-columns: 32rem 1fr;
}
.reload::after{
content: 'reload';
position: absolute;
inset: 0;
background-color: rgba(0,0,205,0.2);
z-index: 999;
pointer-events: none;
color: white;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
}

View File

@ -3,7 +3,7 @@ from hpgl_output_adapted import HpglOutputAdapted
def svgToHPGL (path, speed=1, penCount=8, force=2):
e = HpglOutputAdapted()
e.affect([
e.run([
'--orientation', '0',
'--force', '0',
'--overcut', '0',
@ -12,7 +12,6 @@ def svgToHPGL (path, speed=1, penCount=8, force=2):
'--toolOffset', '0',
'--autoAlign', 'false',
'--speed', str(speed),
'--penCount', str(penCount),
'--force', str(force),
path], False)

View File

@ -24,10 +24,10 @@
<nav>
<ul>
<li><a href="/">index</a></li>
<li><a href="/draw.html">draw</a></li>
<li><a href="/font.html">font</a></li>
<!-- <li><a href="/catalogue.html">catalogue</a></li> -->
<li><a {% if request.url_rule.endpoint == "index" %}class="active"{% endif %} href="/"> index</a></li>
<li><a {% if request.url_rule.endpoint == "draw" %}class="active"{% endif %} href="/draw.html">draw</a></li>
<li><a {% if request.url_rule.endpoint == "font" %}class="active"{% endif %} href="/font.html">font</a></li>
<li><a {% if request.url_rule.endpoint == "catalogue" %}class="active"{% endif %} href="/catalogue.html">catalogue</a></li>
</ul>
</nav>

View File

@ -13,89 +13,118 @@
<button id="button-svg">generate</button>
<input class="get-input" type="text" value="{{params['text']}}" data-name="t" data-frame="svg-iframe"/>
<input class="get-input" id="text-input" type="text" value="{{params['text']}}" data-name="t" data-frame="svg-iframe"/>
<label for="upper-checkbox">uppercase</label>
<input id="upper-checkbox" type="checkbox"/>
<label>weight</label>
<input class="get-input" type="range" min="1" max="8" value="{{params['weight']}}" data-name="w" data-frame="svg-iframe"/>
<label class="text-label" for="text-checkbox"
<label for="text-checkbox"
title="display the remaining text in the svg output in red">
output text</label>
<input id="text-checkbox" type="checkbox" class="get-input"
class="body-class-check" value="check-text" data-name="c" data-frame="svg-iframe" checked/>
<script>
function updateGET(frame, param, value){
// object from GET parameters
let [base_src, params_src] = frame.src.split("?");
let params = new URLSearchParams(params_src);
// update param
params.set(param, value);
// reconstituate URL
let new_src = base_src + "?" + params.toString();
// set and refresh
frame.src = new_src;
}
let button_pad = document.getElementById('button-pad');
let button_svg = document.getElementById('button-svg');
// --- pad go button
button_pad.addEventListener('click', function(){
let svg_iframe = document.getElementById('svg-iframe');
let pad_iframe = document.getElementById('pad-iframe');
let input = document.getElementById(button_pad.dataset.use);
let value = input.value;
let param = input.dataset.name;
let pad_src = pad_iframe.src;
pad_src = pad_src.split('-');
pad_src[pad_src.length-1] = value;
pad_src = pad_src.join('-');
pad_iframe.src = pad_src;
let svg_src = svg_iframe.src;
svg_src = svg_src.split('/');
svg_src[svg_src.length-1] = value;
svg_src = svg_src.join('/');
svg_iframe.src = svg_src;
});
// --- svg generation button
button_svg.addEventListener('click', function(){
let svg_iframe = document.getElementById('svg-iframe');
console.log("IFRAME RELOAD");
svg_iframe.contentWindow.location.reload();
});
// --- get-input but on the pad and checkbox but on the pad
let inputs = document.getElementsByClassName('get-input');
for(let input of inputs){
input.addEventListener('input', function(){
let frame = document.getElementById(input.dataset.frame);
const url = new URL(frame.src);
if(input.type == 'checkbox'){
url.searchParams.set(input.dataset.name, input.checked);
}
else{
url.searchParams.set(input.dataset.name, input.value);
}
console.log(url);
// frame.contentWindow.history.replaceState(null, null, url);
frame.src = url
});
}
</script>
</header>
<div class="font">
<div class="font figfont reload" id="main">
<iframe class="f-ascii" id="pad-iframe" src="{{params['pad-full']}}">
</iframe>
<iframe class="f-double" id="svg-iframe" src="/writing/{{params['pad']}}">
</iframe>
</div>
<script>
let button_pad = document.getElementById('button-pad');
let button_svg = document.getElementById('button-svg');
let svg_iframe = document.getElementById('svg-iframe');
let pad_iframe = document.getElementById('pad-iframe');
function updateGET(frame, param, value){
// object from GET parameters
let [base_src, params_src] = frame.src.split("?");
let params = new URLSearchParams(params_src);
// update param
params.set(param, value);
// reconstituate URL
let new_src = base_src + "?" + params.toString();
// set and refresh
frame.src = new_src;
}
// --- pad go button
button_pad.addEventListener('click', function(){
let input = document.getElementById(button_pad.dataset.use);
let value = input.value;
let param = input.dataset.name;
let pad_src = pad_iframe.src;
pad_src = pad_src.split('-');
pad_src[pad_src.length-1] = value;
pad_src = pad_src.join('-');
pad_iframe.src = pad_src;
let svg_src = svg_iframe.src;
svg_src = svg_src.split('/');
svg_src[svg_src.length-1] = value;
svg_src = svg_src.join('/');
document.getElementById('main').classList.add("reload");
svg_iframe.src = svg_src;
});
// --- svg generation button
button_svg.addEventListener('click', function(){
document.getElementById('main').classList.add("reload");
svg_iframe.contentWindow.location.reload();
});
// --- get-input but on the pad and checkbox but on the pad
let inputs = document.getElementsByClassName('get-input');
for(let input of inputs){
input.addEventListener('change', function(){
let frame = document.getElementById(input.dataset.frame);
const url = new URL(frame.src);
if(input.type == 'checkbox'){
url.searchParams.set(input.dataset.name, input.checked);
}
else{
url.searchParams.set(input.dataset.name, input.value);
}
// frame.contentWindow.history.replaceState(null, null, url);
document.getElementById('main').classList.add("reload");
frame.src = url;
});
}
let upper_checkbox = document.getElementById('upper-checkbox');
let text_input = document.getElementById('text-input');
upper_checkbox.addEventListener('change', function(){
if(upper_checkbox.checked){
text_input.value = text_input.value.toUpperCase();
let frame = document.getElementById("svg-iframe");
const url = new URL(frame.src);
url.searchParams.set(text_input.dataset.name, text_input.value);
document.getElementById('main').classList.add("reload");
frame.src = url
}
else{
text_input.value = text_input.value.toLowerCase();
let frame = document.getElementById("svg-iframe");
const url = new URL(frame.src);
url.searchParams.set(text_input.dataset.name, text_input.value);
document.getElementById('main').classList.add("reload");
frame.src = url
}
})
svg_iframe.addEventListener("load", function() {
document.getElementById('main').classList.remove("reload");
});
</script>
{% endblock %}

View File

@ -12,252 +12,12 @@
-____- \\ / \\/ \\/ \\ \\ / \\/ </pre>
</div>
<div class="f-svg">
<svg xmlns="http://www.w3.org/2000/svg" width="440" height="112" class="svgbob">
<style>.svgbob line, .svgbob path, .svgbob circle, .svgbob rect, .svgbob polygon {
stroke: blue;
stroke-width: 2.5;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
.svgbob text {
white-space: pre;
fill: black;
font-family: Iosevka Fixed, monospace;
font-size: 14px;
}
.svgbob rect.backdrop {
stroke: none;
fill: none;
}
.svgbob .broken {
stroke-dasharray: 8;
}
.svgbob .filled {
fill: black;
}
.svgbob .bg_filled {
fill: white;
stroke-width: 1;
}
.svgbob .nofill {
fill: white;
}
.svgbob .end_marked_arrow {
marker-end: url(#arrow);
}
.svgbob .start_marked_arrow {
marker-start: url(#arrow);
}
.svgbob .end_marked_diamond {
marker-end: url(#diamond);
}
.svgbob .start_marked_diamond {
marker-start: url(#diamond);
}
.svgbob .end_marked_circle {
marker-end: url(#circle);
}
.svgbob .start_marked_circle {
marker-start: url(#circle);
}
.svgbob .end_marked_open_circle {
marker-end: url(#open_circle);
}
.svgbob .start_marked_open_circle {
marker-start: url(#open_circle);
}
.svgbob .end_marked_big_open_circle {
marker-end: url(#big_open_circle);
}
.svgbob .start_marked_big_open_circle {
marker-start: url(#big_open_circle);
}
</style>
<defs>
<marker id="arrow" viewBox="-2 -2 8 8" refX="4" refY="2" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<polygon points="0,0 0,4 4,2 0,0"></polygon>
</marker>
<marker id="diamond" viewBox="-2 -2 8 8" refX="4" refY="2" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<polygon points="0,2 2,0 4,2 2,4 0,2"></polygon>
</marker>
<marker id="circle" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<circle cx="4" cy="4" r="2" class="filled"></circle>
</marker>
<marker id="open_circle" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<circle cx="4" cy="4" r="2" class="bg_filled"></circle>
</marker>
<marker id="big_open_circle" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<circle cx="4" cy="4" r="3" class="bg_filled"></circle>
</marker>
</defs>
<rect class="backdrop" x="0" y="0" width="440" height="112"></rect>
<text x="258" y="12">'</text>
<text x="426" y="12">.</text>
<text x="178" y="44">.</text>
<text x="130" y="60">.</text>
<line x1="136" y1="64" x2="168" y2="64" class="solid"></line>
<text x="170" y="60">.'</text>
<text x="266" y="60">.</text>
<text x="314" y="60">.</text>
<text x="50" y="76">`</text>
<text x="90" y="76">:'</text>
<text x="210" y="76">.</text>
<line x1="216" y1="80" x2="224" y2="80" class="solid"></line>
<text x="98" y="92">.</text>
<text x="170" y="92">'</text>
<text x="218" y="92">`</text>
<line x1="224" y1="88" x2="232" y2="88" class="solid"></line>
<text x="250" y="92">.</text>
<text x="330" y="92">.</text>
<g>
<path d="M 24,8 A 8,8 0,0,1 30,12" class="nofill"></path>
<line x1="30" y1="12" x2="32" y2="16" class="solid"></line>
<path d="M 32,8 A 8,8 0,0,0 26,12" class="nofill"></path>
<line x1="26" y1="12" x2="24" y2="16" class="solid"></line>
<line x1="32" y1="8" x2="40" y2="8" class="solid"></line>
<path d="M 40,8 A 8,8 0,0,1 46,12" class="nofill"></path>
<line x1="46" y1="12" x2="48" y2="16" class="solid"></line>
<path d="M 24,16 A 16,16 0,0,0 24,32" class="nofill"></path>
<line x1="24" y1="32" x2="32" y2="32" class="solid"></line>
<path d="M 32,16 A 16,16 0,0,1 32,32" class="nofill"></path>
<path d="M 48,16 A 16,16 0,0,1 48,32" class="nofill"></path>
<line x1="48" y1="32" x2="16" y2="96" class="solid"></line>
<path d="M 16,72 A 8,8 0,0,0 10,76" class="nofill"></path>
<line x1="10" y1="76" x2="8" y2="80" class="solid"></line>
<line x1="16" y1="72" x2="28" y2="72" class="solid"></line>
<path d="M 8,80 A 16,16 0,0,0 8,96" class="nofill"></path>
<line x1="8" y1="96" x2="16" y2="96" class="solid"></line>
</g>
<g>
<line x1="152" y1="0" x2="112" y2="80" class="solid"></line>
<line x1="152" y1="0" x2="156" y2="8" class="solid"></line>
<line x1="156" y1="8" x2="156" y2="84" class="solid"></line>
<path d="M 156,84 A 4,4 0,0,0 160,88" class="nofill"></path>
<line x1="160" y1="88" x2="168" y2="88" class="solid"></line>
<path d="M 88,72 A 8,8 0,0,0 82,76" class="nofill"></path>
<line x1="82" y1="76" x2="80" y2="80" class="solid"></line>
<path d="M 80,80 A 16,16 0,0,0 80,96" class="nofill"></path>
<line x1="80" y1="96" x2="96" y2="96" class="solid"></line>
<path d="M 112,80 A 32,32 0,0,1 96,96" class="nofill"></path>
</g>
<g>
<path d="M 184,8 A 8,8 0,0,1 190,12" class="nofill"></path>
<line x1="190" y1="12" x2="192" y2="16" class="solid"></line>
<path d="M 192,8 A 8,8 0,0,0 186,12" class="nofill"></path>
<line x1="186" y1="12" x2="184" y2="16" class="solid"></line>
<line x1="192" y1="8" x2="256" y2="8" class="solid"></line>
<path d="M 184,16 A 16,16 0,0,0 184,32" class="nofill"></path>
<line x1="184" y1="32" x2="192" y2="32" class="solid"></line>
<path d="M 192,16 A 16,16 0,0,1 192,32" class="nofill"></path>
</g>
<g>
<path d="M 256,0 A 32,32 0,0,1 272,16" class="nofill"></path>
<line x1="272" y1="16" x2="280" y2="32" class="solid"></line>
<path d="M 280,32 A 16,16 0,0,1 280,48" class="nofill"></path>
<line x1="280" y1="48" x2="264" y2="80" class="solid"></line>
<line x1="272" y1="64" x2="312" y2="64" class="solid"></line>
<line x1="320" y1="0" x2="304" y2="32" class="solid"></line>
<path d="M 304,32 A 16,16 0,0,0 304,48" class="nofill"></path>
<line x1="304" y1="48" x2="320" y2="80" class="solid"></line>
<path d="M 320,80 A 32,32 0,0,0 336,96" class="nofill"></path>
<path d="M 248,72 A 8,8 0,0,0 242,76" class="nofill"></path>
<line x1="242" y1="76" x2="240" y2="80" class="solid"></line>
<path d="M 240,80 A 16,16 0,0,0 240,96" class="nofill"></path>
<line x1="240" y1="96" x2="248" y2="96" class="solid"></line>
<path d="M 264,80 A 32,32 0,0,1 248,96" class="nofill"></path>
</g>
<g>
<path d="M 412,8 A 8,8 0,0,0 404,16" class="nofill"></path>
<line x1="412" y1="8" x2="424" y2="8" class="solid"></line>
</g>
<g>
<line x1="56" y1="24" x2="64" y2="24" class="solid"></line>
<path d="M 64,24 A 8,8 0,0,1 70,28" class="nofill"></path>
<line x1="70" y1="28" x2="80" y2="48" class="solid"></line>
<path d="M 80,48 A 16,16 0,0,1 80,64" class="nofill"></path>
<line x1="80" y1="64" x2="78" y2="68" class="solid"></line>
<line x1="56" y1="72" x2="72" y2="72" class="solid"></line>
<path d="M 78,68 A 8,8 0,0,1 72,72" class="nofill"></path>
</g>
<g>
<line x1="112" y1="32" x2="120" y2="32" class="solid"></line>
<path d="M 112,32 A 16,16 0,0,0 112,48" class="nofill"></path>
<line x1="112" y1="48" x2="114" y2="52" class="solid"></line>
<path d="M 114,52 A 8,8 0,0,0 120,56" class="nofill"></path>
</g>
<g>
<line x1="232" y1="16" x2="192" y2="96" class="solid"></line>
<path d="M 192,72 A 8,8 0,0,0 186,76" class="nofill"></path>
<line x1="186" y1="76" x2="184" y2="80" class="solid"></line>
<line x1="192" y1="72" x2="204" y2="72" class="solid"></line>
<path d="M 184,80 A 16,16 0,0,0 184,96" class="nofill"></path>
<line x1="184" y1="96" x2="192" y2="96" class="solid"></line>
</g>
<g>
<line x1="256" y1="32" x2="264" y2="32" class="solid"></line>
<path d="M 256,32 A 16,16 0,0,0 256,48" class="nofill"></path>
<line x1="256" y1="48" x2="258" y2="52" class="solid"></line>
<path d="M 258,52 A 8,8 0,0,0 264,56" class="nofill"></path>
</g>
<g>
<path d="M 328,16 A 16,16 0,0,0 328,32" class="nofill"></path>
<path d="M 328,32 A 16,16 0,0,1 328,48" class="nofill"></path>
<line x1="328" y1="48" x2="326" y2="52" class="solid"></line>
<path d="M 326,52 A 8,8 0,0,1 320,56" class="nofill"></path>
</g>
<g>
<path d="M 368,24 A 8,8 0,0,0 362,28" class="nofill"></path>
<line x1="362" y1="28" x2="360" y2="32" class="solid"></line>
<line x1="368" y1="24" x2="384" y2="24" class="solid"></line>
<path d="M 384,24 A 8,8 0,0,1 390,28" class="nofill"></path>
<line x1="390" y1="28" x2="392" y2="32" class="solid"></line>
<path d="M 360,32 A 16,16 0,0,0 360,48" class="nofill"></path>
<line x1="360" y1="48" x2="362" y2="52" class="solid"></line>
<path d="M 362,52 A 8,8 0,0,0 368,56" class="nofill"></path>
<line x1="368" y1="56" x2="376" y2="56" class="solid"></line>
<path d="M 376,56 A 8,8 0,0,1 382,60" class="nofill"></path>
<line x1="382" y1="60" x2="384" y2="64" class="solid"></line>
<path d="M 384,64 A 16,16 0,0,1 384,80" class="nofill"></path>
<line x1="384" y1="80" x2="382" y2="84" class="solid"></line>
<path d="M 392,24 A 8,8 0,0,0 386,28" class="nofill"></path>
<line x1="386" y1="28" x2="384" y2="32" class="solid"></line>
<line x1="392" y1="24" x2="404" y2="24" class="solid"></line>
<path d="M 412,16 A 8,8 0,0,1 404,24" class="nofill"></path>
<path d="M 384,32 A 16,16 0,0,0 384,48" class="nofill"></path>
<line x1="384" y1="48" x2="392" y2="48" class="solid"></line>
<path d="M 392,32 A 16,16 0,0,1 392,48" class="nofill"></path>
<line x1="344" y1="80" x2="352" y2="80" class="solid"></line>
<path d="M 344,80 A 16,16 0,0,0 344,96" class="nofill"></path>
<line x1="344" y1="96" x2="352" y2="96" class="solid"></line>
<line x1="360" y1="88" x2="352" y2="96" class="solid"></line>
<line x1="360" y1="88" x2="376" y2="88" class="solid"></line>
<path d="M 382,84 A 8,8 0,0,1 376,88" class="nofill"></path>
</g>
</svg>
</div>
{% include 'logo.svg' %}
</div>
<div class="box">
<ul class="special">
<ul class="special">
<li><a href="https://etherpad.org/" target="_blank">Etherpad</a></li>
<li>2</li>
<li><a href="http://www.figlet.org/" target="_blank">FIGlet</a></li>
<li>2</li>
<li><a href="https://ivanceras.github.io/svgbob-editor/" target="_blank">Svgbob.rs</a></li>
@ -265,8 +25,13 @@
<li><a href="https://en.wikipedia.org/wiki/HP-GL" target="_blank">HPGL</a></li>
</ul>
</div>
<div class="box">
<div class="box two-columns">
<div>
<h2>Cobbled paths</h2>
<p>
It is a web interface that brings multiple tools together, to allow experimental and direct collaboration on
pen-plotted drawings by making Ascii art.
</p>
<p>
It makes a way from the blocky discontinuity of Ascii drawings,
to the smoothness of bezier curves,
@ -279,9 +44,8 @@
Like cobbled paths, it is a reminder of the permeability between the discrete and the continuous,
and how regular stones can form tortuous paths.
</p>
</div>
<div class="box">
</div>
<div>
<h2>Handfull links</h2>
<ul class="classic">
<li><a href="http://www.jave.de/figlet/figfont.html">FIGfont Specification</a>, everything about FIGlet font file format</li>
@ -291,6 +55,7 @@
<li><a href="http://www.jave.de/">JavE</a>, an ascii drawing editor</li>
<li><a href="https://adelfaure.net/">adel faure</a>, an ascii artist</li>
</ul>
</div>
</div>
{% endblock %}

242
templates/logo.svg Normal file
View File

@ -0,0 +1,242 @@
<svg xmlns="http://www.w3.org/2000/svg" width="440" height="112" class="svgbob">
<style>.svgbob line, .svgbob path, .svgbob circle, .svgbob rect, .svgbob polygon {
stroke: black;
vector-effect: non-scaling-stroke;
stroke-width: 1.5px;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
.svgbob text {
white-space: pre;
fill: black;
font-family: Iosevka Fixed, monospace;
font-size: 14px;
}
.svgbob rect.backdrop {
stroke: none;
fill: none;
}
.svgbob .broken {
stroke-dasharray: 8;
}
.svgbob .filled {
fill: black;
}
.svgbob .bg_filled {
fill: white;
stroke-width: 1;
}
.svgbob .nofill {
fill: white;
}
.svgbob .end_marked_arrow {
marker-end: url(#arrow);
}
.svgbob .start_marked_arrow {
marker-start: url(#arrow);
}
.svgbob .end_marked_diamond {
marker-end: url(#diamond);
}
.svgbob .start_marked_diamond {
marker-start: url(#diamond);
}
.svgbob .end_marked_circle {
marker-end: url(#circle);
}
.svgbob .start_marked_circle {
marker-start: url(#circle);
}
.svgbob .end_marked_open_circle {
marker-end: url(#open_circle);
}
.svgbob .start_marked_open_circle {
marker-start: url(#open_circle);
}
.svgbob .end_marked_big_open_circle {
marker-end: url(#big_open_circle);
}
.svgbob .start_marked_big_open_circle {
marker-start: url(#big_open_circle);
}
</style>
<defs>
<marker id="arrow" viewBox="-2 -2 8 8" refX="4" refY="2" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<polygon points="0,0 0,4 4,2 0,0"></polygon>
</marker>
<marker id="diamond" viewBox="-2 -2 8 8" refX="4" refY="2" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<polygon points="0,2 2,0 4,2 2,4 0,2"></polygon>
</marker>
<marker id="circle" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<circle cx="4" cy="4" r="2" class="filled"></circle>
</marker>
<marker id="open_circle" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<circle cx="4" cy="4" r="2" class="bg_filled"></circle>
</marker>
<marker id="big_open_circle" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<circle cx="4" cy="4" r="3" class="bg_filled"></circle>
</marker>
</defs>
<rect class="backdrop" x="0" y="0" width="440" height="112"></rect>
<text x="258" y="12">'</text>
<text x="426" y="12">.</text>
<text x="178" y="44">.</text>
<text x="130" y="60">.</text>
<line x1="136" y1="64" x2="168" y2="64" class="solid"></line>
<text x="170" y="60">.'</text>
<text x="266" y="60">.</text>
<text x="314" y="60">.</text>
<text x="50" y="76">`</text>
<text x="90" y="76">:'</text>
<text x="210" y="76">.</text>
<line x1="216" y1="80" x2="224" y2="80" class="solid"></line>
<text x="98" y="92">.</text>
<text x="170" y="92">'</text>
<text x="218" y="92">`</text>
<line x1="224" y1="88" x2="232" y2="88" class="solid"></line>
<text x="250" y="92">.</text>
<text x="330" y="92">.</text>
<g>
<path d="M 24,8 A 8,8 0,0,1 30,12" class="nofill"></path>
<line x1="30" y1="12" x2="32" y2="16" class="solid"></line>
<path d="M 32,8 A 8,8 0,0,0 26,12" class="nofill"></path>
<line x1="26" y1="12" x2="24" y2="16" class="solid"></line>
<line x1="32" y1="8" x2="40" y2="8" class="solid"></line>
<path d="M 40,8 A 8,8 0,0,1 46,12" class="nofill"></path>
<line x1="46" y1="12" x2="48" y2="16" class="solid"></line>
<path d="M 24,16 A 16,16 0,0,0 24,32" class="nofill"></path>
<line x1="24" y1="32" x2="32" y2="32" class="solid"></line>
<path d="M 32,16 A 16,16 0,0,1 32,32" class="nofill"></path>
<path d="M 48,16 A 16,16 0,0,1 48,32" class="nofill"></path>
<line x1="48" y1="32" x2="16" y2="96" class="solid"></line>
<path d="M 16,72 A 8,8 0,0,0 10,76" class="nofill"></path>
<line x1="10" y1="76" x2="8" y2="80" class="solid"></line>
<line x1="16" y1="72" x2="28" y2="72" class="solid"></line>
<path d="M 8,80 A 16,16 0,0,0 8,96" class="nofill"></path>
<line x1="8" y1="96" x2="16" y2="96" class="solid"></line>
</g>
<g>
<line x1="152" y1="0" x2="112" y2="80" class="solid"></line>
<line x1="152" y1="0" x2="156" y2="8" class="solid"></line>
<line x1="156" y1="8" x2="156" y2="84" class="solid"></line>
<path d="M 156,84 A 4,4 0,0,0 160,88" class="nofill"></path>
<line x1="160" y1="88" x2="168" y2="88" class="solid"></line>
<path d="M 88,72 A 8,8 0,0,0 82,76" class="nofill"></path>
<line x1="82" y1="76" x2="80" y2="80" class="solid"></line>
<path d="M 80,80 A 16,16 0,0,0 80,96" class="nofill"></path>
<line x1="80" y1="96" x2="96" y2="96" class="solid"></line>
<path d="M 112,80 A 32,32 0,0,1 96,96" class="nofill"></path>
</g>
<g>
<path d="M 184,8 A 8,8 0,0,1 190,12" class="nofill"></path>
<line x1="190" y1="12" x2="192" y2="16" class="solid"></line>
<path d="M 192,8 A 8,8 0,0,0 186,12" class="nofill"></path>
<line x1="186" y1="12" x2="184" y2="16" class="solid"></line>
<line x1="192" y1="8" x2="256" y2="8" class="solid"></line>
<path d="M 184,16 A 16,16 0,0,0 184,32" class="nofill"></path>
<line x1="184" y1="32" x2="192" y2="32" class="solid"></line>
<path d="M 192,16 A 16,16 0,0,1 192,32" class="nofill"></path>
</g>
<g>
<path d="M 256,0 A 32,32 0,0,1 272,16" class="nofill"></path>
<line x1="272" y1="16" x2="280" y2="32" class="solid"></line>
<path d="M 280,32 A 16,16 0,0,1 280,48" class="nofill"></path>
<line x1="280" y1="48" x2="264" y2="80" class="solid"></line>
<line x1="272" y1="64" x2="312" y2="64" class="solid"></line>
<line x1="320" y1="0" x2="304" y2="32" class="solid"></line>
<path d="M 304,32 A 16,16 0,0,0 304,48" class="nofill"></path>
<line x1="304" y1="48" x2="320" y2="80" class="solid"></line>
<path d="M 320,80 A 32,32 0,0,0 336,96" class="nofill"></path>
<path d="M 248,72 A 8,8 0,0,0 242,76" class="nofill"></path>
<line x1="242" y1="76" x2="240" y2="80" class="solid"></line>
<path d="M 240,80 A 16,16 0,0,0 240,96" class="nofill"></path>
<line x1="240" y1="96" x2="248" y2="96" class="solid"></line>
<path d="M 264,80 A 32,32 0,0,1 248,96" class="nofill"></path>
</g>
<g>
<path d="M 412,8 A 8,8 0,0,0 404,16" class="nofill"></path>
<line x1="412" y1="8" x2="424" y2="8" class="solid"></line>
</g>
<g>
<line x1="56" y1="24" x2="64" y2="24" class="solid"></line>
<path d="M 64,24 A 8,8 0,0,1 70,28" class="nofill"></path>
<line x1="70" y1="28" x2="80" y2="48" class="solid"></line>
<path d="M 80,48 A 16,16 0,0,1 80,64" class="nofill"></path>
<line x1="80" y1="64" x2="78" y2="68" class="solid"></line>
<line x1="56" y1="72" x2="72" y2="72" class="solid"></line>
<path d="M 78,68 A 8,8 0,0,1 72,72" class="nofill"></path>
</g>
<g>
<line x1="112" y1="32" x2="120" y2="32" class="solid"></line>
<path d="M 112,32 A 16,16 0,0,0 112,48" class="nofill"></path>
<line x1="112" y1="48" x2="114" y2="52" class="solid"></line>
<path d="M 114,52 A 8,8 0,0,0 120,56" class="nofill"></path>
</g>
<g>
<line x1="232" y1="16" x2="192" y2="96" class="solid"></line>
<path d="M 192,72 A 8,8 0,0,0 186,76" class="nofill"></path>
<line x1="186" y1="76" x2="184" y2="80" class="solid"></line>
<line x1="192" y1="72" x2="204" y2="72" class="solid"></line>
<path d="M 184,80 A 16,16 0,0,0 184,96" class="nofill"></path>
<line x1="184" y1="96" x2="192" y2="96" class="solid"></line>
</g>
<g>
<line x1="256" y1="32" x2="264" y2="32" class="solid"></line>
<path d="M 256,32 A 16,16 0,0,0 256,48" class="nofill"></path>
<line x1="256" y1="48" x2="258" y2="52" class="solid"></line>
<path d="M 258,52 A 8,8 0,0,0 264,56" class="nofill"></path>
</g>
<g>
<path d="M 328,16 A 16,16 0,0,0 328,32" class="nofill"></path>
<path d="M 328,32 A 16,16 0,0,1 328,48" class="nofill"></path>
<line x1="328" y1="48" x2="326" y2="52" class="solid"></line>
<path d="M 326,52 A 8,8 0,0,1 320,56" class="nofill"></path>
</g>
<g>
<path d="M 368,24 A 8,8 0,0,0 362,28" class="nofill"></path>
<line x1="362" y1="28" x2="360" y2="32" class="solid"></line>
<line x1="368" y1="24" x2="384" y2="24" class="solid"></line>
<path d="M 384,24 A 8,8 0,0,1 390,28" class="nofill"></path>
<line x1="390" y1="28" x2="392" y2="32" class="solid"></line>
<path d="M 360,32 A 16,16 0,0,0 360,48" class="nofill"></path>
<line x1="360" y1="48" x2="362" y2="52" class="solid"></line>
<path d="M 362,52 A 8,8 0,0,0 368,56" class="nofill"></path>
<line x1="368" y1="56" x2="376" y2="56" class="solid"></line>
<path d="M 376,56 A 8,8 0,0,1 382,60" class="nofill"></path>
<line x1="382" y1="60" x2="384" y2="64" class="solid"></line>
<path d="M 384,64 A 16,16 0,0,1 384,80" class="nofill"></path>
<line x1="384" y1="80" x2="382" y2="84" class="solid"></line>
<path d="M 392,24 A 8,8 0,0,0 386,28" class="nofill"></path>
<line x1="386" y1="28" x2="384" y2="32" class="solid"></line>
<line x1="392" y1="24" x2="404" y2="24" class="solid"></line>
<path d="M 412,16 A 8,8 0,0,1 404,24" class="nofill"></path>
<path d="M 384,32 A 16,16 0,0,0 384,48" class="nofill"></path>
<line x1="384" y1="48" x2="392" y2="48" class="solid"></line>
<path d="M 392,32 A 16,16 0,0,1 392,48" class="nofill"></path>
<line x1="344" y1="80" x2="352" y2="80" class="solid"></line>
<path d="M 344,80 A 16,16 0,0,0 344,96" class="nofill"></path>
<line x1="344" y1="96" x2="352" y2="96" class="solid"></line>
<line x1="360" y1="88" x2="352" y2="96" class="solid"></line>
<line x1="360" y1="88" x2="376" y2="88" class="solid"></line>
<path d="M 382,84 A 8,8 0,0,1 376,88" class="nofill"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -41,6 +41,9 @@
font-size: 1rem;
}
.f-svg svg{
overflow: visible;
}
</style>
</head>