From efedefe535cf3dfb31aa1a2bb908e0d5c10ccab3 Mon Sep 17 00:00:00 2001 From: hacklab Date: Tue, 13 Oct 2026 13:37:34 +0200 Subject: [PATCH] =?UTF-8?q?Cinco=20bocetos=20de=20monigotes=20de=20un=20tr?= =?UTF-8?q?azo=20en=20zigzag,=20en=20pi=C3=B1a=20de=20colores?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docs/bocetos/boceto-1..5.svg y su generador tools/bocetos.py: contenedor, la piña sale a la calle, el portal, calle en diagonal y ausencias. --- README.md | 24 +++++++ docs/bocetos/boceto-1.svg | 6 ++ docs/bocetos/boceto-2.svg | 6 ++ docs/bocetos/boceto-3.svg | 6 ++ docs/bocetos/boceto-4.svg | 6 ++ docs/bocetos/boceto-5.svg | 6 ++ tools/bocetos.py | 136 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 190 insertions(+) create mode 100644 docs/bocetos/boceto-1.svg create mode 100644 docs/bocetos/boceto-2.svg create mode 100644 docs/bocetos/boceto-3.svg create mode 100644 docs/bocetos/boceto-4.svg create mode 100644 docs/bocetos/boceto-5.svg create mode 100644 tools/bocetos.py diff --git a/README.md b/README.md index 1806f12..6f9b9f2 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,30 @@ Una calle corta vista en diagonal, con el punto de fuga a la derecha. Solo se ve 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. + + ![Boceto 1](docs/bocetos/boceto-1.svg) + +2. **La piña sale a la calle**: la masa avanza hacia la derecha y se va soltando. + + ![Boceto 2](docs/bocetos/boceto-2.svg) + +3. **El portal**: del hueco sale una fila de gente y el fuego va delante. + + ![Boceto 3](docs/bocetos/boceto-3.svg) + +4. **Calle en diagonal**: la piña baja por la calle hacia quien mira. + + ![Boceto 4](docs/bocetos/boceto-4.svg) + +5. **Ausencias**: todos en negro y gris, y solo el corazón de la piña en fuego. + + ![Boceto 5](docs/bocetos/boceto-5.svg) + ## 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 new file mode 100644 index 0000000..e21d2c4 --- /dev/null +++ b/docs/bocetos/boceto-1.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/docs/bocetos/boceto-2.svg b/docs/bocetos/boceto-2.svg new file mode 100644 index 0000000..62f073a --- /dev/null +++ b/docs/bocetos/boceto-2.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/docs/bocetos/boceto-3.svg b/docs/bocetos/boceto-3.svg new file mode 100644 index 0000000..9606fee --- /dev/null +++ b/docs/bocetos/boceto-3.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/docs/bocetos/boceto-4.svg b/docs/bocetos/boceto-4.svg new file mode 100644 index 0000000..6784535 --- /dev/null +++ b/docs/bocetos/boceto-4.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/docs/bocetos/boceto-5.svg b/docs/bocetos/boceto-5.svg new file mode 100644 index 0000000..28585a7 --- /dev/null +++ b/docs/bocetos/boceto-5.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/tools/bocetos.py b/tools/bocetos.py new file mode 100644 index 0000000..7f7d387 --- /dev/null +++ b/tools/bocetos.py @@ -0,0 +1,136 @@ +# 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))