in packages/playground/src/playground.ts [123:308]
    function populateParams(metaParameters: MakerJs.IMetaParameter[]) {
        var paramValues = [];
        var paramHtml: string[] = [];
        if (metaParameters) {
            var sliders = 0;
            for (var i = 0; i < metaParameters.length; i++) {
                var attrs = makerjs.cloneObject(metaParameters[i]);
                var id = 'input_param_' + i;
                var prepend = false;
                var input: MakerJs.exporter.XmlTag = null;
                var numberBox: MakerJs.exporter.XmlTag = null;
                switch (attrs.type) {
                    case 'range':
                        sliders++;
                        attrs['id'] = id;
                        attrs['onchange'] = 'MakerJsPlayground.setParam(' + i + ', makerjs.round(this.valueAsNumber, .001)); if (MakerJsPlayground.isSmallDevice()) { MakerJsPlayground.activateParam(this); MakerJsPlayground.deActivateParam(this, 1000); }';
                        attrs['ontouchstart'] = 'MakerJsPlayground.activateParam(this)';
                        attrs['ontouchend'] = 'MakerJsPlayground.deActivateParam(this, 1000)';
                        attrs['onmousedown'] = 'if (MakerJsPlayground.isSmallDevice()) { MakerJsPlayground.activateParam(this); }';
                        attrs['onmouseup'] = 'if (MakerJsPlayground.isSmallDevice()) { MakerJsPlayground.deActivateParam(this, 1000); }';
                        input = new makerjs.exporter.XmlTag('input', attrs);
                        //note: we could also apply the min and max of the range to the number field. however, the useage of the textbox is to deliberately "go out of bounds" when the example range is insufficient.
                        var numberBoxAttrs = {
                            "id": 'numberbox_' + i,
                            "type": 'number',
                            "step": 'any',
                            "value": attrs.value,
                            "onfocus": 'if (MakerJsPlayground.isSmallDevice()) { MakerJsPlayground.activateParam(this.parentElement); }',
                            "onblur": 'if (MakerJsPlayground.isSmallDevice()) { MakerJsPlayground.deActivateParam(this.parentElement, 0); }',
                            "onchange": 'MakerJsPlayground.setParam(' + i + ', makerjs.round(this.valueAsNumber, .001))'
                        };
                        var formAttrs = {
                            "action": 'javascript:void(0);',
                            "onsubmit": 'MakerJsPlayground.setParam(' + i + ', makerjs.round(this.elements[0].valueAsNumber, .001))'
                        };
                        numberBox = new makerjs.exporter.XmlTag('form', formAttrs);
                        numberBox.innerText = new makerjs.exporter.XmlTag('input', numberBoxAttrs).toString();
                        numberBox.innerTextEscaped = true;
                        paramValues.push(attrs.value);
                        break;
                    case 'bool':
                        var checkboxAttrs = {
                            type: 'checkbox',
                            onchange: 'MakerJsPlayground.setParam(' + i + ', this.checked)'
                        };
                        if (attrs.value) {
                            checkboxAttrs['checked'] = true;
                        }
                        input = new makerjs.exporter.XmlTag('input', checkboxAttrs);
                        paramValues.push(attrs.value);
                        prepend = true;
                        break;
                    case 'font':
                        var selectFontAttrs = {
                            id: id,
                            onchange: 'MakerJsPlayground.setParam(' + i + ', this.options[this.selectedIndex].value)'
                        };
                        input = new makerjs.exporter.XmlTag('select', selectFontAttrs);
                        var fontOptions = '';
                        var added = false;
                        for (var fontId in fonts) {
                            var font = fonts[fontId];
                            if (!FontLoader.fontMatches(font, attrs.value)) continue;
                            if (!added) {
                                paramValues.push(fontId);
                                added = true;
                            }
                            var option = new makerjs.exporter.XmlTag('option', { value: fontId });
                            option.innerText = font.displayName;
                            options += option.toString();
                        }
                        input.innerText = options;
                        input.innerTextEscaped = true;
                        break;
                    case 'select':
                        var selectAttrs = {
                            id: id,
                            onchange: 'MakerJsPlayground.setParam(' + i + ', JSON.parse(this.options[this.selectedIndex].innerText))'
                        };
                        input = new makerjs.exporter.XmlTag('select', selectAttrs);
                        var options = '';
                        for (var j = 0; j < attrs.value.length; j++) {
                            var option = new makerjs.exporter.XmlTag('option');
                            option.innerText = JSON.stringify(attrs.value[j]);
                            options += option.toString();
                        }
                        input.innerText = options;
                        input.innerTextEscaped = true;
                        paramValues.push(attrs.value[0]);
                        break;
                    case 'text':
                        attrs['id'] = id;
                        attrs['onchange'] = 'MakerJsPlayground.setParam(' + i + ', this.value)';
                        input = new makerjs.exporter.XmlTag('input', attrs);
                        paramValues.push(attrs.value);
                        break;
                }
                if (!input) continue;
                var div = new makerjs.exporter.XmlTag('div');
                var label = new makerjs.exporter.XmlTag('label');
                label.innerText = attrs.title;
                if (prepend) {
                    var innerText = input.toString() + ' ' + label.getInnerText();
                    label.innerText = innerText;
                    label.innerTextEscaped = true;
                    div.innerText = label.toString();
                } else {
                    label.attrs = { "for": id };
                    label.innerText += ': ';
                    div.innerText = label.toString() + input.toString();
                }
                if (numberBox) {
                    div.innerText += numberBox.toString();
                }
                div.innerTextEscaped = true;
                paramHtml.push(div.toString());
            }
            //if (sliders) {
            //var button = new makerjs.exporter.XmlTag('input', { type: 'button', onclick:'MakerJsPlayground.animate()', value: 'animate'});
            //paramHtml.push(button.toString());
            //}
        }
        processed.paramValues = paramValues;
        if (paramHtml.length) {
            document.body.classList.add('show-params-link');
        } else {
            document.body.classList.remove('show-params-link');
        }
        paramsDiv.innerHTML = paramHtml.join('');
        saveParamsLink();
        paramsDiv.setAttribute('disabled', 'true');
    }