@ -0,0 +1,3 @@ |
|||
__pycache__ |
|||
__pycache__/* |
|||
|
@ -0,0 +1,34 @@ |
|||
Iterative Annotation Toolkit: |
|||
---------------------------- |
|||
|
|||
... |
|||
|
|||
|
|||
Shapes Interface: |
|||
---------------- |
|||
|
|||
Copyright (c) 2019 Raph Levien |
|||
|
|||
Permission is hereby granted, free of charge, to any |
|||
person obtaining a copy of this software and associated |
|||
documentation files (the "Software"), to deal in the |
|||
Software without restriction, including without |
|||
limitation the rights to use, copy, modify, merge, |
|||
publish, distribute, sublicense, and/or sell copies of |
|||
the Software, and to permit persons to whom the Software |
|||
is furnished to do so, subject to the following |
|||
conditions: |
|||
|
|||
The above copyright notice and this permission notice |
|||
shall be included in all copies or substantial portions |
|||
of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF |
|||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
|||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
|||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
|||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR |
|||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|||
DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,106 @@ |
|||
# README |
|||
|
|||
## Handles |
|||
|
|||
*Handle number 1: on the systematics of working together at a time (a |
|||
temporary togetherness):* |
|||
|
|||
\- What are/imply the **systematics of working together** that need to |
|||
be established before a process is even set in motion (like the boot |
|||
system in Linux)? |
|||
|
|||
\- How does the **temporality**/chronological evolution of a process |
|||
have a role in establishing *befores*, *durings* and *afters* for a |
|||
groupal endeavor? How do durabilities, recursions, circularities, |
|||
persistences, repetitions and legacies affect the systematics of the |
|||
process themselves? How does **recursiveness, feedbacklooping and |
|||
crooked circularity of collective practices** become systematic, in |
|||
order to hand over of problematics, sensibilities, methods, tools etc.? |
|||
|
|||
*Handle number 2: on the value and problematization of using the pronoun |
|||
\"we\" while inhabiting shared structures*: |
|||
|
|||
\- **Enmeshed and engaged**: What if the we can mean **a bigger |
|||
*****we*** than the people we actually know? Is the problematization of |
|||
the rigid use of \"we\"s a cultural generation, as well as the potential |
|||
of situated revisable collective declarations of being implicated, |
|||
enmeshed or engaged? What are the implications of limiting the use of |
|||
\"we\" in collaborative processes? |
|||
|
|||
\- If the entanglement of persons, collectives, infrastructures, |
|||
institutions and geopgraphies produce temporary structures for work, |
|||
what are th**e degrees of freedom** of such structures? (in other words: |
|||
does this affirmation apply?: \"it can not be that when one person is |
|||
missing the whole system collapses\" |
|||
|
|||
\- Did Iterations provoke a comment/render/actualisation on the notion |
|||
of **the tyranny of structurelessness** proposed years ago by Jo |
|||
Freeman? <https://www.jofreeman.com/joreen/tyranny.htm> |
|||
|
|||
*Handle number 3: material conditions of possibility (on how matters of |
|||
measurement, situatedness, location, age, social class, funding, |
|||
geopolitics, linguistics, communication skills, queerness, |
|||
racialization, ability, sustainability and/or any differential degree in |
|||
relation to the \"normal\" -not necessarily from an identitarist lens- |
|||
affect collective works)*: |
|||
|
|||
\- On engagement, affordances and **material conditions of |
|||
possibility:** Who can afford what, where, why and for how long? what is |
|||
it that makes certain works -and not others- materially possible? |
|||
|
|||
\- What are the **units of measurement for a *****successful*** |
|||
**entanglement?** And how to not read this question with a |
|||
*goodist/*benevolent tone? // this one would require a playful/creative |
|||
problematisation of the notion of \"sucess\" to then stay with it for a |
|||
consideration of its indicators and/or units of measurements at a |
|||
collective scale (knowing that this collectivity will for sure be |
|||
mutant, changing sizes-places and also never taken for granted) |
|||
|
|||
\- \"**How to co-exist, basically**\" How could explicit or implicit |
|||
how-to\'s that were unfolded during all the meetings, exchanges and |
|||
inbetweens be shared for others to try and/or modify? // this one comes |
|||
with a focus on formats. |
|||
|
|||
*Handle number 4: on the moments of transformation, change and mutation: |
|||
handing over, transitional zones, trouble making, etc.* |
|||
|
|||
\- **generative troublematics**: how to make of trouble a generative |
|||
force? // this option would imply to both provisionally |
|||
define/understand what troble is (or not) in cultural creations, and to |
|||
list and unfold its generative forces/potential. |
|||
|
|||
\- **transitional zones**: there have been lots of iterations before |
|||
the project, and hence this one happens as one more transitional zone // |
|||
What does ot mean, to put the focus on the transitional momentum of |
|||
cultural practices, extitutions, the landscape of contemporary |
|||
collaboration with the subjectivities and projectualities that emerged |
|||
with the combination of EU projects and low cost travelling\... and so |
|||
on and so forth? |
|||
|
|||
\- **handover hanging**: \"you should take it but you don\'t have to use |
|||
it\": what is to handover? Are there any thoughts provoked when |
|||
considering the practice of collective response-ability? |
|||
|
|||
**- partial reparation**: what are the needed transformations to change, |
|||
mutate, let go and/or transition by making troubles in order to |
|||
partially repaire the micro, meso and macro structures that produce our |
|||
\"we\"s? |
|||
|
|||
## Annotation tools |
|||
|
|||
`<<iterations documentation from where the contributions were extracted>handles> annotation tools <contributions<handles>>` |
|||
|
|||
\*1 curves \ |
|||
\*2 colors \ |
|||
\*3 text \ |
|||
\*4 visual traces |
|||
|
|||
first, making markers: |
|||
|
|||
* **curves**: What curves are used in this contribution to engage with \*1? |
|||
* **colors**: What colors/color-combinations are used in this contribution to engage with \*2? |
|||
* **text**: Which anecdotes OR questions OR vocabulary/glossary OR tags in this contribution engage with \*3? |
|||
* **visual traces**: Which visual traces can we "cut out" from this contribution, that engage with \*4? |
|||
|
|||
then, annotate: insert/inject markers throughout the publication |
|||
|
@ -0,0 +1,38 @@ |
|||
import json |
|||
|
|||
# different useful functions |
|||
|
|||
# line = '-----------' |
|||
|
|||
# def write_to_file(filename, string): |
|||
# path = './'+filename |
|||
# f = open(path,'a+') |
|||
# f.write(string) |
|||
# f.write('\n') |
|||
# if 'mark' in filename: |
|||
# f.write(line) |
|||
# f.write('\n') |
|||
# f.close() |
|||
|
|||
def load_db(filename): |
|||
try: |
|||
open(filename,'r') |
|||
except: |
|||
open(filename,'w+') |
|||
f = open(filename,'r').read() |
|||
if f == '': |
|||
f = '{}' |
|||
db = json.loads(f) |
|||
# find last_id used in db |
|||
keys = [int(x) for x in db.keys()] |
|||
keys.sort() |
|||
if len(keys) == 0: |
|||
x = 0 |
|||
else: |
|||
x = int(keys[-1]) |
|||
return db, x |
|||
|
|||
def write_db(filename, db): |
|||
f = open(filename, 'w') |
|||
f.write(json.dumps(db, indent=4)) |
|||
f.close() |
@ -0,0 +1,131 @@ |
|||
import os, json |
|||
from flask import Markup |
|||
|
|||
import tfidf |
|||
|
|||
from nltk import tokenize, pos_tag, RegexpTokenizer |
|||
tokenizer = RegexpTokenizer(r'\w+') # initialize tokenizer |
|||
|
|||
import pprint |
|||
pp = pprint.PrettyPrinter(indent=4) |
|||
|
|||
def load_index(): |
|||
if os.path.isfile('index.json') == False: |
|||
tfidf.create_index() |
|||
f = open('index.json').read() |
|||
index = json.loads(f) |
|||
return index |
|||
|
|||
def get_random(x, y): |
|||
from random import randint |
|||
return randint(x, y) |
|||
|
|||
def generate_random_rgb(): |
|||
r = get_random(0, 255) |
|||
g = get_random(0, 255) |
|||
b = get_random(0, 255) |
|||
return r, g, b |
|||
|
|||
def get_pos(): |
|||
# --- |
|||
# Note: NLTK provides documentation for each tag, |
|||
# which can be queried using the tag, e.g. |
|||
# nltk.help.upenn_tagset('RB'), or a regular expression, |
|||
# e.g. nltk.help.upenn_tagset('NN.*'). Some corpora |
|||
# have README files with tagset documentation, |
|||
# see nltk.corpus.???.readme(), substituting in the name |
|||
# of the corpus. -- http://www.nltk.org/book/ch05.html |
|||
# --- |
|||
|
|||
# data { |
|||
# 'word' : { |
|||
# 'count' : 8, |
|||
# 'sentences' : { |
|||
# 'filename' : [ |
|||
# 'This is a sentence.', |
|||
# 'This is another sentence.' |
|||
# ] |
|||
# } |
|||
# } |
|||
# } |
|||
|
|||
index = load_index() |
|||
sentences_all = [index[document]['sentences'] for document, _ in index.items()] |
|||
data = {} |
|||
data['ADJ'] = {} |
|||
data['PRE'] = {} |
|||
filenames = [filename for filename, _ in index.items()] |
|||
# print(filenames) |
|||
for i, sentences in enumerate(sentences_all): |
|||
r, g, b = generate_random_rgb() |
|||
for sentence in sentences: |
|||
pos = pos_tag(tokenizer.tokenize(sentence)) |
|||
# print(pos) |
|||
for word, tag in pos: |
|||
if 'JJ' in tag: |
|||
# --- |
|||
# JJ: adjective or numeral, ordinal |
|||
# For example: third ill-mannered pre-war regrettable oiled calamitous first separable |
|||
# ectoplasmic battery-powered participatory fourth still-to-be-named |
|||
# multilingual multi-disciplinary ... |
|||
if word.lower() not in data['ADJ']: |
|||
data['ADJ'][word.lower()] = {} |
|||
if 'sentences' not in data['ADJ'][word.lower()]: |
|||
data['ADJ'][word.lower()]['sentences'] = {} |
|||
if filenames[i] not in data['ADJ'][word.lower()].keys(): |
|||
data['ADJ'][word.lower()]['sentences'][filenames[i]] = [] |
|||
s = Markup(sentence.replace(word, '<strong class="query" style="color:rgba({r},{g},{b},1); background-image: radial-gradient(ellipse, rgba({r},{g},{b},0.4), rgba({r},{g},{b},0.2), transparent, transparent);">{word}</strong>'.format(r=r, b=b, g=g, word=word))) |
|||
if s not in data['ADJ'][word.lower()]['sentences'][filenames[i]]: |
|||
data['ADJ'][word.lower()]['sentences'][filenames[i]].append(s) |
|||
if 'TO' in tag or 'IN' in tag: |
|||
# --- |
|||
# TO: "to" as preposition (voorzetsel) or infinitive marker (oneindige beïnvloeder?) |
|||
# For example: to |
|||
# --- |
|||
# IN: preposition or conjunction (voegwoord, samenstelling, verbinding), subordinating (ondergeschikt) |
|||
# For example: astride among uppon whether out inside pro despite on by throughout |
|||
# below within for towards near behind atop around if like until below |
|||
# next into if beside ... |
|||
# --- |
|||
if word.lower() not in data['PRE']: |
|||
data['PRE'][word.lower()] = {} |
|||
if 'sentences' not in data['PRE'][word.lower()]: |
|||
data['PRE'][word.lower()]['sentences'] = {} |
|||
if filenames[i] not in data['PRE'][word.lower()]['sentences'].keys(): |
|||
data['PRE'][word.lower()]['sentences'][filenames[i]] = [] |
|||
s = Markup(sentence.replace(word, '<strong class="query" style="color:rgba({r},{g},{b},1); background-image: radial-gradient(ellipse, rgba({r},{g},{b},0.4), rgba({r},{g},{b},0.2), transparent, transparent);">{word}</strong>'.format(r=r, b=b, g=g, word=word))) |
|||
if s not in data['PRE'][word.lower()]['sentences'][filenames[i]]: |
|||
data['PRE'][word.lower()]['sentences'][filenames[i]].append(s) |
|||
|
|||
# count number of results for each word |
|||
for word_type, words in data.items(): |
|||
for word, _ in words.items(): |
|||
# print(filenames) |
|||
count = 0 |
|||
for filename, sentences in data[word_type][word]['sentences'].items(): |
|||
# print(filename) |
|||
count += len(sentences) |
|||
data[word_type][word.lower()]['count'] = count |
|||
count = 0 |
|||
|
|||
data_sorted = {} |
|||
for word_type, words in data.items(): |
|||
tmp = [] |
|||
for word, _ in words.items(): |
|||
count = data[word_type][word.lower()]['count'] |
|||
tmp.append([count, word]) |
|||
i = 0 |
|||
tmp.sort(reverse=True) |
|||
print('tmp', tmp) |
|||
for count, word in tmp: |
|||
if word_type not in data_sorted: |
|||
data_sorted[word_type] = {} |
|||
data_sorted[word_type][i] = {} |
|||
data_sorted[word_type][i][word.lower()] = data[word_type][word.lower()] |
|||
i += 1 |
|||
|
|||
print(data_sorted) |
|||
return data_sorted, index |
|||
|
|||
# data, index = get_pos() |
|||
# pp.pprint(data) |
@ -0,0 +1,148 @@ |
|||
#!/usr/bin/env python3 |
|||
|
|||
import sys, os |
|||
import flask |
|||
from flask import request, redirect, url_for |
|||
from werkzeug.utils import secure_filename |
|||
|
|||
from functions import * |
|||
import readings |
|||
# import create_index |
|||
import tfidf |
|||
|
|||
from flaskext.markdown import Markdown |
|||
|
|||
# Upload settings |
|||
UPLOAD_FOLDER_TRACES = 'static/visual-traces/' |
|||
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} |
|||
|
|||
# Create the application. |
|||
APP = flask.Flask(__name__) |
|||
APP.config['UPLOAD_FOLDER_TRACES'] = UPLOAD_FOLDER_TRACES |
|||
Markdown(APP) |
|||
|
|||
tools = [ |
|||
"curves", |
|||
"color", |
|||
"text", |
|||
"visual-traces" |
|||
] |
|||
|
|||
def allowed_file(filename): |
|||
return '.' in filename and \ |
|||
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS |
|||
|
|||
@APP.route('/', methods=['GET']) |
|||
def index(): |
|||
return flask.render_template('index.html', tools=tools) |
|||
|
|||
@APP.route('/text/', methods=['GET', 'POST']) |
|||
def text(): |
|||
marker = request.args.get('marker', '').strip() |
|||
markertype = request.args.get('marker-type', '').strip() |
|||
db, x = load_db('text.json') |
|||
markers = [db[x]['marker'] for x in db.keys()] |
|||
|
|||
if marker: |
|||
if marker not in markers: |
|||
x = str(x + 1) |
|||
db[x] = {} |
|||
db[x]['marker'] = marker |
|||
db[x]['type'] = markertype |
|||
write_db('text.json', db) |
|||
|
|||
markers.append(marker) |
|||
|
|||
return flask.render_template('text.html', tools=tools, tool='text', db=db) |
|||
|
|||
@APP.route('/color/', methods=['GET', 'POST']) |
|||
def color(): |
|||
color = request.args.get('color', '').strip() |
|||
db, x = load_db('colors.json') |
|||
colors = [db[x]['color'] for x in db.keys()] |
|||
|
|||
if color: |
|||
if color not in colors: |
|||
x = str(x + 1) |
|||
db[x] = {} |
|||
db[x]['color'] = color |
|||
write_db('colors.json', db) |
|||
colors.append(color) |
|||
|
|||
return flask.render_template('color.html', tools=tools, tool='color',db=db) |
|||
|
|||
@APP.route('/curves/', methods=['GET', 'POST']) |
|||
def curves(): |
|||
curve = request.args.get('curve', '').strip() |
|||
db, x = load_db('curves.json') |
|||
curves = [db[x]['curve'] for x in db.keys()] |
|||
|
|||
if curve: |
|||
if curve not in curves: |
|||
x = str(x + 1) |
|||
filename = '{}.svg'.format(x) |
|||
db[x] = {} |
|||
db[x]['curve'] = curve |
|||
db[x]['filename'] = filename |
|||
write_db('curves.json', db) |
|||
curves.append(curve) |
|||
with open('static/curves/{}'.format(filename), 'w+') as f: |
|||
f.write(curve) |
|||
|
|||
return flask.render_template('curves.html', tools=tools, tool='curves', db=db) |
|||
|
|||
@APP.route('/visual-traces/', methods=['GET', 'POST']) |
|||
def traces(): |
|||
db, x = load_db('visual-traces.json') |
|||
traces = [db[x]['trace'] for x in db.keys()] |
|||
|
|||
if request.method == 'POST': |
|||
if 'trace' not in request.files: |
|||
return redirect(request.url) |
|||
trace = request.files['trace'] |
|||
if trace.filename == '': |
|||
return redirect(request.url) |
|||
if trace and allowed_file(trace.filename): |
|||
filename = secure_filename(trace.filename) |
|||
trace.save(os.path.join(APP.config['UPLOAD_FOLDER_TRACES'], filename)) |
|||
|
|||
if filename not in traces: |
|||
x = str(x + 1) |
|||
db[x] = {} |
|||
db[x]['trace'] = filename |
|||
write_db('visual-traces.json', db) |
|||
traces.append(filename) |
|||
|
|||
return flask.render_template('visual-traces.html', tools=tools, tool='visual-traces', db=db) |
|||
|
|||
from flask import send_from_directory |
|||
|
|||
@APP.route('/visual-traces/<filename>') |
|||
def uploaded_file(filename): |
|||
return send_from_directory(APP.config['UPLOAD_FOLDER_TRACES'], filename) |
|||
|
|||
@APP.route('/text-scans/', methods=['GET', 'POST']) |
|||
def textscan(): |
|||
results = {} |
|||
data, index = readings.get_pos() |
|||
return flask.render_template('text-scans.html', tools=tools, data=data, index=index, results=results) |
|||
|
|||
@APP.route('/text-scans/<word_type>/<word>', methods=['GET', 'POST']) |
|||
def textscanresults(word_type, word): |
|||
data, index = readings.get_pos() |
|||
for ranking, words in data[word_type].items(): |
|||
for w in words.keys(): |
|||
if w == word: |
|||
results = data[word_type][ranking][word.lower()] |
|||
filenames = [document for document, _ in index.items()] |
|||
return flask.render_template('text-scans.html', tools=tools, data=data, results=results, filenames=filenames, word=word, word_type=word_type) |
|||
|
|||
# @APP.route('/text-specifics/', methods=['GET', 'POST']) |
|||
# def specifics(): |
|||
# index = readings.load_index() |
|||
|
|||
# return flask.render_template('text-specifics.html', tools=tools, index=index) |
|||
|
|||
if __name__ == '__main__': |
|||
APP.debug=True |
|||
APP.run(port=5000) |
@ -0,0 +1,2 @@ |
|||
# (backcover) {.hidden} |
|||
|
@ -0,0 +1 @@ |
|||
# COLOPHON {.hidden} |
@ -0,0 +1,3 @@ |
|||
# Iterations {.hidden} |
|||
|
|||
![](images/cover.png) |
@ -0,0 +1,34 @@ |
|||
# INDEX {.hidden} |
|||
|
|||
## curves |
|||
|
|||
|marker|description|used on page| |
|||
|------|-----------|------------| |
|||
|<svg class="curve" width="640" height="480" pointer-events="all"><path id="ctrlpoly" d="" stroke="none" fill="none"></path> <path id="spline" d="M163 338.1333312988281C166.3390650589426 377.33764866760094 185.8241288302834 419.2715210141457 223 436.1333312988281C290.8955766536773 466.92863741221936 366.4172533672779 390.7910761939944 405 331.1333312988281C405.6666666666667 284.46666463216144 406.3333333333333 237.79999796549478 407 191.13333129882812C359.3333333333333 170.46666463216147 311.66666666666663 149.79999796549478 264 129.13333129882812C250.33333333333334 161.13333129882812 236.66666666666666 193.13333129882812 223 225.13333129882812" stroke="black" fill="none" stroke-width="2"></path> <path id="spline2" d="" stroke="blue" fill="none" stroke-width="2"></path> <g id="handles"><g class="handle" transform="translate(163 338.1333312988281)"><rect x="-4" y="-4" width="8" height="8" class="handle"></rect></g><g class="handle" transform="translate(223 436.1333312988281)"><circle cx="0" cy="0" r="4" class="handle"></circle></g><g class="handle" transform="translate(405 331.1333312988281)"><rect x="-4" y="-4" width="8" height="8" class="handle"></rect></g><g class="handle" transform="translate(407 191.13333129882812)"><rect x="-4" y="-4" width="8" height="8" class="handle"></rect></g><g class="handle" transform="translate(264 129.13333129882812)"><rect x="-4" y="-4" width="8" height="8" class="handle"></rect></g><g class="handle selected" transform="translate(223 225.13333129882812)"><rect x="-4" y="-4" width="8" height="8" class="handle"></rect><line pointer-events="none" x1="0" y1="0" class="tan" x2="4.713153967092374" y2="-11.035677581484583"></line><circle r="3" class="tanhandle computed" cx="5.891442458865469" cy="-13.794596976855729"></circle></g></g> <g id="plots"></g></svg>|curved voices|14| |
|||
|
|||
## colors |
|||
|
|||
|marker|description|used on page| |
|||
|------|-----------|------------| |
|||
|<span class="color marker" style="background-color: yellow;"></span>|moments of friction|3| |
|||
|<span class="color marker" style="background-color: red;"></span>|moments of friction|3| |
|||
|<span class="color marker" style="background-color: red;"></span>|moments of friction|3| |
|||
|<span class="color marker" style="background-color: red;"></span>|moments of friction|3| |
|||
|<span class="color marker" style="background-color: red;"></span>|moments of friction|3| |
|||
|<span class="color marker" style="background-color: blue;"></span>|moments of friction|3| |
|||
|<span class="color marker" style="background-color: pink;"></span>|moments of friction|3| |
|||
|<span class="color marker" style="background-color: magenta;"></span>|moments of friction|3| |
|||
|
|||
## text |
|||
|
|||
|marker|description|used on page| |
|||
|------|-----------|------------| |
|||
|(tag) infrastructure|relating to the infrastructures used .....|5| |
|||
|
|||
## visual traces |
|||
|
|||
|marker|description|used on page| |
|||
|------|-----------|------------| |
|||
|![](markers/visual-trace-1-cut.png)|amplification of voice|14| |
|||
|![](markers/visual-trace-1-cut.png)|amplification of voice|14| |
|||
|![](markers/visual-trace-1-cut.png)|amplification of voice|14| |
@ -0,0 +1,107 @@ |
|||
# README {.hidden} |
|||
|
|||
## Handles |
|||
|
|||
\* |
|||
|
|||
*Handle number 1: on the systematics of working together at a time (a |
|||
temporary togetherness):* |
|||
|
|||
\- What are/imply the **systematics of working together** that need to |
|||
be established before a process is even set in motion (like the boot |
|||
system in Linux)? |
|||
|
|||
\- How does the **temporality**/chronological evolution of a process |
|||
have a role in establishing *befores*, *durings* and *afters* for a |
|||
groupal endeavor? How do durabilities, recursions, circularities, |
|||
persistences, repetitions and legacies affect the systematics of the |
|||
process themselves? How does **recursiveness, feedbacklooping and |
|||
crooked circularity of collective practices** become systematic, in |
|||
order to hand over of problematics, sensibilities, methods, tools etc.? |
|||
|
|||
*Handle number 2: on the value and problematization of using the pronoun |
|||
\"we\" while inhabiting shared structures*: |
|||
|
|||
\- **Enmeshed and engaged**: What if the we can mean **a bigger |
|||
*****we*** than the people we actually know? Is the problematization of |
|||
the rigid use of \"we\"s a cultural generation, as well as the potential |
|||
of situated revisable collective declarations of being implicated, |
|||
enmeshed or engaged? What are the implications of limiting the use of |
|||
\"we\" in collaborative processes? |
|||
|
|||
\- If the entanglement of persons, collectives, infrastructures, |
|||
institutions and geopgraphies produce temporary structures for work, |
|||
what are th**e degrees of freedom** of such structures? (in other words: |
|||
does this affirmation apply?: \"it can not be that when one person is |
|||
missing the whole system collapses\" |
|||
|
|||
\- Did Iterations provoke a comment/render/actualisation on the notion |
|||
of **the tyranny of structurelessness** proposed years ago by Jo |
|||
Freeman? <https://www.jofreeman.com/joreen/tyranny.htm> |
|||
|
|||
*Handle number 3: material conditions of possibility (on how matters of |
|||
measurement, situatedness, location, age, social class, funding, |
|||
geopolitics, linguistics, communication skills, queerness, |
|||
racialization, ability, sustainability and/or any differential degree in |
|||
relation to the \"normal\" -not necessarily from an identitarist lens- |
|||
affect collective works)*: |
|||
|
|||
\- On engagement, affordances and **material conditions of |
|||
possibility:** Who can afford what, where, why and for how long? what is |
|||
it that makes certain works -and not others- materially possible? |
|||
|
|||
\- What are the **units of measurement for a *****successful*** |
|||
**entanglement?** And how to not read this question with a |
|||
*goodist/*benevolent tone? // this one would require a playful/creative |
|||
problematisation of the notion of \"sucess\" to then stay with it for a |
|||
consideration of its indicators and/or units of measurements at a |
|||
collective scale (knowing that this collectivity will for sure be |
|||
mutant, changing sizes-places and also never taken for granted) |
|||
|
|||
\- \"**How to co-exist, basically**\" How could explicit or implicit |
|||
how-to\'s that were unfolded during all the meetings, exchanges and |
|||
inbetweens be shared for others to try and/or modify? // this one comes |
|||
with a focus on formats. |
|||
|
|||
*Handle number 4: on the moments of transformation, change and mutation: |
|||
handing over, transitional zones, trouble making, etc.* |
|||
|
|||
\- **generative troublematics**: how to make of trouble a generative |
|||
force? // this option would imply to both provisionally |
|||
define/understand what troble is (or not) in cultural creations, and to |
|||
list and unfold its generative forces/potential. |
|||
|
|||
\- **transitional zones**: there have been lots of iterations before |
|||
the project, and hence this one happens as one more transitional zone // |
|||
What does ot mean, to put the focus on the transitional momentum of |
|||
cultural practices, extitutions, the landscape of contemporary |
|||
collaboration with the subjectivities and projectualities that emerged |
|||
with the combination of EU projects and low cost travelling\... and so |
|||
on and so forth? |
|||
|
|||
\- **handover hanging**: \"you should take it but you don\'t have to use |
|||
it\": what is to handover? Are there any thoughts provoked when |
|||
considering the practice of collective response-ability? |
|||
|
|||
**- partial reparation**: what are the needed transformations to change, |
|||
mutate, let go and/or transition by making troubles in order to |
|||
partially repaire the micro, meso and macro structures that produce our |
|||
\"we\"s? |
|||
|
|||
## Annotation tools |
|||
|
|||
`<<iterations documentation from where the contributions were extracted>handles> annotation tools <contributions<handles>>` |
|||
|
|||
\*1 curves \ |
|||
\*2 colors \ |
|||
\*3 text \ |
|||
\*4 visual traces |
|||
|
|||
first, making markers: |
|||
|
|||
* **curves**: What curves are used in this contribution to engage with \*1? |
|||
* **colors**: What colors/color-combinations are used in this contribution to engage with \*2? |
|||
* **text**: Which anecdotes OR questions OR vocabulary/glossary OR tags in this contribution engage with \*3? |
|||
* **visual traces**: Which visual traces can we "cut out" from this contribution, that engage with \*4? |
|||
|
|||
then, annotate: insert/inject markers throughout the publication |
@ -0,0 +1,12 @@ |
|||
# TOC {.hidden} |
|||
|
|||
| |page| |
|||
|------|----| |
|||
|README|2| |
|||
|INTRODUCTION|2| |
|||
|Iteration #5|2| |
|||
|Rica Rickson|2| |
|||
|score esc|2| |
|||
|Collective Conditions: three documents|2| |
|||
|spideralex|2| |
|||
|INDEX|2| |
@ -0,0 +1,585 @@ |
|||
Collective Conditions: three documents |
|||
====================================== |
|||
|
|||
This contribution consists of three documents which emerged from the |
|||
worksession *Collective Conditions*, an experiment with the generative |
|||
potential of socio-technical protocols such as codes of conduct, |
|||
complaint procedures, bug reports and copyleft licenses. Constant's |
|||
worksessions are temporary research labs, intensive collective |
|||
environments where different types of expertise can come into contact |
|||
with each other. To these otherwise-disciplined situations, artists, |
|||
software developers, theorists, activists and others are invited to |
|||
contribute.[^1] |
|||
|
|||
*Collective Conditions* was activated by the work of trans\*feminist |
|||
collectives on ally-ship, non-violent communication, score-making, |
|||
anti-colonial and intersectional activism, but also by ways of doing |
|||
developed within Free Culture and Free, Libre and Open Source software. |
|||
Out of commitment to the socio-technical protocols that these |
|||
collectives propose to intervene in cultures of harassment, we wanted to |
|||
take serious the role they might play in the (different) imagination of |
|||
complex collectivities. |
|||
|
|||
The need to formulate protocols is felt urgently within on-line |
|||
collectives, that operate on the intersection of social practice and |
|||
technological infrastructures and run up against the limits of |
|||
'openness' and 'freedom'. Protocols have a tendency to focus energy on |
|||
discursive processes, rather than building concrete skills and practices |
|||
within groups and across participants. This worksession therefore |
|||
introduced different modes of 'writing' to challenge, make stumble and |
|||
collide; that posed questions and problems. We experimented with |
|||
feminist tango, self-determined objects, translanguaging, Tango |
|||
Thermique, fragile community scores, micro-lectures and an acapella |
|||
proto-anarcho post-punk operetta featuring Queering Damage songs. |
|||
|
|||
Participants shared various degrees of concern with the possibility that |
|||
we could be re-instating a 'new normal'. The figure of 'complex |
|||
collectivity' helped to articulate these concerns in a way that we could |
|||
imagine ally-ship as a non-equalizing form of togetherness. What |
|||
protocols would for example work for non-normative human constellations, |
|||
or collectives where participants with radically different needs, |
|||
backgrounds and agencies come together? What different needs do 'complex |
|||
collectives' have when they are the result of structural forces such as |
|||
laws, racism, technology, wars, austerity, queerphobia and ecological |
|||
conditions? |
|||
|
|||
We also wondered about how our self-invented protocols might too easily |
|||
repeat law-like ways of doing. We felt we needed to pay attention to how |
|||
they are implemented, to not eventually reiterate the carceral logic of |
|||
victimization and punishment which we felt perpetuates and multiplies |
|||
harm. We made a start with working through non-divisive ways of dealing |
|||
with codes of conduct, complaints procedures, bug reports and copyleft |
|||
licenses, trying to go beyond ostracization and exclusion. |
|||
|
|||
The three documents that follow respond each in their own way to the |
|||
complex challenge of collective conditions. The first document is the |
|||
***Manifesto of Cares*** which emerged as a response to a proposition by |
|||
Elodie Mugrefya and Olave Nduwanje, *Writing manifesto of rest/care*. |
|||
The text was partially written during the worksession, and finished in |
|||
the months after. This first version of the manifesto aims to reclaim |
|||
care as a critical practice, and "reaches out to people who haven\'t |
|||
thought about the social economical racial gendered implications of |
|||
cares, and is also for the people who wish to reinvigorate their cares |
|||
patterns.". The second document is a splash page for ***Bibliostrike***, |
|||
a situated version of the Bibliotecha local digital library set-up. |
|||
During the worksession, a version of Bibliothecha was installed together |
|||
with etherbox[^2]. The shared infrastructure was adjusted, |
|||
re-articulated and weaponized to join the picketline of the University |
|||
and college strikes in the UK. The third and last documents are related |
|||
to the ongoing discussions around the ***Constant Collaboration |
|||
Guidelines***[^3]. The guidelines were tested for the first time during |
|||
*Collective Conditions* and discussed before and after with several |
|||
groups. Constant committed to keep adjusting these guidelines; the |
|||
included document traces the different problems and questions that have |
|||
came up. |
|||
|
|||
## Manifesto of cares |
|||
|
|||
**[Commitment to Cares, Why to commit to care?]{.underline}** |
|||
|
|||
We are a group of intersectional trans\*feminists coming together in the |
|||
context of Collective Conditions, a worksession organised by Constant, |
|||
in Brussels the winter of 2019. We gathered around the notion of cares |
|||
to further understand our relationship to cares in our shifting |
|||
contexts. We are concerned with the urgency of this moment because we |
|||
have noticed that many in positions of power are doing little to enact |
|||
cares. As for us, we are in positions where we can enact contextualized |
|||
cares and we want to revive our commitment towards cares as critical |
|||
practices. We need to talk about cares, not because they don't exist, |
|||
but because cares are not distributed equally, and because to 'take |
|||
care' can have multiple meanings depending on positions of privilege, |
|||
context and who and what we're dealing with. This manifesto is a demand |
|||
towards those subjects within institutional frameworks to reflect on |
|||
their relationship towards the giving, taking, receiving cares, to |
|||
question well worn patterns of cares, and how they can be re-inscribed. |
|||
This manifesto reaches out to people who haven\'t thought about the |
|||
social economical racial gendered implications of cares, and is also for |
|||
the people who wish to reinvigorate their cares patterns. |
|||
|
|||
[**\ |
|||
Caring** **requires**]{.underline} |
|||
|
|||
- active concern, mindfulness and commitment towards all living and |
|||
non living entities. |
|||
|
|||
- attention to entangled environments: physical, digital, |
|||
interpersonal, ecological, and those we share them with. |
|||
|
|||
- attention towards individuals and communities. |
|||
|
|||
- not presuming and asking for different needs. |
|||
|
|||
- time and the understanding of time\'s multidimensional nature. |
|||
|
|||
- actions, not expected services. |
|||
|
|||
- deep listening.[^4] |
|||
|
|||
- patience. |
|||
|
|||
- courage and responsibility. |
|||
|
|||
- multiple interpretations and possibilities. |
|||
|
|||
- \... not knowing what caring might mean. |
|||
|
|||
- to be taken seriously and to take seriously. |
|||
|
|||
- Acknowledgment. |
|||
|
|||
[]{.underline} |
|||
|
|||
**[The state of cares]{.underline}** |
|||
|
|||
[]{.underline} |
|||
|
|||
Caring is: |
|||
|
|||
- Caring is deeply entwined in power relations and not equally |
|||
distributed. |
|||
|
|||
- Caring is currently hegemonic: some have the agency to impose a |
|||
constricting meaning and practice of cares, on behalf of others. |
|||
|
|||
- Caring is subsumed within capitalist frameworks that create the |
|||
conditions for care workers to have less agency and not be |
|||
represented in what they are employed to do. |
|||
|
|||
- Caring is in a false dichotomy of productive/reproductive labour. |
|||
|
|||
- Caring is chronically undervalued. |
|||
|
|||
- Caring is deeply entwined in institutional engagement or lack |
|||
thereof. |
|||
|
|||
- Our society produces vacuums of cares in places where they are |
|||
needed. |
|||
|
|||
- Caring is underdeveloped in institutional contexts. |
|||
|
|||
- Caring is something that cannot be outsourced. |
|||
|
|||
Caring is not a tool.\ |
|||
Cares cannot be instrumentalised.\ |
|||
Cares cannot be generalized.\ |
|||
Cares cannot be constricted by normativity.\ |
|||
Caring cannot be conditional.\ |
|||
Cares are antimanifesto. |
|||
|
|||
**[Outlook of cares]{.underline}** |
|||
|
|||
[]{.underline} |
|||
|
|||
If things stay this way ... |
|||
|
|||
- the tyranny of self-help models of survival will undermine the |
|||
formation of solidarity and collective power. |
|||
|
|||
- we\'ll be suspended in precarious modes of surviving which |
|||
capitalizes on our failures. |
|||
|
|||
- caring will continue to be performed by those who are exploited by |
|||
contemporary slavery. |
|||
|
|||
- slavery will continue to be reproduced as the insidious institution |
|||
that it has always been. |
|||
|
|||
- the continued burning out of those who do the caring will exhaust |
|||
the possibilities of cares that still currently exist. |
|||
|
|||
- there will be a proliferation of ego-centrist hedonists and hoarders |
|||
of goods, wealth, status and power. |
|||
|
|||
- we risk to all become facsimiles of whiteness: greedy, extractive |
|||
and exploitative. |
|||
|
|||
- the logics of extractivism will continue to intensify, spurring |
|||
man-made ecological disasters disproportionately impacting certain |
|||
geographies, geosystems and ecosystems. |
|||
|
|||
- persons, groups, ecosystems, identities will continue to be |
|||
subjected to the violence of categorisation, victimization, |
|||
commodification and marginalisation. |
|||
|
|||
- the end of humanity and the destruction of the ecosystems is |
|||
inevitable. |
|||
|
|||
**[Envisioning Cares]{.underline}** |
|||
|
|||
[]{.underline} |
|||
|
|||
Challenging the current trajectory of cares, we demand now a future in |
|||
which ... |
|||
|
|||
- all living and non living entities are acknowledged as valuable and |
|||
worthy of care. |
|||
|
|||
- the emotional, physical, philosophical and social realities of all |
|||
living beings have abundant expressions. |
|||
|
|||
- living matters will have space to discover their own agencies. |
|||
|
|||
- trees, plants, lands, oceans, river, water, rocks, mountains are |
|||
acknowledged in reciprocal caring relationships |
|||
|
|||
- there is commitment to the work of making ecologically conscious |
|||
decisions |
|||
|
|||
- nation states, borders and advertisement will be abolished in the |
|||
service of equal opportunity for all living and non living entities. |
|||
|
|||
- value is shaped in do-it-together (DIT) collective bottom-up modes. |
|||
|
|||
- institutional, governmental, corporate agents of power will be |
|||
transformed into self-determined agencies. |
|||
|
|||
- desire, love, sex, relationships and cares are liberated with modes |
|||
of enthusiastic consent and freedom to abstain. |
|||
|
|||
- consent is not presumed and crucial to all relationships |
|||
|
|||
- touch implies addressing consent |
|||
|
|||
- cares are mutual, shared across groups, individuals, beings and |
|||
entities according to varying needs, skills, capacities and |
|||
possibilities. |
|||
|
|||
- caring roles exist outside normalised power dynamics |
|||
|
|||
- notions of cares continue to be discussed, to change and to be |
|||
adapted. |
|||
|
|||
**[Crafts of Cares]{.underline}** |
|||
|
|||
[]{.underline} |
|||
|
|||
Possible practices: |
|||
|
|||
- Cultivate curiosity; to care is to be curious, curious enough to |
|||
ask. |
|||
|
|||
- Be humble, humble enough to abandon assumptions. |
|||
|
|||
- Cultivate gentleness, gentle enough to be asked |
|||
|
|||
- Move towards disassembled and loosely structured, interchangeable |
|||
meshwork of enacted communities. |
|||
|
|||
- Acknowledge and deconstruct privileges. |
|||
|
|||
- Be open about failures. |
|||
|
|||
- Cultivating practices of abundance rather than hoarding. |
|||
|
|||
- Value those who do the caring. |
|||
|
|||
- Pay salaries to those who do the caring. |
|||
|
|||
- Value / pay for restorative care to heal deficits of cares. |
|||
|
|||
- Value/pay those who do domestic work. |
|||
|
|||
- Value/pay those who do the child rearing. |
|||
|
|||
- Value/pay those who do the teaching. |
|||
|
|||
- Value/pay those who are the caretakers of spaces. |
|||
|
|||
- Illegalise shareholder models and corporations. |
|||
|
|||
- Denormalise existing structures and power relationships. |
|||
|
|||
- Root power directly within communities to counter historic hoardings |
|||
of power. |
|||
|
|||
- Multiply agencies for new interpretations of cares. |
|||
|
|||
- Commit to activist, sensitive lives; nurturing and facilitating each |
|||
other\'s talents and dreams. |
|||
|
|||
## B I B L I O S T R I K E |
|||
|
|||
Welcome to the picket line and bibliostrike! |
|||
|
|||
(╯°□°)╯︵ ┻━┻ |
|||
|
|||
A bibliostrike is a place to make acts of solidarity, dreaming, |
|||
counter-optimisation, futuring, past-ing and present-ing at the |
|||
picket-line. |
|||
|
|||
It is a potential place for meeting on the picket line through |
|||
liberating texts from behind paywalls, walled gardens and isolated |
|||
libraries. |
|||
|
|||
Why not, it is also a place to create your own documentation of your |
|||
greatest chats, hottest book recommendations and most subversive lines |
|||
of thought? |
|||
|
|||
It is an invitation and the result of collective conditions with the |
|||
intention of (in)forming strategies of resistance, including with |
|||
respect to the (academic) publication industries. |
|||
|
|||
As academics and their allies, we benefit from these neoliberal sites of |
|||
publication, as well as the open or liberated sites which are |
|||
illegalized, with great costs and personal risks to those who maintain |
|||
those infrastructures. |
|||
|
|||
Bibliostrike is a re-orientation towards different infrastructures of |
|||
distribution that resist the many ways in which current |
|||
biblio-technological practices come to optimise knowledge resource |
|||
allocation to benefit a few. |
|||
|
|||
For instance, the new business model of academic publishers is pivoting |
|||
towards "knowledge products" and "information analytics" based on the |
|||
capture of trends on publication "sharing" sites like Researchgate as |
|||
well as Mendeley and SSRN (the latter owned by Elsevier which now |
|||
defines itself as a tech company). |
|||
|
|||
Bibliostrike allows you to access and distribute texts without the nasty |
|||
analytics, free of the bubbly promises of narrow minded predictions, and |
|||
exploitative business models. To do so you can use the link above. To |
|||
read texts, you can just use your browser, if you wish you can download |
|||
the resources, and if you want you can upload your own to share with |
|||
others on the picket-line. You can also curate your special shelves for |
|||
tech-outs, protests, and campaigns. |
|||
|
|||
There is a legal regime which casts a long shadow over the practices we |
|||
promote here. "To be clear", the upload and download of materials that |
|||
fall under the copyright regime is not legal. For those of you for whom |
|||
this risk is concerning, we encourage you to inform yourself about the |
|||
different liberating struggles like copyfight, open access, free |
|||
licenses of distribution, the public domain and orphan books, among |
|||
others. These struggles come with many ways in which you can come to |
|||
resist neoliberal publication practices and industries within legal |
|||
boundaries. |
|||
|
|||
Bibliotecha is a framework built by queer feminist activist groups which |
|||
see technical justice a inseparable part of social justice. It relies on |
|||
a microcomputer running open-source software to serve books over a local |
|||
wifi hotspot. Using the browser to connect to the library one can |
|||
retrieve or donate texts. |
|||
|
|||
## Constant Collaboration Guidelines: Questions and problems |
|||
|
|||
**26 September → 25 November 2019 / Constant\_V: Collaboration |
|||
Guidelines** |
|||
|
|||
- Various comments, graffiti, corrections, appreciations, suggestions on the window of Constant\'s office.[^5] |
|||
|
|||
`Look at the images of the comments on the window, read the texts and see if anything is important to implement in the guidelines.` |
|||
|
|||
**\ |
|||
08 → 16 November 2019 / worksession: Collective Conditions** |
|||
|
|||
*Discussions on consent:*[^6] |
|||
|
|||
- Repeating issues with/discussions on the need for making time for consent, assumptions of agency/control/empowerment and the ability to re-commit, continued consent or changing your mind. Different practices/genealogies of consent: as a notion used by activists and legislators. Implicit, explicit and associated consent. |
|||
|
|||
`Insert a line about the variation of consent, a reminder that consent is not a given, but that it needs (re)affirmation, thinking about variation and evolution of consent (to be worked on).` |
|||
|
|||
*From discussions on transformative justice + anti-carceral activism +\ |
|||
Queering Damage:*[^7] |
|||
|
|||
- The last part of the guidelines ('What if these Guidelines are not met?') does not convince anyone. Several discussions throughout the week on how to deal with this. If there are Guidelines, they need to address responsibility and consequences in some way? At the same time, we feel that we might unwillingly reproduce carceral politics (rules → punishment). But how to approach this? We understand such guidelines as performative documents, so what you write about consequences becomes performative in itself? |
|||
|
|||
`Something in the last section on accountability.` |
|||
`- Rename the last bit “What if the guidelines are not met” to: “This is what we do”` |
|||
`- Turn away from ‘rules and punishment’ logic. This also might deal with the concern that people are instrumentalised to functionaries ...` |
|||
`- Insert the possibility to have listeners as a method.` |
|||
|
|||
- Experiments with having every day two other 'listeners' (otherwise known as whisper-bots) in the room; volonteers (not: organisers) that amplify, deflect, gather or document signals of transgression. Interesting experience of de-centralisation and collectivised responsibility. |
|||
|
|||
`See above!` |
|||
|
|||
- Assuming that crime/harassment is not just other people\'s problems. Attempt to work with practices from Transformative Justice.[^8] |
|||
|
|||
- Another discussion thread on the differences of 'calling out' vs. 'calling in': How to take care of someone who doesn't care?[^9] |
|||
|
|||
- Concern about proceduralisation of guidelines, whereby people become functionaries and not part of the situation: who we are is entangled with how we see problems. Timing matters: processes for immediate action and safety, and ones for long term response. In general, understanding that guidelines cannot be (left) alone: it needs a lot more than precise formulations. Need for developing practices, shared experiences, continuous work.[^10] |
|||
|
|||
*A Critical COC discussion:* |
|||
|
|||
- Most COC we dealt with did not deal with class/economic differences (aside for maybe mentioning class as one of possible discrimination axis) |
|||
|
|||
`Under : "Exchange information, experiences and knowledge,"inequalities created by class: absence / presence: We could insert an example , highlighting the fact that absence can be the result of economic/class differences.` |
|||
|
|||
- Very few COCs are simple enough in text-density / language level / terminology used (at least to be widely accessible or offer way to catch-up and enter as an outsider) |
|||
|
|||
- What is the space/time for checking-in/confirmations of commitments |
|||
|
|||
`Mention the method of coming together and address everyone's involvement and commitment, practically like the moments we have each morning during worksessions.` |
|||
|
|||
*Discussions on audio-visual gymnastics:*[^11] |
|||
|
|||
- Relates to this part of the guideline: \'Do not share photographs or recordings on proprietary social networks unless explicit consent by all involved.\' |
|||
|
|||
- How to not respond to surveillance capitalism by stopping to make and share pictures? How to keep abundance, pleasure, possibilities in documentation; what ways to become visible as collectives, especially when we refuse to be visible as identifiable individuals. Or is there no way out of the dominant regime of exploited visibility? |
|||
|
|||
- Experiments with audio-visual gymnastics. Other imaging practices that re-orient cameras away from faces and ways to sollicit on-the-spot consent of participants, rather than as a general rule or consent beforehand. Protocols for sorting through images afterwards (**no immediate publishing).** |
|||
|
|||
`Thinking about publishing (pictures, videos, ...) that has to be discussed, negotiated and debated, it's not immediate. For the short version somethig sloganesque can work: 'We endorse discursive publishing 'This paragraph can be inserted with some discussion into the long version of the guidelines after: “No immediate publishing”.` |
|||
|
|||
- Also: watch out for discrimination/exclusion based on use of specific technologies: explain what is the problem with these structures (fb, pomme, \...) and how to or not relate this to the use of apps, un.st-a(ble)gram etc. |
|||
|
|||
*Notes from the Modes d\'emploi tables / on arrival:* |
|||
|
|||
- Conflating \"maternalise\" and \"paternalise\" is a problematic linguistic move because it is conceptually putting them at the same level in tems of patterns of oppression and violence; even though they have historically never been equal. So not to say that maternalising doesn\'t exist, but whether that it doesn\'t have the same weight than paternalising. |
|||
|
|||
`Change the line on matronise and patronise with smth like this: “We pay attention to the way informations, experiences and knowledges are shared between us with “possible asymmetries”; need better sentence. Maternalising and paternalisation could be examples, such as now there is teacher /student?` |
|||
|
|||
- These guidelines are very good at creating a sense of community, common sense and will but we have to be careful that if someone doesn\'t comply to it, this person actually falls out of the "community". |
|||
|
|||
- It is good to know that for instance here Constant people are mindful towards the compliance of these guidelines but a good way to involve participants so to share the responsibility towards each other would be to decide on a rotating team of participants who are not only very mindful during exchanges but are also the persons to go to if something went wrong in regards to the guidelines. |
|||
|
|||
`Let's find a wording that doesn't fit within constraints or “not to do” vocabulary, so not using transgression for instance. Example of using extra-legal in the context of Authors of the future so not to go into il-legality but instead referring to another frame of legality.` |
|||
|
|||
**8 November 2019 / HP** |
|||
|
|||
- I would suggest using "informed by" or "found useful" rather than "inspired by" because of the content of the text, somehow "inspired by" for me feels a bit uncomfortable and I think its because of the affective qualities of the word inspire (which include excite) and maybe because so often (and so wrongly) harassment complaints become fetishised as \"exciting\" in complaint processes. |
|||
|
|||
`Yes, let's change it!` |
|||
|
|||
**14 October 2019 / General Assembly Constant** |
|||
|
|||
- It might help people understand what Constant is and does; a kind of manual for those who do not already know. |
|||
|
|||
`But we're not trying to make Constant more “intelligible” with the guidelines, this is not the point...` |
|||
|
|||
- To 'come closer' to Constant what takes time. This is a social process, and guidelines might nog help or be in the way even. |
|||
|
|||
**26 September 2019 / vernissage Constant\_V: Collaboration Guidelines** |
|||
|
|||
- When writing dossiers, we try to avoid negative statements and negative language. Is there a way to approach the guidelines with a similar attitude? |
|||
|
|||
`The principle is interesting, we can do a scan of the guidelines and see what turns up. Let's discuss the two examples that are annotated. Just want to be careful with sugar coating language avoiding negativity (joy and freedom for instance); we want to take a stance.` |
|||
|
|||
This would give things like: |
|||
|
|||
Constant is committed to environments where possible futures, complex |
|||
collectivities and desired technologies can be experimented without |
|||
fear. → *Constant is committed to environments where possible futures, |
|||
complex collectivities and desired technologies can be experimented |
|||
[with joy and freedom]{.underline}.* |
|||
|
|||
The spaces that we initiate are therefore explicitly opposed to sexism, |
|||
racism, queerphobia, ableism and other kinds of hatefulness. → *The |
|||
spaces that we initiate are therefore explicitly [inviting everything |
|||
but]{.underline} sexism, racism, queerphobia, ableism and other kinds of |
|||
hatefulness.* |
|||
|
|||
Because of the intensity of exchanges and interactions during |
|||
worksessions, there are moments of disagreement and discomfort which are |
|||
not to be avoided at any cost, but instead need to be acknowledged and |
|||
discussed within the limits of your own safety and sanity. → *Because of |
|||
the intensity of exchanges and interactions during worksessions, there |
|||
[can be]{.underline} moments of disagreement and discomfort which ~~are |
|||
not to be avoided at any cost, but instead~~ need to be acknowledged and |
|||
discussed within the limits of your own safety and sanity.* |
|||
|
|||
Even if some of the below guidelines sound obvious, we have experienced |
|||
that being together is not always as self-evident as it might seem. → |
|||
*Even if some of the below guidelines sound obvious, we have experienced |
|||
that being together [can be more complicated]{.underline} as it might |
|||
seem.* |
|||
|
|||
Don't speak for others. Do not intrude or impose yourself. → S*peak for |
|||
yourself only. Give/leave* (to be discussed: imply that someone has the |
|||
space - yes but it is the case,some ppl will occupy more space than |
|||
others for various reasons) *other people space.* (leave space for |
|||
others?) |
|||
|
|||
Exchange information, experiences and knowledge. Don't patronise nor |
|||
matronise. → *Exchange information, experiences and knowledge. Others |
|||
always know as much as you, it might take more time to discover it.* |
|||
|
|||
etc. |
|||
|
|||
**20 September 2019 / Constant aan Zee: Discussion with members +\ |
|||
Constant team** |
|||
|
|||
- The point of guidelines is maybe to **de-naturalize behaviors.** Does this interfere with making space for precarity @ Constant? |
|||
|
|||
- Proposal to **reorganise document**; for example: bring short version to the front before the \'commitment\' which contains some complicated language. In general: document is long and structure complex? Things get easily overlooked. |
|||
|
|||
`For every occasion we have to look at the formatting. Clear and short if necessary, and long and informative when needed ...` |
|||
|
|||
- **Some of the examples** (for example: \'dead names\' in the \'no harassment\'-section) are **hard to understand** if you are not already aware, so misses the point |
|||
|
|||
- This might be a courageous step; to make such issues/guidelines explicit, given the current times. |
|||
|
|||
- 'Support and foreground the use of Free Libre and Open Source software' sounds like a prerequisite. It should not be that someone who does not know about FLOSS already, cannot discover it with Constant. |
|||
|
|||
- The 'we' in this document is ambiguous, on purpose. But how does that really work? Many questions about how to take **collective responsibility** for this, and where Constant is or should be (end)responsible. |
|||
|
|||
- Are these some kind of house-rules? But where does the 'house' begin and end? **How to not make this territorial**? (maybe it is more a 'field' - ref. Kate Rich) |
|||
|
|||
- List of hateful -isms: **add ageism**? |
|||
|
|||
- Questions about tone: **imperative or not**? In general, multiple but different allergies surface to wordings/tone. Might need multiple versions for catholics, calvinists, anarchists, puritans, anti-imperialists, \... |
|||
|
|||
- How to not forget that the **auto-restrictions** that this document might produce, also **generate possibilities for others** (ref. Jara Rocha)? |
|||
|
|||
`Add in the intentions that the guidelines, with their ‘restrictions’, create possibilities for others (After "we have written these guidelines to think of ways ..."). hmmm. “the restrictions that these guidelines will produce for some of us, might create possibilities for others of us.”` |
|||
|
|||
- "Do not share photographs or recordings on proprietary social networks unless explicit consent." (and following text in long version) is causing confusion. Why not consent forms? It is an attempt to make space for media/visual production on other terms (agendas not set by GAFAM[^12]), instead of minimizing situations where images can be made and shared. But: might be in conflict with GDPR[^13]? And might even be in conflict with FAL[^14]\... Does this mean Constant gallery needs a \'non-commercial\' license? Need to think this through more. |
|||
|
|||
`Maybe one of us can find a bit of time to attack the regulations and try to understand what they would uimply for us .. and from there we could think of ways to collectively re- imagine 'data', 'protection', 'regulation' for example in a GDPR sprint?` |
|||
|
|||
`Why not write a specific license for the Gallery? Is this possible? Fun? Is it compatible with the GDPR ? "You are free to use these images but we don't want you to share them on FB" :-) so more as a technopolitical statement then an enforceable regulation?` |
|||
|
|||
- Proposal to add to short guidelines: "**accept the limits of your understanding"** \-- not everything can always be processed at the same time/level/speed by everyone (ref. Algolit) |
|||
|
|||
`Why not write a specific license for the Gallery? Is this possible? Fun? Is it compatible with the GDPR ? "You are free to use these images but we don't want you to share them on FB" :-) so more as a technopolitical statement then an enforceable regulation?` |
|||
|
|||
- One should be able to print this document from the website (print CSS needs attention)! |
|||
|
|||
`There is no possibility to print the document at the moment, we're reporting it on the Gitlab issue tracker (DONE, look for 'print css'– ticket opened it already 11 months ago :-/)` |
|||
|
|||
[^1]: Constant worksessions |
|||
[[http://media.constantvzw.org/wefts/103/]{.underline}](http://media.constantvzw.org/wefts/103/) |
|||
|
|||
[^2]: Bibliotecha documentation and installation manual: |
|||
[[https://networksofonesown.varia.zone/Bibliotecha/index.html]{.underline}](https://networksofonesown.varia.zone/Bibliotecha/index.html) |
|||
etherbox documentation and installation manual: |
|||
[[https://networksofonesown.constantvzw.org/etherbox/manual.html]{.underline}](https://networksofonesown.constantvzw.org/etherbox/manual.html) |
|||
|
|||
[^3]: Constant Collaboration Guidelines |
|||
[[http://media.constantvzw.org/wefts/123/]{.underline}](http://constantvzw.org/w/?u=http://media.constantvzw.org/wefts/123/) |
|||
|
|||
[^4]: About deep listening: Earl E. Bakken, Center for Spirituality & |
|||
Healing. *Deep Listening* |
|||
[[https://www.csh.umn.edu/education/focus-areas/whole-systems-healing/leadership/deep-listening]{.underline}](https://www.csh.umn.edu/education/focus-areas/whole-systems-healing/leadership/deep-listening) |
|||
|
|||
[^5]: Images from the comments chalked on the Constant window |
|||
[[https://gallery.constantvzw.org/index.php/Collaboration\_Guidelines]{.underline}](https://gallery.constantvzw.org/index.php/Collaboration_Guidelines) |
|||
|
|||
[^6]: [[http://constantvzw.org/collectiveconditions/no\_u\_in\_dump/etherdump/thepadis.diff.html]{.underline}](http://constantvzw.org/collectiveconditions/no_u_in_dump/etherdump/thepadis.diff.html) |
|||
|
|||
[^7]: Queering Damage |
|||
[[https://queeringdamage.hangar.org]{.underline}](https://queeringdamage.hangar.org/) |
|||
|
|||
[^8]: Transformative Justice is a set of D.I.Y and anti-authoritave |
|||
methods and tools for engaging someone who has perpetuated harm in |
|||
an accountability process. |
|||
[[https://supportny.org/transformative-justice/]{.underline}](https://supportny.org/transformative-justice/) |
|||
|
|||
[^9]: Notes from *Collective Conditions*, on Calling Out and Calling In: |
|||
[[http://constantvzw.org/collectiveconditions/no\_u\_in\_dump/etherdump/keepinout.diff.htm]{.underline}](http://constantvzw.org/collectiveconditions/no_u_in_dump/etherdump/keepinout.diff.html) |
|||
|
|||
[^10]: Notes from *Collective Conditions*, on implementation: |
|||
[[http://constantvzw.org/collectiveconditions/no\_u\_in\_dump/etherdump/consequences.diff.html]{.underline}](http://constantvzw.org/collectiveconditions/no_u_in_dump/etherdump/consequences.diff.html) |
|||
|
|||
[^11]: Notes from *Collective Conditions*, on Audiovisual Gymnastics: |
|||
[[http://constantvzw.org/collectiveconditions/no\_u\_in\_dump/etherdump/pictures\_recordings.diff.html]{.underline}](http://constantvzw.org/collectiveconditions/no_u_in_dump/etherdump/pictures_recordings.diff.html) |
|||
and |
|||
[[http://constantvzw.org/collectiveconditions/no\_u\_in\_dump/etherdump/audio-visual-gymnastics.diff.html]{.underline}](http://constantvzw.org/collectiveconditions/no_u_in_dump/etherdump/audio-visual-gymnastics.diff.html) |
|||
|
|||
[^12]: GAFAM: Google Amazon Facebook Microsoft |
|||
|
|||
[^13]: GDPR: General Data ProtectionRegulation |
|||
|
|||
[^14]: FAL: Free Art License |
|||
[[http://artlibre.org/licence/lal/en/]{.underline}](http://artlibre.org/licence/lal/en/) |
|||
|
|||
All documentation, including the documents in this publication, can |
|||
be found here: \[include link\] |
@ -0,0 +1,90 @@ |
|||
# Iterations ... {.inline} |
|||
|
|||
Iterations investigates the future of artistic collaboration in a digital context. That tag line was used throughout the four years that the project ran. The basic concept was to 'iterate' an action in several similar, but fundamentally different circumstances. |
|||
Inspired by recursive forms of collaboration as they exists in open source software development, the project Iterations applies repetition and circularity to artistic methodologies, in which the output from one activity is used as the input to the next. |
|||
|
|||
The project Iterations consisted of a series of residencies, exhibitions, meetings, exchanges and collective worksessions that were organised between 2017 and 2020. Each activity produced material given to the next iteration. As such the series experimented with collective creation, authorship and conditions, and each presentation was an open invitation for re-appr0priation. Materials, code, images, instructions and documentation are shared under open content licenses on the website of the project. Iterations invests in producing cultural commons. |
|||
|
|||
Although Hangar, esc, Constant and Dyne all operate in the same field, they have different points of departure, missions and modes of operation. For this project we established common methodologies, which were implemented differently by each organisation. |
|||
|
|||
In december 2017, a first colloquium took place in Hangar were some common outsets were discussed. In spring 2018 a group of 30+ artists, hackers, theater makers, musicians embarked for a shared residency to Giampilieri, a small village hidden between the sea and the mountain in the metropolitan area of Messina, Sicily. This Trasformatorio residency was organised by Dyne.org. The works produced turing the residency were festivily presented in the village. As material to be remixed by the artists who joined for the next residency, a song was selected that was sung in a hardly understandable, Sicilian dialect. With this handover, the challenge of multilinguism was introduced. In the residency that followed in Barcelona in November 2018, the work concentrated on forming a collective persona. A collective artistic identity emerged with the name Rica Rickson. The outcome, one rule: any of the residency artsts can inhabit her. In May 2019, several presentations and meetings later, a group of artists worked together under the name 'Common ground' on creating a site-specific installation for the exhibition Collaboration Contamination in the spaces of esc. When you work together, you will be influenced by the people you work with. Over the summer of 2019 two residencies were organised in Brussels resulting in the exhibition Operating / Exploitation in Bozar-Lab in October immediately followed by the worksession Collective Conditions. |
|||
|
|||
# ... Investigates ... {.inline} |
|||
Let's look closer at the words in that sentence 'investigate the future of artistic collaboration in digital contexts'. To start with investigation. The means of inquiry that were developed were led by the practice of doing art together. Allthough Iterations followed a described methodology, the way we investigate is multiple: led by 'intuition', affinities, impulses and less 'Re-search' (searching again for what we know is already there, to prove a thesis). Is this then what we could call 'experiment' ? That hase connotations of: fooling around without a goal, but also: suspicious lab work that exploits living bodies for the sake of science. The artists as lab rats in a white cube test tube? That is far from what we were after. But is any collaboration free of friction? Are the conflicts product of the artificial setting of putting different artists together to coexist or on the nature itself of the collaboration? does collective productions exist without these difficulties? |
|||
|
|||
Inquiring led by the practice of doing art together. Experimenting as fooling around with no goal. Doing art together with no goal. Doing art together. Inquiring, experimenting, fooling around, with no goal. No goal, or the goal was no other than the set of conditions: being together, doing together, doing art, doing art in a way that iterates a previous attempt, and that can be iterated in a future attempt. No goal, or the goal was the reconsider again and again the set of conditions. How often we took a step back, or we set the conditions back to the starting point, to try again! We did that and are doing that in every iteration, but also inside every iteration, but also in the relation of this project and the previous and future one. The iterating method is working in different scales. To step back, reconsider conditions, reset them, and try again. |
|||
|
|||
One thing we are certain about is that the goal of the investigation is not the art piece. It might be the art labor, or the art process, or the experience of togetherness,not certain about this though. |
|||
|
|||
# ... the Future of ... {.inline} |
|||
Starting a rule based Iterations creates new futures. They are plural. And they have repurcusions on the here and now, quantum presences and diffractions, ... \ |
|||
Well maybe that is close to what we hope artistic can do: change perspectives and bring new orientations to rusted concepts? \ |
|||
A small deterioration has immediate effects: the roadmap can go in the bin. it is agile roadbuilding into the vast unmapped territory of having no markers.It can also construct empty spaces to be reconstructed over and over. \ |
|||
Our collective national politics are fucked up by neo-liberal turbocapitalists, and maybe it is good to be in a (carbon neutral) car where every passenger has their own steering wheel. We do not know how to go straight, but we learn to negotiate with materials that matter. Future is made collectively or it will not be. An this collectivity needs communication with other species, the activation of a post-human landscape. |
|||
|
|||
Future not as a promising and well balanced picture that we can offer as the output of this project. Sorry about that. Instead a plural and diffractive future that has consequences in the here and now. A diffractive future in the here and now. Everyone in this car has a steering wheel, but this is only one car, and we are together in it. The future here and now, so not a future separated from us. There is not a waiting period before this future, no open gap available for hope or dispair. Instead a material future, so one future we can touch, made of attempts that diffract and overlay in front of our eyes, departing from our hands. |
|||
|
|||
# ... Artistic Collaboration ... {.inline} |
|||
Is the collaboration artistic, or is the artistic collaborative ? Both (and more) hopefully. A more internal motivation that is proper to our type of organisations is that we have witnessed a rigid underexposure of collective practice in presentation of contemorary art. We want to change this around and highlight the fact that much artistic development of concepts, tools, methods and approaches is done collectively. Esc, Constant, Dyne and Hangar are close to hacksessions and we saw that individual practices spring from these shared situations are not always credited properly when presented. |
|||
So one starting point was to change the paradigm and put collective work as a precondition for participation. And as a header on the output. An attempt to dilute individuality, to create bodies in alliance. |
|||
|
|||
... Commoning and its forms as premise. |
|||
|
|||
... Nevertheless, seems that it is hard to go out of the normal group dynamics in such a short experimental time, so those with strong voices keep the drive, that was always a big question, how to keep the silent voices there, meaning, producing, weaving? |
|||
|
|||
... The collaborative aspect of art labor, but not hidden under the name of the artist, but clearly stated and put on the surface, so it is visible and audible. The name of the artist and the title of the piece as the framing of the art work (work meaning labor). What happens when we take that out? Not clearly framed, the art piece is not well prepared to be seen and listened to, but on the other hand, it is very ready to be repurposed or continued, as a whole or in some of its parts. The communality offers another reading, an integral experience. |
|||
|
|||
The handover meetings were the sharing of an ongoing art piece? This is not very clear at this point. They were the sharing of an ongoing process, but this process was not easily framed as an art piece, and when it was, that framing (the name of the artist and the title of the piece back into play) were a limit and a strong conditioning of the collaborative process that the handover meeting was suppose to trigger. The handover was a situation, a gesture to bridge, to give away some element of the lived experience of the iteration. The Handover was in everycase a metamorphosis, and a becoming action.Contrary to the expectation the exchange among artists was not of materials, but of ideas and experiences, sometimes of data. |
|||
|
|||
We witnessed an increasing abundance of 'co' and 'col' prefixes. (With, together, joint) |
|||
And why did we bother to join 'labor' to the collective ? Is 'collective' not good enough? Is just being together not more desirable then thinking about work ? To collaborate you do not have to be friends, a common goal is enough. Sometimes just a common inspiration, but it is hard to arrive to the common ground. So why did we choose for collaboration? We were inspired by F/LOSS practices that include strategies to make it possible for people to contribute to projects they find important, even when they are not best friends. The Linux kernel, open licenses. A sort of hope for a possible jamming in the arts, a dissolution of ego within technology. But also thinking of the rights of the work, next to rights of the author. Shared work has the right to be disseminated, to have a life of its own, to be exposed to brilliant influences, benefit from the additions of others. One tool we tried from the outset is to apply Open Content licenses to all the work that was produced. That applies to this book as well. It is published under a Free Arts License (?) which means that you are free to copy, change and share it, as long as you make mention to the original authors. |
|||
|
|||
In some key moments, the group involved in Iterations decided to challenge the collaboration and to try to go deeper into the collective. There were discussions about this in the Hangar iteration, for example. So the collaborative, where different people can work, labor, together without being friends, was surpassed toward the collective, where the separation between the different contributions is not clear anymore. This means that, in some moments, the development of the project challenged the decision made in the beginnig of using the word collaboration instead of collective action. The necessity of creating unified criteria is a hard demand, certainly generating common strings or media would have been more effective and less painful. |
|||
|
|||
The prefix 'con-' was also important: in the course of the project, conflict became to be considered as a constructive element. Staying 'with' the trouble as a way to not let go, to make space for difficult relations, that are necessary for practices that want to embrace differences. Yes, belonging to, it is a difficult precondition to fulfill a goal, but it gives space for alliances. At the end to stand with, to be part, can also be a collective statement, an action of bodies in alliance. Corporalities that keep their individuality. |
|||
|
|||
Iterations has created situations in which differences were encountered, discussed and transfered into work. In many cases the artists, organisers, and other parties that worked together met for the first time and had no previous experience in collaborating. Although not always easy, it is important that tensions and frictions can arise from these situations and that they are dealt with, creating productive differences that earn a central place in the common practice. |
|||
|
|||
# ... in Digital ... {.inline} |
|||
When we mention 'digital' as a terrain for our operation, this includes all (im)possibilities of its use in all contexts. Iterations made a continous attempt to inquire in what 'digital' could be, and where it ends to be relevant. But the use of the media delivered a particular aesthetic, some fragmentary landscape that travelled across the Iterations, that is now present in this new attempt to consolidate collaborative approaches: the new experiment, the textual. Intertwining, creating membranes from disgregated elements. |
|||
|
|||
Over the last decades, the 'digital' has shifted meaning. The early net induced the emergence of net art, critical cyborg identity and gender tech experiments, space for independent infrastructures. In our present, this hopeful potentiallity is overshadowed by techno colonial, big data correlating, energy slurping, all invasive commerce. 'Digital' therefore, can not remain un-annotated, but asks for critical positioning of artists. Very present in all Iterations was that artists prefered to close their laptops, and insisted to work on what is between them as humans instead of endorsing machines as a central tool. |
|||
|
|||
The mediation of the digital in this project. The digital media(tion). The writing of this text is being done in a shared pad, to which we connect from three different (european!) cities. Our words come together through our computers, to a common digital ground, in a file that is stored, most probably, in a drive located somewhere in Brussels (perhaps in the very Constant office?). But we know each other, we like and need to come together, and we talk about location, coffee, about details that make our bodies more present in the writing. It seems fair to say that that was a key element of this project: we enjoy being together, phisically in the same place. This is perhaps a previous condition, previous to all the other ones. |
|||
|
|||
Other participants in Iterations were more radical in this, as said before: they put the computers aside, thay wanted to be together, with the bodies together, and to share the time, the food, the temperatures, the sounds and silences, the energy and the fatigue. When this happened, the digital was perhaps no more than a metaphore. But this is a powerful metaphore: to collaborate as we do in the F/LOSS, to let things being taken appart, repurposed and continued as we do in the F/LOSS. |
|||
|
|||
# ... Contexts ... {.inline} |
|||
Ecology, post truth times, musea and exhibitions vs. performatic actions, how are the different contexts influencing the iterations, their dynamics and their products. Ecology as big topic, the post-human as question, as method. A necessity of making kin, of understanding and completing, but why not, of contaminating. Collectives are also formed from intrusions, penetrations and alterations, transpositions or accidents. |
|||
|
|||
As a relativistic concept, what focal event is 'context' depending on? And what (a)symmetries are involved in the position of the subject. Our work in culture is associated with many sectors of society, with tech innovation schemes, with eco(-logical -nomical)politics, it relates to futures we might not be able to imagine. |
|||
|
|||
We think of the context in a way similar as how we think of the future. It is right here, very close, but it is also the diffractive and plural openness of the immediate things. |
|||
|
|||
On another tone: our direct working surroundings, the physcial spaces in which the art workers involved in the project worked in are art centers, a rural area, private houses, and institutes. The context of an institutional exhibition requires very different specific dealings with digital means than a small village in Sicily. |
|||
|
|||
.... A resistance toward how the digital media makes things unlocated and abstract. There is no cloud, but a bunch of drives and cables, as we learned through Joana Moll and other colleagues. But also the digital context, seen as metaphore but also as tool, offers the opportunity to get rid of some oppresive framings of the art process. \ |
|||
... A work, a labor, that takes place here but will continue elsewhere, with this materiality but that can be transfered to another materiality, done by these people, but that can be continued by other people. The context was like this, concrete and dislocated at the same time. \ |
|||
.... Who is here? Who is near us? Who is doing this with us? When is this happening? And where? |
|||
The dislocation, the intuitive bringing together of separated places, things and people, as a method of establishing a context. |
|||
|
|||
Iterations **foregrounds collective work because we find that this is urgent** to do. |
|||
The internet has become an amazingly complex place and can be interpreted as a metaphor for the whole world - no individual is capable of grasping its totality. \ |
|||
For art practitioners interested in technology, this gives reason to get together, to collectively understand, use, develop, or dismantle, the main infrastructure of our times. To take apart and hack together networks of our own, with an attitude, invent and run multiple internets and built futures that we would like to inhabit. \ |
|||
We, early twentyfirst-centurists are living in the post-capitalist ruins that have become our collective home. We are happy to volunteer for doing some housekeeping, maintenance, restoration. This requires that we learn to work together, to negotiate and speak, to struggle and deal with those agencies who are undermining its fundaments. |
|||
|
|||
As a collaboration between several European organisations **Iterations is co-funded by the Creative Europe framework of the European Commission**. Although the project springs from our shared conviction that collectivity in the arts needs investigation and attention, the project is also formatted around the criteria of the Creative Europe framework. There is a duality of potentially conflicting interests. |
|||
An example of this is the fact that we enter into a programme that supports "transnational cooperation projects from different countries", meaning that we endorse a paradigm of increased mobility. Whether we choose to meet and work remotely through online tools, or we travel by train our airplane, our actions are increasing carbon footprints. \ |
|||
Another example of how our work is influenced through such a framework is that the geographical delimitation to European borders is not self evident for our organisations, in other situations we work with partners from outside the EU. \ |
|||
Staying inside the scope of a funding programme without underexposing sides of the work that are less compatible with that programme is interesting cultural-political gymnastic exercise. If a shared long term vector between us is to speed up the end of capitalism, then how are projects such as Iterations benificial to that? Rather then stating this as an explicit part of its mission, it is making an effort by creating space and opportunity for critical art practices to develop. Stimulating awareness, sensitivity, intuition for the politics of tools and technologies, through bringing about togetherness and exchange. |
|||
|
|||
**This publication is not**: a catalogue, complete, a documentation. Rather it aims to create new openings by separating lines of work through a prism that consist of several editorial handles. Approaches and attitudes that give inspiration for new concepts and works yet to be developed. This publication is an Iteration in itself. Inside this book, contributions of some protagonists from the past and Iterators from the future coincide in a joint effort to transport ideas to yet unkown persons and contexts. You, reader might be part of this. The book is a hybrid vessel of ideas, paper, texts and concepts that can be unpacked and remixed. |
|||
|
|||
Thank you to: everyone who participated in the Iterations activities. |
|||
|
|||
(Full list of names! needs to be reviewed) |
|||
|
|||
https://pad.constantvzw.org/p/iterations-participants |
|||
|
|||
|
|||
|
@ -0,0 +1,132 @@ |
|||
# holding spell {.hidden} |
|||
|
|||
we share a rich vocabulary; us. \ |
|||
we can speak of \ |
|||
broad skies and magnitudes, \ |
|||
the sound of a blown voice, \ |
|||
through a horn softly \ |
|||
on a hill far away, \ |
|||
of magnetite swathes \ |
|||
and sparks so sharp, \ |
|||
they can be felt by grazing a little finger. \ |
|||
we can speak of things that \ |
|||
when we don’t feel strong, we think about \ |
|||
and of things that \ |
|||
when we want to feel strong, we think about. \ |
|||
|
|||
little animals, small and quiet and shivering \ |
|||
caressed but \ |
|||
suspended \ |
|||
by the tips of whiskers only air. \ |
|||
when we speak, noses twitching \ |
|||
it can be of \ |
|||
separateness, discreteness \ |
|||
the spaces between circles \ |
|||
overlapped, but still holding \ |
|||
we can multiply interpretations, \ |
|||
and brace against their weight \ |
|||
or \ |
|||
we can scoop up abundance \ |
|||
and bathe lightly. \ |
|||
|
|||
throats, quivering, sound like cold or terror \ |
|||
but they too ask, whether the circles \ |
|||
are organisms micro-vibrating \ |
|||
with the energy it takes \ |
|||
to realise squelchy new forms \ |
|||
to absorb: experience grows the self grows autonomy \ |
|||
by care and love into the blood. \ |
|||
|
|||
our expanding throats \ |
|||
stickily coated with the outside, \ |
|||
wonder \ |
|||
whether us-as-earth, will shift magnetic poles again \ |
|||
as we did recently \ |
|||
780,000 years ago \ |
|||
well, not within my living memory but \ |
|||
maybe within ours. \ |
|||
|
|||
it’s comforting that a polar shift might mean no more \ |
|||
to glottises \ |
|||
than huffing in the wet brown mulch from the forest floor; \ |
|||
yelling in bluebells until we laugh \ |
|||
is anyway more accessible and soothing. \ |
|||
|
|||
to you, the piece of my bruised heart: \ |
|||
that bright lodged glint \ |
|||
is your intelligence \ |
|||
equal to all winds it bends against \ |
|||
think of it like a tinder mushroom - \ |
|||
cupped, it can keep you warm \ |
|||
and light many fires along the way \ |
|||
|
|||
when we loudly open ourselves without \ |
|||
insides \ |
|||
the world rushes in \ |
|||
unbidden even \ |
|||
but making calm salve \ |
|||
by making ourselves space \ |
|||
avoids projection. \ |
|||
when we speak, let’s not speak \ |
|||
about identity \ |
|||
no -isms or -nesses, \ |
|||
just about sheltering \ |
|||
the trembling creatures, we are \ |
|||
just about protecting \ |
|||
the vulnerability in our voices. \ |
|||
|
|||
that belief, in self-knowledge \ |
|||
might even allow \ |
|||
ample vibrant exchange, iron fizzing, \ |
|||
something like a conversation between \ |
|||
million year old magnetic traces found inside a tenth of a millimetre of rock \ |
|||
and a magnetometer \ |
|||
in the key of hysteresis \ |
|||
|
|||
this vocabulary we share, \ |
|||
made of hard and soft sounds \ |
|||
of silences \ |
|||
and recurrences \ |
|||
(i won’t lie) \ |
|||
has lashed at times, \ |
|||
and whipped us round \ |
|||
but it has also gifted us \ |
|||
cycles of growth \ |
|||
and non-linear narratives \ |
|||
comfortably spiky creations \ |
|||
and exuberant wide worlds; \ |
|||
so now \ |
|||
when we speak, intertwined, \ |
|||
i’m grateful for all those words \ |
|||
that bind and support us \ |
|||
leaning back away from another, \ |
|||
onto each other, \ |
|||
overlapped but holding, still. |
|||
|
|||
![](images/spell-screenshots/1.png) |
|||
|
|||
![](images/spell-screenshots/2.png) |
|||
|
|||
![](images/spell-screenshots/3.png) |
|||
|
|||
![](images/spell-screenshots/4.png) |
|||
|
|||
![](images/spell-screenshots/5.png) |
|||
|
|||
![](images/spell-screenshots/6.png) |
|||
|
|||
![](images/spell-screenshots/7.png) |
|||
|
|||
![](images/spell-screenshots/8.png) |
|||
|
|||
![](images/spell-screenshots/9.png) |
|||
|
|||
![](images/spell-screenshots/10.png) |
|||
|
|||
![](images/spell-screenshots/11.png) |
|||
|
|||
![](images/spell-screenshots/12.png) |
|||
|
|||
![](images/spell-screenshots/13.png) |
|||
|
|||
![](images/spell-screenshots/14.png) |
@ -0,0 +1,80 @@ |
|||
# /opt {.hidden} |
|||
|
|||
![](images/iteration-5-1-1.jpg) |
|||
|
|||
![](images/iteration-5-1-2.jpg) |
|||
|
|||
![](images/iteration-5-1-3.png) |
|||
|
|||
![](images/iteration-5-1-4.jpg) |
|||
|
|||
![](images/iteration-5-1-5.jpg) |
|||
|
|||
![](images/iteration-5-2-1.jpg) |
|||
|
|||
![](images/iteration-5-2-2.jpg) |
|||
|
|||
![](images/iteration-5-2-3.jpg) |
|||
|
|||
![](images/iteration-5-2-4.jpg) |
|||
|
|||
![](images/iteration-5-2-5.jpg) |
|||
|
|||
![](images/iteration-5-2-6.jpg) |
|||
|
|||
![](images/iteration-5-2-7.jpg) |
|||
|
|||
![](images/iteration-5-2-8.jpg) |
|||
|
|||
# /var {.hidden} |
|||
|
|||
![](images/iteration-5-3-1.jpg) |
|||
|
|||
![](images/iteration-5-3-1.jpg) |
|||
|
|||
# /boot /home /lost & found {.hidden} |
|||
|
|||
Another story starts with some fruits made of almond-paste. Almondpaste |
|||
from Sicily was rolled between hands in Barcelona and Connie |
|||
chose to make a Nispero. \ |
|||
Nispero is a spring fruit, and this was autumn, so when Iris and Rosa |
|||
searched for it in the shops, they ended up bringing plums home. Home |
|||
was the place were Iris was living together with Azahara and Giulia, |
|||
so plums were eaten in the morning for breakfast accompanied with |
|||
Antonia’s recently made coffee. Coffee was served while awaiting Julia, |
|||
coming with her son Victor, and later on Mafe proposed an exercise |
|||
that consisted of writing another story. |
|||
|
|||
The story goes, Connie bought 4 nispero fruits in Austria where it is |
|||
called Wollmispelfrucht because it reminded her of one of the places |
|||
she used to live in the past. Past midnight Mia tried some for the first |
|||
time in her life, Ulla had some too and the baby in her belly, later known |
|||
as Mika, tried some for the first time pre-life as well. Well-formed, round |
|||
and smooth; Ulla found the seeds of the fruits surprisingly beautiful |
|||
and kept them in the communal kitchen, a small paper cup with them |
|||
all inside. Inside esc one evening, before going to drink schnapps with |
|||
Norbert, Connie had to video-call another collective she is in. In an |
|||
effort to distract her attention back to us, Antonia took two of the |
|||
seeds and spat them across the room, where Mia was standing, who |
|||
spat them back. Back at work the next day Connie gave these two seeds |
|||
to Mia who took them to Brussels where nispero is mostly called néfle |
|||
or loquat by the inhabitants. Inhabiting Brussels, Azahara, who knew |
|||
Connie and Antonia from a different collective, got one seed, the other |
|||
one took many weeks to germinate and springup. Up until now it has |
|||
grown, but it has not yet born any fruit other than this story. |
|||
|
|||
Memory is a fragile thing, and it's hard to tell what a good reminder |
|||
is. Sometimes a simple smell is enough to bring you back to childhood, |
|||
sometimes a modest receipt evokes an entier day full of emotions. |
|||
What should be kept, as evidence or reminder of someone or some collective |
|||
working process ? How to catch the moments that shape a person or a group ? \ |
|||
Usually, we take pictures of what we think on the spot is a good (future) |
|||
memory, or we write postcards to share it with friends. Doing so, we |
|||
usually avoid sad memory or moment of conflict, even though they are |
|||
important too (maybe even more). \ |
|||
For example : how to remember when such a conflict starts ? Or the |
|||
breakpoint between a conflictual sitation that eventually lead to something |
|||
deeper and more destructive like a break of trust ? \ |
|||
It's usually something you'd try to escape as a group, if not individually. |
|||
As it might lead to the end of the group itself, who cares to take a |
|||
picture then ? |
@ -0,0 +1,394 @@ |
|||
# Rica Rickson {.hidden} |
|||
|
|||
[I am here.]{.green}[\ I am also here.]{.red}[\ or there, or somewhere |
|||
else. it depends where I find myself at the moment.]{.green}[\ I am a |
|||
little bit nervous]{.red}[(tense?)]{.green |
|||
.char-style-override-1}[.Shy?]{.red}[\ Melancholic?]{.green}[\ In a |
|||
continuo]{.yellow}[u]{.green}[s hurry?]{.yellow}[\ asking myself, when do |
|||
we really have time for collective digestion of the events happening? |
|||
How can we really understand processes if we cannot stop?]{.pink} |
|||
|
|||
[]{.yellow} |
|||
|
|||
[I was cleaning my cradle this morning and I found this box full of |
|||
memories. On the top of the box there was a bingo board full of english |
|||
words:]{.green} |
|||
|
|||
[questioning -- magic -- empowerment -- (un)selfishness -- |
|||
transformation -- authorship -- staying with the problem -- |
|||
misunderstanding -- improvisation -- singularities -- tension -- taking |
|||
care -- agency -- trust -- porosity -- open mindset -- collective -- |
|||
collaborative -- effort -- joy -- dis/agreement -- respons-ability -- |
|||
needs -- power-relations -- desires]{.green |
|||
.char-style-override-2}[]{.green .char-style-override-1} |
|||
|
|||
[]{.green} |
|||
|
|||
[In the box with the words I also found part of a message\ ]{.yellow}[I |
|||
had sent to Brussels:]{.red}[\ ]{.yellow} |
|||
|
|||
[As I faced a lot of conflicts, uncertainties and questions after the |
|||
residency at Hangar, I would like to further continue our vivid |
|||
discussion about\ ]{.yellow |
|||
.char-style-override-3}[collectiveness]{.yellow .char-style-override-2}[ |
|||
and to further reflect upon and share our experiences. I therefore |
|||
regard the worklab a constructive and interesting environment to |
|||
integrate with and a constructive opportunity to investigate more deeply |
|||
the potentials and\ ]{.yellow .char-style-override-3}[needs]{.yellow |
|||
.char-style-override-2}[\ of my continuously developing |
|||
organism.]{.yellow .char-style-override-3} |
|||
|
|||
[]{.yellow .char-style-override-3} |
|||
|
|||
[I was freshly born, when I felt like being thrown back in a mechanism, |
|||
where I emerged from.]{.violet}[]{.red} |
|||
|
|||
[The individual parts grew together within an intensive reflection about |
|||
]{.red}[authorship]{.red .char-style-override-1}[, |
|||
]{.red}[questioning]{.red .char-style-override-1}[\ the difference |
|||
between\ ]{.red}[collaboration]{.red .char-style-override-1}[\ and |
|||
]{.red}[collectiveness]{.red .char-style-override-1}[, |
|||
]{.red}[questioning]{.red .char-style-override-1}[\ the market logics of |
|||
art production,\ ]{.red}[celebrating female\ ]{.yellow}[magic]{.yellow |
|||
.char-style-override-1}[.]{.yellow}[\ In an organic process of |
|||
mutual]{.red}[\ act of\ ]{.green}[taking care]{.red |
|||
.char-style-override-1}[, listening,]{.red}[\ ]{.blue}[trust]{.blue |
|||
.char-style-override-1}[,\ ]{.blue}[(]{.pink}[un]{.blue |
|||
.char-style-override-1}[)]{.pink}[selfishness]{.blue |
|||
.char-style-override-1}[\ etc. I wanted to create a body that protects |
|||
myself from the artworld outside.]{.red}[\ I thought, then it is my |
|||
decision, whether I care about\ ]{.violet}[authorship]{.violet |
|||
.char-style-override-1}[\ or not,]{.violet}[\ I thought, I am a we, a she, |
|||
a him]{.red}[\ (maybe less)]{.orange}[\ and finally an I, but not a |
|||
label.]{.red}[\ I thought, I can emancipate myself from |
|||
]{.blue}[power-relations]{.blue .char-style-override-1}[\ given by |
|||
institutions,]{.blue}[\ I am the body I live in.\ ]{.red}[(whereas an |
|||
institution is an uncorporeal body.)]{.orange}[\ I thought I could escape |
|||
from market forces, productivity strategies, neoliberalism.]{.red}[\ I |
|||
]{.yellow}[trusted]{.yellow .char-style-override-1}[, that I am my own |
|||
matrix]{.yellow}[\ but I am just a parasite, some uninvited organism that |
|||
]{.green}[needs]{.green .char-style-override-1}[\ its host to exist and |
|||
grow although my presence necessarily disturb its normal functioning. I |
|||
am grateful to this host which is necessary for my own survival and at |
|||
the same time I feel stuck in an environment whose forces go against my |
|||
]{.green}[desires]{.green .char-style-override-1}[\ and structural |
|||
dreams.]{.green}[\ I was freshly born, when I realized that I cannot |
|||
escape and that it does\ ]{.red}[and will]{.green}[\ affect me. That was a |
|||
slightly painful, disappointing conclusion, it destabilized my organism. |
|||
]{.red}[Who am I? May I present your work and what is its meaning? What |
|||
is your name?]{.orange}[\ How much is it? I would like to invite you, who |
|||
will come?]{.yellow} |
|||
|
|||
[]{.yellow} |
|||
|
|||
[I can resist,]{.red}[\ and I have to,]{.blue}[\ if I want to survive the |
|||
surrounding fragmenting forces.]{.red}[\ If I don't, I might be disolved |
|||
in the host, phagocited by the bigger organisms, end up being part of |
|||
the different cells forming this host.]{.green} |
|||
|
|||
[]{.yellow} |
|||
|
|||
[I have to stay with my often controversial\ ]{.red}[needs]{.red |
|||
.char-style-override-1}[, different temporalities, |
|||
]{.red}[misunderstanding]{.red .char-style-override-1}[s. |
|||
]{.red}[]{.yellow} |
|||
|
|||
[Being myself in is a constant state of\ ]{.yellow}[tension]{.yellow |
|||
.char-style-override-1}[, that costs energy,\ ]{.yellow}[effort]{.yellow |
|||
.char-style-override-1}[,\ ]{.yellow}[agency]{.yellow |
|||
.char-style-override-1}[\ and commitment.]{.yellow}[\ I am my own |
|||
]{.green}[desire]{.green .char-style-override-1}[\ and my own |
|||
parasite]{.green}[. I am Frankenstein and Frankensteins Monster]{.blue}[ |
|||
Mother.]{.green} |
|||
|
|||
[]{.green} |
|||
|
|||
[In the box with the words and the message I had sent to Brussels, I |
|||
found part of an email I had sent to Sicily:\ ]{.blue} |
|||
|
|||
[Within the last days I have been reflecting upon different ways of |
|||
collaboration, starting from different concepts I was introduced to, for |
|||
example misunderstanding (between languages, different cultures) or the |
|||
"parasite-concept" asking who hosts whom etc.]{.blue |
|||
.char-style-override-3} |
|||
|
|||
[\...]{.blue .char-style-override-3} |
|||
|
|||
[I would be happy, if you would like to participate, which implicates, |
|||
that your name will not appear, as an individual author. Of course, |
|||
everything I am working on now, will also be open and collectively |
|||
shared.]{.blue .char-style-override-3}[]{.pink .char-style-override-3} |
|||
|
|||
[]{.green} |
|||
|
|||
[]{.green} |
|||
|
|||
[In the morning, I was reading some articles about "identity in art |
|||
production"- very often they\ ]{.red}[- but who are they? -]{.green}[ |
|||
authors :D - referred to "self-care", which means transforming personal |
|||
issues into artworks.]{.red}[\ And I thought about "the death of the |
|||
author" by Roland Barthes that I had just read again yesterday: |
|||
]{.green} |
|||
|
|||
[Here is a quote about it that I found in a very well-know fabric-like |
|||
content website:\ ]{.orange}[In a well-known quotation, Barthes draws an |
|||
analogy between text and textiles, declaring that a "text is a tissue |
|||
\[or fabric\] of quotations," drawn from "innumerable centers of |
|||
culture," rather than from one, individual experience. The essential |
|||
meaning of a work depends on the impressions of the reader, rather than |
|||
the "passions" or "tastes" of the writer; "a text's unity lies not in |
|||
its origins," or its creator, "but in its destination," or its |
|||
audience.]{.orange .char-style-override-3}[]{.green} |
|||
|
|||
[]{.green} |
|||
|
|||
[How to\ ]{.pink}[connect,]{.green}[\ reconnect with myself?]{.pink}[ |
|||
Myself are you hearing me?]{.yellow} |
|||
|
|||
[Every collaborative / collective project is a switch that turns |
|||
on.]{.pink}[\ My daily life is made of many switches, who am I when they |
|||
are all off, but above all who am I when, for some reason, they are all |
|||
on?]{.yellow} |
|||
|
|||
[Economic survival and also a certain character of mine, lead me to work |
|||
on different fronts, to create, a verb that problematically collides |
|||
with "produce" many things / projects / situations / groups.]{.pink}[ |
|||
What was the question again? cultural creation or cultural |
|||
production?]{.green} |
|||
|
|||
[But where am I when I'm here and I have to be there tomorrow? Who am I |
|||
with you today if I have to be with them tomorrow?]{.violet}[]{.pink} |
|||
|
|||
[Okay.]{.yellow} |
|||
|
|||
[Now the switches are all on.]{.blue}[]{.pink} |
|||
|
|||
[I'm getting anxiety. Maybe I should just do one project? Make my |
|||
curriculum vitae coherent, functional, be one thing, a monad.]{.pink}[\ A |
|||
nomad?]{.green}[\ Is this an aspiration of my deep self or the market |
|||
demand? How and when did I embody it? Who am I when I reconnect with |
|||
myself and all the different parts I'm connected to?\ ]{.pink}[How would |
|||
my body react if one of these parts remained passive or atrophied, or |
|||
simply got carry by others? Or on the contrary, if it became more |
|||
active, or even the most active\... like the motor of the whole |
|||
body?]{.blue}[\ Am I still connected to myself if I am not connected with |
|||
anyone else?]{.green} |
|||
|
|||
[]{.green} |
|||
|
|||
[Do I need a body? But what if I don't need the calm of the |
|||
Unity.]{.blue}[\ I want to live WITH and to work IN the contradiction. |
|||
How to develop contradictions as a new form of knowledge? How to embrace |
|||
them as a way to learn that the contrary is in me?]{.yellow}[\ How to |
|||
inhabit the contradictions in myself? The space in between is always an |
|||
interesting textile made of different colors and knots to create a whole |
|||
full of memories.]{.pink}[\ The space in between has an enormous creative |
|||
power.]{.orange}[\ I have the intuition that the idea of Unity it's what |
|||
made Western culture so wrong. The subjective intensity in this "in |
|||
between" erase the ego, the authority, and I recognize my own ignorance. |
|||
]{.violet}[There is a creative explosion IN my contradictions. |
|||
]{.green}[How to take |
|||
de]{.yellow}[c]{.green}[i]{.yellow}[s]{.green}[ions in the |
|||
contradiction? Can they adapt on the in-between]{.yellow}[? Are |
|||
decisions univocal?]{.blue}[\ Maybe the question is not how to overcome |
|||
contradictions but how to live with them, how to inhabit them to avoid |
|||
schizofrenia. To transform schizofrenia into a process of |
|||
knowledge.]{.red}[\ Can I transform my stigma into my emblem? |
|||
]{.blue}[Can I transform my monstrosity into my beauty?]{.violet}[\ How |
|||
to be an alternate body?]{.orange} |
|||
|
|||
[]{.orange} |
|||
|
|||
[Author/authority\... Power Relations]{.green} |
|||
|
|||
[\ Where is the reader, who is\ ]{.orange}[taking care]{.orange |
|||
.char-style-override-1}[\ of what and whom?]{.orange} |
|||
|
|||
[]{.orange} |
|||
|
|||
[Why am I an artist?]{.red}[\ Am I an artist?]{.green}[\ How do I solve my |
|||
problems? Are they problems, traumas or obsessions? Are my obsessions |
|||
contradictory within myself. Are my obsessions individual or |
|||
collective?]{.pink}[\ I am a she\...]{.red}[\ Am]{.yellow} |
|||
|
|||
[I? Is my identity my choice?]{.yellow}[\ Is it what emerges through the |
|||
interconnection of my different parts?]{.violet}[\ Is it the choice of |
|||
the reader? I chose it some time ago but I have the freedom to go |
|||
against my choice.]{.green}[\ Will I forever adolescence?]{.red}[\ Freedom |
|||
can be troublematic\...]{.green}[\ But making choices means |
|||
]{.red}[questioning]{.red .char-style-override-1}[, and a question is |
|||
always a good start for creation.]{.red}[\ What was the question |
|||
again?]{.blue}[\ Is the question still important when having a question |
|||
mark going on?]{.yellow} |
|||
|
|||
[]{.yellow} |
|||
|
|||
[There is something about starting that is always making me nervous, |
|||
]{.green}[tense]{.green .char-style-override-1}[, shy.]{.green}[ |
|||
(Respons-ability)]{.green .char-style-override-1}[]{.green} |
|||
|
|||
[There is no need to start from the beginning.]{.blue}[\ I understand the |
|||
world around me, using the dimensions of my body are my reference. The |
|||
world around me, starts from my body.]{.red}[\ My body is troubled, it is |
|||
human, but multiple.]{.green}[\ And I love,\ ]{.pink}[fight for]{.green}[ |
|||
and will always defend my\ ]{.pink}[porosity]{.pink |
|||
.char-style-override-1}[. My body is in the world, connected to the |
|||
world but not necessarily placed in one specific space at once\... I am |
|||
now in my bed]{.green}[, I am on my sofa]{.violet}[, I am |
|||
outside.]{.blue}[\ ]{.yellow}[There is a small breakfast table holding |
|||
the computer on which I am writing, so it let my belly breath.]{.green}[ |
|||
There is a big window in front of me, showing the grey in grey of the |
|||
sky.]{.red}[\ Where else am I present?]{.green}[\ The sky is grey here, it |
|||
is winter and cold and I wished to be back on a sunny November day in |
|||
Barcelona, having beer - no, what was is? on the streets- on the balcony |
|||
of the casita, having coffee, walking around, jumping in the |
|||
sea.]{.orange}[\ Having fun,]{.yellow}[\ with\ ]{.pink}[joy]{.pink |
|||
.char-style-override-1}[\ ]{.pink}[and\ ]{.blue}[dis/agreement]{.blue |
|||
.char-style-override-1}[]{.blue} |
|||
|
|||
[]{.blue} |
|||
|
|||
[Do I need a body?]{.pink}[\ One body that fills a house, and fills all |
|||
its entities with passion.]{.blue}[\ I walk by the house almost every |
|||
week. I see the balcony and remember the view from there, but I am not |
|||
allowed to enter the]{.green} |
|||
|
|||
[place anymore. The house is now just a shell for other bodies to enter, |
|||
inhabit, cohabit, make the place alive.]{.green}[\ Do I need a house? |
|||
]{.orange}[I enter another body of this kind some month ago in Brussels, |
|||
there was an elephant bone in the middle of the room There was a garden |
|||
too.]{.green}[\ What does it mean, What does it mean, if I can not go |
|||
back to where I started?\ ]{.blue}[Start is not necessarily the |
|||
beginning.]{.red}[\ Does this make me fragmented?]{.pink}[\ Is this |
|||
fragmentation subject of my art?]{.blue}[\ Can I cure this fragmentation |
|||
through my art?]{.yellow}[\ Can I recreate]{.violet}[/reeneact]{.pink}[ |
|||
the start? Do I need hypnosis to do a regression?]{.violet}[\ Do I need |
|||
hypnosis to do a regression?]{.yellow} |
|||
|
|||
[]{.yellow} |
|||
|
|||
[I am a constellation of affinities. A community of sense. A body |
|||
politics.]{.yellow}[\ I think this is a privilege.]{.blue}[\ I feel now |
|||
more solid!]{.red} |
|||
|
|||
[]{.red} |
|||
|
|||
[Can I add visual memories here? |
|||
https://cloud.hangar.org/apps/files/?dir=/Documentation/Photos/05.11.18-Action1&fileid=12866]{.red}[ |
|||
I just erased something that I found irrelevant for the reader, is it |
|||
self censorship?]{.violet}[\ Censorship? It destabilizes my memory, I |
|||
cannot remember what was there.]{.red}[\ What had opened before the |
|||
sky?]{.yellow}[\ The recording platform.]{.violet}[\ I don't remember |
|||
talking about a recording platform today.]{.red}[\ Anyways, The sky also |
|||
just opened. I'll go out quickly to look at the sky without glass |
|||
inbetween There is a discoball in front of the window that fills my room |
|||
with light dots.]{.pink}[\ Once I was at an exhibition, where the artist |
|||
put round colored stickers all over the room (on everythig), so it |
|||
lookied like there was a discolight.The title was "I am here, but |
|||
nothing".]{.orange}[\ Yesterday I was watching the instagram stories two |
|||
friends. They both had a picture of light reflections of there windows |
|||
on their wall. There was a light comunication between their places, it |
|||
often happens when there is a rainbow that is observed by several people |
|||
at the same time but from different places.\ ]{.green}[My body has the |
|||
ability to see the world from different places, angles and timezones. I |
|||
can do that with all my senses, actually. and I can even appear and act |
|||
in different places, without being virtual or a spirit.]{.yellow}[\ My |
|||
flatmate just brought me a crosswordpuzzle.]{.blue}[\ The nursery sent me |
|||
a message, they need diapers.]{.green}[\ I remember the first time I |
|||
misunderstood myself. In front of a bar. Sometimes I understand a |
|||
reference better, than a word.]{.blue}[\ My language is |
|||
allegorical.]{.orange}[\ My language is circunstancial.]{.green}[ |
|||
Allegory is self-conscious poiesis that respect the conditions of |
|||
particularities without reduce the power of the common. Allegorical |
|||
language is aesthetically open.\ ]{.pink}[Even my silence is allegorical, |
|||
]{.blue}[circunstancial.\ ]{.green}[My children also learned to speak it. |
|||
We learned it together. They taught me. Once, they create a very |
|||
beautiful one at Hangar. It was an allegory of gestures and objects, a |
|||
common ground, a garden. We create this center that shaped |
|||
everything.]{.orange} |
|||
|
|||
[]{.orange} |
|||
|
|||
[///\ ]{.yellow}[improvisation]{.yellow .char-style-override-1}[ |
|||
///]{.yellow}[\ What was the question again?]{.red}[\ how to make of |
|||
trouble a generative force?]{.violet}[\ Wait I'll be back.\ ]{.green} |
|||
|
|||
[// this option would imply to both provisionally define/understand what |
|||
trouble is (or not) in cultural creations, and to list and unfold its |
|||
generative forces/potential.]{.yellow}[]{.violet} |
|||
|
|||
[Troubles in cultural creations:]{.violet}[\ disturbing the |
|||
comfort]{.red}[,]{.green}[authorship]{.green |
|||
.char-style-override-1}[/authority]{.green}[, censorship, |
|||
]{.blue}[money,\ ]{.red}[set of values,]{.pink}[ |
|||
]{.red}[misunderstanding]{.red |
|||
.char-style-override-1}[,freedom?]{.orange}[]{.red} |
|||
|
|||
[What is a cultural creation?]{.orange}[\ I tried to avoid this |
|||
question\... Maybe I/you can find references.\ ]{.violet}[I feel lonely, |
|||
uncomplete today.]{.yellow}[\ Melancholy is a well known motif in |
|||
cultural creation.]{.blue}[]{.yellow} |
|||
|
|||
[]{.yellow} |
|||
|
|||
[Maybe after that it was a long time I wasn't seeing myself. Sometimes, |
|||
you feel your entire body as being so many different parts, not even |
|||
knowing which kind of fluctuation causes them to stay together and |
|||
merge.]{.yellow} |
|||
|
|||
[Sometimes I have no sleep, but my eyes are closing.]{.blue}[\ Sometimes |
|||
my legs want to run, but I am still siting here.\ ]{.orange}[In the end, |
|||
the symbiosis that are established between all the parts shows that a |
|||
type of connection]{.pink} |
|||
|
|||
[makes any of of them be here, touching us in some |
|||
way.]{.pink}[]{.yellow} |
|||
|
|||
[]{.yellow} |
|||
|
|||
[I need to change spot, my butt is hurting!]{.green} |
|||
|
|||
[]{.green} |
|||
|
|||
[Hello there reader, back again in a new chair, a new location, a bit |
|||
cold due to the weather conditions of this place.]{.violet}[\ Rica means |
|||
rich, a rich woman in Spanish.\ ]{.blue}[Rica also means sexy, hot, |
|||
tasty, ggood for latinos. My language is circunstacial.]{.green}[\ When I |
|||
was born some of the members of this collective organism were |
|||
]{.yellow}[questioning]{.yellow .char-style-override-1}[\ its own |
|||
precarious situations and while half joking, we thought that being |
|||
called Rica was a]{.yellow} |
|||
|
|||
[good option to get out this precarity, a total contradiction as being |
|||
all artists and working in art institutions]{.yellow}[, we know how |
|||
individual names are the prefered option for most of the places we work |
|||
and try to collaborate with.]{.red} |
|||
|
|||
[]{.red} |
|||
|
|||
[I like]{.blue}[\ to cook with others, do some gardening, write texts |
|||
together]{.violet}[\ and get a bit confused with the limits of |
|||
]{.orange}[my]{.blue}[\ own self]{.orange}[, dance, make sounds |
|||
]{.red}[and try to travel with all its members to the different cities |
|||
they get invited to contribute with their works.]{.blue}[\ I |
|||
]{.green}[need]{.green .char-style-override-1}[\ money and time to get |
|||
mysef together.\ ]{.green}[Am I really\ ]{.orange}[always]{.pink}[\ ok to |
|||
]{.orange}[stay with the trouble?]{.orange |
|||
.char-style-override-1}[]{.green} |
|||
|
|||
[]{.green} |
|||
|
|||
[//Endnote: This text was created by Rica Rickson in a process of |
|||
creative writing, It is a reflection that shall reveal the generative |
|||
forces of troubles. //]{.blue}[]{.green} |
|||
|
|||
[]{.green} |
|||
|
|||
[Ps. I am also fine with the sharing of the Cocktail]{.orange} |
|||
|
|||
[]{.orange} |
|||
|
|||
[#color]: 12 |
|||
[#text]: 2 |
|||
[#trace]: 1 |
|||
[#curve]: 1 |
@ -0,0 +1,27 @@ |
|||
# score esc {.hidden} |
|||
|
|||
Ear Worm sound rotating round the space. Dynamics increasing and decreasing over time. Vibrations of the floor are picked up by an earthqake sensor adding further sound to the soundscape. Soil is put on the floor. The diagram on upper left corner shows growing of plants during the exhibition's time span. Slogans and ideas are written on the windows. |
|||
|
|||
Within this composition we intend to project different musical reflections upon our collective practice and the exhibition within the Iterations in Graz into the concrete physical space. Intentionally, we started from different compositional approaches, to destabilize the dominant Image of the **authentic** Composer, whose **individual** work is stylistically **coherent**. We hereby oppose (propose) a spatial conception, that might be **inconsequent**, but therefore **open** for Interpretation and **Improvisation**. |
|||
|
|||
![](images/scoreESC.jpg) |
|||
|
|||
![](images/scoreESC-1.jpg) |
|||
|
|||
![](images/scoreESC-2.jpg) |
|||
|
|||
![](images/scoreESC-3.jpg) |
|||
|
|||
![](images/scoreESC-4.jpg) |
|||
|
|||
![](images/scoreESC-11.jpg) |
|||
|
|||
![](images/scoreESC-7.jpg) |
|||
|
|||
![](images/scoreESC-8.jpg) |
|||
|
|||
![](images/scoreESC-9.jpg) |
|||
|
|||
![](images/scoreESC-10.jpg) |
|||
|
|||
|
@ -0,0 +1,320 @@ |
|||
# Por debajo y por los lados: Sostener infraestructuras feministas con ficción especulativa |
|||
|
|||
Los talleres de "***Futurotopías feministas***[^1]" han mostrado su |
|||
capacidad para aportar lo que un grupo necesita en ese momento para |
|||
poder sostenerse. En ellos compartimos acerca de cómo la ficción |
|||
especulativa puede sostener nuestros esfuerzos para la creación de |
|||
infraestructuras, comunitarias y feministas. A veces han permitido que |
|||
una comunidad identifique sus malestares y ponga el foco en lo que |
|||
necesita sanar, otras veces han servido para contrabalanzar violencias |
|||
estructurales causadas por el ***patriarcalismo*** (esa alianza criminal |
|||
del patriarcado y el capitalismo), en otras nos ha permitido un respiro |
|||
juntas para seguir cuidando de los posibles; y en otras ha activado |
|||
ecosistemas habitados por narrativas, personajes de ficción y llamadas a |
|||
la acción colectiva transformadora. |
|||
|
|||
En los párrafos que siguen partimos de algunas fricciones que se dan |
|||
entre la infraestructura comunitaria/libertaria y la feminista. Pensamos |
|||
en cómo las ficciones especulativas ayudan a sostener la infraestructura |
|||
feminista, e ilustramos con algunas técnicas para hacer talleres de |
|||
ficción especulativa juntas. |
|||
|
|||
Infraestructuras rugosas |
|||
----------------------------- |
|||
|
|||
**Infraestructura**: Construir una casa o algo que te sostiene desde |
|||
algún lugar (diferente al mercado). Hacer comunidades situadas en una |
|||
multitud de lugares. |
|||
|
|||
Soy parte de una comunidad (Calafou) que "construyo especulativamente" |
|||
con muchas otras personas que no siempre he elegido, acostumbrándome a |
|||
sentir con ellas y quererlas. Un ser polimorfo monstruoso llamado |
|||
comunidad que siempre enraíza en un territorio y un paisaje. Para |
|||
construir comunidad hay que volver a un territorio donde se hace y |
|||
deshace la comunidad, compuesta por seres sentipensantes, pandillas, |
|||
voluntades, experiencias, trayectorias, subjetividades y disonancias |
|||
varias. |
|||
|
|||
Calafou consiste en recorrer uno de los posibles caminos que separa lo |
|||
distópico cyberpunk de una futurotopía. ¿Cómo se hace, cuando siempre |
|||
nos dijeron que la infraestructura o nos matará (*kill you*) o nos |
|||
poseerá (*enslave*)?. En Calafou, a veces, nos pasan ambas cosas. |
|||
|
|||
Multi-gestionamos juntxs una ***infraestructura viva***. Eso genera |
|||
a veces estrés, frustraciones, miedos y sentimientos de culpa. Uno de |
|||
los valores de la comunidad reside en cuántas equivocaciones se permite |
|||
por el camino. También genera técnicas, herramientas, conocimientos e |
|||
infraestructura. Otro de sus valores radica en cuánto se permite soñar y |
|||
especular juntas. |
|||
|
|||
Hacemos especulativamente infraestructura con otrxs, sin saber siempre |
|||
cómo hacerlo. ¿Qué hay que fijar, sistematizar, documentar? ¿Qué hay que |
|||
dejar escapar y no tocar? ¿Qué hay que regular y gobernar? ¿Qué es lo |
|||
que no tiene nada que ver con todo esto? ¿Cómo sobrepasar las tensiones |
|||
causadas por los procesos de fijación y seguir permitiendo que la |
|||
infraestructura también sea fluida, ligera, adaptable? |
|||
|
|||
A veces me gustaría ser *Binti[^2] la harmonizadora,* colaborar en que |
|||
las energías de las entidades que conforman la comunidad puedan |
|||
confluir, resolucionar, transformar juntas. Saber hacerlo con todas las |
|||
especies presentes en el territorio, activar esa interfaz. Las siento |
|||
cerca y lejos, la puesta a distancia de lo sensible sigue allí e |
|||
interfiere en nuestras proyecciones de las infraestructuras comunitarias |
|||
posibles. |
|||
|
|||
Infraestructuras que tienen tanto de técnicas como de tecnologías. Si |
|||
algo las delimita entre ellas, ese algo es relativo, borroso, cambiante. |
|||
Redes comunitarias de comunicación, comunidades que mantienen y |
|||
fortalecen saberes, infraestructuras que sostienen comunidades diversas. |
|||
Hablamos de infraestructuras que se enfocan en lo que consideramos como |
|||
básicamente necesario, como: luz, agua, caca, pis, conectividad, |
|||
compost, aguas residuales, residuos orgánicos/electrónicos/industriales, |
|||
alojamiento, producción de cosas materiales e inmateriales; y a veces se |
|||
procesa y hacen comidas o bebidas. |
|||
|
|||
Se trata de la infraestructura básica que te sostiene y te consume, |
|||
porque ese tipo de infraestructura no siempre te libera, ni a tu tiempo, |
|||
ni a tu energía. No estoy segura de cómo se construyen infraestructuras |
|||
en comunidad que nos sostienen y son a la vez sostenibles |
|||
enérgeticamente y emocionalmente. Y puede que la infraestructura |
|||
feminista nos ofrezca pistas adicionales por explorar. |
|||
|
|||
Infraestructuras feministas |
|||
--------------------------- |
|||
|
|||
Entendemos por ***infraestructuras feministas*** lo que |
|||
sostiene y apuntala con recursos, más o menos estables, las luchas |
|||
feministas: para su desarrollo y avance. Por ***recursos*** nos |
|||
referimos a técnicas, tecnologías y procesos (analógicos, digitales, |
|||
sociales) incluyendo espacios seguros, refugios, bibliotecas, redes de |
|||
sororidad y de confianza, servidores, páginas amarillas, repositorios, |
|||
bots, herramientas de documentación y memoria, enciclopedias, |
|||
HerStories, técnicas para la vida, conjuros, rituales y exorcismos. Se |
|||
incluye aquí también lo móvil, efímero, transicional que pueda residir |
|||
en la infraestructura temporal de encuentros, talleres y fiestas que |
|||
nutren la confianza, el cariño y el bienestar de las compañeras |
|||
feministas. |
|||
|
|||
Creemos que la infraestructura feminista se encuentra ***por debajo y |
|||
por los lados***, es a menudo precaria y a veces difícil de ver. Pero es |
|||
extensa, distribuida y pone en su centro el valor y afecto que se |
|||
ofrecen entre sí las personas, máquinas y ecosistemas que la componen. |
|||
|
|||
Nuestras perspectivas y condiciones de acceso, uso y desarrollo de las |
|||
tecnologías están profundamente influenciadas por cómo el patriarcado, |
|||
el capitalismo y el colonialismo están arraigados en nuestro cotidiano y |
|||
las sociedades en las que vivimos. Por ello necesitamos desarrollar |
|||
metodologías nuevas para identificar los procesos que están creando |
|||
infraestructuras feministas y cómo éstas nos señalan técnicas y |
|||
tecnologías liberadoras pensadas desde y para la vida. |
|||
|
|||
La creación de infraestructura feminista trata de darnos respuestas y |
|||
valor. Pensar en la diversidad de nuestras contribuciones y acciones nos |
|||
permite abrir nuevos horizontes de acción política, así como procesos |
|||
restaurativos, y modelar otras posibilidades para todas nosotras. |
|||
|
|||
Puede que la infraestructura feminista sea la que ofrece también |
|||
capacidad de sostenerse mediante la acción de trabajar juntxs los miedos |
|||
y vergüenzas impuestos por el sistema ***patriarcalista***. La |
|||
infraestructura feminista se parece a la infraestructuras comunitarias |
|||
anteriormente detalladas pero se hace desde otros lugares y |
|||
motivaciones. |
|||
|
|||
Las mujeres y las compañeras feministas siempre han estado allí, por |
|||
debajo y por lados, compartiendo ***técnicas para la vida*** y haciendo |
|||
***tecnologías apropiadas*** (desde una idiosincrasia que no |
|||
contamina ni resta), tecnologías "lentas", tecnologías ancestrales, |
|||
"tecnologías menores", y tecnologías libres en pos de la soberanía y |
|||
autonomía de las comunidades que las desarrollan. Hemos sido portadoras |
|||
y garantes de que el conocimiento acerca de esta diversidad de técnicas |
|||
se compartiera y evolucionara dentro de comunidades ya que como nos |
|||
recuerda Margarita Padilla: "*todas las tecnologías se desarrollan en |
|||
comunidades, que pueden ser, más o menos, autónomas o pueden estar, más |
|||
o menos, controladas por las corporaciones. En la lucha por la |
|||
soberanía, la cosa va de comunidades. Nadie inventa, construye o |
|||
programa en solitario, sencillamente porque la complejidad de la tarea |
|||
es tal que eso resultaría imposible*[^3]". |
|||
|
|||
Técnicas para la vida \<\> Tecnologías apropiadas |
|||
------------------------------------------------- |
|||
|
|||
Pero ¿qué es lo que delimita la línea sensible entre técnicas y |
|||
tecnologías y por qué eso importa para la infraestructura feminista? |
|||
Según Biacini y Carnino, la técnica es "*a la vez un saber hacer y unas |
|||
herramientas, es decir, un conjunto de procesos informales y su |
|||
sedimentación instrumental en los objetos producidos por lx artesanx[^4] |
|||
\[\...\] La tecnología es un conjunto de procesos macrotécnicos (es |
|||
decir, procesos que son más grandes que el ser humano y la comunidad de |
|||
una aldea) que son posibles gracias a la alianza de la ciencia y la |
|||
tecnología[^5]*". |
|||
|
|||
La técnica puede ser no tecnológica, pero la tecnología se hace |
|||
absorbiendo técnicas. En la sistematización inducida por la producción |
|||
de tecnologías, se pueden obviar y destruir por completo técnicas para |
|||
la vida. Las que nos ofrecían otras maneras de pensar nuestra relación |
|||
con el entorno y los valores que proyectamos en esa relación. |
|||
|
|||
Biacini y Carnino nos aportan otro elemento central de reflexión al |
|||
desatacar que "*Según Wigney, el mundo antiguo seguía produciendo hechos |
|||
relativos en lugar de hechos absolutos porque se basaba en conocimientos |
|||
esencialmente situados y difíciles de transferir a otros lugares. La |
|||
industrialización y su corolario, la proletarización definida como |
|||
despojo artesanal, sólo fue posible a escala masiva con la ayuda de la |
|||
ciencia en desarrollo. Esta ciencia, lejos de ser especulativa, está |
|||
profundamente arraigada en la realidad: es un hecho*[^6]\". |
|||
|
|||
En ese deslizamiento sentimos de nuevo el potencial de la práctica de |
|||
ficciones especulativas para recuperar esas técnicas para la vida y ver |
|||
cómo nos llevan hacia tecnologías apropiadas para nuestras comunidades. |
|||
En lo situado y lo especulativo encontramos manera de deshacernos del |
|||
mito de la ciencia y el progreso tecnológico. Esa tecnología se define |
|||
ante todo como una política de hechos consumados (*move fast and break |
|||
things*). Muy pocos participan en soñarla, diseñarla, decidirla; pero |
|||
todas nosotras estamos expuestas a los efectos de su implementación. No |
|||
deja lugar a un diseño especulativo colectivo de las técnicas y |
|||
tecnologías que necesitamos y nos merecemos. Las ciencias modernas y las |
|||
"nuevas" tecnologías se basan en poner a distancia, anular o absorber |
|||
las técnicas necesarias para la vida y nos impiden encontrar los pasos, |
|||
atajos y caminos hacia nuestras tecnologías apropiadas. |
|||
|
|||
Según Elleflane, una "*tecnología adecuada y también apropiada, copiada, |
|||
obtenida. \[...\] describe aquella tecnología que mejor se adecua a |
|||
situaciones medioambientales, culturales y económicas, requiere pocos |
|||
recursos, implica menos costos, tiene un bajo impacto ambiental, no |
|||
requiere altos niveles de mantenimiento, se genera con destrezas, |
|||
herramientas y materiales de la zona y puede ser localmente reparada, |
|||
modificada y transformada. Al fin y al cabo, ¿qué comunidad no necesita |
|||
que una tecnología sea eficiente, se comprenda y se adapte a su contexto |
|||
medioambiental, cultural y económico propio*?[^7]\". En esta comprensión |
|||
y consentimiento mutuo entre comunidades y sus tecnologías apropiadas se |
|||
encuentran las claves para una infraestructura feminista que sostiene |
|||
ecosistemas regeneradores. Como si estuvieran basados en procesos de |
|||
autopoiesis, se alimentan de nuestras ideas, memorias, narrativas, |
|||
historias, fabulaciones y deseos. |
|||
|
|||
Vocabularios nuevos para crear mundos |
|||
-------------------------------------- |
|||
|
|||
Lo que no se nombra no puede existir, por ello invitamos a crear nuevos |
|||
vocabularios y técnicas para explorar estas futurotopías e |
|||
infraestructuras feministas. Por ejemplo, podríamos hablarnos desde |
|||
estas nociones para darles forma: |
|||
|
|||
Eco-tecnología (*Toward an ecological society*, Murray Bookchin): "*Una |
|||
eco-comunidad podría ser sostenida por una nueva clase de tecnología |
|||
compuesta de maquinaria flexible y versátil cuyas aplicaciones |
|||
productivas garanticen la durabilidad y la calidad, no siendo |
|||
programadas para la obsolescencia ni para producir una cantidad absurda |
|||
de baratijas y entrar en la rápida circulación de mercancías básicas*". |
|||
|
|||
Eco-economia (*Trilogía de Marte*, Stanley Robinson): ¿Cómo creamos en |
|||
este y los otros planetas una economía que pone en su centro una |
|||
ecología basada en la solidaridad geológica e inter-especies? |
|||
|
|||
Cacatedra (*Ecosec*): Volverse experta en gestionar nuestra mierda, en |
|||
el sentido literal y figurado, toda la cadena que implica expulsarla, |
|||
recogerla, sacarla a paseo y compostarla. Devolverle su dignidad como |
|||
indicio de buena suerte y abono para la tierra. |
|||
|
|||
Para-paraíso (*Tatiana, THF Editorial*): Se trata de un paraíso cuidado |
|||
por antiguos paramilitares reconvertidos en guíás turísticos y |
|||
guardianes del bosque y los ríos, o de un paraíso situado en una |
|||
dimensión paralela/alternativa que está muy cerca pero a la cual no |
|||
sabes aun como llegar. |
|||
|
|||
Narcofeminismo (*Metzineres*): Teoría práctica basada en lo desarrollado |
|||
y hablado en los espacios autogestionados por mujeres que consumen |
|||
drogas, construyendo una relación diferente con un hábito de consumo a |
|||
través del feminismo y la solidaridad, empoderándose juntas para |
|||
sobrepasar situaciones de violencia de genero sistémicas. Apropiarse de |
|||
tecnologías blandas, químicas y relacionales. |
|||
|
|||
Futurotopía (*B01*): Contraer los futuros y nuestras utopías, resaltar |
|||
la posibilidad de pensar juntas en los futuros hacia los cuales queremos |
|||
caminar juntas, volviéndolos posibles al permitir pensarlos y |
|||
contárselos a otras personas. Para trabajar juntas en el eje del tiempo, |
|||
también proponemos algunas técnicas de Black Quantum Futurism[^8]: |
|||
|
|||
Visión de futuro : a través de este modo de práctica se aumenta la |
|||
capacidad de conocer el futuro al ser capaz de verlo con más claridad |
|||
visual de lo normal. Este modo implica poca o ninguna desviación del |
|||
futuro, sólo una mayor precisión sin visualizarlo. |
|||
|
|||
Alteración futura: este modo de práctica implica una estrecha desviación |
|||
de la realidad presente, utilizando lo que ya está disponible y lo que |
|||
es estadísticamente probable para elegir el futuro de un pequeño |
|||
subconjunto de futuros probables |
|||
|
|||
Manifestación futura: este modo de práctica implica el mayor grado de |
|||
creatividad, permitiendo al practicante construir el futuro paso a paso, |
|||
pieza a pieza. |
|||
|
|||
Y añadimos generar nuestras propias profecías autorrealizadas "*una |
|||
predicción que, una vez hecha, es en sí misma es la causa de que se haga |
|||
realidad*". |
|||
|
|||
Finalmente, listamos otras técnicas posibles[^9] que hemos ido |
|||
detectando en nuestras ficciones especulativas: visionar, relatar |
|||
nuestros suenos y pesadillas, contar nuestras memorias, meditar, dormir |
|||
despiertas, ramificar, crear recuerdos del futuro, rescatar y exorcizar |
|||
pasados no escritos, apuntar a los vacíos, suturar las grietas, viajar |
|||
en nuestras cuerpas, crear procesos restaurativos, sanar los traumas, |
|||
limitar las narrativas impuestas, escritura automática. |
|||
|
|||
Pensar nuestras infraestructuras desde los puntos de tensión |
|||
------------------------------------------------------------- |
|||
|
|||
La infraestructura comunitaria y la feminista comparten puntos en |
|||
común y algunas tensiones que las atraviesan. |
|||
|
|||
Creemos que ambas se basan en procesos de hacer juntas de manera |
|||
especulativa. Ambas pueden explotar, reventar, desaparecer rápidamente |
|||
también. |
|||
|
|||
Implican técnicas para la vida, tecnologías que permiten |
|||
sistematizar/fijar ciertos procesos y que existen en ecosistemas que |
|||
necesitan ser documentados, comunicados, circulados para así existir. |
|||
|
|||
Tienden a sistematizar/sedimentar ciertos procesos, absorbiendo técnicas |
|||
para la vida y haciendo a veces con ellas tecnologías apropriadas. |
|||
|
|||
Orientan ciertas necesidades/acciones hacia algunos recursos pensados |
|||
para cubrirlos/darles una respuesta, generando efectos varios que no |
|||
sabemos aún cómo rastrear/leer. |
|||
|
|||
La infraestructura tiende a (re)generar y (a)cumular, y hay que revisar |
|||
con periodicidad la alquimia que se deriva de esa tensión, para drenar o |
|||
regar/alimentar a tiempo. |
|||
|
|||
La infraestructura estable, o la que está en beta, nos adentra en una |
|||
tensión paradójica entre "ganar" en autonomía y no "perder" en |
|||
independencia . |
|||
|
|||
Así que en sí misma es una pregunta abierta acerca de cómo podemos o |
|||
seguir con ella, o vivir sin ella, y en qué grado o de qué modos lo |
|||
hacemos posible juntas. |
|||
|
|||
[^1]: <https://zoiahorn.anarchaserver.org/specfic/> |
|||
|
|||
[^2]: https://en.wikipedia.org/wiki/Nnedi\_Okorafor |
|||
|
|||
[^3]: Margarita Padilla, "Soberanía Tecnológica, Volumen 2", 2018, |
|||
Disponible: |
|||
https://www.ritimo.org/IMG/pdf/sobtech2-es-with-covers-web-150dpi-2018-01-13-v2.pdf |
|||
|
|||
[^4]: El lenguaje es también una tecnología, a menudo binaria, y en esta |
|||
ocasión he decidido des-binarizar alx artesanx. |
|||
|
|||
[^5]: "On arrête parfois le progrès", Cedric Biacini y Guillaume |
|||
Carnino, \"Les luddites en France: Résistances a |
|||
l\'industrialisation et a l\'informatisation\", Ed. L\'échapée, 2010 |
|||
|
|||
[^6]: ibid |
|||
|
|||
[^7]: De las tecnologías apropiadas a las Tecnologías Re-Apropiadas, por |
|||
Elleflâne, Soberanía Tecnológica, Volumen 2", 2018, Disponible: |
|||
https://www.ritimo.org/IMG/pdf/sobtech2-es-with-covers-web-150dpi-2018-01-13-v2.pdf |
|||
|
|||
[^8]: https://www.blackquantumfuturism.com/ |
|||
|
|||
[^9]: https://zoiahorn.anarchaserver.org/specfic/2020/02/11/iterations/ |
@ -0,0 +1,157 @@ |
|||
svg { |
|||
touch-action: none; |
|||
display: block; |
|||
clear: both; |
|||
/*border:1px dotted magenta;*/ |
|||
/*margin-top:-1px;*/ |
|||
} |
|||
.handle { |
|||
fill: none; |
|||
pointer-events: all; |
|||
} |
|||
/* including #handles is a hack to increase specificity */ |
|||
#handles .handle:hover { |
|||
/*fill: #f00;*/ |
|||
fill: black; |
|||
} |
|||
svg:hover .handle { |
|||
/*fill: #800;*/ |
|||
fill: black; |
|||
} |
|||
svg:hover .selected .handle { |
|||
/*fill: #fcb;*/ |
|||
fill: black; |
|||
stroke: black; |
|||
} |
|||
#handles line.target { |
|||
stroke: black; |
|||
} |
|||
#handles circle.target { |
|||
fill: none; |
|||
stroke: black; |
|||
stroke-opacity: 0.15; |
|||
stroke-width: 10; |
|||
} |
|||
svg:hover #handles line.tan { |
|||
/*stroke: #00f;*/ |
|||
fill: black; |
|||
stroke-width: 1; |
|||
} |
|||
svg:hover #handles .tanhandle { |
|||
/*fill: white;*/ |
|||
fill: black; |
|||
/*stroke: #00f;*/ |
|||
} |
|||
svg:hover #handles .tanhandle.computed { |
|||
/*fill: rgba(255, 255, 255, 0.3);*/ |
|||
fill: black; |
|||
/*stroke: rgba(0, 0, 255, 0.3);*/ |
|||
} |
|||
svg:hover #handles .tanhandle:hover { |
|||
/*fill: #fcb;*/ |
|||
fill: black; |
|||
} |
|||
#grid line { |
|||
stroke: #ddf; |
|||
} |
|||
|
|||
#nav { |
|||
position: relative; |
|||
font-size: 12px; |
|||
/* float: left; */ |
|||
height: 25px; |
|||
z-index: 10; |
|||
top: 0px; |
|||
left: 0; |
|||
padding: 0; |
|||
margin: 0; |
|||
width: 100%; |
|||
user-select: none; |
|||
} |
|||
#nav li { |
|||
float: left; |
|||
position: relative; |
|||
list-style: none; |
|||
} |
|||
#nav li a { |
|||
display: block; |
|||
padding: 5px 10px; |
|||
color: #000; |
|||
text-decoration: none; |
|||
cursor: default; |
|||
} |
|||
#nav a:hover:not(.inactive) { |
|||
background: #cdf; |
|||
} |
|||
#nav li ul { |
|||
position: absolute; |
|||
display: none; |
|||
background: #fff; |
|||
box-shadow: 2px 2px 5px 0 rgba(0, 0, 0, 0.3); |
|||
/*float: none;*/ |
|||
} |
|||
#nav li ul a { |
|||
width: 10em; |
|||
width: -moz-max-content; |
|||
width: max-content; |
|||
padding: 4px 10px; |
|||
cursor: default; |
|||
} |
|||
#nav li ul a.inactive { |
|||
color: #888; |
|||
} |
|||
#nav li:hover ul { |
|||
display: block; |
|||
left: 0; |
|||
margin: 0; |
|||
padding: 0; |
|||
border-width: 1px; |
|||
border-style: solid; |
|||
border-color: #000; |
|||
} |
|||
#nav li:hover ul.off { |
|||
display: none; |
|||
} |
|||
|
|||
.modal { |
|||
display: none; |
|||
position: fixed; |
|||
z-index: 1; |
|||
left: 0; |
|||
top: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
overflow: auto; |
|||
background-color: rgba(255, 255, 255, 0.3); |
|||
} |
|||
|
|||
.modal-content { |
|||
margin: 15% auto; |
|||
padding: 20px; |
|||
border: 1px solid #888; |
|||
width: 60%; |
|||
background-color: rgba(255, 255, 255, 0.8); |
|||
} |
|||
.modal-content pre { |
|||
white-space: pre-wrap; |
|||
} |
|||
.modal-content textarea { |
|||
width: 100%; |
|||
} |
|||
.modal-content button { |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.close { |
|||
float: right; |
|||
font-size: 28px; |
|||
user-select: none; |
|||
} |
|||
|
|||
.close:hover, .close.focus { |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.invisible { |
|||
opacity: 0; |
|||
} |
@ -0,0 +1,162 @@ |
|||
@font-face{ |
|||
font-family: 'main'; |
|||
src:url(../fonts/go-mono/Go-Mono.ttf); |
|||
font-weight: normal; |
|||
font-style: normal; |
|||
} |
|||
@font-face{ |
|||
font-family: 'main'; |
|||
src:url(../fonts/go-mono/Go-Mono-Bold.ttf); |
|||
font-weight: bold; |
|||
font-style: normal; |
|||
} |
|||
@font-face{ |
|||
font-family: 'brazil'; |
|||
src:url(../fonts/Brazil/Brazil-Regular.otf); |
|||
} |
|||
body{ |
|||
color: black; |
|||
/*background-color: rgba(255, 0, 255, 0.35);*/ |
|||
/*background-color: rgba(194, 216, 28, 0.35);*/ |
|||
background-color: rgb(247, 245, 243); |
|||
font-family: 'main'; |
|||
font-size: 20px; |
|||
line-height: 1.7; |
|||
text-align: center; |
|||
} |
|||
|
|||
/* general */ |
|||
/* ------- */ |
|||
|
|||
div#main{ |
|||
margin-top:5.5em; |
|||
} |
|||
hr{ |
|||
border:0; |
|||
border-bottom:1px dotted magenta; |
|||
/*border-bottom:50px dotted #8fbeff;*/ |
|||
/*border-bottom:50px solid #8fbeff;*/ |
|||
margin:5em 0; |
|||
clear: both; |
|||
} |
|||
small{ |
|||
display: block; |
|||
line-height: 1.6; |
|||
margin:2em; |
|||
} |
|||
.block{ |
|||
color:magenta; |
|||
width: calc(50% - 8em); |
|||
float: left; |
|||
padding:0em 4em 3em; |
|||
} |
|||
.block p{ |
|||
margin-top:2em; |
|||
} |
|||
.info{ |
|||
color:magenta; |
|||
padding:1em 0 0; |
|||
font-size: 32px; |
|||
max-width: 1000px; |
|||
margin:0 auto; |
|||
position: relative; |
|||
} |
|||
|
|||
/* nav */ |
|||
div#tools-nav, |
|||
div#tools-extra{ |
|||
position: fixed; |
|||
top:5px; |
|||
z-index: 10; |
|||
} |
|||
div#tools-nav button, |
|||
div#tools-extra button{ |
|||
line-height: 1.5; |
|||
} |
|||
div#tools-extra{ |
|||
right: 5px; |
|||
} |
|||
|
|||
/* special font for handles and annotation tools*/ |
|||
#title, |
|||
strong.handle, |
|||
strong.annotation, |
|||
button{ |
|||
font-family: 'brazil'; |
|||
font-size: 190%; |
|||
font-weight: normal; |
|||
line-height: 0; |
|||
} |
|||
#title{ |
|||
font-size: 110%; |
|||
} |
|||
svg#index{ |
|||
width: 400px; |
|||
} |
|||
table{ |
|||
width: 100%; |
|||
margin:1em 0 5em; |
|||
} |
|||
table th, |
|||
table td{ |
|||
padding:1em; |
|||
border:1px solid; |
|||
vertical-align: top; |
|||
} |
|||
table td textarea{ |
|||
width: calc(100% - 2em); |
|||
height: 100%; |
|||
margin: 0.25em 1em; |
|||
} |
|||
table td select{ |
|||
width: 100%; |
|||
} |
|||
|
|||
|
|||
/* forms */ |
|||
form{ |
|||
line-height: 3; |
|||
} |
|||
input{ |
|||
vertical-align: middle; |
|||
margin-left: 1em; |
|||
} |
|||
input.submit, |
|||
input.reset, |
|||
a#reset, |
|||
button a{ |
|||
margin:0; |
|||
text-decoration: none; |
|||
color:black; |
|||
} |
|||
|
|||
/* annotation tools */ |
|||
/* ---------------- */ |
|||
|
|||
/* curves */ |
|||
svg{ |
|||
margin:0 auto; |
|||
} |
|||
svg.canvas{ |
|||
background-color: rgba(220,220,220,0.8); |
|||
} |
|||
div#curves svg.canvas{ |
|||
background-color: transparent; |
|||
} |
|||
/* color */ |
|||
#color-preview{ |
|||
width: 100px; |
|||
height: 100px; |
|||
float: left; |
|||
border-radius: 100%; |
|||
margin:1em; |
|||
} |
|||
/* text */ |
|||
|
|||
/* visual-traces */ |
|||
img.traces{ |
|||
max-width: 500px; |
|||
vertical-align: middle; |
|||
margin:0 0 1em 1em; |
|||
} |
|||
|
@ -0,0 +1,44 @@ |
|||
/* --------- */ |
|||
/* text-scan */ |
|||
#wrapper{ |
|||
width: calc(100% - 0em); |
|||
} |
|||
div#crossings, div#sentences, div#ADJ, div#PRE{ |
|||
position: relative; |
|||
display: inline-block; |
|||
width: calc(50% - 1.5em); |
|||
top:0; |
|||
left: 0; |
|||
margin:0 1em 2em 0; |
|||
padding:0; |
|||
vertical-align: top; |
|||
font-size: 90%; |
|||
} |
|||
div#crossings{ |
|||
float: right; |
|||
} |
|||
div#txtfiles{ |
|||
position: absolute; |
|||
width:200px; |
|||
top:0; |
|||
right: 40px; |
|||
} |
|||
div.sentence{ |
|||
margin:-0.5em 0 0; |
|||
} |
|||
strong.query{ |
|||
display: inline; |
|||
width: 100%; |
|||
height: 12em; |
|||
margin:10em -6em -10.5em -6em; |
|||
padding: 10em 6em; |
|||
text-align: center; |
|||
} |
|||
small, sup{ |
|||
font-family: monospace; |
|||
font-size: 10pt; |
|||
} |
|||
div.sentence small{ |
|||
display: block; |
|||
margin-bottom: 5em; |
|||
} |
After Width: | Height: | Size: 3.5 MiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |
@ -0,0 +1 @@ |
|||
2f3c42b9-3fc0-4acd-a79a-bb5cd3ef114f |
After Width: | Height: | Size: 789 KiB |
@ -0,0 +1,23 @@ |
|||
{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 |
|||
{\fonttbl\f0\fnil\fcharset0 Brazil-Regular;} |
|||
{\colortbl;\red255\green255\blue255;\red53\green53\blue53;\red251\green0\blue7;} |
|||
\paperw11900\paperh16840\margl1440\margr1440\vieww11460\viewh12380\viewkind0 |
|||
\deftab560 |
|||
\pard\pardeftab560\sl192\slmult1\partightenfactor0 |
|||
|
|||
\f0\fs48 \cf2 \ |
|||
bRAZIL: motivated by a tag seen on the wall of an Amsterdam fondue cafE toilet in 2010. Designed in collaboration with Bram van den Berg. \cf0 \kerning1\expnd2\expndtw12 |
|||
\dn4 \super \ |
|||
\pard\pardeftab720\ri-2323\sl192\slmult1\partightenfactor0 |
|||
\cf0 \ |
|||
This work is licensed under an SIL Open Font License (OFL). For details see here {\field{\*\fldinst{HYPERLINK "http://scripts.sil.org/OFL"}}{\fldrslt \cf3 \expnd0\expndtw0\kerning0 |
|||
\up0 \nosupersub \ul \ulc3 http://scripts.sil.org/OFL}} \ |
|||
\ |
|||
For a free printed type specimen, send a self addressed, return envelope to: Colophon, Willemsstraat 32, 1015 JD Amsterdam, The Netherlands.\ |
|||
\pard\pardeftab720\ri-1780\sl288\slmult1\partightenfactor0 |
|||
\cf0 \kerning1\expnd13\expndtw68 |
|||
\up0 \nosupersub \ |
|||
\pard\pardeftab720\ri-2323\sl192\slmult1\partightenfactor0 |
|||
\cf0 \kerning1\expnd2\expndtw12 |
|||
\dn4 \super \ |
|||
} |
@ -0,0 +1,95 @@ |
|||
Copyright (c) <2016>, <Colophon> (<www.colophon.info>), |
|||
with Reserved Font Name <Brazil>. |
|||
|
|||
|
|||
This Font Software is licensed under the SIL Open Font License, Version 1.1. |
|||
This license is copied below, and is also available with a FAQ at: |
|||
http://scripts.sil.org/OFL |
|||
|
|||
|
|||
----------------------------------------------------------- |
|||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 |
|||
----------------------------------------------------------- |
|||
|
|||
PREAMBLE |
|||
The goals of the Open Font License (OFL) are to stimulate worldwide |
|||
development of collaborative font projects, to support the font creation |
|||
efforts of academic and linguistic communities, and to provide a free and |
|||
open framework in which fonts may be shared and improved in partnership |
|||
with others. |
|||
|
|||
The OFL allows the licensed fonts to be used, studied, modified and |
|||
redistributed freely as long as they are not sold by themselves. The |
|||
fonts, including any derivative works, can be bundled, embedded, |
|||
redistributed and/or sold with any software provided that any reserved |
|||
names are not used by derivative works. The fonts and derivatives, |
|||
however, cannot be released under any other type of license. The |
|||
requirement for fonts to remain under this license does not apply |
|||
to any document created using the fonts or their derivatives. |
|||
|
|||
DEFINITIONS |
|||
"Font Software" refers to the set of files released by the Copyright |
|||
Holder(s) under this license and clearly marked as such. This may |
|||
include source files, build scripts and documentation. |
|||
|
|||
"Reserved Font Name" refers to any names specified as such after the |
|||
copyright statement(s). |
|||
|
|||
"Original Version" refers to the collection of Font Software components as |
|||
distributed by the Copyright Holder(s). |
|||
|
|||
"Modified Version" refers to any derivative made by adding to, deleting, |
|||
or substituting -- in part or in whole -- any of the components of the |
|||
Original Version, by changing formats or by porting the Font Software to a |
|||
new environment. |
|||
|
|||
"Author" refers to any designer, engineer, programmer, technical |
|||
writer or other person who contributed to the Font Software. |
|||
|
|||
PERMISSION & CONDITIONS |
|||
Permission is hereby granted, free of charge, to any person obtaining |
|||
a copy of the Font Software, to use, study, copy, merge, embed, modify, |
|||
redistribute, and sell modified and unmodified copies of the Font |
|||
Software, subject to the following conditions: |
|||
|
|||
1) Neither the Font Software nor any of its individual components, |
|||
in Original or Modified Versions, may be sold by itself. |
|||
|
|||
2) Original or Modified Versions of the Font Software may be bundled, |
|||
redistributed and/or sold with any software, provided that each copy |
|||
contains the above copyright notice and this license. These can be |
|||
included either as stand-alone text files, human-readable headers or |
|||
in the appropriate machine-readable metadata fields within text or |
|||
binary files as long as those fields can be easily viewed by the user. |
|||
|
|||
3) No Modified Version of the Font Software may use the Reserved Font |
|||
Name(s) unless explicit written permission is granted by the corresponding |
|||
Copyright Holder. This restriction only applies to the primary font name as |
|||
presented to the users. |
|||
|
|||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font |
|||
Software shall not be used to promote, endorse or advertise any |
|||
Modified Version, except to acknowledge the contribution(s) of the |
|||
Copyright Holder(s) and the Author(s) or with their explicit written |
|||
permission. |
|||
|
|||
5) The Font Software, modified or unmodified, in part or in whole, |
|||
must be distributed entirely under this license, and must not be |
|||
distributed under any other license. The requirement for fonts to |
|||
remain under this license does not apply to any document created |
|||
using the Font Software. |
|||
|
|||
TERMINATION |
|||
This license becomes null and void if any of the above conditions are |
|||
not met. |
|||
|
|||
DISCLAIMER |
|||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF |
|||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT |
|||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE |
|||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL |
|||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM |
|||
OTHER DEALINGS IN THE FONT SOFTWARE. |
@ -0,0 +1,427 @@ |
|||
OFL FAQ - Frequently Asked Questions about the SIL Open Font License (OFL) |
|||
Version 1.1-update4 - Sept 2014 |
|||
(See http://scripts.sil.org/OFL for updates) |
|||
|
|||
|
|||
CONTENTS OF THIS FAQ |
|||
1 USING AND DISTRIBUTING FONTS LICENSED UNDER THE OFL |
|||
2 USING OFL FONTS FOR WEB PAGES AND ONLINE WEB FONT SERVICES |
|||
3 MODIFYING OFL-LICENSED FONTS |
|||
4 LICENSING YOUR ORIGINAL FONTS UNDER THE OFL |
|||
5 CHOOSING RESERVED FONT NAMES |
|||
6 ABOUT THE FONTLOG |
|||
7 MAKING CONTRIBUTIONS TO OFL PROJECTS |
|||
8 ABOUT THE LICENSE ITSELF |
|||
9 ABOUT SIL INTERNATIONAL |
|||
APPENDIX A - FONTLOG EXAMPLE |
|||
|
|||
1 USING AND DISTRIBUTING FONTS LICENSED UNDER THE OFL |
|||
|
|||
1.1 Can I use the fonts for a book or other print publication, to create logos or other graphics or even to manufacture objects based on their outlines? |
|||
Yes. You are very welcome to do so. Authors of fonts released under the OFL allow you to use their font software as such for any kind of design work. No additional license or permission is required, unlike with some other licenses. Some examples of these uses are: logos, posters, business cards, stationery, video titling, signage, t-shirts, personalised fabric, 3D-printed/laser-cut shapes, sculptures, rubber stamps, cookie cutters and lead type. |
|||
|
|||
1.1.1 Does that restrict the license or distribution of that artwork? |
|||
No. You remain the author and copyright holder of that newly derived graphic or object. You are simply using an open font in the design process. It is only when you redistribute, bundle or modify the font itself that other conditions of the license have to be respected (see below for more details). |
|||
|
|||
1.1.2 Is any kind of acknowledgement required? |
|||
No. Font authors may appreciate being mentioned in your artwork's acknowledgements alongside the name of the font, possibly with a link to their website, but that is not required. |
|||
|
|||
1.2 Can the fonts be included with Free/Libre and Open Source Software collections such as GNU/Linux and BSD distributions and repositories? |
|||
Yes! Fonts licensed under the OFL can be freely included alongside other software under FLOSS (Free/Libre and Open Source Software) licenses. Since fonts are typically aggregated with, not merged into, existing software, there is little need to be concerned about incompatibility with existing software licenses. You may also repackage the fonts and the accompanying components in a .rpm or .deb package (or other similar package formats or installers) and include them in distribution CD/DVDs and online repositories. (Also see section 5.9 about rebuilding from source.) |
|||
|
|||
1.3 I want to distribute the fonts with my program. Does this mean my program also has to be Free/Libre and Open Source Software? |
|||
No. Only the portions based on the Font Software are required to be released under the OFL. The intent of the license is to allow aggregation or bundling with software under restricted licensing as well. |
|||
|
|||
1.4 Can I sell a software package that includes these fonts? |
|||
Yes, you can do this with both the Original Version and a Modified Version of the fonts. Examples of bundling made possible by the OFL would include: word processors, design and publishing applications, training and educational software, games and entertainment software, mobile device applications, etc. |
|||
|
|||
1.5 Can I include the fonts on a CD of freeware or commercial fonts? |
|||
Yes, as long some other font or software is also on the disk, so the OFL font is not sold by itself. |
|||
|
|||
1.6 Why won't the OFL let me sell the fonts alone? |
|||
The intent is to keep people from making money by simply redistributing the fonts. The only people who ought to profit directly from the fonts should be the original authors, and those authors have kindly given up potential direct income to distribute their fonts under the OFL. Please honour and respect their contribution! |
|||
|
|||
1.7 What about sharing OFL fonts with friends on a CD, DVD or USB stick? |
|||
You are very welcome to share open fonts with friends, family and colleagues through removable media. Just remember to include the full font package, including any copyright notices and licensing information as available in OFL.txt. In the case where you sell the font, it has to come bundled with software. |
|||
|
|||
1.8 Can I host the fonts on a web site for others to use? |
|||
Yes, as long as you make the full font package available. In most cases it may be best to point users to the main site that distributes the Original Version so they always get the most recent stable and complete version. See also discussion of web fonts in Section 2. |
|||
|
|||
1.9 Can I host the fonts on a server for use over our internal network? |
|||
Yes. If the fonts are transferred from the server to the client computer by means that allow them to be used even if the computer is no longer attached to the network, the full package (copyright notices, licensing information, etc.) should be included. |
|||
|
|||
1.10 Does the full OFL license text always need to accompany the font? |
|||
The only situation in which an OFL font can be distributed without the text of the OFL (either in a separate file or in font metadata), is when a font is embedded in a document or bundled within a program. In the case of metadata included within a font, it is legally sufficient to include only a link to the text of the OFL on http://scripts.sil.org/OFL, but we strongly recommend against this. Most modern font formats include metadata fields that will accept the full OFL text, and full inclusion increases the likelihood that users will understand and properly apply the license. |
|||
|
|||
1.11 What do you mean by 'embedding'? How does that differ from other means of distribution? |
|||
By 'embedding' we mean inclusion of the font in a document or file in a way that makes extraction (and redistribution) difficult or clearly discouraged. In many cases the names of embedded fonts might also not be obvious to those reading the document, the font data format might be altered, and only a subset of the font - only the glyphs required for the text - might be included. Any other means of delivering a font to another person is considered 'distribution', and needs to be accompanied by any copyright notices and licensing information available in OFL.txt. |
|||
|
|||
1.12 So can I embed OFL fonts in my document? |
|||
Yes, either in full or a subset. The restrictions regarding font modification and redistribution do not apply, as the font is not intended for use outside the document. |
|||
|
|||
1.13 Does embedding alter the license of the document itself? |
|||
No. Referencing or embedding an OFL font in any document does not change the license of the document itself. The requirement for fonts to remain under the OFL does not apply to any document created using the fonts and their derivatives. Similarly, creating any kind of graphic using a font under OFL does not make the resulting artwork subject to the OFL. |
|||
|
|||
1.14 If OFL fonts are extracted from a document in which they are embedded (such as a PDF file), what can be done with them? Is this a risk to author(s)? |
|||
The few utilities that can extract fonts embedded in a PDF will typically output limited amounts of outlines - not a complete font. To create a working font from this method is much more difficult and time consuming than finding the source of the original OFL font. So there is little chance that an OFL font would be extracted and redistributed inappropriately through this method. Even so, copyright laws address any misrepresentation of authorship. All Font Software released under the OFL and marked as such by the author(s) is intended to remain under this license regardless of the distribution method, and cannot be redistributed under any other license. We strongly discourage any font extraction - we recommend directly using the font sources instead - but if you extract font outlines from a document, please be considerate: respect the work of the author(s) and the licensing model. |
|||
|
|||
1.15 What about distributing fonts with a document? Within a compressed folder structure? Is it distribution, bundling or embedding? |
|||
Certain document formats may allow the inclusion of an unmodified font within their file structure which may consist of a compressed folder containing the various resources forming the document (such as pictures and thumbnails). Including fonts within such a structure is understood as being different from embedding but rather similar to bundling (or mere aggregation) which the license explicitly allows. In this case the font is conveyed unchanged whereas embedding a font usually transforms it from the original format. The OFL does not allow anyone to extract the font from such a structure to then redistribute it under another license. The explicit permission to redistribute and embed does not cancel the requirement for the Font Software to remain under the license chosen by its author(s). Even if the font travels inside the document as one of its assets, it should not lose its authorship information and licensing. |
|||
|
|||
1.16 What about ebooks shipping with open fonts? |
|||
The requirements differ depending on whether the fonts are linked, embedded or distributed (bundled or aggregated). Some ebook formats use web technologies to do font linking via @font-face, others are designed for font embedding, some use fonts distributed with the document or reading software, and a few rely solely on the fonts already present on the target system. The license requirements depend on the type of inclusion as discussed in 1.15. |
|||
|
|||
1.17 Can Font Software released under the OFL be subject to URL-based access restrictions methods or DRM (Digital Rights Management) mechanisms? |
|||
Yes, but these issues are out-of-scope for the OFL. The license itself neither encourages their use nor prohibits them since such mechanisms are not implemented in the components of the Font Software but through external software. Such restrictions are put in place for many different purposes corresponding to various usage scenarios. One common example is to limit potentially dangerous cross-site scripting attacks. However, in the spirit of libre/open fonts and unrestricted writing systems, we strongly encourage open sharing and reuse of OFL fonts, and the establishment of an environment where such restrictions are unnecessary. Note that whether you wish to use such mechanisms or you prefer not to, you must still abide by the rules set forth by the OFL when using fonts released by their authors under this license. Derivative fonts must be licensed under the OFL, even if they are part of a service for which you charge fees and/or for which access to source code is restricted. You may not sell the fonts on their own - they must be part of a larger software package, bundle or subscription plan. For example, even if the OFL font is distributed in a software package or via an online service using a DRM mechanism, the user would still have the right to extract that font, use, study, modify and redistribute it under the OFL. |
|||
|
|||
1.18 I've come across a font released under the OFL. How can I easily get more information about the Original Version? How can I know where it stands compared to the Original Version or other Modified Versions? |
|||
Consult the copyright statement(s) in the license for ways to contact the original authors. Consult the FONTLOG (see section 6 for more details and examples) for information on how the font differs from the Original Version, and get in touch with the various contributors via the information in the acknowledgement section. Please consider using the Original Versions of the fonts whenever possible. |
|||
|
|||
1.19 What do you mean in condition 4 of the OFL's permissions and conditions? Can you provide examples of abusive promotion / endorsement / advertisement vs. normal acknowledgement? |
|||
The intent is that the goodwill and reputation of the author(s) should not be used in a way that makes it sound like the original author(s) endorse or approve of a specific Modified Version or software bundle. For example, it would not be right to advertise a word processor by naming the author(s) in a listing of software features, or to promote a Modified Version on a web site by saying "designed by ...". However, it would be appropriate to acknowledge the author(s) if your software package has a list of people who deserve thanks. We realize that this can seem to be a grey area, but the standard used to judge an acknowledgement is that if the acknowledgement benefits the author(s) it is allowed, but if it primarily benefits other parties, or could reflect poorly on the author(s), then it is not. |
|||
|
|||
1.20 I'm writing a small app for mobile platforms, do I need to include the whole package? |
|||
If you bundle a font under the OFL with your mobile app you must comply with the terms of the license. At a minimum you must include the copyright statement, the license notice and the license text. A mention of this information in your About box or Changelog, with a link to where the font package is from, is good practice, and the extra space needed to carry these items is very small. You do not, however, need to include the full contents of the font package - only the fonts you use and the copyright and license that apply to them. For example, if you only use the regular weight in your app, you do not need to include the italic and bold versions. |
|||
|
|||
1.21 What about including OFL fonts by default in my firmware or dedicated operating system? |
|||
Many such systems are restricted and turned into appliances so that users cannot study or modify them. Using open fonts to increase quality and language coverage is a great idea, but you need to be aware that if there is a way for users to extract fonts you cannot legally prevent them from doing that. The fonts themselves, including any changes you make to them, must be distributed under the OFL even if your firmware has a more restrictive license. If you do transform the fonts and change their formats when you include them in your firmware you must respect any names reserved by the font authors via the RFN mechanism and pick your own font name. Alternatively if you directly add a font under the OFL to the font folder of your firmware without modifying or optimizing it you are simply bundling the font like with any other software collection, and do not need to make any further changes. |
|||
|
|||
1.22 Can I make and publish CMS themes or templates that use OFL fonts? Can I include the fonts themselves in the themes or templates? Can I sell the whole package? |
|||
Yes, you are very welcome to integrate open fonts into themes and templates for your preferred CMS and make them more widely available. Remember that you can only sell the fonts and your CMS add-on as part of a software bundle. (See 1.4 for details and examples about selling bundles). |
|||
|
|||
1.23 Can OFL fonts be included in services that deliver fonts to the desktop from remote repositories? Even if they contain both OFL and non-OFL fonts? |
|||
Yes. Some foundries have set up services to deliver fonts to subscribers directly to desktops from their online repositories; similarly, plugins are available to preview and use fonts directly in your design tool or publishing suite. These services may mix open and restricted fonts in the same channel, however they should make a clear distinction between them to users. These services should also not hinder users (such as through DRM or obfuscation mechanisms) from extracting and using the OFL fonts in other environments, or continuing to use OFL fonts after subscription terms have ended, as those uses are specifically allowed by the OFL. |
|||
|
|||
1.24 Can services that provide or distribute OFL fonts restrict my use of them? |
|||
No. The terms of use of such services cannot replace or restrict the terms of the OFL, as that would be the same as distributing the fonts under a different license, which is not allowed. You are still entitled to use, modify and redistribute them as the original authors have intended outside of the sole control of that particular distribution channel. Note, however, that the fonts provided by these services may differ from the Original Versions. |
|||
|
|||
|
|||
2 USING OFL FONTS FOR WEBPAGES AND ONLINE WEB FONT SERVICES |
|||
|
|||
NOTE: This section often refers to a separate paper on 'Web Fonts & RFNs'. This is available at http://scripts.sil.org/OFL_web_fonts_and_RFNs |
|||
|
|||
2.1 Can I make webpages using these fonts? |
|||
Yes! Go ahead! Using CSS (Cascading Style Sheets) is recommended. Your three best options are: |
|||
- referring directly in your stylesheet to open fonts which may be available on the user's system |
|||
- providing links to download the full package of the font - either from your own website or from elsewhere - so users can install it themselves |
|||
- using @font-face to distribute the font directly to browsers. This is recommended and explicitly allowed by the licensing model because it is distribution. The font file itself is distributed with other components of the webpage. It is not embedded in the webpage but referenced through a web address which will cause the browser to retrieve and use the corresponding font to render the webpage (see 1.11 and 1.15 for details related to embedding fonts into documents). As you take advantage of the @font-face cross-platform standard, be aware that web fonts are often tuned for a web environment and not intended for installation and use outside a browser. The reasons in favour of using web fonts are to allow design of dynamic text elements instead of static graphics, to make it easier for content to be localized and translated, indexed and searched, and all this with cross-platform open standards without depending on restricted extensions or plugins. You should check the CSS cascade (the order in which fonts are being called or delivered to your users) when testing. |
|||
|
|||
2.2 Can I make and use WOFF (Web Open Font Format) versions of OFL fonts? |
|||
Yes, but you need to be careful. A change in font format normally is considered modification, and Reserved Font Names (RFNs) cannot be used. Because of the design of the WOFF format, however, it is possible to create a WOFF version that is not considered modification, and so would not require a name change. You are allowed to create, use and distribute a WOFF version of an OFL font without changing the font name, but only if: |
|||
|
|||
- the original font data remains unchanged except for WOFF compression, and |
|||
- WOFF-specific metadata is either omitted altogether or present and includes, unaltered, the contents of all equivalent metadata in the original font. |
|||
|
|||
If the original font data or metadata is changed, or the WOFF-specific metadata is incomplete, the font must be considered a Modified Version, the OFL restrictions would apply and the name of the font must be changed: any RFNs cannot be used and copyright notices and licensing information must be included and cannot be deleted or modified. You must come up with a unique name - we recommend one corresponding to your domain or your particular web application. Be aware that only the original author(s) can use RFNs. This is to prevent collisions between a derivative tuned to your audience and the original upstream version and so to reduce confusion. |
|||
|
|||
Please note that most WOFF conversion tools and online services do not meet the two requirements listed above, and so their output must be considered a Modified Version. So be very careful and check to be sure that the tool or service you're using is compressing unchanged data and completely and accurately reflecting the original font metadata. |
|||
|
|||
2.3 What about other web font formats such as EOT/EOTLite/CWT/etc.? |
|||
In most cases these formats alter the original font data more than WOFF, and do not completely support appropriate metadata, so their use must be considered modification and RFNs may not be used. However, there may be certain formats or usage scenarios that may allow the use of RFNs. See http://scripts.sil.org/OFL_web_fonts_and_RFNs |
|||
|
|||
2.4 Can I make OFL fonts available through web font online services? |
|||
Yes, you are welcome to include OFL fonts in online web font services as long as you properly meet all the conditions of the license. The origin and open status of the font should be clear among the other fonts you are hosting. Authorship, copyright notices and license information must be sufficiently visible to your users or subscribers so they know where the font comes from and the rights granted by the author(s). Make sure the font file contains the needed copyright notice(s) and licensing information in its metadata. Please double-check the accuracy of every field to prevent contradictory information. Other font formats, including EOT/EOTLite/CWT and superior alternatives like WOFF, already provide fields for this information. Remember that if you modify the font within your library or convert it to another format for any reason the OFL restrictions apply and you need to change the names accordingly. Please respect the author's wishes as expressed in the OFL and do not misrepresent original designers and their work. Don't lump quality open fonts together with dubious freeware or public domain fonts. Consider how you can best work with the original designers and foundries, support their efforts and generate goodwill that will benefit your service. (See 1.17 for details related to URL-based access restrictions methods or DRM mechanisms). |
|||
|
|||
2.5 Some web font formats and services provide ways of "optimizing" the font for a particular website or web application; is that allowed? |
|||
Yes, it is permitted, but remember that these optimized versions are Modified Versions and so must follow OFL requirements like appropriate renaming. Also you need to bear in mind the other important parameters beyond compression, speed and responsiveness: you need to consider the audience of your particular website or web application, as choosing some optimization parameters may turn out to be less than ideal for them. Subsetting by removing certain glyphs or features may seriously limit functionality of the font in various languages that your users expect. It may also introduce degradation of quality in the rendering or specific bugs on the various target platforms compared to the original font from upstream. In other words, remember that one person's optimized font may be another person's missing feature. Various advanced typographic features (OpenType, Graphite or AAT) are also available through CSS and may provide the desired effects without the need to modify the font. |
|||
|
|||
2.6 Is subsetting a web font considered modification? |
|||
Yes. Removing any parts of the font when delivering a web font to a browser, including unused glyphs and smart font code, is considered modification. This is permitted by the OFL but would not normally allow the use of RFNs. Some newer subsetting technologies may be able to subset in a way that allows users to effectively have access to the complete font, including smart font behaviour. See 2.8 and http://scripts.sil.org/OFL_web_fonts_and_RFNs |
|||
|
|||
2.7 Are there any situations in which a modified web font could use RFNs? |
|||
Yes. If a web font is optimized only in ways that preserve Functional Equivalence (see 2.8), then it may use RFNs, as it reasonably represents the Original Version and respects the intentions of the author(s) and the main purposes of the RFN mechanism (avoids collisions, protects authors, minimizes support, encourages derivatives). However this is technically very difficult and often impractical, so a much better scenario is for the web font service or provider to sign a separate agreement with the author(s) that allows the use of RFNs for Modified Versions. |
|||
|
|||
2.8 How do you know if an optimization to a web font preserves Functional Equivalence? |
|||
Functional Equivalence is described in full in the 'Web fonts and RFNs' paper at http://scripts.sil.org/OFL_web_fonts_and_RFNs, in general, an optimized font is deemed to be Functionally Equivalent (FE) to the Original Version if it: |
|||
|
|||
- Supports the same full character inventory. If a character can be properly displayed using the Original Version, then that same character, encoded correctly on a web page, will display properly. |
|||
- Provides the same smart font behavior. Any dynamic shaping behavior that works with the Original Version should work when optimized, unless the browser or environment does not support it. There does not need to be guaranteed support in the client, but there should be no forced degradation of smart font or shaping behavior, such as the removal or obfuscation of OpenType, Graphite or AAT tables. |
|||
- Presents text with no obvious degradation in visual quality. The lettershapes should be equally (or more) readable, within limits of the rendering platform. |
|||
- Preserves original author, project and license metadata. At a minimum, this should include: Copyright and authorship; The license as stated in the Original Version, whether that is the full text of the OFL or a link to the web version; Any RFN declarations; Information already present in the font or documentation that points back to the Original Version, such as a link to the project or the author's website. |
|||
|
|||
If an optimized font meets these requirements, and so is considered to be FE, then it's very likely that the original author would feel that the optimized font is a good and reasonable equivalent. If it falls short of any of these requirements, the optimized font does not reasonably represent the Original Version, and so should be considered to be a Modified Version. Like other Modified Versions, it would not be allowed to use any RFNs and you simply need to pick your own font name. |
|||
|
|||
2.9 Isn't use of web fonts another form of embedding? |
|||
No. Unlike embedded fonts in a PDF, web fonts are not an integrated part of the document itself. They are not specific to a single document and are often applied to thousands of documents around the world. The font data is not stored alongside the document data and often originates from a different location. The ease by which the web fonts used by a document may be identified and downloaded for desktop use demonstrates that they are philosophically and technically separate from the web pages that specify them. See http://scripts.sil.org/OFL_web_fonts_and_RFNs |
|||
|
|||
2.10 So would it be better to not use RFNs at all if you want your font to be distributed by a web fonts service? |
|||
No. Although the OFL does not require authors to use RFNs, the RFN mechanism is an important part of the OFL model and completely compatible with web font services. If that web font service modifies the fonts, then the best solution is to sign a separate agreement for the use of any RFNs. It is perfectly valid for an author to not declare any RFNs, but before they do so they need to fully understand the benefits they are giving up, and the overall negative effect of allowing many different versions bearing the same name to be widely distributed. As a result, we don't generally recommend it. |
|||
|
|||
2.11 What should an agreement for the use of RFNs say? Are there any examples? |
|||
There is no prescribed format for this agreement, as legal systems vary, and no recommended examples. Authors may wish to add specific clauses to further restrict use, require author review of Modified Versions, establish user support mechanisms or provide terms for ending the agreement. Such agreements are usually not public, and apply only to the main parties. However, it would be very beneficial for web font services to clearly state when they have established such agreements, so that the public understands clearly that their service is operating appropriately. |
|||
|
|||
See the separate paper on 'Web Fonts & RFNs' for in-depth discussion of issues related to the use of RFNs for web fonts. This is available at http://scripts.sil.org/OFL_web_fonts_and_RFNs |
|||
|
|||
|
|||
3 MODIFYING OFL-LICENSED FONTS |
|||
|
|||
3.1 Can I change the fonts? Are there any limitations to what things I can and cannot change? |
|||
You are allowed to change anything, as long as such changes do not violate the terms of the license. In other words, you are not allowed to remove the copyright statement(s) from the font, but you could put additional information into it that covers your contribution. See the placeholders in the OFL header template for recommendations on where to add your own statements. (Remember that, when authors have reserved names via the RFN mechanism, you need to change the internal names of the font to your own font name when making your modified version even if it is just a small change.) |
|||
|
|||
3.2 I have a font that needs a few extra glyphs - can I take them from an OFL licensed font and copy them into mine? |
|||
Yes, but if you distribute that font to others it must be under the OFL, and include the information mentioned in condition 2 of the license. |
|||
|
|||
3.3 Can I charge people for my additional work? In other words, if I add a bunch of special glyphs or OpenType/Graphite/AAT code, can I sell the enhanced font? |
|||
Not by itself. Derivative fonts must be released under the OFL and cannot be sold by themselves. It is permitted, however, to include them in a larger software package (such as text editors, office suites or operating systems), even if the larger package is sold. In that case, you are strongly encouraged, but not required, to also make that derived font easily and freely available outside of the larger package. |
|||
|
|||
3.4 Can I pay someone to enhance the fonts for my use and distribution? |
|||
Yes. This is a good way to fund the further development of the fonts. Keep in mind, however, that if the font is distributed to others it must be under the OFL. You won't be able to recover your investment by exclusively selling the font, but you will be making a valuable contribution to the community. Please remember how you have benefited from the contributions of others. |
|||
|
|||
3.5 I need to make substantial revisions to the font to make it work with my program. It will be a lot of work, and a big investment, and I want to be sure that it can only be distributed with my program. Can I restrict its use? |
|||
No. If you redistribute a Modified Version of the font it must be under the OFL. You may not restrict it in any way beyond what the OFL permits and requires. This is intended to ensure that all released improvements to the fonts become available to everyone. But you will likely get an edge over competitors by being the first to distribute a bundle with the enhancements. Again, please remember how you have benefited from the contributions of others. |
|||
|
|||
3.6 Do I have to make any derivative fonts (including extended source files, build scripts, documentation, etc.) publicly available? |
|||
No, but please consider sharing your improvements with others. You may find that you receive in return more than what you gave. |
|||
|
|||
3.7 If a trademark is claimed in the OFL font, does that trademark need to remain in modified fonts? |
|||
Yes. Any trademark notices must remain in any derivative fonts to respect trademark laws, but you may add any additional trademarks you claim, officially registered or not. For example if an OFL font called "Foo" contains a notice that "Foo is a trademark of Acme", then if you rename the font to "Bar" when creating a Modified Version, the new trademark notice could say "Foo is a trademark of Acme Inc. - Bar is a trademark of Roadrunner Technologies Ltd.". Trademarks work alongside the OFL and are not subject to the terms of the licensing agreement. The OFL does not grant any rights under trademark law. Bear in mind that trademark law varies from country to country and that there are no international trademark conventions as there are for copyright. You may need to significantly invest in registering and defending a trademark for it to remain valid in the countries you are interested in. This may be costly for an individual independent designer. |
|||
|
|||
3.8 If I commit changes to a font (or publish a branch in a DVCS) as part of a public open source software project, do I have to change the internal font names? |
|||
Only if there are declared RFNs. Making a public commit or publishing a public branch is effectively redistributing your modifications, so any change to the font will require that you do not use the RFNs. Even if there are no RFNs, it may be useful to change the name or add a suffix indicating that a particular version of the font is still in development and not released yet. This will clearly indicate to users and fellow designers that this particular font is not ready for release yet. See section 5 for more details. |
|||
|
|||
|
|||
4 LICENSING YOUR ORIGINAL FONTS UNDER THE OFL |
|||
|
|||
4.1 Can I use the SIL OFL for my own fonts? |
|||
Yes! We heartily encourage everyone to use the OFL to distribute their own original fonts. It is a carefully constructed license that allows great freedom along with enough artistic integrity protection for the work of the authors as well as clear rules for other contributors and those who redistribute the fonts. The licensing model is used successfully by various organisations, both for-profit and not-for-profit, to release fonts of varying levels of scope and complexity. |
|||
|
|||
4.2 What do I have to do to apply the OFL to my font? |
|||
If you want to release your fonts under the OFL, we recommend you do the following: |
|||
|
|||
4.2.1 Put your copyright and Reserved Font Names information at the beginning of the main OFL.txt file in place of the dedicated placeholders (marked with the <> characters). Include this file in your release package. |
|||
|
|||
4.2.2 Put your copyright and the OFL text with your chosen Reserved Font Name(s) into your font files (the copyright and license fields). A link to the OFL text on the OFL web site is an acceptable (but not recommended) alternative. Also add this information to any other components (build scripts, glyph databases, documentation, test files, etc). Accurate metadata in your font files is beneficial to you as an increasing number of applications are exposing this information to the user. For example, clickable links can bring users back to your website and let them know about other work you have done or services you provide. Depending on the format of your fonts and sources, you can use template human-readable headers or machine-readable metadata. You should also double-check that there is no conflicting metadata in the font itself contradicting the license, such as the fstype bits in the os2 table or fields in the name table. |
|||
|
|||
4.2.3 Write an initial FONTLOG.txt for your font and include it in the release package (see Section 6 and Appendix A for details including a template). |
|||
|
|||
4.2.4 Include the relevant practical documentation on the license by adding the current OFL-FAQ.txt file in your package. |
|||
|
|||
4.2.5 If you wish you can use the OFL graphics (http://scripts.sil.org/OFL_logo) on your website. |
|||
|
|||
4.3 Will you make my font OFL for me? |
|||
We won't do the work for you. We can, however, try to answer your questions, unfortunately we do not have the resources to review and check your font packages for correct use of the OFL. We recommend you turn to designers, foundries or consulting companies with experience in doing open font design to provide this service to you. |
|||
|
|||
4.4 Will you distribute my OFL font for me? |
|||
No, although if the font is of sufficient quality and general interest we may include a link to it on our partial list of OFL fonts on the OFL web site. You may wish to consider other open font catalogs or hosting services, such as the Unifont Font Guide (http://unifont.org/fontguide), The League of Movable Type (http://theleagueofmovabletype.com) or the Open Font Library (http://openfontlibrary.org/), which despite the name has no direct relationship to the OFL or SIL. We do not endorse any particular catalog or hosting service - it is your responsibility to determine if the service is right for you and if it treats authors with fairness. |
|||
|
|||
4.5 Why should I use the OFL for my fonts? |
|||
- to meet needs for fonts that can be modified to support lesser-known languages |
|||
- to provide a legal and clear way for people to respect your work but still use it (and reduce piracy) |
|||
- to involve others in your font project |
|||
- to enable your fonts to be expanded with new weights and improved writing system/language support |
|||
- to allow more technical font developers to add features to your design (such as OpenType, Graphite or AAT support) |
|||
- to renew the life of an old font lying on your hard drive with no business model |
|||
- to allow your font to be included in Libre Software operating systems like Ubuntu |
|||
- to give your font world status and wide, unrestricted distribution |
|||
- to educate students about quality typeface and font design |
|||
- to expand your test base and get more useful feedback |
|||
- to extend your reach to new markets when users see your metadata and go to your website |
|||
- to get your font more easily into one of the web font online services |
|||
- to attract attention for your commercial fonts |
|||
- to make money through web font services |
|||
- to make money by bundling fonts with applications |
|||
- to make money adjusting and extending existing open fonts |
|||
- to get a better chance that foundations/NGOs/charities/companies who commission fonts will pick you |
|||
- to be part of a sharing design and development community |
|||
- to give back and contribute to a growing body of font sources |
|||
|
|||
|
|||
5 CHOOSING RESERVED FONT NAMES |
|||
|
|||
5.1 What are Reserved Font Names? |
|||
These are font names, or portions of font names, that the author has chosen to reserve for use only with the Original Version of the font, or for Modified Version(s) created by the original author. |
|||
|
|||
5.2 Why can't I use the Reserved Font Names in my derivative font names? I'd like people to know where the design came from. |
|||
The best way to acknowledge the source of the design is to thank the original authors and any other contributors in the files that are distributed with your revised font (although no acknowledgement is required). The FONTLOG is a natural place to do this. Reserved Font Names ensure that the only fonts that have the original names are the unmodified Original Versions. This allows designers to maintain artistic integrity while allowing collaboration to happen. It eliminates potential confusion and name conflicts. When choosing a name, be creative and avoid names that reuse almost all the same letters in the same order or sound like the original. It will help everyone if Original Versions and Modified Versions can easily be distinguished from one another and from other derivatives. Any substitution and matching mechanism is outside the scope of the license. |
|||
|
|||
5.3 What do you mean by "primary name as presented to the user"? Are you referring to the font menu name? |
|||
Yes, this applies to the font menu name and other mechanisms that specify a font in a document. It would be fine, however, to keep a text reference to the original fonts in the description field, in your modified source file or in documentation provided alongside your derivative as long as no one could be confused that your modified source is the original. But you cannot use the Reserved Font Names in any way to identify the font to the user (unless the Copyright Holder(s) allow(s) it through a separate agreement). Users who install derivatives (Modified Versions) on their systems should not see any of the original Reserved Font Names in their font menus, for example. Again, this is to ensure that users are not confused and do not mistake one font for another and so expect features only another derivative or the Original Version can actually offer. |
|||
|
|||
5.4 Am I not allowed to use any part of the Reserved Font Names? |
|||
You may not use individual words from the Reserved Font Names, but you would be allowed to use parts of words, as long as you do not use any word from the Reserved Font Names entirely. We do not recommend using parts of words because of potential confusion, but it is allowed. For example, if "Foobar" was a Reserved Font Name, you would be allowed to use "Foo" or "bar", although we would not recommend it. Such an unfortunate choice would confuse the users of your fonts as well as make it harder for other designers to contribute. |
|||
|
|||
5.5 So what should I, as an author, identify as Reserved Font Names? |
|||
Original authors are encouraged to name their fonts using clear, distinct names, and only declare the unique parts of the name as Reserved Font Names. For example, the author of a font called "Foobar Sans" would declare "Foobar" as a Reserved Font Name, but not "Sans", as that is a common typographical term, and may be a useful word to use in a derivative font name. Reserved Font Names should also be single words for simplicity and legibility. A font called "Flowing River" should have Reserved Font Names "Flowing" and "River", not "Flowing River". You also need to be very careful about reserving font names which are already linked to trademarks (whether registered or not) which you do not own. |
|||
|
|||
5.6 Do I, as an author, have to identify any Reserved Font Names? |
|||
No. RFNs are optional and not required, but we encourage you to use them. This is primarily to avoid confusion between your work and Modified Versions. As an author you can release a font under the OFL and not declare any Reserved Font Names. There may be situations where you find that using no RFNs and letting your font be changed and modified - including any kind of modification - without having to change the original name is desirable. However you need to be fully aware of the consequences. There will be no direct way for end-users and other designers to distinguish your Original Version from many Modified Versions that may be created. You have to trust whoever is making the changes and the optimizations to not introduce problematic changes. The RFNs you choose for your own creation have value to you as an author because they allow you to maintain artistic integrity and keep some control over the distribution channel to your end-users. For discussion of RFNs and web fonts see section 2. |
|||
|
|||
5.7 Are any names (such as the main font name) reserved by default? |
|||
No. That is a change to the license as of version 1.1. If you want any names to be Reserved Font Names, they must be specified after the copyright statement(s). |
|||
|
|||
5.8 Is there any situation in which I can use Reserved Font Names for a Modified Version? |
|||
The Copyright Holder(s) can give certain trusted parties the right to use any of the Reserved Font Names through separate written agreements. For example, even if "Foobar" is a RFN, you could write up an agreement to give company "XYZ" the right to distribute a modified version with a name that includes "Foobar". This allows for freedom without confusion. The existence of such an agreement should be made as clear as possible to downstream users and designers in the distribution package and the relevant documentation. They need to know if they are a party to the agreement or not and what they are practically allowed to do or not even if all the details of the agreement are not public. |
|||
|
|||
5.9 Do font rebuilds require a name change? Do I have to change the name of the font when my packaging workflow includes a full rebuild from source? |
|||
Yes, all rebuilds which change the font data and the smart code are Modified Versions and the requirements of the OFL apply: you need to respect what the Author(s) have chosen in terms of Reserved Font Names. However if a package (or installer) is simply a wrapper or a compressed structure around the final font - leaving them intact on the inside - then no name change is required. Please get in touch with the author(s) and copyright holder(s) to inquire about the presence of font sources beyond the final font file(s) and the recommended build path. That build path may very well be non-trivial and hard to reproduce accurately by the maintainer. If a full font build path is made available by the upstream author(s) please be aware that any regressions and changes you may introduce when doing a rebuild for packaging purposes is your own responsibility as a package maintainer since you are effectively creating a separate branch. You should make it very clear to your users that your rebuilt version is not the canonical one from upstream. |
|||
|
|||
5.10 Can I add other Reserved Font Names when making a derivative font? |
|||
Yes. List your additional Reserved Font Names after your additional copyright statement, as indicated with example placeholders at the top of the OFL.txt file. Be sure you do not remove any existing RFNs but only add your own. RFN statements should be placed next to the copyright statement of the relevant author as indicated in the OFL.txt template to make them visible to designers wishing to make their separate version. |
|||
|
|||
|
|||
6 ABOUT THE FONTLOG |
|||
|
|||
6.1 What is this FONTLOG thing exactly? |
|||
It has three purposes: 1) to provide basic information on the font to users and other designers and developers, 2) to document changes that have been made to the font or accompanying files, either by the original authors or others, and 3) to provide a place to acknowledge authors and other contributors. Please use it! |
|||
|
|||
6.2 Is the FONTLOG required? |
|||
It is not a requirement of the license, but we strongly recommend you have one. |
|||
|
|||
6.3 Am I required to update the FONTLOG when making Modified Versions? |
|||
No, but users, designers and other developers might get very frustrated with you if you don't. People need to know how derivative fonts differ from the original, and how to take advantage of the changes, or build on them. There are utilities that can help create and maintain a FONTLOG, such as the FONTLOG support in FontForge. |
|||
|
|||
6.4 What should the FONTLOG look like? |
|||
It is typically a separate text file (FONTLOG.txt), but can take other formats. It commonly includes these four sections: |
|||
|
|||
- brief header describing the FONTLOG itself and name of the font family |
|||
- Basic Font Information - description of the font family, purpose and breadth |
|||
- ChangeLog - chronological listing of changes |
|||
- Acknowledgements - list of authors and contributors with contact information |
|||
|
|||
It could also include other sections, such as: where to find documentation, how to make contributions, information on contributing organizations, source code details, and a short design guide. See Appendix A for an example FONTLOG. |
|||
|
|||
|
|||
7 MAKING CONTRIBUTIONS TO OFL PROJECTS |
|||
|
|||
7.1 Can I contribute work to OFL projects? |
|||
In many cases, yes. It is common for OFL fonts to be developed by a team of people who welcome contributions from the wider community. Contact the original authors for specific information on how to participate in their projects. |
|||
|
|||
7.2 Why should I contribute my changes back to the original authors? |
|||
It would benefit many people if you contributed back in response to what you've received. Your contributions and improvements to the fonts and other components could be a tremendous help and would encourage others to contribute as well and 'give back'. You will then benefit from other people's contributions as well. Sometimes maintaining your own separate version takes more effort than merging back with the original. Be aware that any contributions, however, must be either your own original creation or work that you own, and you may be asked to affirm that clearly when you contribute. |
|||
|
|||
7.3 I've made some very nice improvements to the font. Will you consider adopting them and putting them into future Original Versions? |
|||
Most authors would be very happy to receive such contributions. Keep in mind that it is unlikely that they would want to incorporate major changes that would require additional work on their end. Any contributions would likely need to be made for all the fonts in a family and match the overall design and style. Authors are encouraged to include a guide to the design with the fonts. It would also help to have contributions submitted as patches or clearly marked changes - the use of smart source revision control systems like subversion, mercurial, git or bzr is a good idea. Please follow the recommendations given by the author(s) in terms of preferred source formats and configuration parameters for sending contributions. If this is not indicated in a FONTLOG or other documentation of the font, consider asking them directly. Examples of useful contributions are bug fixes, additional glyphs, stylistic alternates (and the smart font code to access them) or improved hinting. Keep in mind that some kinds of changes (esp. hinting) may be technically difficult to integrate. |
|||
|
|||
7.4 How can I financially support the development of OFL fonts? |
|||
It is likely that most authors of OFL fonts would accept financial contributions - contact them for instructions on how to do this. Such contributions would support future development. You can also pay for others to enhance the fonts and contribute the results back to the original authors for inclusion in the Original Version. |
|||
|
|||
|
|||
8 ABOUT THE LICENSE ITSELF |
|||
|
|||
8.1 I see that this is version 1.1 of the license. Will there be later changes? |
|||
Version 1.1 is the first minor revision of the OFL. We are confident that version 1.1 will meet most needs, but are open to future improvements. Any revisions would be for future font releases, and previously existing licenses would remain in effect. No retroactive changes are possible, although the Copyright Holder(s) can re-release the font under a revised OFL. All versions will be available on our web site: http://scripts.sil.org/OFL. |
|||
|
|||
8.2 Does this license restrict the rights of the Copyright Holder(s)? |
|||
No. The Copyright Holder(s) still retain(s) all the rights to their creation; they are only releasing a portion of it for use in a specific way. For example, the Copyright Holder(s) may choose to release a 'basic' version of their font under the OFL, but sell a restricted 'enhanced' version under a different license. They may also choose to release the same font under both the OFL and some other license. Only the Copyright Holder(s) can do this, and doing so does not change the terms of the OFL as it applies to that font. |
|||
|
|||
8.3 Is the OFL a contract or a license? |
|||
The OFL is a worldwide license based on international copyright agreements and conventions. It is not a contract and so does not require you to sign it to have legal validity. By using, modifying and redistributing components under the OFL you indicate that you accept the license. |
|||
|
|||
8.4 I really like the terms of the OFL, but want to change it a little. Am I allowed to take ideas and actual wording from the OFL and put them into my own custom license for distributing my fonts? |
|||
We strongly recommend against creating your very own unique open licensing model. Using a modified or derivative license will likely cut you off - along with the font(s) under that license - from the community of designers using the OFL, potentially expose you and your users to legal liabilities, and possibly put your work and rights at risk. The OFL went though a community and legal review process that took years of effort, and that review is only applicable to an unmodified OFL. The text of the OFL has been written by SIL (with review and consultation from the community) and is copyright (c) 2005-2013 SIL International. You may re-use the ideas and wording (in part, not in whole) in another non-proprietary license provided that you call your license by another unambiguous name, that you do not use the preamble, that you do not mention SIL and that you clearly present your license as different from the OFL so as not to cause confusion by being too similar to the original. If you feel the OFL does not meet your needs for an open license, please contact us. |
|||
|
|||
8.5 Can I translate the license and the FAQ into other languages? |
|||
SIL certainly recognises the need for people who are not familiar with English to be able to understand the OFL and its use. Making the license very clear and readable has been a key goal for the OFL, but we know that people understand their own language best. |
|||
|
|||
If you are an experienced translator, you are very welcome to translate the OFL and OFL-FAQ so that designers and users in your language community can understand the license better. But only the original English version of the license has legal value and has been approved by the community. Translations do not count as legal substitutes and should only serve as a way to explain the original license. SIL - as the author and steward of the license for the community at large - does not approve any translation of the OFL as legally valid because even small translation ambiguities could be abused and create problems. |
|||
|
|||
SIL gives permission to publish unofficial translations into other languages provided that they comply with the following guidelines: |
|||
|
|||
- Put the following disclaimer in both English and the target language stating clearly that the translation is unofficial: |
|||
|
|||
"This is an unofficial translation of the SIL Open Font License into <language_name>. It was not published by SIL International, and does not legally state the distribution terms for fonts that use the OFL. A release under the OFL is only valid when using the original English text. However, we recognize that this unofficial translation will help users and designers not familiar with English to better understand and use the OFL. We encourage designers who consider releasing their creation under the OFL to read the OFL-FAQ in their own language if it is available. Please go to http://scripts.sil.org/OFL for the official version of the license and the accompanying OFL-FAQ." |
|||
|
|||
- Keep your unofficial translation current and update it at our request if needed, for example if there is any ambiguity which could lead to confusion. |
|||
|
|||
If you start such a unofficial translation effort of the OFL and OFL-FAQ please let us know. |
|||
|
|||
8.6 Does the OFL have an explicit expiration term? |
|||
No, the implicit intent of the OFL is that the permissions granted are perpetual and irrevocable. |
|||
|
|||
|
|||
9 ABOUT SIL INTERNATIONAL |
|||
|
|||
9.1 Who is SIL International and what do they do? |
|||
SIL serves language communities worldwide, building their capacity for sustainable language development, by means of research, translation, training and materials development. SIL makes its services available to all without regard to religious belief, political ideology, gender, race, or ethnic background. SIL's members and volunteers share a Christian commitment. |
|||
|
|||
9.2 What does this have to do with font licensing? |
|||
The ability to read, write, type and publish in one's own language is one of the most critical needs for millions of people around the world. This requires fonts that are widely available and support lesser-known languages. SIL develops - and encourages others to develop - a complete stack of writing systems implementation components available under open licenses. This open stack includes input methods, smart fonts, smart rendering libraries and smart applications. There has been a need for a common open license that is specifically applicable to fonts and related software (a crucial component of this stack), so SIL developed the SIL Open Font License with the help of the Free/Libre and Open Source Software community. |
|||
|
|||
9.3 How can I contact SIL? |
|||
Our main web site is: http://www.sil.org/ |
|||
Our site about complex scripts is: http://scripts.sil.org/ |
|||
Information about this license (and contact information) is at: http://scripts.sil.org/OFL |
|||
|
|||
|
|||
APPENDIX A - FONTLOG EXAMPLE |
|||
|
|||
Here is an example of the recommended format for a FONTLOG, although other formats are allowed. |
|||
|
|||
----- |
|||
FONTLOG for the GlobalFontFamily fonts |
|||
|
|||
This file provides detailed information on the GlobalFontFamily Font Software. This information should be distributed along with the GlobalFontFamily fonts and any derivative works. |
|||
|
|||
Basic Font Information |
|||
|
|||
GlobalFontFamily is a Unicode typeface family that supports all languages that use the Latin script and its variants, and could be expanded to support other scripts. |
|||
|
|||
NewWorldFontFamily is based on the GlobalFontFamily and also supports Greek, Hebrew, Cyrillic and Armenian. |
|||
|
|||
More specifically, this release supports the following Unicode ranges... |
|||
This release contains... |
|||
Documentation can be found at... |
|||
To contribute to the project... |
|||
|
|||
ChangeLog |
|||
|
|||
10 December 2010 (Fred Foobar) GlobalFontFamily-devel version 1.4 |
|||
- fix new build and testing system (bug #123456) |
|||
|
|||
1 August 2008 (Tom Parker) GlobalFontFamily version 1.2.1 |
|||
- Tweaked the smart font code (Branch merged with trunk version) |
|||
- Provided improved build and debugging environment for smart behaviours |
|||
|
|||
7 February 2007 (Pat Johnson) NewWorldFontFamily Version 1.3 |
|||
- Added Greek and Cyrillic glyphs |
|||
|
|||
7 March 2006 (Fred Foobar) NewWorldFontFamily Version 1.2 |
|||
- Tweaked contextual behaviours |
|||
|
|||
1 Feb 2005 (Jane Doe) NewWorldFontFamily Version 1.1 |
|||
- Improved build script performance and verbosity |
|||
- Extended the smart code documentation |
|||
- Corrected minor typos in the documentation |
|||
- Fixed position of combining inverted breve below (U+032F) |
|||
- Added OpenType/Graphite smart code for Armenian |
|||
- Added Armenian glyphs (U+0531 -> U+0587) |
|||
- Released as "NewWorldFontFamily" |
|||
|
|||
1 Jan 2005 (Joe Smith) GlobalFontFamily Version 1.0 |
|||
- Initial release |
|||
|
|||
Acknowledgements |
|||
|
|||
If you make modifications be sure to add your name (N), email (E), web-address (if you have one) (W) and description (D). This list is in alphabetical order. |
|||
|
|||
N: Jane Doe |
|||
E: jane@university.edu |
|||
W: http://art.university.edu/projects/fonts |
|||
D: Contributor - Armenian glyphs and code |
|||
|
|||
N: Fred Foobar |
|||
E: fred@foobar.org |
|||
W: http://foobar.org |
|||
D: Contributor - misc Graphite fixes |
|||
|
|||
N: Pat Johnson |
|||
E: pat@fontstudio.org |
|||
W: http://pat.fontstudio.org |
|||
D: Designer - Greek & Cyrillic glyphs based on Roman design |
|||
|
|||
N: Tom Parker |
|||
E: tom@company.com |
|||
W: http://www.company.com/tom/projects/fonts |
|||
D: Engineer - original smart font code |
|||
|
|||
N: Joe Smith |
|||
E: joe@fontstudio.org |
|||
W: http://joe.fontstudio.org |
|||
D: Designer - original Roman glyphs |
|||
|
|||
Fontstudio.org is an not-for-profit design group whose purpose is... |
|||
Foobar.org is a distributed community of developers... |
|||
Company.com is a small business who likes to support community designers... |
|||
University.edu is a renowned educational institution with a strong design department... |
|||
----- |
|||
|
@ -0,0 +1,36 @@ |
|||
These fonts were created by the Bigelow & Holmes foundry specifically for the |
|||
Go project. See https://blog.golang.org/go-fonts for details. |
|||
|
|||
They are licensed under the same open source license as the rest of the Go |
|||
project's software: |
|||
|
|||
Copyright (c) 2016 Bigelow & Holmes Inc.. All rights reserved. |
|||
|
|||
Distribution of this font is governed by the following license. If you do not |
|||
agree to this license, including the disclaimer, do not distribute or modify |
|||
this font. |
|||
|
|||
Redistribution and use in source and binary forms, with or without |
|||
modification, are permitted provided that the following conditions are met: |
|||
|
|||
* Redistributions of source code must retain the above copyright notice, |
|||
this list of conditions and the following disclaimer. |
|||
|
|||
* Redistributions in binary form must reproduce the above copyright notice, |
|||
this list of conditions and the following disclaimer in the documentation |
|||
and/or other materials provided with the distribution. |
|||
|
|||
* Neither the name of Google Inc. nor the names of its contributors may be |
|||
used to endorse or promote products derived from this software without |
|||
specific prior written permission. |
|||
|
|||
DISCLAIMER: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
|||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE |
|||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,137 @@ |
|||
// Copyright 2018 Raph Levien
|
|||
|
|||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|||
// option. This file may not be copied, modified, or distributed
|
|||
// except according to those terms.
|
|||
|
|||
//! Utilities for representing and manipulating bezier paths.
|
|||
|
|||
const MOVETO = "m"; |
|||
const LINETO = "l"; |
|||
const CURVETO = "c"; |
|||
const CLOSEPATH = "z"; |
|||
const MARK = "#"; |
|||
|
|||
class BezPath { |
|||
constructor() { |
|||
this.cmds = []; |
|||
} |
|||
|
|||
// Construction mutations (builder could be separate but oh well).
|
|||
moveto(x, y) { |
|||
this.cmds.push([MOVETO, x, y]); |
|||
} |
|||
|
|||
lineto(x, y) { |
|||
this.cmds.push([LINETO, x, y]); |
|||
} |
|||
|
|||
curveto(x1, y1, x2, y2, x3, y3) { |
|||
this.cmds.push([CURVETO, x1, y1, x2, y2, x3, y3]); |
|||
} |
|||
|
|||
closepath() { |
|||
this.cmds.push([CLOSEPATH]); |
|||
} |
|||
|
|||
mark(i) { |
|||
this.cmds.push([MARK, i]); |
|||
} |
|||
|
|||
renderSvg() { |
|||
let path = ""; |
|||
for (let cmd of this.cmds) { |
|||
let op = cmd[0]; |
|||
if (op === MOVETO) { |
|||
path += `M${cmd[1]} ${cmd[2]}`; |
|||
} else if (op === LINETO) { |
|||
path += `L${cmd[1]} ${cmd[2]}`; |
|||
} else if (op === CURVETO) { |
|||
path += `C${cmd[1]} ${cmd[2]} ${cmd[3]} ${cmd[4]} ${cmd[5]} ${cmd[6]}`; |
|||
} else if (op === CLOSEPATH) { |
|||
path += "Z"; |
|||
} |
|||
} |
|||
return path; |
|||
} |
|||
|
|||
hitTest(x, y) { |
|||
let result = new HitTestResult(x, y); |
|||
let curX; |
|||
let curY; |
|||
let curMark = null; |
|||
for (let cmd of this.cmds) { |
|||
let op = cmd[0]; |
|||
if (op === MOVETO) { |
|||
curX = cmd[1]; |
|||
curY = cmd[2]; |
|||
} else if (op === LINETO) { |
|||
result.accumLine(curX, curY, cmd[1], cmd[2], curMark); |
|||
curX = cmd[1]; |
|||
curY = cmd[2]; |
|||
} else if (op === CURVETO) { |
|||
result.accumCurve(curX, curY, cmd[1], cmd[2], cmd[3], cmd[4], |
|||
cmd[5], cmd[6], curMark); |
|||
curX = cmd[5]; |
|||
curY = cmd[6]; |
|||
} else if (op === MARK) { |
|||
curMark = cmd[1]; |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
} |
|||
|
|||
class HitTestResult { |
|||
constructor(x, y) { |
|||
this.x = x; |
|||
this.y = y; |
|||
this.bestDist = 1e12; |
|||
this.bestMark = null; |
|||
} |
|||
|
|||
accumulate(dist, pt, mark) { |
|||
if (dist < this.bestDist) { |
|||
this.bestDist = dist; |
|||
this.bestMark = mark; |
|||
} |
|||
} |
|||
|
|||
accumLine(x0, y0, x1, y1, mark) { |
|||
let dx = x1 - x0; |
|||
let dy = y1 - y0; |
|||
let dotp = (this.x - x0) * dx + (this.y - y0) * dy; |
|||
let linDotp = dx * dx + dy * dy; |
|||
let r = Math.hypot(this.x - x0, this.y - y0); |
|||
let rMin = r; |
|||
r = Math.hypot(this.x - x1, this.y - y1); |
|||
rMin = Math.min(rMin, r); |
|||
if (dotp > 0 && dotp < linDotp) { |
|||
let norm = (this.x - x0) * dy - (this.y - y0) * dx; |
|||
r = Math.abs(norm / Math.sqrt(linDotp)); |
|||
rMin = Math.min(rMin, r); |
|||
} |
|||
if (rMin < this.bestDist) { |
|||
this.bestDist = rMin; |
|||
this.bestMark = mark; |
|||
} |
|||
} |
|||
|
|||
accumCurve(x0, y0, x1, y1, x2, y2, x3, y3, mark) { |
|||
let n = 32; // TODO: be adaptive
|
|||
let dt = 1.0 / n; |
|||
let lastX = x0; |
|||
let lastY = y0; |
|||
for (let i = 0; i < n; i++) { |
|||
let t = (i + 1) * dt; |
|||
let mt = 1 - t; |
|||
let x = (x0 * mt * mt + 3 * (x1 * mt * t + x2 * t * t)) * mt + x3 * t * t * t; |
|||
let y = (y0 * mt * mt + 3 * (y1 * mt * t + y2 * t * t)) * mt + y3 * t * t * t; |
|||
this.accumLine(lastX, lastY, x, y, mark); |
|||
lastX = x; |
|||
lastY = y; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,770 @@ |
|||
// Copyright 2018 Raph Levien
|
|||
|
|||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|||
// option. This file may not be copied, modified, or distributed
|
|||
// except according to those terms.
|
|||
|
|||
//! A library of primitives for curves and splines.
|
|||
|
|||
/// A simple container for 2-vectors
|
|||
class Vec2 { |
|||
constructor(x, y) { |
|||
this.x = x; |
|||
this.y = y; |
|||
} |
|||
|
|||
norm() { |
|||
return Math.hypot(this.x, this.y); |
|||
} |
|||
|
|||
dot(other) { |
|||
return this.x * other.x + this.y * other.y; |
|||
} |
|||
|
|||
cross(other) { |
|||
return this.x * other.y - this.y * other.x; |
|||
} |
|||
} |
|||
|
|||
class CubicBez { |
|||
/// Argument is array of coordinate values [x0, y0, x1, y1, x2, y2, x3, y3].
|
|||
constructor(coords) { |
|||
this.c = coords; |
|||
} |
|||
|
|||
weightsum(c0, c1, c2, c3) { |
|||
let x = c0 * this.c[0] + c1 * this.c[2] + c2 * this.c[4] + c3 * this.c[6]; |
|||
let y = c0 * this.c[1] + c1 * this.c[3] + c2 * this.c[5] + c3 * this.c[7]; |
|||
return new Vec2(x, y); |
|||
} |
|||
|
|||
eval(t) { |
|||
let mt = 1 - t; |
|||
let c0 = mt * mt * mt; |
|||
let c1 = 3 * mt * mt * t; |
|||
let c2 = 3 * mt * t * t; |
|||
let c3 = t * t * t; |
|||
return this.weightsum(c0, c1, c2, c3); |
|||
} |
|||
|
|||
deriv(t) { |
|||
let mt = 1 - t; |
|||
let c0 = -3 * mt * mt; |
|||
let c3 = 3 * t * t; |
|||
let c1 = -6 * t * mt - c0; |
|||
let c2 = 6 * t * mt - c3; |
|||
return this.weightsum(c0, c1, c2, c3); |
|||
} |
|||
|
|||
deriv2(t) { |
|||
let mt = 1 - t; |
|||
let c0 = 6 * mt; |
|||
let c3 = 6 * t; |
|||
let c1 = 6 - 18 * mt; |
|||
let c2 = 6 - 18 * t; |
|||
return this.weightsum(c0, c1, c2, c3); |
|||
} |
|||
|
|||
curvature(t) { |
|||
let d = this.deriv(t); |
|||
let d2 = this.deriv2(t); |
|||
return d.cross(d2) / Math.pow(d.norm(), 3); |
|||
} |
|||
|
|||
atanCurvature(t) { |
|||
let d = this.deriv(t); |
|||
let d2 = this.deriv2(t); |
|||
return Math.atan2(d.cross(d2), Math.pow(d.norm(), 3)); |
|||
} |
|||
|
|||
// de Casteljau's algorithm
|
|||
leftHalf() { |
|||
let c = new Float64Array(8); |
|||
c[0] = this.c[0]; |
|||
c[1] = this.c[1]; |
|||
c[2] = 0.5 * (this.c[0] + this.c[2]); |
|||
c[3] = 0.5 * (this.c[1] + this.c[3]); |
|||
c[4] = 0.25 * (this.c[0] + 2 * this.c[2] + this.c[4]); |
|||
c[5] = 0.25 * (this.c[1] + 2 * this.c[3] + this.c[5]); |
|||
c[6] = 0.125 * (this.c[0] + 3 * (this.c[2] + this.c[4]) + this.c[6]); |
|||
c[7] = 0.125 * (this.c[1] + 3 * (this.c[3] + this.c[5]) + this.c[7]); |
|||
return new CubicBez(c); |
|||
} |
|||
|
|||
rightHalf() { |
|||
let c = new Float64Array(8); |
|||
c[0] = 0.125 * (this.c[0] + 3 * (this.c[2] + this.c[4]) + this.c[6]); |
|||
c[1] = 0.125 * (this.c[1] + 3 * (this.c[3] + this.c[5]) + this.c[7]); |
|||
c[2] = 0.25 * (this.c[2] + 2 * this.c[4] + this.c[6]); |
|||
c[3] = 0.25 * (this.c[3] + 2 * this.c[5] + this.c[7]); |
|||
c[4] = 0.5 * (this.c[4] + this.c[6]); |
|||
c[5] = 0.5 * (this.c[5] + this.c[7]); |
|||
c[6] = this.c[6]; |
|||
c[7] = this.c[7]; |
|||
return new CubicBez(c); |
|||
} |
|||
} |
|||
|
|||
function testCubicBez() { |
|||
let c = new Float64Array(8); |
|||
for (var i = 0; i < 8; i++) { |
|||
c[i] = Math.random(); |
|||
} |
|||
let cb = new CubicBez(c); |
|||
let t = Math.random(); |
|||
let epsilon = 1e-6; |
|||
let xy0 = cb.eval(t); |
|||
let xy1 = cb.eval(t + epsilon); |
|||
console.log(new Vec2((xy1.x - xy0.x) / epsilon, (xy1.y - xy0.y) / epsilon)); |
|||
console.log(cb.deriv(t)); |
|||
|
|||
let dxy0 = cb.deriv(t); |
|||
let dxy1 = cb.deriv(t + epsilon); |
|||
console.log(new Vec2((dxy1.x - dxy0.x) / epsilon, (dxy1.y - dxy0.y) / epsilon)); |
|||
console.log(cb.deriv2(t)); |
|||
} |
|||
|
|||
class Polynomial { |
|||
constructor(c) { |
|||
this.c = c; |
|||
} |
|||
|
|||
eval(x) { |
|||
let xi = 1; |
|||
let s = 0; |
|||
for (let a of this.c) { |
|||
s += a * xi; |
|||
xi *= x; |
|||
} |
|||
return s; |
|||
} |
|||
|
|||
deriv() { |
|||
let c = new Float64Array(this.c.length - 1); |
|||
for (let i = 0; i < c.length; i++) { |
|||
c[i] = (i + 1) * this.c[i + 1]; |
|||
} |
|||
return new Polynomial(c); |
|||
} |
|||
} |
|||
|
|||
function hermite5(x0, x1, v0, v1, a0, a1) { |
|||
return new Polynomial([x0, |
|||
v0, |
|||
0.5 * a0, |
|||
-10 * x0 + 10 * x1 - 6 * v0 - 4 * v1 - 1.5 * a0 + 0.5 * a1, |
|||
15 * x0 - 15 * x1 + 8 * v0 + 7 * v1 + 1.5 * a0 - a1, |
|||
-6 * x0 + 6 * x1 - 3 * v0 - 3 * v1 + -.5 * a0 + 0.5 * a1]); |
|||
} |
|||
|
|||
/// Solve tridiagonal matrix system. Destroys inputs, leaves output in x.
|
|||
///
|
|||
/// Solves a[i] * x[i - 1] + b[i] * x[i] + c[i] * x[i + 1] = d[i]
|
|||
///
|
|||
/// Inputs are array-like objects (typed arrays are good for performance).
|
|||
///
|
|||
/// Note: this is not necessarily the fastest, see:
|
|||
/// https://en.wikibooks.org/wiki/Algorithm_Implementation/Linear_Algebra/Tridiagonal_matrix_algorithm
|
|||
function tridiag(a, b, c, d, x) { |
|||
let n = x.length; |
|||
for (var i = 1; i < n; i++) { |
|||
let m = a[i] / b[i - 1]; |
|||
b[i] -= m * c[i - 1]; |
|||
d[i] -= m * d[i - 1]; |
|||
} |
|||
x[n - 1] = d[n - 1] / b[n - 1]; |
|||
for (var i = n - 2; i >= 0; i--) { |
|||
x[i] = (d[i] - c[i] * x[i + 1]) / b[i]; |
|||
} |
|||
} |
|||
|
|||
function testTridiag(n) { |
|||
let a = new Float64Array(n); |
|||
let b = new Float64Array(n); |
|||
let c = new Float64Array(n); |
|||
let d = new Float64Array(n); |
|||
let x = new Float64Array(n); |
|||
|
|||
for (var i = 0; i < n; i++) { |
|||
a[i] = Math.random(); |
|||
b[i] = 2 + Math.random(); |
|||
c[i] = Math.random(); |
|||
d[i] = Math.random(); |
|||
x[i] = Math.random(); |
|||
} |
|||
let bsave = new Float64Array(b); |
|||
let dsave = new Float64Array(d); |
|||
let xsave = new Float64Array(x); |
|||
tridiag(a, b, c, d, x); |
|||
b = bsave; d = dsave; |
|||
console.log(b[0] * x[0] + c[0] * x[1] - d[0]); |
|||
for (var i = 1; i < n - 1; i++) { |
|||
console.log(a[i] * x[i - 1] + b[i] * x[i] + c[i] * x[i + 1] - d[i]); |
|||
} |
|||
console.log(a[n - 1] * x[n - 2] + b[n - 1] * x[n - 1] - d[n - 1]); |
|||
} |
|||
|
|||
//testTridiag(10);
|
|||
//testCubicBez();
|
|||
|
|||
/// Create a smooth cubic bezier.
|
|||
function myCubic(th0, th1) { |
|||
function myCubicLen(th0, th1) { |
|||
let offset = 0.3 * Math.sin(th1 * 2 - 0.4 * Math.sin(th1 * 2)); |
|||
let newShape = true; |
|||
if (newShape) { |
|||
let scale = 1.0 / (3 * 0.8); |
|||
let len = scale * (Math.cos(th0 - offset) - 0.2 * Math.cos((3 * (th0 - offset)))); |
|||
return len; |
|||
} else { |
|||
let drive = 2.0; |
|||
let scale = 1.0 / (3 * Math.tanh(drive)); |
|||
let len = scale * Math.tanh(drive * Math.cos(th0 - offset)); |
|||
return len; |
|||
} |
|||
} |
|||
|
|||
var coords = new Float64Array(8); |
|||
let len0 = myCubicLen(th0, th1); |
|||
coords[2] = Math.cos(th0) * len0; |
|||
coords[3] = Math.sin(th0) * len0; |
|||
|
|||
let len1 = myCubicLen(th1, th0); |
|||
coords[4] = 1 - Math.cos(th1) * len1; |
|||
coords[5] = Math.sin(th1) * len1; |
|||
coords[6] = 1; |
|||
return coords; |
|||
} |
|||
|
|||
//! Base class for two parameter curve families
|
|||
|
|||
class TwoParamCurve { |
|||
/// Render the curve, providing an array of _interior_ cubic bezier
|
|||
/// control points only. Return value is an array of 3n-1 Vec2's.
|
|||
// render(th0, th1)
|
|||
|
|||
/// Compute curvature.
|
|||
///
|
|||
/// Result is an object with ak0 and ak1 (arctan of curvature at endpoints).
|
|||
/// Quadrant is significant - a value outside -pi/2 to pi/2 means a reversal
|
|||
/// of direction.
|
|||
// computeCurvature(th0, th1)
|
|||
|
|||
/// Get endpoint condition.
|
|||
///
|
|||
/// Return tangent at endpoint given next-to-endpoint tangent.
|
|||
// endpointTangent(th)
|
|||
|
|||
/// Compute curvature derivatives.
|
|||
///
|
|||
/// Result is an object with dak0dth0 and friends.
|
|||
/// Default implementation is approximate through central differencing, but
|
|||
/// curves can override.
|
|||
computeCurvatureDerivs(th0, th1) { |
|||
let epsilon = 1e-6; |
|||
let scale = 2.0 / epsilon; |
|||
let k0plus = this.computeCurvature(th0 + epsilon, th1); |
|||
let k0minus = this.computeCurvature(th0 - epsilon, th1); |
|||
let dak0dth0 = scale * (k0plus.ak0 - k0minus.ak0); |
|||
let dak1dth0 = scale * (k0plus.ak1 - k0minus.ak1); |
|||
let k1plus = this.computeCurvature(th0, th1 + epsilon); |
|||
let k1minus = this.computeCurvature(th0, th1 - epsilon); |
|||
let dak0dth1 = scale * (k1plus.ak0 - k1minus.ak0); |
|||
let dak1dth1 = scale * (k1plus.ak1 - k1minus.ak1); |
|||
return {dak0dth0: dak0dth0, dak1dth0: dak1dth0, dak0dth1: dak0dth1, dak1dth1: dak1dth1}; |
|||
} |
|||
} |
|||
|
|||
class MyCurve extends TwoParamCurve { |
|||
render(th0, th1) { |
|||
let c = myCubic(th0, th1); |
|||
return [new Vec2(c[2], c[3]), new Vec2(c[4], c[5])]; |
|||
} |
|||
|
|||
/// Render as a 4-parameter curve with optional adjusted endpoint curvatures.
|
|||
render4Quintic(th0, th1, k0, k1) { |
|||
//let cb = new CubicBez(myCubic(th0, th1));
|
|||
let cb = this.convCubic(this.render4Cubic(th0, th1, k0, k1)); |
|||
// compute second deriv tweak to match curvature
|
|||
function curvAdjust(t, th, k) { |
|||
if (k === null) return new Vec2(0, 0); |
|||
let c = Math.cos(th); |
|||
let s = Math.sin(th); |
|||
let d2 = cb.deriv2(t); |
|||
let d2cross = d2.y * c - d2.x * s; |
|||
let d = cb.deriv(t); |
|||
let ddot = d.x * c + d.y * s; |
|||
// TODO: if ddot = 0, cusp, no adjustment
|
|||
let oldK = d2cross / (ddot * ddot); |
|||
let kAdjust = k - oldK; |
|||
let aAdjust = kAdjust * (ddot * ddot); |
|||
return new Vec2(-s * aAdjust, c * aAdjust); |
|||
} |
|||
let a0 = curvAdjust(0, th0, k0); |
|||
let a1 = curvAdjust(1, -th1, k1); |
|||
let hx = hermite5(0, 0, 0, 0, a0.x, a1.x); |
|||
let hy = hermite5(0, 0, 0, 0, a0.y, a1.y); |
|||
let hxd = hx.deriv(); |
|||
let hyd = hy.deriv(); |
|||
// This really would be cleaner if we had arbitrary deCasteljau...
|
|||
let c0 = cb.leftHalf(); |
|||
let c1 = cb.rightHalf(); |
|||
let cs = [c0.leftHalf(), c0.rightHalf(), c1.leftHalf(), c1.rightHalf()]; |
|||
let result = []; |
|||
let scale = 1./12; |
|||
for (let i = 0; i < 4; i++) { |
|||
let t = 0.25 * i; |
|||
let t1 = t + 0.25; |
|||
let c = cs[i].c; |
|||
let x0 = hx.eval(t); |
|||
let y0 = hy.eval(t); |
|||
let x1 = x0 + scale * hxd.eval(t); |
|||
let y1 = y0 + scale * hyd.eval(t); |
|||
let x3 = hx.eval(t1); |
|||
let y3 = hy.eval(t1); |
|||
let x2 = x3 - scale * hxd.eval(t1); |
|||
let y2 = y3 - scale * hyd.eval(t1); |
|||
if (i != 0) { |
|||
result.push(new Vec2(c[0] + x0, c[1] + y0)); |
|||
} |
|||
result.push(new Vec2(c[2] + x1, c[3] + y1)); |
|||
result.push(new Vec2(c[4] + x2, c[5] + y2)); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
convCubic(pts) { |
|||
let coords = new Float64Array(8); |
|||
coords[2] = pts[0].x; |
|||
coords[3] = pts[0].y; |
|||
coords[4] = pts[1].x; |
|||
coords[5] = pts[1].y; |
|||
coords[6] = 1; |
|||
return new CubicBez(coords); |
|||
} |
|||
|
|||
// Ultimately we want to exactly match the endpoint curvatures (probably breaking
|
|||
// into two cubic segments), but for now, just approximate...
|
|||
render4Cubic(th0, th1, k0, k1) { |
|||
let cb = new CubicBez(myCubic(th0, th1)); |
|||
let result = []; |
|||
function deriv_scale(t, th, k) { |
|||
if (k === null) return 1/3; |
|||
let c = Math.cos(th); |
|||
let s = Math.sin(th); |
|||
let d = cb.deriv(t); |
|||
let d2 = cb.deriv2(t); |
|||
let d2cross = d2.y * c - d2.x * s; |
|||
let ddot = d.x * c + d.y * s; |
|||
let oldK = d2cross / (ddot * ddot); |
|||
// fudge to avoid divide-by-zero
|
|||
if (Math.abs(oldK) < 1e-6) oldK = 1e-6; |
|||
let ratio = k / oldK; |
|||
// TODO: fine tune this dodgy formula
|
|||
//let scale = ratio < 1 ? 1/2 - ratio/6 : 1/(3*ratio);
|
|||
let scale = 1/(2 + ratio); |
|||
return scale; |
|||
} |
|||
let scale0 = deriv_scale(0, th0, k0); |
|||
let d0 = cb.deriv(0); |
|||
result.push(new Vec2(d0.x * scale0, d0.y * scale0)); |
|||
let d1 = cb.deriv(1); |
|||
let scale1 = deriv_scale(1, -th1, k1); |
|||
result.push(new Vec2(1 - d1.x * scale1, - d1.y * scale1)); |
|||
return result; |
|||
} |
|||
|
|||
render4(th0, th1, k0, k1) { |
|||
if (k0 === null && k1 === null) { |
|||
return this.render(th0, th1); |
|||
} |
|||
return this.render4Quintic(th0, th1, k0, k1); |
|||
} |
|||
|
|||
computeCurvature(th0, th1) { |
|||
let cb = new CubicBez(myCubic(th0, th1)); |
|||
function curv(t, th) { |
|||
let c = Math.cos(th); |
|||
let s = Math.sin(th); |
|||
let d2 = cb.deriv2(t); |
|||
let d2cross = d2.y * c - d2.x * s; |
|||
let d = cb.deriv(t); |
|||
let ddot = d.x * c + d.y * s; |
|||
return Math.atan2(d2cross, ddot * Math.abs(ddot)); |
|||
} |
|||
|
|||
//let ak0 = cb.atanCurvature(0);
|
|||
//let ak1 = cb.atanCurvature(1);
|
|||
let ak0 = curv(0, th0); |
|||
let ak1 = curv(1, -th1); |
|||
|
|||
return {ak0: ak0, ak1: ak1}; |
|||
} |
|||
|
|||
endpointTangent(th) { |
|||
// Same value as parabola:
|
|||
//return Math.atan(2 * Math.tan(th)) - th;
|
|||
|
|||
return 0.5 * Math.sin(2 * th); |
|||
} |
|||
} |
|||
|
|||
//! Global spline solver
|
|||
|
|||
// normalize theta to -pi..pi
|
|||
function mod2pi(th) { |
|||
let twopi = 2 * Math.PI; |
|||
let frac = th * (1 / twopi); |
|||
return twopi * (frac - Math.round(frac)); |
|||
} |
|||
|
|||
|
|||
class TwoParamSpline { |
|||
constructor(curve, ctrlPts) { |
|||
this.curve = curve; |
|||
this.ctrlPts = ctrlPts; |
|||
this.startTh = null; |
|||
this.endTh = null; |
|||
} |
|||
|
|||
/// Determine initial tangent angles, given array of Vec2 control points.
|
|||
initialThs() { |
|||
var ths = new Float64Array(this.ctrlPts.length); |
|||
for (var i = 1; i < ths.length - 1; i++) { |
|||
let dx0 = this.ctrlPts[i].x - this.ctrlPts[i - 1].x; |
|||
let dy0 = this.ctrlPts[i].y - this.ctrlPts[i - 1].y; |
|||
let l0 = Math.hypot(dx0, dy0); |
|||
let dx1 = this.ctrlPts[i + 1].x - this.ctrlPts[i].x; |
|||
let dy1 = this.ctrlPts[i + 1].y - this.ctrlPts[i].y; |
|||
let l1 = Math.hypot(dx1, dy1); |
|||
let th0 = Math.atan2(dy0, dx0); |
|||
let th1 = Math.atan2(dy1, dx1); |
|||
let bend = mod2pi(th1 - th0); |
|||
let th = mod2pi(th0 + bend * l0 / (l0 + l1)); |
|||
ths[i] = th; |
|||
if (i == 1) { ths[0] = th0; } |
|||
if (i == ths.length - 2) { ths[i + 1] = th1; } |
|||
} |
|||
if (this.startTh !== null) { |
|||
ths[0] = this.startTh; |
|||
} |
|||
if (this.endTh !== null) { |
|||
ths[ths.length - 1] = this.endTh; |
|||
} |
|||
this.ths = ths; |
|||
return ths; |
|||
} |
|||
|
|||
/// Get tangent angles relative to endpoints, and chord length.
|
|||
getThs(i) { |
|||
let dx = this.ctrlPts[i + 1].x - this.ctrlPts[i].x; |
|||
let dy = this.ctrlPts[i + 1].y - this.ctrlPts[i].y; |
|||
let th = Math.atan2(dy, dx); |
|||
let th0 = mod2pi(this.ths[i] - th); |
|||
let th1 = mod2pi(th - this.ths[i + 1]); |
|||
let chord = Math.hypot(dx, dy); |
|||
return {th0: th0, th1: th1, chord: chord}; |
|||
} |
|||
|
|||
/// Crawl towards a curvature continuous solution.
|
|||
iterDumb(iter) { |
|||
function computeErr(ths0, ak0, ths1, ak1) { |
|||
// rescale tangents by geometric mean of chordlengths
|
|||
let ch0 = Math.sqrt(ths0.chord); |
|||
let ch1 = Math.sqrt(ths1.chord); |
|||
let a0 = Math.atan2(Math.sin(ak0.ak1) * ch1, Math.cos(ak0.ak1) * ch0); |
|||
let a1 = Math.atan2(Math.sin(ak1.ak0) * ch0, Math.cos(ak1.ak0) * ch1); |
|||
return a0 - a1; |
|||
/* |
|||
return ths1.chord * Math.sin(ak0.ak1) * Math.cos(ak1.ak0) |
|||
- ths0.chord * Math.sin(ak1.ak0) * Math.cos(ak0.ak1); |
|||
*/ |
|||
} |
|||
|
|||
let n = this.ctrlPts.length; |
|||
// Fix endpoint tangents; we rely on iteration for this to converge
|
|||
if (this.startTh === null) { |
|||
let ths0 = this.getThs(0); |
|||
this.ths[0] += this.curve.endpointTangent(ths0.th1) - ths0.th0; |
|||
} |
|||
|
|||
if (this.endTh === null) { |
|||
let ths0 = this.getThs(n - 2); |
|||
this.ths[n - 1] -= this.curve.endpointTangent(ths0.th0) - ths0.th1; |
|||
} |
|||
if (n < 3) return 0; |
|||
|
|||
var absErr = 0; |
|||
var x = new Float64Array(n - 2); |
|||
var ths0 = this.getThs(0); |
|||
var ak0 = this.curve.computeCurvature(ths0.th0, ths0.th1); |
|||
//console.log('');
|
|||
for (var i = 0; i < n - 2; i++) { |
|||
let ths1 = this.getThs(i + 1); |
|||
let ak1 = this.curve.computeCurvature(ths1.th0, ths1.th1); |
|||
let err = computeErr(ths0, ak0, ths1, ak1); |
|||
absErr += Math.abs(err); |
|||
|
|||
let epsilon = 1e-3; |
|||
let ak0p = this.curve.computeCurvature(ths0.th0, ths0.th1 + epsilon); |
|||
let ak1p = this.curve.computeCurvature(ths1.th0 - epsilon, ths1.th1); |
|||
let errp = computeErr(ths0, ak0p, ths1, ak1p); |
|||
let derr = (errp - err) * (1 / epsilon); |
|||
//console.log(err, derr, ak0, ak1, ak0p, ak1p);
|
|||
x[i] = err / derr; |
|||
|
|||
ths0 = ths1; |
|||
ak0 = ak1; |
|||
} |
|||
|
|||
for (var i = 0; i < n - 2; i++) { |
|||
let scale = Math.tanh(0.25 * (iter + 1)); |
|||
this.ths[i + 1] += scale * x[i]; |
|||
} |
|||
|
|||
return absErr; |
|||
} |
|||
|
|||
/// Perform one step of a Newton solver.
|
|||
// Not yet implemented
|
|||
iterate() { |
|||
let n = this.ctrlPts.length; |
|||
if (n < 3) return; |
|||
var a = new Float64Array(n - 2); |
|||
var b = new Float64Array(n - 2); |
|||
var c = new Float64Array(n - 2); |
|||
var d = new Float64Array(n - 2); |
|||
var x = new Float64Array(n - 2); |
|||
|
|||
let ths0 = this.getThs(0); |
|||
var last_ak = this.curve.computeCurvature(ths0.th0, ths0.th1); |
|||
var last_dak = this.curve.computeCurvatureDerivs(ths0.th0, ths0.th1); |
|||
var last_a = Math.hypot(this.ctrlPts[1].x - this.ctrlPts[0].x, |
|||
this.ctrlPts[1].y - this.ctrlPts[0].y); |
|||
for (var i = 0; i < n - 2; i++) { |
|||
let ths = this.getThs(i + 1); |
|||
let ak = this.curve.computeCurvature(ths.th0, ths.th1); |
|||
let dak = this.curve.computeCurvatureDerivs(ths.th0, ths.th1); |
|||
var a = Math.hypot(this.ctrlPts[i + 2].x - this.ctrlPts[i + 1].x, |
|||
this.ctrlPts[i + 2].y - this.ctrlPts[i + 1].y); |
|||
let c0 = Math.cos(last_ak.ak1); |
|||
let s0 = Math.sin(last_ak.ak1); |
|||
let c1 = Math.cos(ak.ak0); |
|||
let s1 = Math.sin(ak.ak0); |
|||
|
|||
// TODO: fill in derivatives properly
|
|||
d[i] = a * s0 * c1 - last_a * s1 * c0; |
|||
|
|||
last_ak = ak; |
|||
last_dak = dak; |
|||
last_a = a; |
|||
} |
|||
|
|||
tridiag(a, b, c, d, x); |
|||
for (var i = 0; i < n - 2; i++) { |
|||
this.ths[i + 1] -= x[i]; |
|||
} |
|||
} |
|||
|
|||
/// Return an SVG path string.
|
|||
renderSvg() { |
|||
let c = this.ctrlPts; |
|||
if (c.length == 0) { return ""; } |
|||
let path = `M${c[0].x} ${c[0].y}`; |
|||
let cmd = " C"; |
|||
for (var i = 0; i < c.length - 1; i++) { |
|||
let ths = this.getThs(i); |
|||
let render = this.curve.render(ths.th0, ths.th1); |
|||
let dx = c[i + 1].x - c[i].x; |
|||
let dy = c[i + 1].y - c[i].y; |
|||
for (var j = 0; j < render.length; j++) { |
|||
let pt = render[j]; |
|||
let x = c[i].x + dx * pt.x - dy * pt.y; |
|||
let y = c[i].y + dy * pt.x + dx * pt.y; |
|||
path += `${cmd}${x} ${y}`; |
|||
cmd = " "; |
|||
} |
|||
path += ` ${c[i + 1].x} ${c[i + 1].y}`; |
|||
} |
|||
return path; |
|||
} |
|||
} |
|||
|
|||
/// Spline handles more general cases, including corners.
|
|||
class Spline { |
|||
constructor(ctrlPts, isClosed) { |
|||
this.ctrlPts = ctrlPts; |
|||
this.isClosed = isClosed; |
|||
this.curve = new MyCurve(); |
|||
} |
|||
|
|||
pt(i, start) { |
|||
let length = this.ctrlPts.length; |
|||
return this.ctrlPts[(i + start + length) % length]; |
|||
} |
|||
|
|||
startIx() { |
|||
if (!this.isClosed) { |
|||
return 0; |
|||
} |
|||
for (let i = 0; i < this.ctrlPts.length; i++) { |
|||
let pt = this.ctrlPts[i]; |
|||
if (pt.ty === "corner" || pt.lth !== null) { |
|||
return i; |
|||
} |
|||
} |
|||
// Path is all-smooth and closed.
|
|||
return 0; |
|||
} |
|||
|
|||
solve() { |
|||
let start = this.startIx(); |
|||
let length = this.ctrlPts.length - (this.isClosed ? 0 : 1); |
|||
let i = 0; |
|||
while (i < length) { |
|||
let ptI = this.pt(i, start); |
|||
let ptI1 = this.pt(i + 1, start); |
|||
if ((i + 1 == length || ptI1.ty === "corner") |
|||
&& ptI.rth === null && ptI1.lth === null) { |
|||
let dx = ptI1.pt.x - ptI.pt.x; |
|||
let dy = ptI1.pt.y - ptI.pt.y; |
|||
let th = Math.atan2(dy, dx); |
|||
ptI.rTh = th; |
|||
ptI1.lTh = th; |
|||
i += 1; |
|||
} else { |
|||
// We have a curve.
|
|||
let innerPts = [ptI.pt]; |
|||
let j = i + 1; |
|||
while (j < length + 1) { |
|||
let ptJ = this.pt(j, start); |
|||
innerPts.push(ptJ.pt); |
|||
j += 1; |
|||
if (ptJ.ty === "corner" || ptJ.lth !== null) { |
|||
break; |
|||
} |
|||
} |
|||
//console.log(innerPts);
|
|||
let inner = new TwoParamSpline(this.curve, innerPts); |
|||
inner.startTh = this.pt(i, start).rth; |
|||
inner.endTh = this.pt(j - 1, start).lth; |
|||
let nIter = 10; |
|||
inner.initialThs(); |
|||
for (let k = 0; k < nIter; k++) { |
|||
inner.iterDumb(k); |
|||
} |
|||
for (let k = i; k + 1 < j; k++) { |
|||
this.pt(k, start).rTh = inner.ths[k - i]; |
|||
this.pt(k + 1, start).lTh = inner.ths[k + 1 - i]; |
|||
// Record curvatures (for blending, not all will be used)
|
|||
let ths = inner.getThs(k - i); |
|||
let aks = this.curve.computeCurvature(ths.th0, ths.th1); |
|||
this.pt(k, start).rAk = aks.ak0; |
|||
this.pt(k + 1, start).lAk = aks.ak1; |
|||
} |
|||
|
|||
i = j - 1; |
|||
} |
|||
} |
|||
} |
|||
|
|||
chordLen(i) { |
|||
let ptI = this.pt(i, 0).pt; |
|||
let ptI1 = this.pt(i + 1, 0).pt; |
|||
return Math.hypot(ptI1.x - ptI.x, ptI1.y - ptI.y); |
|||
} |
|||
|
|||
// Determine whether a control point requires curvature blending, and if so,
|
|||
// the blended curvature. To be invoked after solving.
|
|||
computeCurvatureBlending() { |
|||
function myTan(th) { |
|||
if (th > Math.PI / 2) { |
|||
return Math.tan(Math.PI - th); |
|||
} else if (th < -Math.PI / 2) { |
|||
return Math.tan(-Math.PI - th); |
|||
} else { |
|||
return Math.tan(th); |
|||
} |
|||
} |
|||
for (let pt of this.ctrlPts) { |
|||
pt.kBlend = null; |
|||
} |
|||
let length = this.ctrlPts.length - (this.isClosed ? 0 : 1); |
|||
for (let i = 0; i < length; i++) { |
|||
let pt = this.pt(i, 0); |
|||
if (pt.ty === "smooth" && pt.lth !== null) { |
|||
let thresh = Math.PI / 2 - 1e-6; |
|||
//if (Math.abs(pt.rAk) > thresh || Math.abs(pt.lAk) > thresh) {
|
|||
// // Don't blend reversals. We might reconsider this, but punt for now.
|
|||
// continue;
|
|||
//}
|
|||
if (Math.sign(pt.rAk) != Math.sign(pt.lAk)) { |
|||
pt.kBlend = 0; |
|||
} else { |
|||
let rK = myTan(pt.rAk) / this.chordLen(i - 1); |
|||
let lK = myTan(pt.lAk) / this.chordLen(i); |
|||
pt.kBlend = 2 / (1 / rK + 1 / lK); |
|||
//console.log(`point ${i}: kBlend = ${pt.kBlend}`);
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
render() { |
|||
let path = new BezPath; |
|||
if (this.ctrlPts.length == 0) { |
|||
return path; |
|||
} |
|||
let pt0 = this.ctrlPts[0]; |
|||
path.moveto(pt0.pt.x, pt0.pt.y); |
|||
let length = this.ctrlPts.length - (this.isClosed ? 0 : 1); |
|||
let i = 0; |
|||
for (let i = 0; i < length; i++) { |
|||
path.mark(i); |
|||
let ptI = this.pt(i, 0); |
|||
let ptI1 = this.pt(i + 1, 0); |
|||
let dx = ptI1.pt.x - ptI.pt.x; |
|||
let dy = ptI1.pt.y - ptI.pt.y; |
|||
let chth = Math.atan2(dy, dx); |
|||
let chord = Math.hypot(dy, dx); |
|||
let th0 = mod2pi(ptI.rTh - chth); |
|||
let th1 = mod2pi(chth - ptI1.lTh); |
|||
// Apply curvature blending
|
|||
let k0 = ptI.kBlend !== null ? ptI.kBlend * chord : null; |
|||
let k1 = ptI1.kBlend !== null ? ptI1.kBlend * chord : null; |
|||
//console.log(`segment ${i}: ${k0} ${k1}`);
|
|||
let render = this.curve.render4(th0, th1, k0, k1); |
|||
let c = []; |
|||
for (let j = 0; j < render.length; j++) { |
|||
let pt = render[j]; |
|||
c.push(ptI.pt.x + dx * pt.x - dy * pt.y); |
|||
c.push(ptI.pt.y + dy * pt.x + dx * pt.y); |
|||
} |
|||
c.push(ptI1.pt.x); |
|||
c.push(ptI1.pt.y); |
|||
for (let j = 0; j < c.length; j += 6) { |
|||
path.curveto(c[j], c[j + 1], c[j + 2], c[j + 3], c[j + 4], c[j + 5]); |
|||
} |
|||
} |
|||
if (this.isClosed) { |
|||
path.closepath(); |
|||
} |
|||
return path; |
|||
} |
|||
|
|||
renderSvg() { |
|||
return this.render().renderSvg(); |
|||
} |
|||
} |
|||
|
|||
/// ControlPoint is a lot like `Knot` but has no UI, is used for spline solving.
|
|||
class ControlPoint { |
|||
constructor(pt, ty, lth, rth) { |
|||
this.pt = pt; |
|||
this.ty = ty; |
|||
this.lth = lth; |
|||
this.rth = rth; |
|||
} |
|||
} |
@ -0,0 +1,860 @@ |
|||
// Copyright 2018 Raph Levien
|
|||
|
|||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|||
// option. This file may not be copied, modified, or distributed
|
|||
// except according to those terms.
|
|||
|
|||
//! UI for drawing splines
|
|||
|
|||
/// Fancy name for something that just detects double clicks, but might expand.
|
|||
class GestureDet { |
|||
constructor(ui) { |
|||
this.ui = ui; |
|||
this.lastEv = null; |
|||
this.lastPt = null; |
|||
this.clickCount = 0; |
|||
} |
|||
|
|||
onPointerDown(ev) { |
|||
let dblClickThreshold = 550; // ms
|
|||
let radiusThreshold = 5; |
|||
let pt = this.ui.getCoords(ev); |
|||
if (this.lastEv !== null) { |
|||
if (ev.timeStamp - this.lastEv.timeStamp > dblClickThreshold |
|||
|| Math.hypot(pt.x - this.lastPt.x, pt.y - this.lastPt.y) > radiusThreshold) { |
|||
this.clickCount = 0; |
|||
} |
|||
} |
|||
this.lastEv = ev; |
|||
this.lastPt = pt; |
|||
this.clickCount++; |
|||
} |
|||
} |
|||
|
|||
// Dimensions of the tangent target
|
|||
// Inside this radius, convert to corner point
|
|||
let tanR1 = 5; |
|||
// Radius of drawn tangent marker
|
|||
let tanR2 = 15; |
|||
// Outside this radius, remove explicit tangent
|
|||
let tanR3 = 45; |
|||
|
|||
/// State and UI for an editable spline
|
|||
class SplineEdit { |
|||
constructor(ui) { |
|||
this.ui = ui; |
|||
this.knots = []; |
|||
this.isClosed = false; |
|||
this.bezpath = new BezPath; |
|||
this.selection = new Set(); |
|||
this.mode = "start"; |
|||
this.grid = 20; |
|||
this.shiftOnDrag = false; |
|||
} |
|||
|
|||
renderGrid(visible) { |
|||
let grid = document.getElementById("grid"); |
|||
this.ui.removeAllChildren(grid); |
|||
if (!visible) return; |
|||
let w = 640; |
|||
let h = 480; |
|||
for (let i = 0; i < w; i += this.grid) { |
|||
let line = this.ui.createSvgElement("line"); |
|||
line.setAttribute("x1", i); |
|||
line.setAttribute("y1", 0); |
|||
line.setAttribute("x2", i); |
|||
line.setAttribute("y2", h); |
|||
grid.appendChild(line); |
|||
} |
|||
for (let i = 0; i < h; i += this.grid) { |
|||
let line = this.ui.createSvgElement("line"); |
|||
line.setAttribute("x1", 0); |
|||
line.setAttribute("y1", i); |
|||
line.setAttribute("x2", w); |
|||
line.setAttribute("y2", i); |
|||
grid.appendChild(line); |
|||
} |
|||
} |
|||
|
|||
setSelection(sel) { |
|||
this.selection = sel; |
|||
} |
|||
|
|||
roundToGrid(pt) { |
|||
let g = this.grid; |
|||
return new Vec2(g * Math.round(pt.x / g), g * Math.round(pt.y / g)); |
|||
} |
|||
|
|||
onPointerDown(ev, obj) { |
|||
let pt = this.ui.getCoords(ev); |
|||
if (obj === null) { |
|||
let subdivideDist = 5; |
|||
if (ev.shiftKey) { |
|||
pt = this.roundToGrid(pt); |
|||
} |
|||
let ty = ev.altKey ? "smooth" : "corner"; |
|||
let hit = this.bezpath.hitTest(pt.x, pt.y); |
|||
let insIx = this.knots.length; |
|||
if (hit.bestDist < subdivideDist) { |
|||
ty = "smooth"; |
|||
insIx = hit.bestMark + 1; |
|||
} |
|||
let knot = new Knot(this, pt.x, pt.y, ty); |
|||
this.knots.splice(insIx, 0, knot); |
|||
this.ui.attachReceiver(knot.handleEl, this, knot); |
|||
// TODO: setter rather than state change?
|
|||
this.ui.receiver = this; |
|||
this.setSelection(new Set([knot])); |
|||
if (ty === "corner") { |
|||
this.mode = "creating"; |
|||
} else { |
|||
this.mode = "dragging"; |
|||
} |
|||
this.initPt = pt; |
|||
} else if (obj instanceof TanHandle) { |
|||
this.mode = "tanhandle"; |
|||
this.isRight = obj.isRight; |
|||
// This suggests maybe we should use selected point, not initPt
|
|||
this.initPt = new Vec2(obj.knot.x, obj.knot.y); |
|||
this.updateTan(obj.knot, pt, ev); |
|||
this.setSelection(new Set([obj.knot])); |
|||
} else { |
|||
if (this.selection.size == 1 |
|||
&& this.selection.has(this.knots[this.knots.length - 1]) |
|||
&& this.knots.length >= 3 |
|||
&& obj === this.knots[0]) |
|||
{ |
|||
this.isClosed = true; |
|||
} |
|||
this.mode = "dragging"; |
|||
if (this.ui.gestureDet.clickCount > 1) { |
|||
if (obj.ty === "corner") { |
|||
obj.setTy("smooth"); |
|||
} else { |
|||
obj.setTy("corner"); |
|||
} |
|||
obj.setTan(null); |
|||
} |
|||
let sel; |
|||
this.shiftOnDrag = ev.shiftKey; |
|||
if (ev.shiftKey) { |
|||
// toggle point selection
|
|||
sel = new Set(this.selection); |
|||
if (sel.has(obj)) { |
|||
sel.delete(obj); |
|||
} else { |
|||
sel.add(obj); |
|||
} |
|||
} else { |
|||
if (this.selection.has(obj)) { |
|||
sel = this.selection; |
|||
} else { |
|||
sel = new Set([obj]); |
|||
} |
|||
} |
|||
this.setSelection(sel); |
|||
} |
|||
this.render(); |
|||
this.lastPt = pt; |
|||
} |
|||
|
|||
onPointerMove(ev) { |
|||
let pt = this.ui.getCoords(ev); |
|||
let dx = pt.x - this.lastPt.x; |
|||
let dy = pt.y - this.lastPt.y; |
|||
if (this.mode === "dragging") { |
|||
for (let knot of this.selection) { |
|||
if (ev.shiftKey && !this.shiftOnDrag && this.selection.size == 1) { |
|||
pt = this.roundToGrid(pt); |
|||
knot.updatePos(pt.x, pt.y); |
|||
} else { |
|||
knot.updatePos(knot.x + dx, knot.y + dy); |
|||
} |
|||
} |
|||
} else if (this.mode === "creating") { |
|||
let r = Math.hypot(pt.x - this.initPt.x, pt.y - this.initPt.y); |
|||
let ty = r < tanR1 ? "corner" : "smooth"; |
|||
for (let knot of this.selection) { |
|||
knot.setTy(ty); |
|||
} |
|||
} else if (this.mode === "tanhandle") { |
|||
let r = Math.hypot(pt.x - this.initPt.x, pt.y - this.initPt.y); |
|||
for (let knot of this.selection) { |
|||
this.updateTan(knot, pt, ev); |
|||
} |
|||
} |
|||
this.render(); |
|||
this.lastPt = pt; |
|||
} |
|||
|
|||
onPointerUp(ev) { |
|||
this.mode = "start"; |
|||
this.render(); |
|||
} |
|||
|
|||
onPointerHover(ev) { |
|||
let pt = this.ui.getCoords(ev); |
|||
// TODO: hover the knots and the visible tangent handles
|
|||
let hit = this.bezpath.hitTest(pt.x, pt.y); |
|||
// TODO: display proposed knot
|
|||
} |
|||
|
|||
onKeyDown(ev) { |
|||
if (ev.key === "Backspace" || ev.key === "Delete") { |
|||
this.delete(); |
|||
return true; |
|||
} else if (ev.key === "ArrowLeft") { |
|||
this.nudge(-1, 0, ev); |
|||
return true; |
|||
} else if (ev.key === "ArrowRight") { |
|||
this.nudge(1, 0, ev); |
|||
return true; |
|||
} else if (ev.key === "ArrowUp") { |
|||
this.nudge(0, -1, ev); |
|||
return true; |
|||
} else if (ev.key === "ArrowDown") { |
|||
this.nudge(0, 1, ev); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
delete() { |
|||
for (let i = 0; i < this.knots.length; i++) { |
|||
let knot = this.knots[i]; |
|||
if (this.selection.has(knot)) { |
|||
this.knots.splice(i, 1); |
|||
knot.handleEl.remove(); |
|||
i--; |
|||
} |
|||
} |
|||
if (this.knots.length < 3) { |
|||
this.isClosed = false; |
|||
} |
|||
this.selection = new Set(); |
|||
this.render(); |
|||
} |
|||
|
|||
|
|||
nudge(dx, dy, ev) { |
|||
if (ev && ev.shiftKey) { |
|||
dx *= 10; |
|||
dy *= 10; |
|||
} |
|||
for (let knot of this.selection) { |
|||
knot.updatePos(knot.x + dx, knot.y + dy); |
|||
} |
|||
this.render(); |
|||
} |
|||
|
|||
updateTan(knot, pt, ev) { |
|||
let dx = pt.x - this.initPt.x; |
|||
let dy = pt.y - this.initPt.y; |
|||
if (!this.isRight) { |
|||
dx = -dx; |
|||
dy = -dy; |
|||
} |
|||
let r = Math.hypot(dx, dy); |
|||
let th = null; |
|||
if (r < tanR3) { |
|||
th = Math.atan2(dy, dx); |
|||
if (ev.shiftKey) { |
|||
th = Math.PI / 2 * Math.round(th * (2 / Math.PI)); |
|||
} |
|||
} |
|||
knot.setTan(th, this.isRight); |
|||
} |
|||
|
|||
renderSpline() { |
|||
let ctrlPts = []; |
|||
for (let knot of this.knots) { |
|||
let pt = new ControlPoint(new Vec2(knot.x, knot.y), knot.ty, knot.lth, knot.rth); |
|||
ctrlPts.push(pt); |
|||
} |
|||
this.spline = new Spline(ctrlPts, this.isClosed); |
|||
this.spline.solve(); |
|||
// Should this be bundled into solve?
|
|||
this.spline.computeCurvatureBlending(); |
|||
this.bezpath = this.spline.render(); |
|||
let path = this.bezpath.renderSvg(); |
|||
document.getElementById("spline").setAttribute("d", path); |
|||
} |
|||
|
|||
renderSel() { |
|||
for (let i = 0; i < this.knots.length; i++) { |
|||
let knot = this.knots[i]; |
|||
knot.computedLTh = this.spline.pt(i, 0).lTh; |
|||
knot.computedRTh = this.spline.pt(i, 0).rTh; |
|||
knot.updateSelDecoration(this.selection.has(knot), this.mode); |
|||
} |
|||
} |
|||
|
|||
render() { |
|||
this.renderSpline(); |
|||
this.renderSel(); |
|||
} |
|||
|
|||
/// Return a JSON object (suitable for stringify)
|
|||
serialize() { |
|||
function r(x, adj) { |
|||
return Math.round(x * adj) / adj; |
|||
} |
|||
let pts = []; |
|||
for (let knot of this.knots) { |
|||
let pt = {"x": r(knot.x, 100), "y": r(knot.y, 100)}; |
|||
if (knot.ty === "corner") { |
|||
pt["c"] = 0; |
|||
if (knot.lth !== null) { |
|||
pt["l"] = r(knot.lth, 1000); |
|||
} |
|||
if (knot.rth !== null) { |
|||
pt["r"] = r(knot.rth, 1000); |
|||
} |
|||
} else { |
|||
pt["c"] = 1; |
|||
if (knot.lth !== null) { |
|||
pt["t"] = r(knot.lth, 1000); |
|||
} |
|||
} |
|||
pts.push(pt); |
|||
} |
|||
let sp = {"closed": this.isClosed, "pts": pts}; |
|||
let result = {"subpaths": [sp]}; |
|||
return result; |
|||
} |
|||
|
|||
|
|||
/// Take either a JSON object or a string, and set UI state to it
|
|||
deserialize(data) { |
|||
if (typeof data === 'string') { |
|||
data = JSON.parse(data); |
|||
} |
|||
let sp = data.subpaths[0]; |
|||
let knots = []; |
|||
for (let pt of sp.pts) { |
|||
let ty = pt.c ? "smooth" : "corner"; |
|||
let knot = new Knot(this, pt.x, pt.y, ty); |
|||
if (pt.c) { |
|||
if ("t" in pt) { |
|||
knot.lth = pt.t; |
|||
knot.rth = knot.lth; |
|||
} |
|||
} else { |
|||
if ("l" in pt) { |
|||
knot.lth = pt.l; |
|||
} |
|||
if ("r" in pt) { |
|||
knot.lth = pt.r; |
|||
} |
|||
} |
|||
knots.push(knot); |
|||
} |
|||
// Hopefully for invalid data an exception would have occurred by here.
|
|||
|
|||
for (let knot of this.knots) { |
|||
knot.handleEl.remove(); |
|||
} |
|||
this.knots = knots; |
|||
for (let knot of knots) { |
|||
this.ui.attachReceiver(knot.handleEl, this, knot); |
|||
} |
|||
this.isClosed = sp.closed; |
|||
console.log(sp.closed); |
|||
this.selection = new Set(); |
|||
this.render(); |
|||
} |
|||
} |
|||
|
|||
class Knot { |
|||
/// ty is one of 'corner', 'smooth'.
|
|||
constructor(se, x, y, ty) { |
|||
this.se = se; |
|||
this.x = x; |
|||
this.y = y; |
|||
this.ty = ty; |
|||
this.lth = null; |
|||
this.rth = null; |
|||
this.selected = false; |
|||
this.lthLine = null; |
|||
this.rthLine = null; |
|||
this.lthCircle = null; |
|||
this.rthCircle = null; |
|||
|
|||
this.handleEl = this.createHandleEl(); |
|||
} |
|||
|
|||
createHandleEl() { |
|||
let handle = this.se.ui.createSvgElement("g", true); |
|||
handle.setAttribute("class", "handle"); |
|||
handle.setAttribute("transform", `translate(${this.x} ${this.y})`); |
|||
// TODO: handles group should probably be variable in ui
|
|||
document.getElementById("handles").appendChild(handle); |
|||
let inner = this.renderHandleEl(); |
|||
handle.appendChild(inner); |
|||
return handle; |
|||
} |
|||
|
|||
renderHandleEl() { |
|||
let r = 4; |
|||
let inner; |
|||
if (this.ty === "corner") { |
|||
inner = this.se.ui.createSvgElement("rect", true); |
|||
inner.setAttribute("x", -r); |
|||
inner.setAttribute("y", -r); |
|||
inner.setAttribute("width", r * 2); |
|||
inner.setAttribute("height", r * 2); |
|||
} else { |
|||
inner = this.se.ui.createSvgElement("circle", true); |
|||
inner.setAttribute("cx", 0); |
|||
inner.setAttribute("cy", 0); |
|||
inner.setAttribute("r", r); |
|||
} |
|||
inner.setAttribute("class", "handle"); |
|||
return inner; |
|||
} |
|||
|
|||
setTan(th, isRight) { |
|||
if (this.ty === "smooth" || !isRight) { |
|||
this.lth = th; |
|||
} |
|||
if (this.ty === "smooth" || isRight) { |
|||
this.rth = th; |
|||
} |
|||
} |
|||
|
|||
updateSelLine(th, el, r) { |
|||
if (th === null && el !== null) { |
|||
el.remove(); |
|||
el = null; |
|||
} else if (th !== null && el === null) { |
|||
el = this.se.ui.createSvgElement("line"); |
|||
el.setAttribute("x1", 0); |
|||
el.setAttribute("y1", 0); |
|||
el.setAttribute("class", "tan"); |
|||
this.handleEl.appendChild(el); |
|||
} |
|||
if (el !== null) { |
|||
el.setAttribute("x2", r * Math.cos(th)); |
|||
el.setAttribute("y2", r * Math.sin(th)); |
|||
} |
|||
return el; |
|||
} |
|||
|
|||
updateSelCircle(th, el, r, computed) { |
|||
if (th === null && el !== null) { |
|||
el.remove(); |
|||
el = null; |
|||
} else if (th !== null && el === null) { |
|||
el = this.se.ui.createSvgElement("circle", true); |
|||
el.setAttribute("r", 3); |
|||
el.setAttribute("class", "tanhandle"); |
|||
this.handleEl.appendChild(el); |
|||
let tanHandle = new TanHandle(this, r > 0); |
|||
// To be more object oriented, receiver might be the knot or tanHandle. Ah well.
|
|||
this.se.ui.attachReceiver(el, this.se, tanHandle); |
|||
} |
|||
if (el !== null) { |
|||
if (computed) { |
|||
el.classList.add("computed"); |
|||
} else { |
|||
el.classList.remove("computed"); |
|||
} |
|||
el.setAttribute("cx", r * Math.cos(th)); |
|||
el.setAttribute("cy", r * Math.sin(th)); |
|||
} |
|||
return el; |
|||
} |
|||
|
|||
updateSelDecoration(selected, mode) { |
|||
if (!selected && this.selected) { |
|||
this.handleEl.classList.remove("selected"); |
|||
} else if (selected && !this.selected) { |
|||
this.handleEl.classList.add("selected"); |
|||
} |
|||
let lComputed = this.lth === null; |
|||
let rComputed = this.rth === null; |
|||
let drawCirc = selected && (mode !== "creating" && mode !== "dragging"); |
|||
let drawLTan = !lComputed || drawCirc; |
|||
let drawRTan = !rComputed || drawCirc; |
|||
let lth = null; |
|||
if (drawLTan && this.lth != null) { |
|||
lth = this.lth; |
|||
} else if (drawLTan && this.computedLTh !== undefined) { |
|||
lth = this.computedLTh; |
|||
} |
|||
let rth = null; |
|||
if (drawRTan && this.rth != null) { |
|||
rth = this.rth; |
|||
} else if (drawRTan && this.computedRTh !== undefined) { |
|||
rth = this.computedRTh; |
|||
} |
|||
this.rthLine = this.updateSelLine(rth, this.rthLine, tanR2 - 3); |
|||
this.lthLine = this.updateSelLine(lth, this.lthLine, -tanR2 + 3); |
|||
if (!drawCirc) { |
|||
lth = null; |
|||
rth = null; |
|||
} |
|||
this.lthCircle = this.updateSelCircle(lth, this.lthCircle, -tanR2, lComputed); |
|||
this.rthCircle = this.updateSelCircle(rth, this.rthCircle, tanR2, rComputed); |
|||
this.selected = selected; |
|||
} |
|||
|
|||
setTy(ty) { |
|||
if (ty !== this.ty) { |
|||
this.ty = ty; |
|||
let oldHandle = this.handleEl.querySelector(".handle"); |
|||
this.handleEl.replaceChild(this.renderHandleEl(), oldHandle); |
|||
} |
|||
} |
|||
|
|||
updatePos(x, y) { |
|||
this.x = x; |
|||
this.y = y; |
|||
this.handleEl.setAttribute("transform", `translate(${x} ${y})`); |
|||
} |
|||
} |
|||
|
|||
class TanHandle { |
|||
constructor(knot, isRight) { |
|||
this.knot = knot; |
|||
this.isRight = isRight; |
|||
} |
|||
} |
|||
|
|||
// TODO: create UI base class rather than cutting and pasting.
|
|||
class Ui { |
|||
constructor() { |
|||
this.svgNS = "http://www.w3.org/2000/svg"; |
|||
this.setupHandlers(); |
|||
this.controlPts = []; |
|||
this.se = new SplineEdit(this); |
|||
this.gestureDet = new GestureDet(this); |
|||
this.showGrid = true; |
|||
this.se.renderGrid(this.showGrid); |
|||
this.setupDialogs(); |
|||
this.keyHandlerActive = true; |
|||
} |
|||
|
|||
setupHandlers() { |
|||
let svg = document.getElementById("s"); |
|||
|
|||
if ("PointerEvent" in window) { |
|||
svg.addEventListener("pointermove", e => this.pointerMove(e)); |
|||
svg.addEventListener("pointerup", e => this.pointerUp(e)); |
|||
svg.addEventListener("pointerdown", e => this.pointerDown(e)); |
|||
} else { |
|||
// Fallback for ancient browsers
|
|||
svg.addEventListener("mousemove", e => this.mouseMove(e)); |
|||
svg.addEventListener("mouseup", e => this.mouseUp(e)); |
|||
svg.addEventListener("mousedown", e => this.mouseDown(e)); |
|||
// TODO: add touch handlers
|
|||
} |
|||
window.addEventListener("keydown", e => this.keyDown(e)); |
|||
this.mousehandler = null; |
|||
this.receiver = null; |
|||
} |
|||
|
|||
attachHandler(element, handler) { |
|||
let svg = document.getElementById("s"); |
|||
if ("PointerEvent" in window) { |
|||
element.addEventListener("pointerdown", e => { |
|||
svg.setPointerCapture(e.pointerId); |
|||
this.mousehandler = handler; |
|||
e.preventDefault(); |
|||
e.stopPropagation(); |
|||
}); |
|||
} else { |
|||
element.addEventListener("mousedown", e => { |
|||
this.mousehandler = handler; |
|||
e.preventDefault(); |
|||
e.stopPropagation(); |
|||
}); |
|||
// TODO: add touch handlers
|
|||
} |
|||
} |
|||
|
|||
/// This is the pattern for the new object-y style.
|
|||
|
|||
// Maybe just rely on closures to capture obj?
|
|||
attachReceiver(element, receiver, obj) { |
|||
let svg = document.getElementById("s"); |
|||
if ("PointerEvent" in window) { |
|||
element.addEventListener("pointerdown", e => { |
|||
this.gestureDet.onPointerDown(e); |
|||
svg.setPointerCapture(e.pointerId); |
|||
this.receiver = receiver; |
|||
receiver.onPointerDown(e, obj); |
|||
e.preventDefault(); |
|||
e.stopPropagation(); |
|||
}); |
|||
} else { |
|||
element.addEventListener("mousedown", e => { |
|||
this.gestureDet.onPointerDown(e); |
|||
this.receiver = receiver; |
|||
receiver.onPointerDown(e, obj); |
|||
e.preventDefault(); |
|||
e.stopPropagation(); |
|||
}); |
|||
// TODO: add touch handlers
|
|||
} |
|||
} |
|||
|
|||
pointerDownCommon(e) { |
|||
this.gestureDet.onPointerDown(e); |
|||
this.se.onPointerDown(e, null); |
|||
e.preventDefault(); |
|||
} |
|||
|
|||
pointerDown(e) { |
|||
let svg = document.getElementById("s"); |
|||
svg.setPointerCapture(e.pointerId); |
|||
this.pointerDownCommon(e); |
|||
} |
|||
|
|||
mouseDown(e) { |
|||
this.pointerDownCommon(e); |
|||
} |
|||
|
|||
pointerMove(e) { |
|||
if (this.receiver !== null) { |
|||
this.receiver.onPointerMove(e); |
|||
} else if (this.mousehandler !== null) { |
|||
this.mousehandler(e); |
|||
} else { |
|||
this.se.onPointerHover(e); |
|||
} |
|||
e.preventDefault(); |
|||
} |
|||
|
|||
mouseMove(e) { |
|||
this.pointerMove(e); |
|||
} |
|||
|
|||
pointerUpCommon(e) { |
|||
if (this.receiver !== null) { |
|||
this.receiver.onPointerUp(e); |
|||
} |
|||
this.mousehandler = null; |
|||
this.receiver = null; |
|||
e.preventDefault(); |
|||
} |
|||
|
|||
pointerUp(e) { |
|||
e.target.releasePointerCapture(e.pointerId); |
|||
this.pointerUpCommon(e); |
|||
} |
|||
|
|||
mouseUp(e) { |
|||
this.pointerUpCommon(e); |
|||
} |
|||
|
|||
keyDown(e) { |
|||
// Maybe would be better to use focus instead of explicit logic...
|
|||
if (!this.keyHandlerActive) { return; } |
|||
let handled = this.se.onKeyDown(e); |
|||
if (handled) { |
|||
e.preventDefault(); |
|||
} |
|||
} |
|||
|
|||
// On Chrome, just offsetX, offsetY work, but on FF it takes the group transforms
|
|||
// into account. We always want coords relative to the SVG.
|
|||
getCoords(e) { |
|||
let svg = document.getElementById("s"); |
|||
let rect = svg.getBoundingClientRect(); |
|||
let x = e.clientX - rect.left; |
|||
let y = e.clientY - rect.top; |
|||
return new Vec2(x, y); |
|||
} |
|||
|
|||
createSvgElement(tagName, isRaw = false) { |
|||
let element = document.createElementNS(this.svgNS, tagName); |
|||
if (!isRaw) { |
|||
element.setAttribute("pointer-events", "none"); |
|||
} |
|||
return element; |
|||
} |
|||
|
|||
resetPlots() { |
|||
this.removeAllChildren(document.getElementById("plots")); |
|||
} |
|||
|
|||
plotCircle(x, y, r = 2, color = "black", isRaw = false) { |
|||
let circle = this.createSvgElement("circle", isRaw); |
|||
circle.setAttribute("cx", x); |
|||
circle.setAttribute("cy", y); |
|||
circle.setAttribute("r", r); |
|||
if (color !== null) { |
|||
circle.setAttribute("fill", color); |
|||
} |
|||
document.getElementById("plots").appendChild(circle); |
|||
return circle; |
|||
} |
|||
|
|||
tangentMarker(x, y, th) { |
|||
let len = 8; |
|||
let dx = len * Math.cos(th); |
|||
let dy = len * Math.sin(th); |
|||
let line = this.createSvgElement("line"); |
|||
line.setAttribute("x1", x - dx); |
|||
line.setAttribute("y1", y + dy); |
|||
line.setAttribute("x2", x + dx); |
|||
line.setAttribute("y2", y - dy); |
|||
line.setAttribute("stroke", "green"); |
|||
document.getElementById("plots").appendChild(line); |
|||
} |
|||
|
|||
redraw() { |
|||
this.resetPlots(); |
|||
let path = ""; |
|||
let cmd = "M"; |
|||
for (let pt of this.controlPts) { |
|||
path += `${cmd}${pt.x} ${pt.y}`; |
|||
cmd = " L"; |
|||
} |
|||
document.getElementById("ctrlpoly").setAttribute("d", path); |
|||
|
|||
let showMyCurve = true; |
|||
let showBiParabola = true; |
|||
let spline2Offset = 200; |
|||
let nIter = 10; |
|||
|
|||
if (showMyCurve) { |
|||
let spline = new TwoParamSpline(new MyCurve, this.controlPts); |
|||
let ths = spline.initialThs(); |
|||
for (let i = 0; i < nIter; i++) { |
|||
spline.iterDumb(i); |
|||
} |
|||
let splinePath = spline.renderSvg(); |
|||
document.getElementById("spline").setAttribute("d", splinePath); |
|||
} |
|||
|
|||
if (showBiParabola) { |
|||
let pts = []; |
|||
for (let pt of this.controlPts) { |
|||
pts.push(new Vec2(pt.x + spline2Offset, pt.y)); |
|||
} |
|||
let spline2 = new TwoParamSpline(new BiParabola, pts); |
|||
spline2.initialThs(); |
|||
for (let i = 0; i < nIter; i++) { |
|||
let absErr = spline2.iterDumb(i); |
|||
if (i == nIter - 1) { |
|||
console.log(`biparabola err: ${absErr}`); |
|||
} |
|||
} |
|||
let spline2Path = spline2.renderSvg(); |
|||
document.getElementById("spline2").setAttribute("d", spline2Path); |
|||
} |
|||
|
|||
/* |
|||
for (let i = 0; i < ths.length; i++) { |
|||
let pt = this.controlPts[i] |
|||
this.tangentMarker(pt.x, pt.y, -ths[i]); |
|||
} |
|||
*/ |
|||
} |
|||
|
|||
// TODO: extend so it can insert at an arbitrary location
|
|||
addPoint(x, y) { |
|||
let ix = this.controlPts.length; |
|||
this.controlPts.push(new Vec2(x, y)); |
|||
|
|||
let handle = this.createSvgElement("circle", true); |
|||
handle.setAttribute("cx", x); |
|||
handle.setAttribute("cy", y); |
|||
handle.setAttribute("r", 4); |
|||
handle.setAttribute("class", "handle"); |
|||
document.getElementById("handles").appendChild(handle); |
|||
this.attachHandler(handle, e => { |
|||
this.movePoint(handle, ix, e.offsetX, e.offsetY); |
|||
}); |
|||
this.mousehandler = e => this.movePoint(handle, ix, e.offsetX, e.offsetY); |
|||
} |
|||
|
|||
movePoint(handle, ix, x, y) { |
|||
handle.setAttribute("cx", x); |
|||
handle.setAttribute("cy", y); |
|||
this.controlPts[ix] = new Vec2(x, y); |
|||
this.redraw(); |
|||
} |
|||
|
|||
updateShowGrid(showGrid) { |
|||
if (showGrid) { |
|||
document.getElementById("show-grid-check").classList.remove("invisible"); |
|||
} else { |
|||
document.getElementById("show-grid-check").classList.add("invisible"); |
|||
} |
|||
this.se.renderGrid(showGrid); |
|||
this.showGrid = showGrid; |
|||
} |
|||
|
|||
addMenuHandler(id, handler) { |
|||
document.getElementById(id).addEventListener("click", e => { |
|||
handler(e); |
|||
let el = e.target; |
|||
while (el.nodeName != "UL") { |
|||
el = el.parentNode; |
|||
} |
|||
// Hacks like this make me think we should just control the menu logic with
|
|||
// JS instead of trying to leverage CSS. Oh well, it works...
|
|||
el.classList.add("off"); |
|||
window.setTimeout(() => el.classList.remove("off"), 50); |
|||
}); |
|||
} |
|||
|
|||
saveToJson() { |
|||
document.getElementById("save-json-modal").style.display = "block"; |
|||
let jsonStr = JSON.stringify(this.se.serialize()); |
|||
let el = document.getElementById("save-json-content"); |
|||
this.removeAllChildren(el); |
|||
el.appendChild(document.createTextNode(jsonStr)); |
|||
} |
|||
|
|||
/// This displays the load dialog, doesn't do the load action.
|
|||
loadFromJson() { |
|||
document.getElementById("load-json-modal").style.display = "block"; |
|||
document.getElementById("load-text").focus(); |
|||
this.keyHandlerActive = false; |
|||
} |
|||
|
|||
doLoadAction(data) { |
|||
// TODO: error handling
|
|||
this.se.deserialize(data); |
|||
document.getElementById("load-json-modal").style.display = "none"; |
|||
this.keyHandlerActive = true; |
|||
} |
|||
|
|||
setupDialogs() { |
|||
this.addMenuHandler("menu-save", e => |
|||
this.saveToJson()); |
|||
this.addMenuHandler("menu-load", e => |
|||
this.loadFromJson()); |
|||
this.addMenuHandler("menu-show-grid", e => |
|||
this.updateShowGrid(!this.showGrid)); |
|||
this.addMenuHandler("menu-delete", e => |
|||
this.se.delete()); |
|||
this.addMenuHandler("menu-help", e => |
|||
document.getElementById("help-modal").style.display = "block"); |
|||
|
|||
document.getElementById("help-close").addEventListener("click", e => |
|||
document.getElementById("help-modal").style.display = "none"); |
|||
document.getElementById("save-json-close").addEventListener("click", e => |
|||
document.getElementById("save-json-modal").style.display = "none"); |
|||
document.getElementById("load-json-close").addEventListener("click", e => { |
|||
document.getElementById("load-json-modal").style.display = "none"; |
|||
this.keyHandlerActive = true; |
|||
}); |
|||
document.getElementById("load-button").addEventListener("click", e => |
|||
this.doLoadAction(document.getElementById("load-text").value)); |
|||
} |
|||
|
|||
removeAllChildren(el) { |
|||
while (el.firstChild) { |
|||
el.removeChild(el.firstChild); |
|||
} |
|||
} |
|||
} |
|||
|
|||
let ui = new Ui(); |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 65 KiB |
@ -0,0 +1,40 @@ |
|||
<!DOCTYPE html> |
|||
<html lang='en'> |
|||
<head> |
|||
<meta charset="utf-8" /> |
|||
<title>Iterative Annotation Tools</title> |
|||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/stylesheet.css')}}"> |
|||
{% block head %} |
|||
{% endblock %} |
|||
</head> |
|||
<body> |
|||
<div id="tools-nav"> |
|||
{% if tool is defined %} |
|||
<a href="/"><button>⭠</button></a> |
|||
{% else %} |
|||
{% block toolsnav %} |
|||
<a href="/"><button style="visibility: hidden;">⭠</button></a> |
|||
{% endblock %} |
|||
{% endif %} |
|||
{% if tools %} |
|||
{% for t in tools %} |
|||
{% if tool == t %} |
|||
<a href="/{{ t }}/"><button style="color:magenta;">{{ t }}</button></a> |
|||
{% else %} |
|||
<a href="/{{ t }}/"><button>{{ t }}</button></a> |
|||
{% endif %} |
|||
{% endfor %} |
|||
{% endif %} |
|||
</div> |
|||
<div id="tools-extra"> |
|||
{% block toolsextra %} |
|||
{% endblock %} |
|||
</div> |
|||
<div id="main"> |
|||
{% block page %} |
|||
{% endblock %} |
|||
</div> |
|||
</body> |
|||
{% block footer %} |
|||
{% endblock %} |
|||
</html> |
@ -0,0 +1,48 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block page %} |
|||
<div class="info"> |
|||
<p><strong class="handle">*2</strong>: “we”, temporary structures that condition work (who? where? how? why?)</p> |
|||
<p><strong class="annotation">color</strong>: What colors are used to engage with <strong class="handle">*2</strong>?</p> |
|||
</div> |
|||
<hr> |
|||
<form action="" method="GET"> |
|||
<div id="inputfields"> |
|||
Select a color: <input type="color" name="color"/><br> |
|||
</div> |
|||
<br> |
|||
<input class="submit" type="submit" value="submit"/> |
|||
<input type="reset"> |
|||
<hr> |
|||
<div id="colors"> |
|||
<h2><strong class="annotation">colors</strong> gathered so far include:</h2> |
|||
<br> |
|||
<table> |
|||
<thead> |
|||
<th>marker</th> |
|||
<th>description</th> |
|||
<th>status</th> |
|||
</thead> |
|||
<tbody> |
|||
{% for x in db.keys() %} |
|||
<tr> |
|||
<td> |
|||
<div id="color-preview" style="background-color: {{ db[x]['color'] }}"></div> |
|||
</td> |
|||
<td> |
|||
<textarea cols="100" rows="8" name="description-{{x}}"></textarea> |
|||
</td> |
|||
<td> |
|||
<select name="status-{{x}}"> |
|||
<option value="include" selected="selected">include</option> |
|||
<option value="unsure">unsure</option> |
|||
<option value="delete">delete</option> |
|||
</select> |
|||
</td> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
</form> |
|||
</div> |
|||
{% endblock %} |
|||
|
@ -0,0 +1,78 @@ |
|||
{% extends "base.html" %} |
|||
{% block head %} |
|||
<!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/curves.css')}}"> --> |
|||
{% endblock %} |
|||
|
|||
{% block page %} |
|||
<div class="block"> |
|||
<p><strong class="handle">*1</strong>: systematics, temporalities (group formations)</p> |
|||
<p><strong class="annotation">curves</strong>: What curves are used to engage with <strong class="handle">*1</strong>?</p> |
|||
</div> |
|||
<hr> |
|||
<form action="" method="GET"> |
|||
<!-- https://spline.technology/demo/# --> |
|||
<!-- <div class="modal" id="help-modal"> |
|||
<div class="modal-content"> |
|||
<span class="close" id="help-close">×</span> |
|||
<p><b>A new spline</b></p> |
|||
<p>Add a new corner point: click. Add a new smooth point, Alt + click, or click and drag.</p> |
|||
<p>Select multiple points: Shift + click.</p> |
|||
<p>Refine a curve: click on the curve and drag.</p> |
|||
<p>Set an explicit tangent: click and drag on the handles. Set axis-aligned: Shift + click. Unset an explicit tangent: drag away.</p> |
|||
<p>Toggle between smooth and corner points: double-click.</p> |
|||
<p>Delete a point: delete (or backspace) key. |
|||
<p>Nudge points by 1 px: arrow keys. Nudge by 10 px: Shift + arrow keys. |
|||
<p>Copyright 2018 Raph Levien</p> |
|||
<p>Github repo: <a href="https://github.com/raphlinus/spline-research">raphlinus/spline-research</a></p> |
|||
</div> |
|||
</div> |
|||
<div class="modal" id="save-json-modal"> |
|||
<div class="modal-content"> |
|||
<span class="close" id="save-json-close">×</span> |
|||
<pre id="save-json-content"></pre> |
|||
</div> |
|||
</div> |
|||
<div class="modal" id="load-json-modal"> |
|||
<div class="modal-content"> |
|||
<span class="close" id="load-json-close">×</span> |
|||
<p><b>Load from JSON</b></p> |
|||
<textarea id="load-text" placeholder="Paste JSON data here..." rows=20></textarea> |
|||
<p><button id="load-button" type="button">Load</button></p> |
|||
</div> |
|||
</div> |
|||
<svg id="s" class="canvas" width="640" height="480" pointer-events="all"> |
|||
<path id="ctrlpoly" d="" stroke="none" fill="none" /> |
|||
<path id="spline" d="" stroke="black" fill="none" stroke-width="2" /> |
|||
<path id="spline2" d="" stroke="blue" fill="none" stroke-width="2" /> |
|||
<g id="handles" /> |
|||
<g id="plots" /> |
|||
</svg> --> |
|||
<!-- --> |
|||
<!-- <input class="ready" type="button" value="ready" onclick="ready()" /> --> |
|||
<input type="file" name="curve" accept=".svg"><br> |
|||
<!-- <textarea id="curve" name="curve" style="display:none;" required></textarea> --> |
|||
<input class="submit" type="submit" value="submit"/> |
|||
<a id="reset" href="/curves/"><input class="reset" type="button" value="reset"></a> |
|||
</form> |
|||
<hr> |
|||
<div id="shapes"> |
|||
<h2><strong class="annotation">shapes</strong> gathered so far include:</h2> |
|||
{% for x in db.keys() %} |
|||
{{ db[x]['shape'] | safe }} |
|||
{% endfor %} |
|||
</div> |
|||
{% endblock %} |
|||
{% block footer %} |
|||
<!-- <script type="text/javascript"> |
|||
function ready(){ |
|||
var svg = document.getElementById("s").outerHTML; |
|||
console.log(svg); |
|||
// var svg = svg.innerHTML(); |
|||
var shape = document.getElementById("shape").innerHTML = svg; |
|||
} |
|||
|
|||
</script> |
|||
<script type="text/javascript" src="{{ url_for('static', filename='js/bezpath.js')}}"></script> |
|||
<script type="text/javascript" src="{{ url_for('static', filename='js/curves.js')}}"></script> |
|||
<script type="text/javascript" src="{{ url_for('static', filename='js/splineui.js')}}"></script> --> |
|||
{% endblock %} |
@ -0,0 +1,99 @@ |
|||
{% extends "base.html" %} |
|||
{% block head %} |
|||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/curves.css')}}"> |
|||
{% endblock %} |
|||
|
|||
{% block page %} |
|||
<div class="info"> |
|||
<p><strong class="handle">*1</strong>: systematics, temporalities (group formations)</p> |
|||
<p><strong class="annotation">curves</strong>: What curves are used to engage with <strong class="handle">*1</strong>?</p> |
|||
</div> |
|||
<hr> |
|||
<form action="" method="GET"> |
|||
<!-- https://spline.technology/demo/# --> |
|||
<div class="modal" id="help-modal"> |
|||
<div class="modal-content"> |
|||
<span class="close" id="help-close">×</span> |
|||
<p><b>A new spline</b></p> |
|||
<p>Add a new corner point: click. Add a new smooth point, Alt + click, or click and drag.</p> |
|||
<p>Select multiple points: Shift + click.</p> |
|||
<p>Refine a curve: click on the curve and drag.</p> |
|||
<p>Set an explicit tangent: click and drag on the handles. Set axis-aligned: Shift + click. Unset an explicit tangent: drag away.</p> |
|||
<p>Toggle between smooth and corner points: double-click.</p> |
|||
<p>Delete a point: delete (or backspace) key. |
|||
<p>Nudge points by 1 px: arrow keys. Nudge by 10 px: Shift + arrow keys. |
|||
<p>Copyright 2018 Raph Levien</p> |
|||
<p>Github repo: <a href="https://github.com/raphlinus/spline-research">raphlinus/spline-research</a></p> |
|||
</div> |
|||
</div> |
|||
<div class="modal" id="save-json-modal"> |
|||
<div class="modal-content"> |
|||
<span class="close" id="save-json-close">×</span> |
|||
<pre id="save-json-content"></pre> |
|||
</div> |
|||
</div> |
|||
<div class="modal" id="load-json-modal"> |
|||
<div class="modal-content"> |
|||
<span class="close" id="load-json-close">×</span> |
|||
<p><b>Load from JSON</b></p> |
|||
<textarea id="load-text" placeholder="Paste JSON data here..." rows=20></textarea> |
|||
<p><button id="load-button" type="button">Load</button></p> |
|||
</div> |
|||
</div> |
|||
<svg id="s" class="canvas" width="640" height="480" pointer-events="all"> |
|||
<path id="ctrlpoly" d="" stroke="none" fill="none" /> |
|||
<path id="spline" d="" stroke="black" fill="none" stroke-width="2" /> |
|||
<path id="spline2" d="" stroke="blue" fill="none" stroke-width="2" /> |
|||
<g id="handles" /> |
|||
<g id="plots" /> |
|||
</svg> |
|||
<!-- --> |
|||
<input class="ready" type="button" value="ready" onclick="ready()" /><br> |
|||
<textarea id="curve" name="curve" cols="89" rows="10" required></textarea><br> |
|||
<input class="submit" type="submit" value="submit"/> |
|||
<a id="reset" href="/curves/"><input class="reset" type="button" value="reset"></a> |
|||
<hr> |
|||
<div id="curves"> |
|||
<h2><strong class="annotation">curves</strong> gathered so far include:</h2> |
|||
<br> |
|||
<table> |
|||
<thead> |
|||
<th>marker</th> |
|||
<th>description</th> |
|||
<th>status</th> |
|||
</thead> |
|||
<tbody> |
|||
{% for x in db.keys() %} |
|||
<tr> |
|||
<td> |
|||
{{ db[x]['curve'] | safe }} |
|||
</td> |
|||
<td> |
|||
<textarea cols="100" rows="25" name="description-{{x}}"></textarea> |
|||
</td> |
|||
<td> |
|||
<select name="status-{{x}}"> |
|||
<option value="include" selected="selected">include</option> |
|||
<option value="unsure">unsure</option> |
|||
<option value="delete">delete</option> |
|||
</select> |
|||
</td> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</form> |
|||
{% endblock %} |
|||
{% block footer %} |
|||
<script type="text/javascript"> |
|||
function ready(){ |
|||
var svg = document.getElementById("s").outerHTML; |
|||
// console.log(svg); |
|||
var curve = document.getElementById("curve").innerHTML = svg; |
|||
} |
|||
|
|||
</script> |
|||
<script type="text/javascript" src="{{ url_for('static', filename='js/bezpath.js')}}"></script> |
|||
<script type="text/javascript" src="{{ url_for('static', filename='js/curves.js')}}"></script> |
|||
<script type="text/javascript" src="{{ url_for('static', filename='js/splineui.js')}}"></script> |
|||
{% endblock %} |
@ -0,0 +1,58 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block page %} |
|||
<svg id="index" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> |
|||
<path id="title" fill="none" stroke="blue" |
|||
d="M10,90 Q90,90 90,45 Q90,10 50,10 Q10,10 10,40 Q10,70 45,70 Q70,70 75,50" /> |
|||
<text> |
|||
<textPath id="title" href="#title"> |
|||
Iterative Annotation Tools |
|||
</textPath> |
|||
</text> |
|||
</svg> |
|||
|
|||
<hr> |
|||
|
|||
<div class="block"> |
|||
<!-- <p><strong class="handle">*</strong></p> --> |
|||
<h2>handles</h2> |
|||
|
|||
<p><strong class="handle">*1</strong>: systematics, temporalities (group formations)</p> |
|||
<p><strong class="handle">*2</strong>: “we”, temporary structures that condition work (who? where? how? why?)</p> |
|||
<p><strong class="handle">*3</strong>: conditions of possibility, units of measurement for succes, sharing how-to’s (how to co-exist, basically)</p> |
|||
<p><strong class="handle">*4</strong>: transitional moments of handing over, generative troublematics (collective response-ability)</p> |
|||
<br> |
|||
</div> |
|||
|
|||
<div class="block"> |
|||
<!-- <p><strong class="annotation"> </strong></p> --> |
|||
<h2>annotations</h2> |
|||
|
|||
<p><strong class="annotation">curves</strong>: What curves are used to engage with <strong class="handle">*1</strong>?</p> |
|||
<p><strong class="annotation">color</strong>: What colors are used to engage with <strong class="handle">*2</strong>?</p> |
|||
<p><strong class="annotation">text</strong>: Which anecdotes/questions/vocabulary/glossary/tags engage with <strong class="handle">*3</strong>?</p> |
|||
<p><strong class="annotation">visual traces</strong>: Which visual traces can we “cut out” that engage with <strong class="handle">*4</strong>? <!-- What questions can we formulate and attach as annotations to image documentation of the hand-over-moments? --></p> |
|||
</div> |
|||
|
|||
<hr> |
|||
|
|||
<p><u>stage a</u> - making markers: based upon each contribution using these tools</p> |
|||
|
|||
<p><u>stage b</u> - annotate: throughout the publication</p> |
|||
|
|||
<hr> |
|||
|
|||
<!-- <p>< < iterations documentation from where the contributions were extracted > handles > annotation tools < contributions < handles > ></p> |
|||
--> |
|||
<!-- <hr> --> |
|||
|
|||
<div class="info"> |
|||
<p><strong class="handle">*1 shapes</strong></p> |
|||
<p><strong class="handle">*2 color</strong></p> |
|||
<p><strong class="handle">*3 text</strong></p> |
|||
<p><strong class="handle">*4 visual traces</strong></p> |
|||
</div> |
|||
|
|||
<hr> |
|||
|
|||
{% endblock %} |
@ -0,0 +1,52 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block head %} |
|||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/text-scan.css')}}"> |
|||
{% endblock %} |
|||
|
|||
{% block toolsnav %} |
|||
<a href="/"><button>⭠</button></a> |
|||
{% endblock %} |
|||
|
|||
{% block toolsextra %} |
|||
<a href="/text-scans/"><button style="color:magenta;">text-scans</button></a> |
|||
<!-- <a href="/text-specifics/"><button>text-specifics</button></a> --> |
|||
{% endblock %} |
|||
|
|||
{% block page %} |
|||
<div class="info"> |
|||
<strong>text-scans</strong> |
|||
</div> |
|||
<hr> |
|||
<div id="wrapper"> |
|||
<div id="crossings"> |
|||
{% if data == {} %} |
|||
<div>I have no words for this.</div> |
|||
{% else %} |
|||
<!-- <h1 style="margin-bottom:0;margin-top:1.25em;line-height: 0;">attachments</h1> --> |
|||
{% for word_type, ranking in data.items() %} |
|||
<div id="{{ word_type }}"> |
|||
<h1>{{ word_type }}</h1> |
|||
{% for rank, words in ranking.items() %} |
|||
{% for word in words.keys() %} |
|||
<a href="/text-scans/{{ word_type }}/{{ word }}">{{ word }}</a><sup>{{ words[word]['count'] }}</sup> |
|||
{% endfor %} |
|||
{% endfor %} |
|||
</div> |
|||
{% endfor %} |
|||
{% endif %} |
|||
</div> |
|||
<div id="sentences"> |
|||
{% if results == {} %} |
|||
<h1></h1> |
|||
{% else %} |
|||
<h1><em>{{ word }}</em> ({{ word_type }})</h1> |
|||
{% for document, sentences in results['sentences'].items() %} |
|||
{% for sentence in sentences %} |
|||
<div class="{{ word_type }} sentence">{{ sentence|markdown }} <small>({{ document }})</small></div> |
|||
{% endfor %} |
|||
{% endfor %} |
|||
{% endif %} |
|||
</div> |
|||
</div> |
|||
{% endblock %} |
@ -0,0 +1,38 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block head %} |
|||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/text-scan.css')}}"> |
|||
{% endblock %} |
|||
|
|||
{% block toolsnav %} |
|||
<a href="/"><button>⭠</button></a> |
|||
{% endblock %} |
|||
|
|||
{% block toolsextra %} |
|||
<a href="/text-scans/"><button>text-scans</button></a> |
|||
<a href="/text-specifics/"><button style="color:magenta;">text-specifics</button></a> |
|||
{% endblock %} |
|||
|
|||
{% block page %} |
|||
<div class="info"> |
|||
<strong>text-specifics</strong> |
|||
<div>words with a TF-IDF score > 0.01</div> |
|||
<br> |
|||
<div>NOTE: the "specificity" scanning does not work when different languages are mixed</div> |
|||
</div> |
|||
<hr> |
|||
<div id="wrapper"> |
|||
{% for filename in index.keys() %} |
|||
<div> |
|||
<h1>{{filename}}</h1> |
|||
{% if 'tfidf' in index[filename].keys() %} |
|||
{% for word, value in index[filename]['tf'].items() %} |
|||
{% if value > 0.01 %} |
|||
{{ word }}<sup>({{ value}})</sup><br> |
|||
{% endif %} |
|||
{% endfor %} |
|||
{% endif %} |
|||
</div> |
|||
{% endfor %}s |
|||
</div> |
|||
{% endblock %} |
@ -0,0 +1,56 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block toolsextra %} |
|||
<a href="/text-scans/"><button>text-scans</button></a> |
|||
<!-- <a href="/text-specifics/"><button>text-specifics</button></a> --> |
|||
{% endblock %} |
|||
|
|||
{% block page %} |
|||
<div class="info"> |
|||
<p><strong class="handle">*3</strong>: conditions of possibility, units of measurement for succes, sharing how-to’s (how to co-exist, basically)</p> |
|||
<p><strong class="annotation">text</strong>: Which anecdotes/questions/vocabulary/glossary/tags engage with <strong class="handle">*3</strong>?</p> |
|||
</div> |
|||
<hr> |
|||
<form action="" method="GET"> |
|||
<textarea cols="100" rows="15" name="marker"></textarea><br> |
|||
type: |
|||
<select name="marker-type"> |
|||
<option value="anecdote">anecdote</option> |
|||
<option value="question">question</option> |
|||
<option value="glossary">glossary</option> |
|||
<option value="tag">tag</option> |
|||
</select> |
|||
<input class="submit" type="submit" value="submit"/> |
|||
<input class="reset" type="reset"> |
|||
</form> |
|||
<hr> |
|||
<div id="markers"> |
|||
<h2><strong class="annotation">textual markers</strong> gathered so far include:</h2> |
|||
<br> |
|||
<table> |
|||
<thead> |
|||
<th>marker</th> |
|||
<th>description</th> |
|||
<th>status</th> |
|||
</thead> |
|||
<tbody> |
|||
{% for x in db.keys() %} |
|||
<tr> |
|||
<td> |
|||
<div>({{ db[x]['type'] }}) {{ db[x]['marker'] }}</div> |
|||
</td> |
|||
<td> |
|||
<textarea cols="100" rows="5" name="description-{{x}}"></textarea> |
|||
</td> |
|||
<td> |
|||
<select name="status-{{x}}"> |
|||
<option value="delete">delete</option> |
|||
<option value="unsure">unsure</option> |
|||
<option value="include" selected="selected">include</option> |
|||
</select> |
|||
</td> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
{% endblock %} |
@ -0,0 +1,50 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block page %} |
|||
<div class="info"> |
|||
<p><strong class="handle">*4</strong>: transitional moments of handing over, generative troublematics (collective response-ability)</p> |
|||
<p><strong class="annotation">visual traces</strong>: Which visual traces can we “cut out” that engage with <strong class="handle">*4</strong>? <!-- What questions can we formulate and attach as annotations to image documentation of the hand-over-moments? --></p> |
|||
</div> |
|||
<hr> |
|||
<form method="POST" enctype=multipart/form-data> |
|||
<input type="file" name="trace" accept=".png, .gif|image/*"><br> |
|||
<input type="submit" value="upload"/> |
|||
<a id="reset" href="/visual-traces/"><input class="reset" type="button" value="reset"></a> |
|||
<br> |
|||
<small> |
|||
<strong>Works with file formats</strong>: png, gif<br> |
|||
<strong>Note</strong>: please submit traces with transparent backgrounds! |
|||
</small> |
|||
<hr> |
|||
<div id="traces"> |
|||
<h2><strong class="annotation">visual-traces</strong> gathered so far include:</h2> |
|||
<br> |
|||
<table> |
|||
<thead> |
|||
<th>marker</th> |
|||
<th>description</th> |
|||
<th>status</th> |
|||
</thead> |
|||
<tbody> |
|||
{% for x in db.keys() %} |
|||
<tr> |
|||
<td> |
|||
<img class="traces" src="{{ url_for('static', filename='visual-traces/')}}{{ db[x]['trace'] }}"> |
|||
</td> |
|||
<td> |
|||
<textarea cols="100" rows="15" name="description-{{x}}"></textarea> |
|||
</td> |
|||
<td> |
|||
<select name="status-{{x}}"> |
|||
<option value="include" selected="selected">include</option> |
|||
<option value="unsure">unsure</option> |
|||
<option value="delete">delete</option> |
|||
</select> |
|||
</td> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
</form> |
|||
</div> |
|||
{% endblock %} |
|||
|
@ -0,0 +1,30 @@ |
|||
# text annotation tool |
|||
# see handles on line 532 and further: https://pad.constantvzw.org/p/iterations-publication |
|||
|
|||
def intensify(string, intensity): |
|||
intensified = '' |
|||
for character in string: |
|||
if character != ' ': |
|||
intensified += (character * intensity) |
|||
else: |
|||
intensified += ' ' |
|||
return intensified |
|||
|
|||
def scopify(string, reach): |
|||
marker = ':' * reach |
|||
scope = '{} {} {}\n'.format(marker, string, marker) |
|||
return scope |
|||
|
|||
def temporalify(string, duration): |
|||
temporalified = string * duration |
|||
return temporalified |
|||
|
|||
def translate(string, intensity=3, duration=2, reach=5): |
|||
string = intensify(string, intensity) |
|||
string = scopify(string, reach) |
|||
string = temporalify(string, duration) |
|||
return string |
|||
|
|||
if __name__ == '__main__': |
|||
string = 'hello' |
|||
print(translate(string)) |
@ -0,0 +1,131 @@ |
|||
import os, json, re |
|||
from math import log, exp |
|||
|
|||
import nltk |
|||
from nltk import sent_tokenize |
|||
from nltk.tokenize import RegexpTokenizer |
|||
tokenizer = RegexpTokenizer(r'\w+') # initialize tokenizer |
|||
|
|||
import pprint |
|||
pp = pprint.PrettyPrinter(indent=4) |
|||
|
|||
def tfidf(query, words, corpus): |
|||
# Term Frequency |
|||
tf_count = 0 |
|||
for word in words: |
|||
if query == word: |
|||
tf_count += 1 |
|||
tf = tf_count/len(words) |
|||
# print('TF count:', tf_count) |
|||
# print('Total number of words:', len(words)) |
|||
# print('TF - count/total', tf_count/len(words)) |
|||
|
|||
# Inverse Document Frequency |
|||
idf_count = 0 |
|||
for words in corpus: |
|||
if query in words: |
|||
idf_count += 1 |
|||
# print('count:', idf_count) |
|||
idf = log(len(corpus)/idf_count) |
|||
# print('Total number of documents:', len(corpus)) |
|||
# print('documents/count', len(corpus)/idf_count) |
|||
# print('IDF - log(documents/count)', log(len(corpus)/idf_count)) |
|||
|
|||
tfidf_value = tf * idf |
|||
# print('TF-IDF:', tfidf_value) |
|||
|
|||
return tf, idf_count, tfidf_value |
|||
|
|||
def get_language(document): |
|||
match = re.search(r'\[.*\]', document, flags=re.IGNORECASE) |
|||
if match: |
|||
language = match.group().replace('[','').replace(']','').lower() |
|||
else: |
|||
language = 'undefined' |
|||
return language |
|||
|
|||
def load_text_files(): |
|||
files = [] |
|||
corpus = [] |
|||
sentences = {} |
|||
wordlists = {} |
|||
dir = 'static/contributions/' |
|||
|
|||
for document in sorted(os.listdir(dir)): |
|||
if not 'annotated' in document: |
|||
document = document.replace('.md','') |
|||
# print('document:', document) |
|||
lines = open('{}/{}.md'.format(dir, document), "r").read() # list of lines in .txt file |
|||
# lines = lines.replace(' •', '. ') # turn custom linebreaks into full-stops to let the tokenizer recognize them as end-of-lines |
|||
words = [word.lower() for word in tokenizer.tokenize(lines)] # all words of one document, in reading order + lowercased! (!important) |
|||
wordlists[document] = words |
|||
corpus.append(words) |
|||
s = sent_tokenize(lines) |
|||
sentences[document] = s |
|||
files.append(document) # list of filenames |
|||
|
|||
print('---------') |
|||
print('*md files loaded*') |
|||
return files, corpus, sentences, wordlists |
|||
|
|||
def make_human_readable_name(document): |
|||
name = document.replace('_', ' ').replace('-', ' ') |
|||
return name |
|||
|
|||
def create_index(): |
|||
files, corpus, sentences, wordlists = load_text_files() |
|||
index = {} |
|||
|
|||
# index = { |
|||
# Fem document : { |
|||
# 'sentences' : [], |
|||
# 'tf' : { |
|||
# 'aap': 4, |
|||
# 'beer': 6, |
|||
# 'citroen': 2 |
|||
# }, |
|||
# 'idf' : { |
|||
# 'aap': 2, |
|||
# 'beer': 1, |
|||
# 'citroen': 5 |
|||
# }, |
|||
# 'tfidf' : { |
|||
# 'aap': 39.2, |
|||
# 'beer': 20.456, |
|||
# 'citroen': 3.21 |
|||
# }, |
|||
# 'name': 'Feminist document (2000)', |
|||
# 'language': 'en' |
|||
# } |
|||
# } |
|||
|
|||
|
|||
for document in files: |
|||
print('---------') |
|||
print('document:', document) |
|||
index[document] = {} |
|||
index[document]['sentences'] = sentences[document] |
|||
words = wordlists[document] |
|||
for word in words: |
|||
tf_count, idf_count, tfidf_value = tfidf(word, words, corpus) |
|||
if 'tf' not in index[document]: |
|||
index[document]['tf'] = {} |
|||
index[document]['tf'][word] = tf_count |
|||
if 'idf' not in index[document]: |
|||
index[document]['idf'] = {} |
|||
index[document]['idf'][word] = idf_count |
|||
if 'tfidf' not in index[document]: |
|||
index[document]['tfidf'] = {} |
|||
index[document]['tfidf'][word] = tfidf_value |
|||
index[document]['language'] = get_language(document) |
|||
|
|||
index[document]['name'] = make_human_readable_name(document) |
|||
|
|||
with open('index.json','w+') as out: |
|||
out.write(json.dumps(index, indent=4, sort_keys=True)) |
|||
out.close() |
|||
print('---------') |
|||
print('*index created*') |
|||
print('---------') |
|||
|
|||
# create_index() |