Transporte: al cargar un track el loop arranca desde cero
Cargar un proyecto (pestaña Projects o anterior/siguiente de la barra) deja pendiente un reinicio que se aplica en la siguiente evaluacion: el tema nuevo empieza en el ciclo 0 aunque el reloj del scheduler siga corriendo. Editar y actualizar en vivo no reinicia nada. Funciona con Cyclist y NeoCyclist (ambos tienen setCycle). README-HACKLAB mas breve y con enlaces: upstream, TidalCycles, algorave, librerias de samples y video introductorio.
This commit is contained in:
parent
b6dbe97a62
commit
921647020c
4 changed files with 53 additions and 42 deletions
|
|
@ -1,81 +1,81 @@
|
|||
# Strudel · fork del hacklab
|
||||
|
||||
Fork de [Strudel](https://codeberg.org/uzu/strudel) (live coding de música en
|
||||
el navegador, port de TidalCycles a JavaScript) con mejoras de usabilidad
|
||||
pensadas para pinchar en directo y para gente que empieza.
|
||||
el navegador, port de TidalCycles a JavaScript) con mejoras de usabilidad para
|
||||
pinchar en directo. Misma licencia que upstream: AGPL-3.0 (ver `LICENSE`).
|
||||
|
||||
Upstream: <https://codeberg.org/uzu/strudel> · Licencia: AGPL-3.0 (la misma,
|
||||
ver `LICENSE`). Gracias al equipo de Strudel/TidalCycles por la base ♥
|
||||
## Qué añade
|
||||
|
||||
## Qué añade este fork
|
||||
|
||||
- **Interfaz multiidioma** (`website/src/i18n.mjs`): castellano, inglés,
|
||||
francés, alemán, italiano, portugués y más. Se cambia desde el selector del
|
||||
header y se guarda en los ajustes.
|
||||
- **Pestaña Projects**: gestor de proyectos locales (localStorage) con
|
||||
carpetas, buscador y una librería de tracks de fábrica lista para pinchar
|
||||
(bases techno/acid originales, de la casa).
|
||||
- **Barra de transporte** estilo reproductor bajo el editor: anterior /
|
||||
play-pausa / siguiente, tiempo transcurrido y **barra de progreso
|
||||
arrastrable** (seek real: se añadió `Cyclist.setCycle()` en
|
||||
`packages/core`).
|
||||
- **Pestaña Guía**: chuleta de síntesis y sonidos para tener a mano mientras
|
||||
se pincha.
|
||||
- **Packs de temas** para el editor (`neon-madrid` + `hacklab-pack`: 5 neón
|
||||
sobre negro y 5 estándar).
|
||||
- **Lanzador de escritorio** (`strudel-launcher.sh`): sirve la build estática
|
||||
en local y abre el navegador. Ideal para un icono clicable.
|
||||
- Interfaz multiidioma (castellano, inglés, francés, alemán, italiano,
|
||||
portugués y más). Selector en el header.
|
||||
- Pestaña Projects: proyectos locales con carpetas, buscador y una librería
|
||||
de tracks de fábrica para empezar a pinchar.
|
||||
- Barra de transporte bajo el editor: anterior / play-pausa / siguiente,
|
||||
tiempo y barra de progreso arrastrable (seek real sobre el reloj del
|
||||
scheduler). Al cargar un track el loop arranca desde cero; editar y
|
||||
actualizar en vivo no reinicia nada.
|
||||
- Pestaña Guía: chuleta de síntesis y sonidos.
|
||||
- Packs de temas del editor: neon-madrid y hacklab-pack.
|
||||
- Lanzador de escritorio: `strudel-launcher.sh`.
|
||||
|
||||
## Instalación (Linux)
|
||||
|
||||
Requisitos: `git`, `node` >= 20 y `pnpm` (`corepack enable` lo activa).
|
||||
Requisitos: `git`, `node` >= 20 y `pnpm` (`corepack enable`).
|
||||
|
||||
```bash
|
||||
git clone https://gitea.laenre.net/hacklab/strudel.git
|
||||
cd strudel
|
||||
pnpm i # instala las dependencias del monorepo
|
||||
pnpm i
|
||||
```
|
||||
|
||||
### Modo desarrollo (recarga en vivo)
|
||||
Desarrollo (recarga en vivo):
|
||||
|
||||
```bash
|
||||
pnpm dev # abre http://localhost:4321
|
||||
pnpm dev # http://localhost:4321
|
||||
```
|
||||
|
||||
### Modo "aparato" (build estática + lanzador)
|
||||
Uso diario (build estática + lanzador):
|
||||
|
||||
```bash
|
||||
pnpm build # genera la web estática
|
||||
./strudel-launcher.sh # la sirve en http://127.0.0.1:3009 y abre el navegador
|
||||
pnpm build
|
||||
./strudel-launcher.sh # sirve http://127.0.0.1:3009 y abre el navegador
|
||||
```
|
||||
|
||||
Para el icono de escritorio, crea `~/.local/share/applications/strudel.desktop`:
|
||||
Icono de escritorio: `~/.local/share/applications/strudel.desktop`
|
||||
|
||||
```ini
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Strudel
|
||||
Comment=Live coding de música
|
||||
Comment=Live coding de musica
|
||||
Exec=/ruta/a/strudel/strudel-launcher.sh
|
||||
Icon=audio-x-generic
|
||||
Terminal=false
|
||||
Categories=AudioVideo;Audio;
|
||||
```
|
||||
|
||||
## Añadir tus propios packs de proyectos
|
||||
## Packs de proyectos propios
|
||||
|
||||
La librería de fábrica vive en
|
||||
La librería de fábrica está en
|
||||
`website/src/repl/components/panel/default-projects.mjs`. Para un pack
|
||||
personal sin tocar el repo, crea un módulo local con el mismo formato
|
||||
`{name, folder, code}` y concaténalo en `DEFAULT_PROJECTS` (los packs
|
||||
personales están en `.gitignore`). También puedes crear y organizar proyectos
|
||||
directamente desde la pestaña Projects de la interfaz.
|
||||
personal crea un módulo con el mismo formato `{name, folder, code}` y
|
||||
concaténalo en `DEFAULT_PROJECTS` (los packs personales están en
|
||||
`.gitignore`). También se pueden crear proyectos desde la propia pestaña.
|
||||
|
||||
## Mantenerse al día con upstream
|
||||
|
||||
El remoto `upstream` apunta al Strudel original:
|
||||
## Actualizar desde upstream
|
||||
|
||||
```bash
|
||||
git fetch upstream
|
||||
git merge upstream/main # y resolver conflictos si los hay
|
||||
git merge upstream/main
|
||||
```
|
||||
|
||||
## Enlaces
|
||||
|
||||
- Strudel (upstream): <https://codeberg.org/uzu/strudel>
|
||||
- Documentación / tutorial: <https://strudel.cc/learn>
|
||||
- TidalCycles, el original en Haskell: <https://tidalcycles.org>
|
||||
- Algorave, la escena: <https://algorave.com>
|
||||
- Samples para empezar a jugar:
|
||||
- Dirt-Samples (la librería clásica de Tidal): <https://github.com/tidalcycles/Dirt-Samples>
|
||||
- tidal-drum-machines (Roland TR-808/909 y muchas más): <https://github.com/ritchse/tidal-drum-machines>
|
||||
- Para ver de qué va esto en directo: <https://www.youtube.com/watch?v=iu5rnQkfO6M>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useStore } from '@nanostores/react';
|
|||
import { useEffect, useRef, useState } from 'react';
|
||||
import cx from '@src/cx.mjs';
|
||||
import { useT } from '@src/i18n.mjs';
|
||||
import { $projects, $playing, parseMeta, fmt } from './panel/ProjectsTab.jsx';
|
||||
import { $projects, $playing, $resetPending, parseMeta, fmt } from './panel/ProjectsTab.jsx';
|
||||
|
||||
// Barra de transporte estilo Spotify, FIJA debajo del editor de código:
|
||||
// · fila superior: controles CENTRADOS (anterior / play-pausa / siguiente)
|
||||
|
|
@ -98,6 +98,7 @@ export function TransportBar({ context }) {
|
|||
const p = displayed[idx];
|
||||
e.setCode(p.code);
|
||||
$playing.set(p.name);
|
||||
$resetPending.set(true); // el track nuevo arranca desde el ciclo 0
|
||||
e.evaluate();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,9 @@ const migrate = (list) => {
|
|||
export const $projects = atom(migrate(load()));
|
||||
// nombre del sample cargado en el editor (compartido con la barra de transporte)
|
||||
export const $playing = atom(null);
|
||||
// true = se acaba de cargar un track: la proxima evaluacion arranca el loop
|
||||
// desde el ciclo 0 (editar y actualizar en vivo no pasa por aqui)
|
||||
export const $resetPending = atom(false);
|
||||
|
||||
const persist = (list) => {
|
||||
try {
|
||||
|
|
@ -261,6 +264,7 @@ export function ProjectsTab({ context }) {
|
|||
ed.setCode(p.code);
|
||||
setPreviewed(p);
|
||||
$playing.set(p.name);
|
||||
$resetPending.set(true);
|
||||
};
|
||||
|
||||
const del = (p) => {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import { audioEngineTargets } from '../settings.mjs';
|
|||
import { useStore } from '@nanostores/react';
|
||||
import { prebake } from './prebake.mjs';
|
||||
import { getRandomTune, initCode, loadModules, shareCode } from './util.mjs';
|
||||
import { $resetPending } from './components/panel/ProjectsTab.jsx';
|
||||
import './Repl.css';
|
||||
import { setInterval, clearInterval } from 'worker-timers';
|
||||
import { getMetadata } from '../metadata_parser';
|
||||
|
|
@ -104,6 +105,11 @@ export function useReplContext() {
|
|||
beforeEval: () => audioReady,
|
||||
afterEval: (all) => {
|
||||
const { code } = all;
|
||||
// track recien cargado desde Projects: el loop arranca desde cero
|
||||
if ($resetPending.get()) {
|
||||
$resetPending.set(false);
|
||||
editorRef.current?.repl?.scheduler?.setCycle?.(0);
|
||||
}
|
||||
//post to iframe parent (like Udels) if it exists...
|
||||
window.parent?.postMessage(code);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue