tutticode 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -5
- package/README.zh-CN.md +3 -3
- package/dist/skills/tutticode/SKILL.md +12 -15
- package/dist/skills/tutticode/references/agent-loop.md +2 -4
- package/dist/skills/tutticode/references/for-agents.md +2 -2
- package/dist/skills/tutticode/references/functions.md +11 -1
- package/dist/skills/tutticode/references/mixing-groups.md +73 -0
- package/dist/skills/tutticode-sound-for-media/SKILL.md +2 -2
- package/dist/tutticode.cjs +9 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,8 +12,7 @@ tuttidaw.com/code, so a file sounds exactly like the editor. Nothing is
|
|
|
12
12
|
rendered on a server and it costs nothing. Every result carries an `editUrl`
|
|
13
13
|
that opens the program in TuttiDAW to keep editing.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
no render is cut or tagged), renders without an account are limited to 60 s,
|
|
15
|
+
Renders without an account are limited to 60 s,
|
|
17
16
|
and renders over 30 s carry a spoken "register at TuttiDAW" tag. A free
|
|
18
17
|
account lifts both:
|
|
19
18
|
`tutticode login` (renders up to 5 minutes, no tag). See
|
|
@@ -107,9 +106,8 @@ The reference documents are also MCP resources (`tutticode://skills/...`).
|
|
|
107
106
|
|
|
108
107
|
## Sign-in and limits
|
|
109
108
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
today.
|
|
109
|
+
TuttiDAW enforces the limits below. A CLI older than 0.2.1 is refused with
|
|
110
|
+
error `upgrade` (exit 6): update it with `npm i -g tutticode`.
|
|
113
111
|
|
|
114
112
|
| | Without sign-in | Free account |
|
|
115
113
|
| --- | --- | --- |
|
package/README.zh-CN.md
CHANGED
|
@@ -10,7 +10,7 @@ MCP server,适用于 Claude Code、Copilot CLI、Codex、Cursor、Claude Desktop
|
|
|
10
10
|
文件和编辑器里听到的一模一样。不经过服务器渲染,也不收费。每个结果都带一个
|
|
11
11
|
`editUrl`,可以在 TuttiDAW 里打开这段程序继续编辑。
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
不登录时每次渲染最长 60 秒,超过 30 秒的渲染会混入一段语音标签
|
|
14
14
|
"register at TuttiDAW"。用免费账号登录(`tutticode login`)就没有这些限制:
|
|
15
15
|
每次最长 5 分钟,没有语音标签。见[登录与限制](#登录与限制)。
|
|
16
16
|
|
|
@@ -93,8 +93,8 @@ TuttiCode" 元数据;仅登录后有效。
|
|
|
93
93
|
|
|
94
94
|
## 登录与限制
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
TuttiDAW 已经启用下面的限制。低于 0.2.1 的 CLI 会被拒绝,报错 `upgrade`(退出码 6):
|
|
97
|
+
用 `npm i -g tutticode` 升级。
|
|
98
98
|
|
|
99
99
|
| | 不登录 | 免费账号 |
|
|
100
100
|
| --- | --- | --- |
|
|
@@ -40,7 +40,9 @@ _lead: n("0 2 4 7").scale("C:minor") // a leading _ mutes a voice
|
|
|
40
40
|
- TuttiDAW only: `.inst("Device:Preset", {key: value})` instrument,
|
|
41
41
|
`.midifx(...)` before it, `.fx(...)` after it, in call order. Params use the
|
|
42
42
|
device's keys and units (`"4s"`, `"-6dB"`, `"1/16"`); constants only for now.
|
|
43
|
-
`
|
|
43
|
+
Mixing: `bus("verb").fx("Reverb")` + `.send("verb", -12)`, `.mix({vol, pan,
|
|
44
|
+
mute})`, `master.fx("Limiter")`, `group("drums")` + `.group("drums")`.
|
|
45
|
+
`toggle(1)` is an inline switch; `note("do re mi")` = `note("c d e")`.
|
|
44
46
|
|
|
45
47
|
## Top mistakes
|
|
46
48
|
|
|
@@ -68,13 +70,12 @@ _lead: n("0 2 4 7").scale("C:minor") // a leading _ mutes a voice
|
|
|
68
70
|
|
|
69
71
|
## Tools: two backends, one API
|
|
70
72
|
|
|
71
|
-
The same tools
|
|
72
|
-
Use whichever this agent has; prefer the local one.
|
|
73
|
+
The same tools and report shapes run on two backends; prefer the local one.
|
|
73
74
|
|
|
74
75
|
- **Local `tutticode`** (default; free): the `tutticode` CLI
|
|
75
76
|
and MCP server (`npm i -g tutticode`, `tutticode mcp`) render in the
|
|
76
77
|
user's own browser with the tuttidaw.com/code engine and write files to
|
|
77
|
-
disk, up to 300 s (60 s without sign-in
|
|
78
|
+
disk, up to 300 s (60 s without sign-in, below). Its tool descriptions
|
|
78
79
|
say "Runs locally". Without MCP,
|
|
79
80
|
call the CLI: `tutticode check prog.tc`, `tutticode render prog.tc -o
|
|
80
81
|
out.wav --seconds 12 --lufs -16 --json`, `tutticode open prog.tc`.
|
|
@@ -94,13 +95,10 @@ Use whichever this agent has; prefer the local one.
|
|
|
94
95
|
| `code_reference` | (local) search these references |
|
|
95
96
|
| `code_account` | (local) signed in or not, the length limits, today's usage |
|
|
96
97
|
|
|
97
|
-
**Without sign-in**,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
never edit code to remove it). When a render hits one, tell the user once;
|
|
102
|
-
`tutticode login` (free) lifts both. Agents: run `tutticode login
|
|
103
|
-
--device --no-wait --json`, give the user its link (`references/agent-loop.md`).
|
|
98
|
+
**Without sign-in**, local renders stop at 60 s (error `limit`) and over 30 s carry a
|
|
99
|
+
spoken "register at TuttiDAW" tag (`watermark`; never edit code to remove it).
|
|
100
|
+
Tell the user once; `tutticode login` (free) lifts both. Agents: run
|
|
101
|
+
`tutticode login --device --no-wait --json` and give the user its link.
|
|
104
102
|
|
|
105
103
|
## Workflow: write -> check -> render -> revise
|
|
106
104
|
|
|
@@ -116,9 +114,7 @@ never edit code to remove it). When a render hits one, tell the user once;
|
|
|
116
114
|
4. **Hand over** the `editUrl` (local) or `listenUrl` (web) with the
|
|
117
115
|
files: it opens the program in TuttiCode, where **Open in TuttiDAW**
|
|
118
116
|
saves it as a project with one track per voice. Without tools, link
|
|
119
|
-
`https://tuttidaw.com/code
|
|
120
|
-
in base64, URI-encoded (`encodeURIComponent(btoa(utf8))`, as strudel.cc's
|
|
121
|
-
long links).
|
|
117
|
+
`https://tuttidaw.com/code#` + `encodeURIComponent(btoa(utf8 code))`.
|
|
122
118
|
|
|
123
119
|
Pattern Clips in an open TuttiDAW project are edited with the web MCP's
|
|
124
120
|
`read_pattern` / `write_pattern` (notes only; devices apply on /code and in
|
|
@@ -141,11 +137,12 @@ Read only what the task needs:
|
|
|
141
137
|
- `references/sample-operations.md`: Sample operations. Play part of a sample, change its speed, cut it into slices, fit it to the tempo and choke it.
|
|
142
138
|
- `references/tuttidaw-extensions.md`: TuttiDAW extensions. Load any TuttiDAW instrument, MIDI effect or audio effect with presets and parameters; voices, groups and Open in TuttiDAW.
|
|
143
139
|
- `references/mixing.md`: Mixing: buses and master. Shared reverbs and delays on buses, sends from the voices, each voice's fader and pan, and the program's master chain - the same tracks Open in TuttiDAW makes.
|
|
140
|
+
- `references/mixing-groups.md`: Mixing: groups. Put voices in a group with its own effects, fader and sends - a drum bus inside the program, the same group track Open in TuttiDAW makes.
|
|
144
141
|
- `references/javascript.md`: JavaScript in code. Variables, functions, loops and register - and the sandbox, determinism and limits that keep shared code safe.
|
|
145
142
|
- `references/muse.md`: Muse on /TuttiCode. Ask TuttiDAW's AI assistant to write, explain, fix or restyle your program, from text, a Strudel tune, a screenshot or a reference track.
|
|
146
143
|
- `references/for-agents.md`: TuttiCode for agents. Let Claude Code, Copilot, Codex or any MCP client write TuttiCode and render it to audio files in your own browser, with the tutticode CLI, MCP server and skills.
|
|
147
144
|
- `references/functions.md`: every function, method and signal, with signature, description and example (generated from the engine).
|
|
148
145
|
- `references/devices.md`: every instrument and effect for `.inst/.fx/.midifx`, with `references/devices/<id>.md` per device: param keys, ranges, units, presets (generated from the device catalogue).
|
|
149
146
|
|
|
150
|
-
Language: PATTERN LANGUAGE 1.
|
|
147
|
+
Language: PATTERN LANGUAGE 1.3.0, engine 17.
|
|
151
148
|
Human guide: https://tuttidaw.com/code/learn; agents: https://tuttidaw.com/code/learn/for-agents
|
|
@@ -91,10 +91,8 @@ or mute (`_`) the voices you are not listening to.
|
|
|
91
91
|
|
|
92
92
|
## Sign-in, limits and the voice tag (*local*)
|
|
93
93
|
|
|
94
|
-
- **Limits.**
|
|
95
|
-
|
|
96
|
-
most 60 s, and a render over 30 s carries a spoken "register at
|
|
97
|
-
TuttiDAW" tag throughout. A free account (`tutticode login`) lifts both. `code_account` (or `tutticode
|
|
94
|
+
- **Limits.** A render without sign-in is at most 60 s, and a render
|
|
95
|
+
over 30 s carries a spoken "register at TuttiDAW" tag throughout. A free account (`tutticode login`) lifts both. `code_account` (or `tutticode
|
|
98
96
|
whoami --json`) says which applies (`limits.maxSeconds`,
|
|
99
97
|
`limits.watermarkAfterSeconds`, null = never tagged): plan within it,
|
|
100
98
|
for example keep an anonymous draft at 30 s or less.
|
|
@@ -41,8 +41,8 @@ a target or an earlier render). Only where the audio is made differs:
|
|
|
41
41
|
|
|
42
42
|
- **tutticode on your computer** (the default): renders in your own browser
|
|
43
43
|
and writes the files to your disk. Free, up to 5 minutes of audio per
|
|
44
|
-
render with a free account (`tutticode login`); without sign-in,
|
|
45
|
-
|
|
44
|
+
render with a free account (`tutticode login`); without sign-in, up to
|
|
45
|
+
60 seconds, and renders
|
|
46
46
|
over 30 seconds carry a spoken "register at TuttiDAW" tag. It also offers `code_open` (open a program here for you to hear),
|
|
47
47
|
`code_reference` (search the language reference) and `code_account`
|
|
48
48
|
(signed in or not, and the limits).
|
|
@@ -64,6 +64,16 @@ Sets chord symbols; also available as .chord(symbols) or .chord().
|
|
|
64
64
|
chord("<Bbm9 Fm9>/4").dict("ireal").voicing()
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
### `group(name)` *(TuttiDAW only)*
|
|
68
|
+
|
|
69
|
+
TuttiDAW extension, not in Strudel: declares a group, a group track inside the program; give it .fx(...), .mix(...) and .send(bus, dB), and put voices in it with .group(name).
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
group("drums").fx("Drum Buss").mix({vol: -3})
|
|
73
|
+
kick: s("bd*4").group("drums")
|
|
74
|
+
snare: s("~ sd").group("drums")
|
|
75
|
+
```
|
|
76
|
+
|
|
67
77
|
### `hush()`
|
|
68
78
|
|
|
69
79
|
Silence.
|
|
@@ -1049,7 +1059,7 @@ note("[c3,e3,g3]").midifx("Arpeggiator", {style: "UpDown", rate: "1/16"})
|
|
|
1049
1059
|
|
|
1050
1060
|
### `.mix(mixer)` *(TuttiDAW only)*
|
|
1051
1061
|
|
|
1052
|
-
TuttiDAW extension, not in Strudel: the voice's mixer: vol in dB (-70..6), pan -1..1, mute true / false; a bus's and the master's too.
|
|
1062
|
+
TuttiDAW extension, not in Strudel: the voice's mixer: vol in dB (-70..6), pan -1..1, mute true / false; a bus's, a group's and the master's too.
|
|
1053
1063
|
|
|
1054
1064
|
```js
|
|
1055
1065
|
note("c3 e3").mix({vol: -6, pan: -0.3})
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Mixing: groups
|
|
2
|
+
|
|
3
|
+
Put voices in a group with its own effects, fader and sends - a drum bus inside the program, the same group track Open in TuttiDAW makes.
|
|
4
|
+
|
|
5
|
+
A **group** gathers voices so you can treat them as one: a compressor on all
|
|
6
|
+
the drums, one fader for the whole kit, one send to the reverb. "Open in
|
|
7
|
+
TuttiDAW" makes it a group track inside the program's group, with those
|
|
8
|
+
voices in it.
|
|
9
|
+
|
|
10
|
+
| Code | What it is | In the studio |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `group(name)` | a group of voices | a group track inside the program's group |
|
|
13
|
+
| `.group(name)` | puts a voice in a group | the voice's track becomes a child of that group |
|
|
14
|
+
|
|
15
|
+
Like `bus` and `.send`, these are TuttiDAW-only: a program that uses them
|
|
16
|
+
does not play on strudel.cc.
|
|
17
|
+
|
|
18
|
+
## A drum group
|
|
19
|
+
|
|
20
|
+
Declare the group on its own line, give it effects with `.fx` and a fader
|
|
21
|
+
with `.mix`, and put voices in it with `.group(name)`:
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
group("drums").fx("Drum Buss").mix({vol: -3})
|
|
25
|
+
|
|
26
|
+
kick: s("bd*4").bank("tr909").group("drums")
|
|
27
|
+
snare: s("~ sd").bank("tr909").group("drums")
|
|
28
|
+
hats: s("hh*8").bank("tr909").group("drums").mix({vol: -8})
|
|
29
|
+
bass: note("<c2 g1 a1 f1>").ply(4).s("sawtooth").lpf(600)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The kick, snare and hats play through the Drum Buss, then through the
|
|
33
|
+
group's fader: `-3` lowers all three by 3 dB. Each voice keeps its own
|
|
34
|
+
`.mix` too - the hats are 8 dB down inside the group.
|
|
35
|
+
|
|
36
|
+
## Sends from a group
|
|
37
|
+
|
|
38
|
+
A group sends to a bus like a voice does, with a level in dB. The whole
|
|
39
|
+
group goes to the bus at that level - here the drums share one room while
|
|
40
|
+
the bass stays dry:
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
bus("room").fx("Reverb", {dryWetBalance: 1, decayTime: "1.5s"})
|
|
44
|
+
group("drums").send("room", -14)
|
|
45
|
+
|
|
46
|
+
kick: s("bd*4").group("drums")
|
|
47
|
+
snare: s("~ sd").group("drums")
|
|
48
|
+
bass: note("c2 ~ c2 g1").s("sawtooth").lpf(500)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Buses belong to the program: a group can send to any bus the program
|
|
52
|
+
declares, and its voices can still send on their own too.
|
|
53
|
+
|
|
54
|
+
A group's fader, pan and send levels are numbers (a group track has no clip
|
|
55
|
+
to move them). A group cannot be put inside another group.
|
|
56
|
+
|
|
57
|
+
## A voice without a group
|
|
58
|
+
|
|
59
|
+
`.group("drums")` with no `group("drums")` in the program is a warning: the
|
|
60
|
+
editor offers to add the declaration, and until then the voice plays in the
|
|
61
|
+
program's group like any other.
|
|
62
|
+
|
|
63
|
+
## In the studio
|
|
64
|
+
|
|
65
|
+
The group track sits inside the program's group, with its voices as its
|
|
66
|
+
children. Its effects, fader and sends belong to the code, like a bus's:
|
|
67
|
+
change one by hand and the group is detached from the code (Re-attach
|
|
68
|
+
brings it back). Move a voice out of its group by hand and that voice is
|
|
69
|
+
detached. Remove `.group("drums")` from a voice and its track moves back
|
|
70
|
+
to the program's group; remove `group("drums")` itself and the group track
|
|
71
|
+
stays, marked "not in code", while its voices move back.
|
|
72
|
+
|
|
73
|
+
Source: https://tuttidaw.com/code/learn/mixing-groups
|
|
@@ -11,8 +11,8 @@ the `tutticode` skill (install both: `tutticode skills install`); the tools
|
|
|
11
11
|
are `code_check`, `code_render`, `code_compare` from the local `tutticode`
|
|
12
12
|
MCP server or CLI (default: free, renders in the user's browser, writes
|
|
13
13
|
files) or TuttiDAW's web MCP (server renders, Muse points, 60 s, no files:
|
|
14
|
-
a `listenUrl`).
|
|
15
|
-
the local tools
|
|
14
|
+
a `listenUrl`). Without sign-in,
|
|
15
|
+
the local tools render at most 60 s and tag renders over
|
|
16
16
|
30 s with a spoken "register at TuttiDAW": for a longer delivery, when a
|
|
17
17
|
render hits a limit (`limit` error, `watermark`), suggest
|
|
18
18
|
`tutticode login` (free) to the user (the `tutticode` skill says how an
|
package/dist/tutticode.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/* tutticode v0.2.
|
|
2
|
+
/* tutticode v0.2.2 | https://tuttidaw.com */
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
@@ -4598,13 +4598,14 @@ function tutticodeTermsUrl(origin) {
|
|
|
4598
4598
|
}
|
|
4599
4599
|
var TUTTICODE_LOGIN_HINT_COMMAND = "tutticode login --device --no-wait";
|
|
4600
4600
|
var DEFAULT_TUTTICODE_LIMITS = {
|
|
4601
|
-
enforce:
|
|
4601
|
+
enforce: true,
|
|
4602
4602
|
anonMaxSeconds: 60,
|
|
4603
4603
|
anonWatermarkAfterSeconds: 30,
|
|
4604
4604
|
watermarkGapSeconds: 3,
|
|
4605
4605
|
signedInMaxSeconds: 300,
|
|
4606
4606
|
signedInDailyRenders: 1e3,
|
|
4607
|
-
|
|
4607
|
+
// 0.2.0's sign-in is broken on Windows
|
|
4608
|
+
minCliVersion: "0.2.1"
|
|
4608
4609
|
};
|
|
4609
4610
|
var VERSION = /^(\d{1,6})\.(\d{1,6})\.(\d{1,6})(?:-[0-9A-Za-z.-]{1,32})?$/;
|
|
4610
4611
|
function isCliVersion(v) {
|
|
@@ -4902,7 +4903,7 @@ var import_node_path2 = require("node:path");
|
|
|
4902
4903
|
var import_node_fs = require("node:fs");
|
|
4903
4904
|
var import_node_os = require("node:os");
|
|
4904
4905
|
var import_node_path = require("node:path");
|
|
4905
|
-
var VERSION2 = true ? "0.2.
|
|
4906
|
+
var VERSION2 = true ? "0.2.2" : readPackageVersion();
|
|
4906
4907
|
function envBrowserArgs() {
|
|
4907
4908
|
const args = process.env.TUTTICODE_BROWSER_ARGS?.split(" ").filter(Boolean);
|
|
4908
4909
|
return args?.length ? args : void 0;
|
|
@@ -4999,7 +5000,7 @@ function saveAccount(origin, account) {
|
|
|
4999
5000
|
var PrivateDirError = class extends Error {
|
|
5000
5001
|
};
|
|
5001
5002
|
var privateDirs = /* @__PURE__ */ new Map();
|
|
5002
|
-
var fileId = (st) => `${st.dev}:${st.ino}`;
|
|
5003
|
+
var fileId = (st, platform = process.platform) => platform === "win32" ? `${st.ino}` : `${st.dev}:${st.ino}`;
|
|
5003
5004
|
function refusal(dir, why) {
|
|
5004
5005
|
return new PrivateDirError(
|
|
5005
5006
|
`${dir} ${why}, so tutticode will not keep a sign-in there. Point TUTTICODE_HOME at a folder you own that only you can use (or unset it for ~/.tutticode).`
|
|
@@ -6223,9 +6224,8 @@ Usage:
|
|
|
6223
6224
|
tutticode setup optional browser policy + skills
|
|
6224
6225
|
tutticode skills install install the agent skills
|
|
6225
6226
|
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
at TuttiDAW" tag. TUTTICODE_TOKEN (an access token from the
|
|
6227
|
+
Renders without sign-in are limited to 60 s, and renders over 30 s carry a
|
|
6228
|
+
spoken "register at TuttiDAW" tag. TUTTICODE_TOKEN (an access token from the
|
|
6229
6229
|
account page) signs in CI.
|
|
6230
6230
|
|
|
6231
6231
|
Exit codes: 0 ok, 1 errors in the code, 2 bridge/browser problem, 3 usage,
|
|
@@ -8957,7 +8957,7 @@ var CODE_OPEN_TOOL = "code_open";
|
|
|
8957
8957
|
var CODE_REFERENCE_TOOL = "code_reference";
|
|
8958
8958
|
var CODE_ACCOUNT_TOOL = "code_account";
|
|
8959
8959
|
var BACKEND_NOTE = "Runs locally: tutticode renders in your own browser with the tuttidaw.com/code engine (free).";
|
|
8960
|
-
var LIMITS_NOTE = `
|
|
8960
|
+
var LIMITS_NOTE = `Renders without sign-in are limited to ${DEFAULT_TUTTICODE_LIMITS.anonMaxSeconds} s (error code "limit") and renders over ${DEFAULT_TUTTICODE_LIMITS.anonWatermarkAfterSeconds} s carry a spoken "register at TuttiDAW" tag, reported as \`watermark\`: it is not part of the program and is in the stats; never change the code to remove it, tell the user once that \`tutticode login\` (free) removes it.`;
|
|
8961
8961
|
var codeProperty2 = codeCheckTool.inputSchema.properties.code;
|
|
8962
8962
|
var renderProperties2 = {
|
|
8963
8963
|
code: codeProperty2,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tutticode",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Turn TuttiCode (tuttidaw.com/code pattern code) into audio files from any agent: a CLI and an MCP server that render in your own browser with the TuttiDAW engine.",
|
|
6
6
|
"license": "MIT",
|