diff --git a/README.md b/README.md
index 6f9b9f2..565aacf 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@

-
+
**takethestreet.net / takethestreet.org**: red internacional de las acampadas por la vivienda que nacieron en la Puerta del Sol el 26 de septiembre de 2026 (26S). La vivienda es un derecho, no un negocio.
@@ -137,38 +137,16 @@ Grindy Brush es una versión demo **solo para uso personal**. Antes de usar el l
## 6. Dibujo
-
+
-Una calle corta vista en diagonal, con el punto de fuga a la derecha. Solo se ve la planta baja: la fachada se desvanece hacia arriba, sin pisos, y la calle también se pierde por la derecha. De cada portal sale gente que avanza hacia la calzada y hacia quien mira. Son «presencias» abstractas a la manera de Suso33 (el mural *Presencias/Ausencias* de Tetuán): una mancha afilada con la cabeza, y algunas con zancada o con el puño en alto. Todo en negro; el naranja va solo en líneas de detalle (el bordillo, algún dintel, alguna estela). Se genera con `tools/calle.py`, sin dependencias:
+Una calle vista desde un primer piso, con el punto de fuga a la derecha. La calle va solo con líneas negras a pincel: el pie de la fachada, los contornos de los portales, los bordillos y la línea discontinua del centro. No hay pisos arriba, y la acera de enfrente se pierde por la derecha.
+
+La gente va en color, en una piña que llena la calzada. Cada monigote es un solo trazo de spray en zigzag (una espiral para la cabeza, un cuello estrecho y un cuerpo alto que se afila hacia los pies), a la manera de las *Ausencias* y del contenedor de Suso33. Algunos dan una zancada o llevan el puño en alto. El corazón de la piña va en colores de fuego (blanco, amarillo, naranja y rojo) y alrededor fríos (morados, azules, verde y negro). La gente se reparte en metros sobre la calle, así que al fondo no se amontona. Se genera con `tools/calle.py`, sin dependencias:
```
python3 tools/calle.py docs/calle.svg
```
-### Bocetos nuevos (a la manera de Suso33)
-
-Cinco bocetos para sustituir el dibujo de la portada. Cada monigote es un solo trazo de spray en zigzag: una espiral para la cabeza y un cuerpo alto que se afila hacia los pies, como en las *Ausencias* y en el contenedor de Suso33. Van en piña: el centro en colores de fuego (blanco, amarillo, naranja, rojo) y alrededor fríos (morados, azules, blanco y negro). Se generan con `python3 tools/bocetos.py docs/bocetos`.
-
-1. **Contenedor**: la piña de fuego sobre una pared gris.
-
- 
-
-2. **La piña sale a la calle**: la masa avanza hacia la derecha y se va soltando.
-
- 
-
-3. **El portal**: del hueco sale una fila de gente y el fuego va delante.
-
- 
-
-4. **Calle en diagonal**: la piña baja por la calle hacia quien mira.
-
- 
-
-5. **Ausencias**: todos en negro y gris, y solo el corazón de la piña en fuego.
-
- 
-
## 7. Maqueta
`mockup/index.html` es HTML y CSS, sin JavaScript. Se abre directamente en el navegador. Sigue el estilo de acampada26s.net (blanco y negro, bordes de 3 px, sombra de color): firma en la cabecera, portada con el lema y el dibujo debajo, y debajo el deck.Capturas al principio de este README.
diff --git a/docs/bocetos/boceto-1.svg b/docs/bocetos/boceto-1.svg
deleted file mode 100644
index e21d2c4..0000000
--- a/docs/bocetos/boceto-1.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/docs/bocetos/boceto-2.svg b/docs/bocetos/boceto-2.svg
deleted file mode 100644
index 62f073a..0000000
--- a/docs/bocetos/boceto-2.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/docs/bocetos/boceto-3.svg b/docs/bocetos/boceto-3.svg
deleted file mode 100644
index 9606fee..0000000
--- a/docs/bocetos/boceto-3.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/docs/bocetos/boceto-4.svg b/docs/bocetos/boceto-4.svg
deleted file mode 100644
index 6784535..0000000
--- a/docs/bocetos/boceto-4.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/docs/bocetos/boceto-5.svg b/docs/bocetos/boceto-5.svg
deleted file mode 100644
index 28585a7..0000000
--- a/docs/bocetos/boceto-5.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/docs/calle.svg b/docs/calle.svg
index 69679b9..e14b7cf 100644
--- a/docs/calle.svg
+++ b/docs/calle.svg
@@ -1,225 +1,405 @@
-
\ No newline at end of file
diff --git a/docs/deck-movil.png b/docs/deck-movil.png
index 99d1bea..587f0a9 100644
Binary files a/docs/deck-movil.png and b/docs/deck-movil.png differ
diff --git a/docs/deck.png b/docs/deck.png
index 8475466..d0988ea 100644
Binary files a/docs/deck.png and b/docs/deck.png differ
diff --git a/mockup/index.html b/mockup/index.html
index 561659f..d305b8f 100644
--- a/mockup/index.html
+++ b/mockup/index.html
@@ -16,7 +16,7 @@
diff --git a/tools/bocetos.py b/tools/bocetos.py
deleted file mode 100644
index 7f7d387..0000000
--- a/tools/bocetos.py
+++ /dev/null
@@ -1,136 +0,0 @@
-# Genera docs/bocetos/boceto-1..5.svg. Monigotes de un solo trazo de spray en zigzag,
-# altos y juntos, en piña: el centro en colores de fuego y alrededor fríos
-# (a la manera del contenedor y las «Ausencias» de Suso33).
-import sys, random, math, os
-OUT = sys.argv[1]
-W, H = 1600, 700
-FUEGO = ["#fffbe6", "#ffe066", "#ffb627", "#ff7b1c", "#f04e23", "#c8102e"] # del centro hacia fuera
-FRIO = ["#5b2a86", "#8e44c9", "#3b5bdb", "#6c7ae0", "#e9e6f5", "#111", "#b07cd8"]
-
-DEFS = '''
-
-
-
-
-'''
-
-def fuego(d): # d = 0 en el centro de la piña, 1 en el borde
- i = min(len(FUEGO) - 1, int(max(0, d + random.uniform(-.12, .12)) * len(FUEGO)))
- return FUEGO[i]
-
-def monigote(o, x, y, h, col, lean=0.0, paso=False, brazo=False, sombra=False):
- """Un trazo: cabeza en zigzag apretado y cuerpo en zigzag alto. (x, y) = pies."""
- sw = max(1.1, h * .011)
- dy = sw * 2.0 # renglones del zigzag
- if sombra:
- o.append(f'')
- top = y - h
- pts = []
- yy = top
- i = 0
- while yy <= y:
- t = (yy - top) / h
- cx = x + lean * h * (1 - t)
- if t < .13: # cabeza
- w = h * .05 * math.sin(math.pi * t / .13) ** .6 + sw * .3
- elif t < .16: # cuello
- w = h * .008
- else: # cuerpo: hombros y se afila hacia los pies
- u = (t - .16) / .84
- w = h * (.062 * (1 - u) ** .8 + .014)
- if paso and u > .5: # zancada: el zigzag se abre en dos
- k = (u - .5) / .5
- cx += (-1 if (i // 2) % 2 else 1) * h * .035 * k
- w *= .6
- s = -1 if i % 2 else 1
- pts.append((cx + s * w + random.uniform(-.3, .3) * sw, yy))
- yy += dy * random.uniform(.85, 1.15) * (.55 if t < .13 else 1)
- i += 1
- d = "M" + " L".join(f"{px:.1f},{py:.1f}" for px, py in pts)
- o.append(f'')
- if brazo: # brazo en alto
- bx, by = x + lean * h * .84 + h * .05, top + h * .2
- p, n = [], 10
- for j in range(n):
- t = j / (n - 1)
- p.append((bx + t * h * .06 + (-1 if j % 2 else 1) * h * .012, by - t * h * .30))
- d = "M" + " L".join(f"{px:.1f},{py:.1f}" for px, py in p)
- o.append(f'')
-
-def portal(o, x, y, w, h, fondo="#111"):
- o.append(f''
- f'')
-
-def svg(cuerpo, fondo="#fff"):
- return (f'{DEFS}'
- f'' + "".join(cuerpo) + "\n")
-
-def fila(o, xs, y0, h0, centro, radio, frio=FRIO, lean=0.0, jit=12, hvar=.15, paso=.2, brazo=.08):
- """Una piña: monigotes muy juntos; los cercanos al centro, en fuego."""
- for x in xs:
- d = abs(x - centro) / radio
- col = fuego(d) if d < 1 else random.choice(frio)
- h = h0 * random.uniform(1 - hvar, 1 + hvar) * (1.05 if d < 1 else 1)
- monigote(o, x, y0 + random.uniform(-jit, jit), h, col, lean, random.random() < paso, random.random() < brazo)
-
-# 1 · Contenedor: piña de fuego en una pared gris, como el contenedor
-def b1():
- random.seed(1); o = []
- o.append('')
- xs = sorted(random.uniform(90, 1510) for _ in range(70))
- fila(o, xs[::2], 610, 470, 800, 260)
- fila(o, xs[1::2], 650, 500, 800, 230)
- return o, "#9aa0a8"
-
-# 2 · Piña que sale a la calle: en blanco, la masa avanza hacia la derecha
-def b2():
- random.seed(2); o = []
- o.append('')
- xs = sorted(random.gauss(820, 300) for _ in range(55))
- xs = [x for x in xs if 80 < x < 1520]
- fila(o, xs, 630, 400, 1000, 230, lean=.12, paso=.45, brazo=.12)
- return o, "#fff"
-
-# 3 · El portal: del hueco sale la gente y el fuego va delante
-def b3():
- random.seed(3); o = []
- o.append('')
- portal(o, 150, 610, 190, 380)
- o.append('')
- for i in range(30):
- t = i / 29
- x = 250 + t * 1250 + random.uniform(-25, 25)
- d = abs(t - .32) / .25
- col = fuego(d) if d < 1 else random.choice(FRIO)
- monigote(o, x, 610 + t * 70 + random.uniform(-8, 8), 300 + t * 120, col, .1, random.random() < .45, random.random() < .12)
- return o, "#fff"
-
-# 4 · Calle en diagonal: la piña baja por la calle hacia quien mira
-def b4():
- random.seed(4); o = []
- o.append(''
- '')
- ps = []
- for _ in range(1500):
- t = random.random()
- x = 1240 - t * 700 + random.gauss(0, 40 + t * 150)
- y = 300 + t * 390 + random.gauss(0, 10)
- if 290 < y < 695 and all(math.hypot(x - a, (y - b) * 3) > 22 + t * 50 for a, b, _ in ps):
- ps.append((x, y, t))
- for x, y, t in sorted(ps, key=lambda p: p[1]):
- d = math.hypot(x - 820, (y - 520) * 1.5) / 230
- col = fuego(d) if d < 1 else random.choice(FRIO)
- monigote(o, x, y, 60 + t * 230, col, -.1, random.random() < .35, random.random() < .1)
- return o, "#fff"
-
-# 5 · Ausencias: todos en negro y gris, y solo el corazón de la piña en fuego
-def b5():
- random.seed(5); o = []
- xs = sorted(random.uniform(100, 1500) for _ in range(42))
- fila(o, xs, 650, 430, 900, 120, frio=["#111", "#111", "#333", "#555", "#888"], lean=.06, hvar=.12, paso=.3, brazo=.1)
- return o, "#fff"
-
-os.makedirs(OUT, exist_ok=True)
-for n, f in enumerate([b1, b2, b3, b4, b5], 1):
- cuerpo, fondo = f()
- open(f"{OUT}/boceto-{n}.svg", "w").write(svg(cuerpo, fondo))
diff --git a/tools/calle.py b/tools/calle.py
index e66206c..fc6a1c7 100644
--- a/tools/calle.py
+++ b/tools/calle.py
@@ -1,111 +1,111 @@
-# Genera docs/calle.svg: una calle corta vista en diagonal. De cada portal sale
-# gente que avanza hacia la calzada (presencias abstractas, a la manera de Suso33).
-# Arriba no hay pisos: la fachada se desvanece, y la calle también hacia la derecha.
+# Genera docs/calle.svg: una calle en perspectiva dibujada solo con líneas negras
+# (bordillos, pie de fachada, portales, línea del centro) y, encima, una piña de
+# monigotes de un solo trazo de spray en zigzag, de colores: fuego en el centro y
+# fríos alrededor (a la manera de Suso33).
import sys, random, math
-random.seed(26)
+random.seed(4)
OUT = sys.argv[1]
-W, H = 1600, 700
-VX, VY, F, EYE = 1150, 210, 520, 1.6 # punto de fuga a la derecha, focal, ojo a 1,6 m
-FX, KX = -5.0, -2.6 # fachada y bordillo (m)
-INK, ORA = "#111", "#f04e23"
+W, H = 1600, 680
+VX, VY, F, EYE = 1180, 110, 520, 5.0 # punto de fuga, focal, ojo en un primer piso (m)
+FACH, KI, KD = -7.0, -4.5, 3.6 # fachada, bordillo izquierdo y derecho (m)
+INK = "#111"
+FUEGO = ["#fffbe6", "#ffe066", "#ffb627", "#ff7b1c", "#f04e23", "#c8102e"] # del centro hacia fuera
+FRIO = ["#5b2a86", "#8e44c9", "#3b5bdb", "#6c7ae0", "#b07cd8", "#2a9d8f", "#111"]
o = []
add = o.append
-def P(X, Yh, Z): # Yh = altura sobre el suelo
+def P(X, Yh, Z):
return VX + X * F / Z, VY + (EYE - Yh) * F / Z
-def pts(*ps):
- return " ".join(f"{x:.1f},{y:.1f}" for x, y in ps)
-def brush(a, b, w, n=4, col=INK, op=.9):
- for _ in range(n):
- j = lambda: random.uniform(-w, w) * .35
- add(f'')
-HV = 570 # se recorta el suelo vacío de abajo
-add(f'')
+def linea(a, b, w, op=.95):
+ add(f'')
+
+Y0 = 100 # arriba solo hay blanco: se recorta
+add(f'')
add('''
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+''')
-ZN, ZF = 1.5, 70
-# --- calle: suelo, bordillo y carretera; se va a blanco por la derecha ---
-add('')
-add('')
-add(f'')
-add(f'') # acera
-brush(P(KX, 0, ZN), P(KX, 0, 40), 9, 5) # bordillo
-brush(P(KX + .25, 0, ZN), P(KX + .25, 0, 34), 3, 2, col=ORA) # línea naranja de detalle
-add('')
+# --- la calle: solo líneas negras a pincel ---
+ZN, ZF = 3.0, 90
+add('')
+linea(P(FACH, 0, ZN), P(FACH, 0, ZF), 7) # pie de la fachada
+linea(P(KI, 0, ZN), P(KI, 0, ZF), 9) # bordillo
+linea(P(KI + .18, 0, ZN), P(KI + .18, 0, ZF), 3, .7) # canto del bordillo
+linea(P(KD, 0, 5), P(KD, 0, ZF), 6, .8) # bordillo de enfrente
+z = 4.5
+while z < 60: # línea discontinua del centro
+ linea(P(-.3, 0, z), P(-.3, 0, z + 2.2), 2 + 16 / z, .8)
+ z += 5
+for zd in (4.0, 7.5, 11.5, 17.5, 26.0, 38.0): # portales: solo el contorno
+ a, b = P(FACH, 0, zd), P(FACH, 0, zd + 1.5)
+ c, d = P(FACH, 2.5, zd), P(FACH, 2.5, zd + 1.5)
+ w = 30 / zd + 2
+ linea(a, c, w); linea(c, d, w); linea(d, b, w)
+ linea(P(FACH, 2.8, zd - .3), P(FACH, 2.8, zd + 1.8), w * .6, .6) # dintel
+add('')
-# --- fachada solo a la altura de los portales: arriba se desvanece ---
-add('')
-add(f'')
-brush(P(FX, 0, ZN), P(FX, 0, ZF), 7, 4) # pie de la fachada
-DOORS = [4.0, 7.5, 12.0, 18.5, 28.0]
-for zd in DOORS:
- d = [P(FX, 0, zd), P(FX, 2.5, zd), P(FX, 2.5, zd + 1.5), P(FX, 0, zd + 1.5)]
- add(f'')
- w = 90 / zd
- brush(d[0], d[1], w, 3); brush(d[1], d[2], w, 3) # marco
- if zd in (4.0, 12.0): # dintel en naranja
- brush(P(FX, 2.7, zd - .1), P(FX, 2.7, zd + 1.6), w * .5, 2, col=ORA, op=.8)
-add('')
-
-# --- presencias: salen de los portales hacia la calzada y hacia quien mira ---
-def presencia(X, Z, paso, brazo):
- fx, fy = P(X, 0, Z)
- h = 1.75 * F / Z # alto en pantalla
- lean = h * .09 # inclinados hacia delante (derecha)
- sx, sy = fx + lean, fy - h * .80 # hombros
- r = h * .095
- w = h * .17
- # sombra en el suelo, hacia atrás a la izquierda
- add(f'')
- if paso: # zancada: tronco y dos piernas de pincel
- hip = (fx + lean * .4, fy - h * .45)
- add(f'')
- for fxx, fyy in ((fx - h * .16, fy), (fx + h * .17, fy - h * .03)):
- add(f'')
- else: # cuerpo afilado
- add(f'')
- if brazo == "arriba": # brazo en alto
- hx, hy = sx + h * .14, sy - h * .30
- add(f'')
- add(f'')
- elif brazo == "atras": # brazo que se balancea hacia atrás
- add(f'')
- add(f'')
- if random.random() < .15: # estela de movimiento en naranja
- for k in range(2):
- y = sy + h * (.15 + .22 * k)
- add(f'')
+# --- monigotes de un trazo ---
+def monigote(x, y, h, col, lean=0.0, paso=False, brazo=False):
+ sw = max(1.1, h * .011)
+ dy = sw * 2.0
+ top = y - h
+ pts, yy, i = [], top, 0
+ while yy <= y:
+ t = (yy - top) / h
+ cx = x + lean * h * (1 - t)
+ if t < .13: # cabeza
+ w = h * .05 * math.sin(math.pi * t / .13) ** .6 + sw * .3
+ elif t < .16: # cuello
+ w = h * .008
+ else: # cuerpo que se afila hacia los pies
+ u = (t - .16) / .84
+ w = h * (.062 * (1 - u) ** .8 + .014)
+ if paso and u > .5: # zancada: el zigzag se abre en dos
+ cx += (-1 if (i // 2) % 2 else 1) * h * .035 * (u - .5) / .5
+ w *= .6
+ pts.append((cx + (-1 if i % 2 else 1) * w + random.uniform(-.3, .3) * sw, yy))
+ yy += dy * random.uniform(.85, 1.15) * (.55 if t < .13 else 1)
+ i += 1
+ d = "M" + " L".join(f"{px:.1f},{py:.1f}" for px, py in pts)
+ add(f'')
+ if brazo: # brazo en alto
+ bx, by = x + lean * h * .84 + h * .05, top + h * .2
+ p = [(bx + j / 9 * h * .06 + (-1 if j % 2 else 1) * h * .012, by - j / 9 * h * .30) for j in range(10)]
+ d = "M" + " L".join(f"{px:.1f},{py:.1f}" for px, py in p)
+ add(f'')
+# reparto en metros sobre el suelo: la piña por la calzada y regueros desde los portales
+CX, CZ, R = -.4, 8.5, 2.8 # centro de la piña (fuego) y radio
gente = []
-for zd in DOORS:
- n = random.randint(7, 10) if zd < 20 else 5
- for i in range(n):
- t = (i + random.uniform(.1, .9)) / n # 0 en el portal, 1 en la calzada
- X = FX + .5 + t * random.uniform(4, 9)
- Z = zd + .75 - t * zd * random.uniform(.3, .5)
- if Z < 2.6 or any(abs(Z - g[0]) < .35 and abs(X - g[1]) < .45 for g in gente):
- continue
- paso = random.random() < .3
- brazo = random.choices(["arriba", "atras", None], [.15, .2, .65])[0]
- gente.append((Z, X, paso, brazo))
-gente.sort(reverse=True) # de lejos a cerca
-add('')
-for Z, X, paso, brazo in gente:
- presencia(X, Z, paso, brazo)
-add('')
+def cabe(X, Z):
+ return all(math.hypot(X - a, (Z - b) * .8) > .5 for a, b in gente)
+for _ in range(14000):
+ X, Z = random.gauss(-.2, 2.4), random.gauss(9.5, 4.2)
+ if KI - 1.5 < X < KD - .3 and 4.9 < Z < 32 and cabe(X, Z):
+ gente.append((X, Z))
+for zd in (7.5, 11.5, 17.5): # salen de los portales hacia la calzada
+ for k in range(4):
+ X, Z = FACH + .6 + k * .7, zd + .75 - k * .5
+ if cabe(X, Z):
+ gente.append((X, Z))
+
+add(f'')
+for X, Z in sorted(gente, key=lambda g: -g[1]): # de lejos a cerca
+ x, y = P(X, 0, Z)
+ h = 1.7 * F / Z * random.uniform(.9, 1.08)
+ dist = math.hypot(X - CX, Z - CZ) / R
+ if dist < 1:
+ col = FUEGO[min(len(FUEGO) - 1, int(max(0, dist + random.uniform(-.12, .12)) * len(FUEGO)))]
+ else:
+ col = random.choice(FRIO)
+ monigote(x, y, h, col, random.uniform(-.06, .04), random.random() < .35, random.random() < .1)
+add('')
open(OUT, "w").write("\n".join(o))
-print(f"{len(gente)} presencias", file=sys.stderr)
+print(f"{len(gente)} monigotes", file=sys.stderr)