Skip to content

Commit 2315686

Browse files
authored
Merge pull request #494 from shorepine/tutorials
deploying Tulip Web
2 parents e629412 + 0131168 commit 2315686

18 files changed

Lines changed: 276 additions & 187 deletions

tulip/shared/py/tulip.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,17 @@ def exists(fn):
514514
return True
515515

516516

517+
def download_and_run(name):
518+
if board()=="WEB":
519+
import world_web as world
520+
else:
521+
import world
522+
def rt():
523+
run(name)
524+
world.download(name,done_cb=rt)
525+
print("Downloading '%s'... please wait..." % (name))
526+
527+
517528
# reloads, runs and cleans up a Tulip "app"
518529
# Some ways to run things
519530
# (1) run('module') # imports module.py in your cwd

tulip/web/static/amyrepl.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ canvas {
5151
}
5252
.cm-s-lucario .CodeMirror-gutters { color: #002b36; }
5353
.cm-s-lucario .CodeMirror-cursor { border-left: solid thin #E6C845; }
54-
.cm-s-lucario .CodeMirror-linenumber { color: #f8f8f2; }
54+
.cm-s-lucario .CodeMirror-linenumber { color: #a8a8a2; }
5555
.cm-s-lucario .CodeMirror-selected { background: #243443; }
5656
.cm-s-lucario .CodeMirror-line::selection, .cm-s-lucario .CodeMirror-line > span::selection, .cm-s-lucario .CodeMirror-line > span > span::selection { background: #243443; }
5757
.cm-s-lucario .CodeMirror-line::-moz-selection, .cm-s-lucario .CodeMirror-line > span::-moz-selection, .cm-s-lucario .CodeMirror-line > span > span::-moz-selection { background: #243443; }

tulip/web/static/examples.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// examples.js
2+
const example_snippets = [{
3+
d:"Download and run a <b>pattern sequencer</b>",
4+
c:`
5+
tulip.download_and_run('tracks')
6+
7+
`},{
8+
d:"Run a drum machine",
9+
c:`
10+
run('drums')
11+
`},{
12+
d:"Set up a MIDI channel to play a piano",
13+
c:`
14+
midi.config.reset()
15+
midi.config.add_synth(synth.PatchSynth(6, 256))
16+
# Now set your MIDI device on this page and play a note!
17+
`},{
18+
d:"Move a sprite around the screen with the keyboard",
19+
c:`
20+
# Use control-Q to exit
21+
run("planet_boing")
22+
`},{
23+
d:"Chat on the Tulip World BBS",
24+
c:`
25+
# Set your own username!!
26+
world.username="anonymous"
27+
run('worldui')
28+
`},{
29+
d:"Play a complex FM synthesis example",
30+
c:`
31+
run('xanadu')
32+
`},{
33+
d:"Scrolling backgrounds",
34+
c:`
35+
# Use control-Q to exit
36+
run('parallax')
37+
`},{
38+
d:"Buttons, sliders and entry widgets",
39+
c:`
40+
run("buttons")
41+
`},{
42+
d:"Load a .wav sample and play a chord",
43+
c:`
44+
# some stuart dempster in your browser
45+
import music
46+
amy.load_sample('../sys/ex/bcla3.wav', patch=50)
47+
s = synth.OscSynth(wave=amy.PCM, patch=50)
48+
for i,note in enumerate(music.Chord('F:min7').midinotes()):
49+
s.note_on(note+24, 1, time=i*4000)
50+
s.note_off(note+24, time=20000)
51+
`},{
52+
d:"Load a small holiday animation with music",
53+
c:`
54+
tulip.download_and_run('xmas')
55+
`},{
56+
d:"Construct a custom FM synth and play a progression",
57+
c:`
58+
import midi, music
59+
# WOOD PIANO amy setup, 4-op FM synth
60+
61+
midi.config.reset()
62+
amy.start_store_patch()
63+
amy.send(osc=1, bp0="0,1,5300,0,0,0", phase=0.25, ratio=1, amp="0.3,0,0,1,0,0")
64+
amy.send(osc=2, bp0="0,1,3400,0,0,0", phase=0.25, ratio=0.5, amp="1.68,0,0,1,0,0")
65+
amy.send(osc=3, bp0="0,1,6700,0,0,0", phase=0.25, ratio=1, amp="0.23,0,0,1,0,0")
66+
amy.send(osc=4, bp0="0,1,3400,0,0,0", phase=0.25, ratio=0.5, amp="1.68,0,0,1,0,0")
67+
amy.send(osc=0, wave=amy.ALGO, algorithm=5, algo_source="1,2,3,4", bp0="0,1,147,0", bp1="0,1,179,1", freq="0,1,0,0,1,1")
68+
amy.stop_store_patch(1024)
69+
70+
s = synth.PatchSynth(8, 1024)
71+
72+
p = music.Progression(["I", "vi", "IV", "V"], music.Key("E:maj"))
73+
chord_len = 2000
74+
note_len = 500
75+
start = 1000
76+
for x,chord in enumerate(p.chords):
77+
# Play a chord
78+
chord_time = (x*chord_len)
79+
for i,note in enumerate(chord.midinotes()):
80+
s.note_on(note-12, 1, time=start+chord_time)
81+
s.note_off(note-12, time=start+chord_time+chord_len-100)
82+
# And a little arp over it
83+
for i,note in enumerate(chord.midinotes()):
84+
note_time = (x*chord_len)+(i*note_len)
85+
s.note_on(note, 1, time=start+note_time)
86+
s.note_off(note, time=start+note_time+100)
87+
`
88+
}
89+
]

tulip/web/static/index.html

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
<!-- These filenames are replaced by the build system -->
4646
<script src="TULIPCCMJS" type="module"></script>
4747
<script type="text/javascript" src="AMYJS"></script>
48+
<script type="text/javascript" src="examples.js"></script>
4849
<script type="text/javascript" src="spss.js"></script>
4950

5051
<!-- Matomo -->
@@ -53,12 +54,12 @@
5354
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
5455
_paq.push(['trackPageView']);
5556
_paq.push(['enableLinkTracking']);
56-
(function() { var u="https://tulipcomputer.matomo.cloud/";
57+
try {(function() { var u="https://tulipcomputer.matomo.cloud/";
5758
_paq.push(['setTrackerUrl', u+'matomo.php']);
5859
_paq.push(['setSiteId', '1']);
5960
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
6061
g.async=true; g.src='https://cdn.matomo.cloud/tulipcomputer.matomo.cloud/matomo.js'; s.parentNode.insertBefore(g,s);
61-
})();
62+
})()} catch(err) { console.log("matomo CORS error"); }
6263
</script>
6364
</head>
6465

@@ -128,9 +129,6 @@ <h1><A HREF="https://tulip.computer/"><img src="/img/favicon.png"/ width=40></A>
128129
<button class="btn btn-sm btn-primary" type="button" id="showhideeditor" data-bs-toggle="collapse" data-bs-target="#collapseEditor" aria-expanded="true" aria-controls="collapseEditor" onclick="show_editor();">
129130
Show code editor
130131
</button>
131-
<button class="btn btn-sm btn-warning" type="button" id="showhidetutorials" data-bs-toggle="collapse" data-bs-target="#collapseTutorials" aria-expanded="true" aria-controls="collapseTutorials" onclick="show_tutorials();">
132-
Show tutorials
133-
</button>
134132
</p>
135133

136134

@@ -173,13 +171,6 @@ <h1><A HREF="https://tulip.computer/"><img src="/img/favicon.png"/ width=40></A>
173171
</div>
174172
</div>
175173

176-
<div class="tutorials collapse" id="collapseTutorials">
177-
<button type="button" class="btn btn-sm btn-primary float-end" onclick="hide_tutorials();"
178-
data-bs-toggle="collapse" title="Hide tutorials" data-toggle="tooltip" data-placement="top" data-bs-target="#collapseTutorials" aria-expanded="true" aria-controls="collapseTutorials">
179-
Hide
180-
</button>
181-
</div>
182-
183174
<!-- Fake textarea to capture keystrokes to the SDL canvas -->
184175
<textarea id="textinput" autocapitalize="off" rows="1"></textarea>
185176

@@ -204,8 +195,12 @@ <h1><A HREF="https://tulip.computer/"><img src="/img/favicon.png"/ width=40></A>
204195
</div>
205196
</form>
206197

207-
<div id="tutorials" class="pt-4">
198+
<!-- Tutorial pills block -->
199+
<div class="pt-4">
200+
<h6>Try some examples:</h6>
201+
<div id="tutorials"></div>
208202
</div>
203+
209204
</div>
210205
</div>
211206

tulip/web/static/spss.js

Lines changed: 16 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var midiOutputDevice = null;
77
var midiInputDevice = null;
88
var editor = null;
99
var treeView = null;
10+
var editor_shown = false;
1011

1112
// Once AMY module is loaded, register its functions and start AMY (not yet audio, you need to click for that)
1213
amyModule().then(async function(am) {
@@ -320,89 +321,43 @@ async function tulip_world_upload_file(pwd, filename, username, description) {
320321
body: data,
321322
});
322323
}
323-
async function show_tutorials() {
324-
document.getElementById('showhidetutorials').style.display='none';
325-
document.getElementById('canvas').classList.remove("canvas-solo");
326-
document.getElementById('canvas').classList.add("canvas-editor");
327-
}
328-
329-
async function hide_tutorials() {
330-
document.getElementById('showhidetutorials').style.display='';
331-
document.getElementById('canvas').classList.remove("canvas-editor");
332-
document.getElementById('canvas').classList.add("canvas-solo");
333-
}
334-
335324

336325
async function show_editor() {
337326
document.getElementById('showhideeditor').style.display='none';
338327
if(editor) editor.refresh();
339328
document.getElementById('canvas').classList.remove("canvas-solo");
340329
document.getElementById('canvas').classList.add("canvas-editor");
330+
editor_shown = true;
341331
}
342332

343333
async function hide_editor() {
344334
document.getElementById('showhideeditor').style.display='';
345335
document.getElementById('canvas').classList.remove("canvas-editor");
346336
document.getElementById('canvas').classList.add("canvas-solo");
337+
editor_shown = false;
347338
}
348339

349-
const example_snippets = [{
350-
description:"Download and run a <b>pattern sequencer</b>",
351-
code:`
352-
def rt():
353-
run('tracks')
354-
world.download('tracks',done_cb=rt)
355-
`},{
356-
description:"Run a drum machine",
357-
code:`
358-
run('drums')
359-
`},{
360-
description:"Set up a MIDI channel to play a piano",
361-
code:`
362-
midi.config.reset()
363-
midi.config.add_synth(synth.PatchSynth(6, 256))
364-
`},{
365-
description:"Move a sprite around the screen with the keyboard",
366-
code:`
367-
run("planet_boing")
368-
`},{
369-
description:"Chat on the Tulip World BBS",
370-
code:`
371-
world.username="anonymous"
372-
run('worldui')
373-
`},{
374-
description:"Play a complex FM synthesis example",
375-
code:`
376-
run('xanadu')
377-
`},{
378-
description:"Scrolling backgrounds",
379-
code:`
380-
run('parallax')
381-
`},{
382-
description:"Buttons, sliders and entry widgets",
383-
code:`
384-
run("buttons")
385-
`}
386-
]
340+
387341
async function run_snippet(i) {
388-
var code = example_snippets[i].code;
389-
var ti = document.getElementById('textinput');
390-
// maybe send a keydown message to the textinput instead
391-
//for (let i = 0; i < code.length; i++) {
392-
//const event = new KeyboardEvent('keydown', {'a'});
393-
//ti.dispatchEvent(event);
394-
//mp.runPythonAsync('tulip.key_send('+code.charCodeAt(i).toString()+')');
395-
//}
396-
await mp.runPythonAsync("print(\"\"\"" + code + "\"\"\")");
397-
runCodeBlock(code);
342+
var code = example_snippets[i].c.trimStart();
343+
if(!editor_shown) {
344+
var editorElement = document.getElementById('collapseEditor');
345+
var bsCollapse = new bootstrap.Collapse(editorElement, { toggle: true });
346+
show_editor();
347+
}
348+
editor.setValue(code);
349+
setTimeout(function () { editor.save() }, 100);
350+
setTimeout(function () { editor.refresh() }, 250);
351+
setTimeout(function () { window.scrollTo(0,0) }, 300);
352+
runEditorBlock();
398353
}
399354

400355
async function fill_examples() {
401356
colors = ['bg-primary', 'bg-secondary', 'bg-success', 'bg-danger', 'bg-warning text-dark', 'bg-info text-dark', 'bg-light text-dark', 'bg-dark'];
402357
h = '';
403358
var i = 0;
404359
for (i=0;i<example_snippets.length;i++) {
405-
h += ' <a href="#" onclick="run_snippet('+i.toString()+');"><span class="badge rounded-pill ' + colors[i%colors.length] + '">'+example_snippets[i].description+'</span></a>';
360+
h += ' <a href="#" onclick="run_snippet('+i.toString()+');"><span class="badge rounded-pill ' + colors[i%colors.length] + '">'+example_snippets[i].d+'</span></a>';
406361
}
407362
document.getElementById('tutorials').innerHTML = h;
408363

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)