diff --git a/pd/nw/dialog_canvas.html b/pd/nw/dialog_canvas.html
index dc9fff2168c2c293d664e34c0c9b25ee7d0f68e7..077e838b73fe7abad2191cbe5e6e9d8b51e62410 100644
--- a/pd/nw/dialog_canvas.html
+++ b/pd/nw/dialog_canvas.html
@@ -491,7 +491,7 @@ function apply() {
         gop = +document.getElementsByName('gop')[0].checked;
         hide_name = +document.getElementsByName('hide-name')[0].checked;
 
-        pdgui.pdsend([pd_object_callback, 'donecanvasdialog',
+        pdgui.pdsend(pd_object_callback, 'donecanvasdialog',
             +get_input('x-scale'),
             +get_input('y-scale'),
             (gop + 2 * hide_name),
@@ -503,7 +503,7 @@ function apply() {
             +get_input('y-pix'),
             +get_input('x-margin'),
             +get_input('y-margin'),
-            ].join(' '));
+            );
     }
 
     // Now send the array properties, in a separate
@@ -514,7 +514,7 @@ function apply() {
         if (name.slice(0, 1) === '$') {
             name = '#' + name.slice(1);
         }
-        pdgui.pdsend([
+        pdgui.pdsend(
             get_array_value('array_gfxstub', attrs),
             'arraydialog',
             name,
@@ -526,7 +526,7 @@ function apply() {
             0, // ydraw-- not sure if this is still used
             get_array_value('array_fill', attrs),
             get_array_value('array_outline', attrs),
-        ].join(' '));
+        );
 
     }
 }
@@ -535,11 +535,11 @@ function cancel() {
     var i, attrs, gfxstub;
     pdgui.gui_post("closing the window at this point");
     //window.close(true);
-    pdgui.pdsend(pd_object_callback + " cancel");
+    pdgui.pdsend(pd_object_callback, "cancel");
     for (i = 0; i < pd_garray_attrs.length; i++) {
         attrs = pd_garray_attrs[i];
         gfxstub = attrs.array_gfxstub;
-        pdgui.pdsend(gfxstub + " cancel");
+        pdgui.pdsend(gfxstub, "cancel");
     }
 }
 
diff --git a/pd/nw/dialog_font.html b/pd/nw/dialog_font.html
index bfc2476e58a6c5bacd4d13a70991c8574b6b3fb1..32658dc2efc1f4bc8bb3bda0de3e48ab7793f2b8 100644
--- a/pd/nw/dialog_font.html
+++ b/pd/nw/dialog_font.html
@@ -118,18 +118,18 @@ function change_size() {
 
 function apply() {
     pdgui.gui_post("we're applying font size changes!");
-    pdgui.pdsend([canvas, 'font', 
+    pdgui.pdsend(canvas, 'font', 
         +document.querySelector('input[name="font_size"]:checked').value,
         current_size,
         100,
         0, // "$noundo" from pd.tk-- not sure what it does
-    ].join(' '));
+    );
 }
 
 function cancel() {
     pdgui.gui_post("closing the window at this point");
     //window.close(true);
-    pdgui.pdsend(pd_object_callback + " cancel");
+    pdgui.pdsend(pd_object_callback, "cancel");
 }
 
 // This gets called from the nw_create_window function in index.html
diff --git a/pd/nw/dialog_gatom.html b/pd/nw/dialog_gatom.html
index a36a1a8ba28014b135a49e98c33e0f32e6f9cadf..b839609542107b8b2e88d70b4b2400e03cbee804 100644
--- a/pd/nw/dialog_gatom.html
+++ b/pd/nw/dialog_gatom.html
@@ -186,7 +186,7 @@ function gatom_escape(str) {
 
 function apply() {
     pdgui.gui_post("we're applying gatom changes!");
-    pdgui.pdsend([pd_object_callback, 'param', 
+    pdgui.pdsend(pd_object_callback, 'param', 
         +document.getElementById('width').value,
         +document.getElementById('minimum-range').value,
         +document.getElementById('maximum-range').value,
@@ -194,13 +194,13 @@ function apply() {
         document.querySelector('input[name="labelpos"]:checked').value,
         gatom_escape(document.getElementById('receive-symbol').value),
         gatom_escape(document.getElementById('send-symbol').value)
-    ].join(' '));
+    );
 }
 
 function cancel() {
     pdgui.gui_post("closing the window at this point");
     //window.close(true);
-    pdgui.pdsend(pd_object_callback + " cancel");
+    pdgui.pdsend(pd_object_callback, "cancel");
 }
 
 // This gets called from the nw_create_window function in index.html
@@ -272,7 +272,7 @@ function add_events(name) {
     // closing the Window
     nw.Window.get().on("close", function() {
         // this needs to do whatever the "cancel" button does
-        //pdgui.pdsend(name + " menuclose 0");
+        //pdgui.pdsend(name, "menuclose 0");
         //cancel();
         pdgui.remove_dialogwin(pd_object_callback);
         this.close(true);
diff --git a/pd/nw/dialog_iemgui.html b/pd/nw/dialog_iemgui.html
index a4dcd07b72caa76b02d99d95cfa705f03aae75e3..f44470f6abd0113e8d8a0c320c229dde3010a21b 100644
--- a/pd/nw/dialog_iemgui.html
+++ b/pd/nw/dialog_iemgui.html
@@ -448,7 +448,7 @@ function apply() {
 
     var slot18 = +document.getElementsByName('steady-on-click')[0].checked;
 
-    pdgui.pdsend([pd_object_callback, 'dialog',
+    pdgui.pdsend(pd_object_callback, 'dialog',
         width, height,
         slot3, // bng: flash-interrupt
                // slider: min-range
@@ -468,13 +468,13 @@ function apply() {
         background_color, foreground_color,
         label_color,
         slot18, // steady on click
-        0].join(' '));
+        0);
 }
 
 function cancel() {
     pdgui.gui_post("closing the window at this point");
     //window.close(true);
-    pdgui.pdsend(pd_object_callback + " cancel");
+    pdgui.pdsend(pd_object_callback, "cancel");
 }
 
 // This gets called from the nw_create_window function in index.html
@@ -557,7 +557,7 @@ function add_events(name) {
     // closing the Window
     nw.Window.get().on("close", function() {
         // this needs to do whatever the "cancel" button does
-        //pdgui.pdsend(name + " menuclose 0");
+        //pdgui.pdsend(name, "menuclose 0");
         //cancel();
         pdgui.remove_dialogwin(pd_object_callback);
         this.close(true);
diff --git a/pd/nw/dialog_prefs.html b/pd/nw/dialog_prefs.html
index f7fb0b37e86aed6362866e7c304ab2e5a34c51d9..d7c7a96f09f7d989c0d2748f43e9502fba682bf7 100644
--- a/pd/nw/dialog_prefs.html
+++ b/pd/nw/dialog_prefs.html
@@ -351,7 +351,7 @@ function apply() {
     pdgui.gui_post("we're applying shits!");
 
     // Audio dialog
-    pdgui.pdsend([
+    pdgui.pdsend(
         'pd audio-dialog',
         kludge_dev('in', attrs, 0),
         kludge_dev('in', attrs, 1),
@@ -373,11 +373,11 @@ function apply() {
         get_attr('advance', attrs),
         get_attr('cancallback', attrs),
         get_attr('blocksize', attrs)
-        ].join(' '));
+        );
 
     attrs = pd_midi_attrs;
     // Midi dialog
-    pdgui.pdsend([
+    pdgui.pdsend(
         'pd midi-dialog',
         get_attr('pd-indevs', attrs)[0],
         get_attr('pd-indevs', attrs)[1],
@@ -389,23 +389,23 @@ function apply() {
         get_attr('pd-outdevs', attrs)[3],
         0, // midi_alsain
         0  // midi_alsaout
-    ].join(' '));
+    );
 }
 
 function cancel() {
     var i, attrs, gfxstub;
     pdgui.gui_post("closing the window at this point");
     window.close(true);
-    //pdgui.pdsend(pd_object_callback + " cancel");
+    //pdgui.pdsend(pd_object_callback, "cancel");
 }
 
 function change_api(elem) {
     var id = elem.getAttribute('id'),
         value = elem.getAttribute('value');
     if (id === 'audio_api') {
-        pdgui.pdsend("pd audio-setapi " + value);
+        pdgui.pdsend("pd audio-setapi", value);
     } else {
-        pdgui.pdsend("pd midi-setapi " + value);
+        pdgui.pdsend("pd midi-setapi", value);
     }
 }
 
diff --git a/pd/nw/index.html b/pd/nw/index.html
index 29ebe831c08d040a964cfc131ded968171c79e09..59cc09dbf55db2cc1b91c772feeb7ce7760c61c3 100644
--- a/pd/nw/index.html
+++ b/pd/nw/index.html
@@ -45,7 +45,7 @@
         document.getElementById("dsp_control").addEventListener("click",
             function(evt) {
                 var dsp_state = this.checked ? 1 : 0;
-                pdgui.pdsend("pd dsp " + dsp_state);
+                pdgui.pdsend("pd dsp", dsp_state);
             }
         );
 
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 34119701a758cd9715d1f49cead5c83a54ea64d9..44778dd5f9b16841285119b127b12183a9d326a4 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -260,13 +260,13 @@ function canvas_check_geometry(cid) {
         win_y = patchwin[cid].y,
         cnv_width = patchwin[cid].window.innerWidth,
         cnv_height = patchwin[cid].window.innerHeight;
-    pdsend([cid, "relocate",
+    pdsend(cid, "relocate",
             pd_geo_string(win_w, win_h, win_x, win_y),
             // We're reusing win_x and win_y here, as it
             // shouldn't make a difference to the bounds
             // algorithm in Pd
             pd_geo_string(cnv_width, cnv_height, win_x, win_y),
-           ].join(" "));
+           );
 }
 
 exports.canvas_check_geometry = canvas_check_geometry;
@@ -321,8 +321,7 @@ function saveas_callback(cid, file) {
     //}
     var directory = path.dirname(filename);
     var basename = path.basename(filename);
-    pdsend(cid + " savetofile " + enquote(basename) + " " +
-        enquote(directory));
+    pdsend(cid, "savetofile", enquote(basename), enquote(directory));
 
     // haven't implemented these last few commands yet...
     // set untitled_directory $directory
@@ -341,8 +340,8 @@ exports.menu_saveas = menu_saveas;
 function menu_new () {
     //if { ! [file isdirectory $untitled_directory]} {set untitled_directory $::env(HOME)}
     untitled_directory = pwd;
-    pdsend("pd filename " +
-           "Untitled-" + untitled_number + " " +
+    pdsend("pd filename",
+           "Untitled-" + untitled_number,
            enquote(untitled_directory));
     if (k12_mode == 1) {
         k12_saveas_on_new = 1;
@@ -476,7 +475,7 @@ function open_file(file) {
         //}
     }
     if (basename.match(/\.(pd|pat|mxt)$/i) != null) {
-        pdsend("pd open" + " " + enquote(basename) + " " + enquote(directory));
+        pdsend("pd open", enquote(basename), enquote(directory));
         pd_opendir = directory;
         //::pd_guiprefs::update_recentfiles "$filename" 1
     }
@@ -597,7 +596,7 @@ function gui_startup(version, fontname_from_pd, fontweight_from_pd,
 //    } else {
 //        set oldtclversion 0
 //    }
-    pdsend("pd init " + enquote(pwd) + " 0 " + font_fixed_metrics);
+    pdsend("pd init", enquote(pwd), "0", font_fixed_metrics);
 
 //    # add the audio and help menus to the Pd window.  We delayed this
 //    # so that we'd know the value of "apilist".
@@ -698,14 +697,9 @@ function gui_canvas_cursor(cid, pd_event_type) {
 }
 
 function gui_canvas_sendkey(cid, state, evt, char_code) {
-    pdsend(
-        cid + " key " +
-        state + " " +
-        char_code + " " +
-        (evt.shiftKey ? 1 : 0) + " " +
-        1 + " " +
-        (evt.repeat ? 1 : 0)
-    );
+    var shift = evt.shiftKey ? 1 : 0,
+        repeat = evt.repeat ? 1 : 0;
+    pdsend(cid, "key", state, char_code, shift, 1, repeat);
 }
 
 exports.gui_canvas_sendkey = gui_canvas_sendkey;
@@ -901,7 +895,8 @@ function init_socket_events () {
 exports.init_socket_events = init_socket_events;
 
 // Send commands to Pd
-function pdsend(string) {
+function pdsend() {
+    var string = Array.prototype.join.call(arguments, ' ');
     client.write(string + ';');
     // for now, let's reprint the outgoing string to the pdwindow
     //gui_post(string + ';', 'red');
@@ -2206,7 +2201,7 @@ function gui_drawimage_new(obj_tag, file_path, canvasdir, flags) {
     if (i > 0) {
         img = new pd_window.Image(); // create an image in the pd_window context
         img.onload = function() {
-            pdsend(obj_tag + ' size ' + this.width + ' ' + this.height);
+            pdsend(obj_tag, "size", this.width, this.height);
         };
         img.src = 'data:image/' + drawimage_data[obj_tag][0].type +
             ';base64,' + drawimage_data[obj_tag][0].data;
@@ -2338,7 +2333,7 @@ function gui_canvas_popup(cid, xpos, ypos, canprop, canopen, isobject) {
 }
 
 function popup_action(cid, index) {
-    pdsend(cid + " done-popup " + index + " " + popup_coords.join(" "));
+    pdsend(cid, "done-popup", index, popup_coords.join(" "));
 }
 
 exports.popup_action = popup_action;
@@ -2563,7 +2558,7 @@ function gui_savepanel(cid, target, path) {
 }
 
 exports.file_dialog_callback = function(file_string) {
-    pdsend(file_dialog_target + " callback " + enquote(file_string));
+    pdsend(file_dialog_target, "callback", enquote(file_string));
 }
 
 // Used to convert the ["key", "value"...] arrays coming from