// title : SK8CAD for Roarockit Builders
// author : Beau Trifiro
// license : Copyright 2020 - present, Open Source Skateboards
// description: Skateboard and mold customizer
// last edit : 1/26/21
function getParameterDefinitions()
{
return ([
/*{ name: 'mold', type: 'choice', caption: 'Select Mold', values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], captions: ['None',
'Asymmetrical - Small',
'Asymmetrical - Mid',
'Freestyle - Modern Era',
'Freestyle - SF',
'Freestyle - Sweden',
'Freestyle - RadRat',
'Mellow Symmetrical',
'Medium/Mellow Symmetrical',
'Medium Symmetrical',
'Steep Symmetrical',
'Shark',
'XL Medium'], initial: 0},*/
{ name: 'display_title', caption: '<span class="category">Display</span>', type: 'group', class: 'category'},
{ name: 'display_item', caption: 'Show ', type: 'choice', values: [0, 1], initial: 0, captions: ['Mold', 'Board']},
//{ name: 'templates', caption: '<hr> <span class="category">Pre-Designed Templates</span> <br> <button style="font-size: 10px;">Template specs</button>', type: 'group'},
//{ name: 'profile_choice', caption: 'Select Profile', type: 'choice', values: [0, 1, 2, 3], initial: 0, captions: ['None', '8.25" Street Deck', 'Longboard Dancer', 'Cruiser']},
//{ name: 'mold_choice', caption: 'Select Mold', type: 'choice', values: [0, 1, 2, 3], initial: 0, captions: ['None', 'Street Deck', 'Longboard Dancer', 'Cruiser']},
{ name: 'mold_design', caption: '<hr> <span class="category">Choose Your Mold</span>', type: 'group'},
{ name: 'mold_size', caption: 'Size', type: 'choice', values: [0, 1], initial: 0, captions: ['9.5" x 34" x 3"', '12" x 47" x 2"']},
{ name: 'board_design', caption: '<hr> <span class="category">Design Your Board</span> <br> <p style="font-size: 11px; font-weight: normal;"> Board Length: <span id="lengthDisplay"> </span>" <br> <span style="font-size: 9px; font-weight: normal;"> (To change this, update wheelbase,<br> nose length, and tail length.) </span> </p>', type: 'group'},
{ name: 'profile', type: 'checkbox', checked: false, caption: 'Show Board Outline, Only <br>(Faster rendering)'},
{ name: 'width', type: 'float', initial: 8.25, step: 0.125, caption: 'Width, inches'},
{ name: 'wheelbase', type: 'float', initial: 14.0, step: 0.125, caption: 'Wheelbase, inches'},
{ name: 'nose_length', type: 'float', initial: 6.75, step: 0.125, caption: 'Nose Length, inches'},
{ name: 'tail_length', type: 'float', initial: 6.75, step: 0.125, caption: 'Tail Length, inches'},
{ name: 'concave_drop', type: 'float', initial: 0.4, step: 0.1, max: 0.6, min: 0.0, caption: 'Concave Drop, in.'}, // concave_radius=0, make flat board
{ name: 'kicknose_angle', type: 'float', initial: 20.0, step: 1, min: 0, max: 25.0, caption: 'Kicknose, deg.'},
{ name: 'kicktail_angle', type: 'float', initial: 20.0, step: 1, min: 0, max: 25.0, caption: 'Kicktail, deg.'},
{ name: 'nose_radius', type: 'float', initial: 6, step: 1, max: 20, min: 4, caption: 'Nose Radius, in.'},
{ name: 'tail_radius', type: 'float', initial: 6, step: 1, max: 20, min: 4, caption: 'Tail Radius, in.'},
{ name: 'kick_gap', type: 'float', initial: 1, step: 0.125, max: 3, min: 0, caption: 'Kick Gap'},
{ name: 'taperN', type: 'float', initial: 6.75, step: 0.125, caption: 'Nose Taper Point, in.'},
{ name: 'taperT', type: 'float', initial: 6.75, step: 0.125, caption: 'Tail Taper Point, in.'},
{ name: 'nose_adjust', type: 'slider', class: 'paramSlider', min: 50, max: 100, initial: 70, step: 1, caption: 'Nose Shape'},
{ name: 'tail_adjust', type: 'slider', class: 'paramSlider', min: 50, max: 100, initial: 75, step: 1, caption: 'Tail Shape'},
{ name: 'cutout_specs', caption: '<hr> <span class="category">Wheel Cutouts</span>', type: 'group'},
{ name: 'make_cutouts', type: 'checkbox', checked: false, caption: 'Make Cutouts'},
{ name: 'noseLipX', type: 'slider', class: 'paramSlider', min: 5, max: 18, step: 0.5, initial: 14.5, caption: 'Nose Cutout Depth'},
{ name: 'noseLipY', type: 'slider', class: 'paramSlider', min: -2, max: 4, step: 0.5, initial: 1, caption: 'Nose Cutout Width'},
{ name: 'noseY', type: 'slider', class: 'paramSlider', min: 2, max: 9, initial: 6, step: 0.5, caption: 'Nose Width'},
{ name: 'tailLipX', type: 'slider', class: 'paramSlider', min: 5, max: 18, step: 0.5, initial: 14.5, caption: 'Tail Cutout Depth'},
{ name: 'tailLipY', type: 'slider', class: 'paramSlider', min: -2, max: 4, step: 0.5, initial: 1, caption: 'Tail Cutout Width'},
{ name: 'tailY', type: 'slider', class: 'paramSlider', min: 2, max: 9, initial: 6, step: 0.5, caption: 'Tail Width'},
{ name: 'resolution', type: 'float', initial: 0.25, step: 0.0625, caption: '<hr>Model Resolution<br><span style="font-size: 9px;">(For advanced users)</span><hr>'}
]);
}
/*
Interactive parametric models
It is possible to make certain parameters editable in the browser. This allows users not familiar with JavaScript to create customized STL files.
To do so, add a function getParameterDefinitions() to your .jscad source. This function should return an array with parameter definitions. Currently 6 parameters types are supported: float, int, text, longtext, bool and choice. The user edited values of the parameters will be supplied as an object parameter to the main() function of your .jscad file.
*/
function main (parameters)
{
//var mold = parameters.mold;
var display = parameters.display_item;
var mold_size;
var showProfile = parameters.profile;
//var profile_choice = parameters.profile_choice;
//var mold_choice = parameters.mold_choice;
var mold_choice = '0';
var profile_choice = mold_choice;
var make_cutouts;
var width;
var wheelbase;
var tail_length;
var nose_length;
var nose_shape;
var tail_shape;
var taperN;
var taperT;
var noseLipX;
var noseLipY;
var noseY;
var tailLipX;
var tailLipY;
var tailY;
var concave_drop;
var concave_radius;
var kicknose_angle;
var kicktail_angle;
var kicknose_radius;
var kicktail_radius;
var kick_gap;
var thickness = 0.4375;
var bolt_pattern_width = 1.625;
var bolt_pattern_length = 2.125;
var nose_transition_length;
var tail_transition_length;
nose_transition_length = 4;
tail_transition_length = 4;
var mold_length;
var mold_width;
var mold_height;
if (profile_choice == '0') {
width = parameters.width;
wheelbase = parameters.wheelbase;
tail_length = parameters.tail_length;
nose_length = parameters.nose_length;
nose_shape = parameters.nose_adjust/100;
tail_shape = parameters.tail_adjust/100;
taperN = parameters.taperN;
taperT = parameters.taperT;
noseLipX = parameters.noseLipX;
noseLipY = parameters.noseLipY;
noseY = parameters.noseY;
tailLipX = parameters.tailLipX;
tailLipY = parameters.tailLipY;
tailY = parameters.tailY;
make_cutouts = parameters.make_cutouts;
}
else {
switch (profile_choice) {
case '1': //street deck;
width = 8.25;
wheelbase = 14;
tail_length = 6.75;
nose_length = 6.75;
nose_shape = 70/100;
tail_shape = 70/100;
taperN = 6.75;
taperT = 6.75;
noseLipX = parameters.noseLipX;
noseLipY = parameters.noseLipY;
noseY = parameters.noseY;
tailLipX = parameters.tailLipX;
tailLipY = parameters.tailLipY;
tailY = parameters.tailY;
make_cutouts = false;
break;
case '2': //dancer
width = 9;
wheelbase = 30;
tail_length = 5;
nose_length = 5;
nose_shape = 70/100;
tail_shape = 70/100;
taperN = 15;
taperT = 15;
noseLipX = 15;
noseLipY = 1;
noseY = 6;
tailLipX = 15;
tailLipY = 1;
tailY = 6;
make_cutouts = true;
break;
case '3': //cruiser
width = 8.25;
wheelbase = 15;
tail_length = 6.5;
nose_length = 5;
nose_shape = 60/100;
tail_shape = 82/100;
taperN = 10;
taperT = 12;
noseLipX = 15;
noseLipY = 1;
noseY = 6;
tailLipX = 15;
tailLipY = 1;
tailY = 6;
make_cutouts = false;
break;
}
}
if (mold_choice == '0') {
concave_drop = parseFloat(parameters.concave_drop);
concave_radius = (Math.pow((width/2),2) + Math.pow(concave_drop,2))/(2*concave_drop);
if (concave_drop == 0) {
concave_radius = 0;
}
kicknose_angle = parameters.kicknose_angle;
kicktail_angle = parameters.kicktail_angle;
kicknose_radius = parameters.nose_radius;
kicktail_radius = parameters.tail_radius;
kick_gap = parseFloat(parameters.kick_gap);
mold_size = parameters.mold_size;
}
else {
switch (mold_choice) {
case '1': //street deck
concave_drop = 0.375;
concave_radius = (Math.pow((width/2),2) + Math.pow(concave_drop,2))/(2*concave_drop);
if (concave_drop == 0) {
concave_radius = 0;
}
kicknose_angle = 20;
kicktail_angle = 20;
kicknose_radius = 6;
kicktail_radius = 6;
kick_gap = 1;
mold_size = '0';
break;
case '2': //dancer
concave_drop = 0.125;
concave_radius = (Math.pow((width/2),2) + Math.pow(concave_drop,2))/(2*concave_drop);
if (concave_drop == 0) {
concave_radius = 0;
}
kicknose_angle = 12;
kicktail_angle = 12;
kicknose_radius = 6;
kicktail_radius = 6;
kick_gap = 1;
mold_size = '1';
break;
case '3': //cruiser
concave_drop = 0.25;
concave_radius = (Math.pow((width/2),2) + Math.pow(concave_drop,2))/(2*concave_drop);
if (concave_drop == 0) {
concave_radius = 0;
}
kicknose_angle = 12;
kicktail_angle = 21;
kicknose_radius = 6;
kicktail_radius = 6;
kick_gap = 1;
mold_size = '0';
break;
}
}
switch (mold_size) {
case '0':
mold_length = 34;
mold_width = 9.5;
mold_height = 3;
break;
case '1':
mold_length = 47;
mold_width = 12;
mold_height = 2;
break;
}
/*switch (mold) {
case '0':
kick_to_kick = 21; //placeholder, not used
break;
case '1': //13-16-11A22-05
concave_radius = 16.25;
kicknose_angle = 11;
kicktail_angle = 22;
nose_transition_length = 4.5;
tail_transition_length = 4.5;
kicknose_radius = 5;
kicktail_radius = 5;
kick_to_kick = 19.25;
break;
case '2': //asymmetrical - mid
concave_radius = 22.875;
kicknose_angle = 16;
kicktail_angle = 19;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 6;
kicktail_radius = 8;
kick_to_kick = 20.25;
break;
case '3': //13-20-21-05
concave_radius = 20;
kicknose_angle = 21;
kicktail_angle = 21;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 5;
kicktail_radius = 5;
kick_to_kick = 20.375;
break;
case '4': //14-34-15-06
concave_radius = 34;
kicknose_angle = 15;
kicktail_angle = 15;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 6;
kicktail_radius = 6;
kick_to_kick = 19.5;
break;
case '5': //14-62-14-09
concave_radius = 62;
kicknose_angle = 14;
kicktail_angle = 14;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 9;
kicktail_radius = 9;
kick_to_kick = 20.25;
break;
case '6': //14-33-18-10
concave_radius = 33;
kicknose_angle = 18;
kicktail_angle = 18;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 10;
kicktail_radius = 10;
kick_to_kick = 20.25;
break;
case '7': //14-20-18-09
concave_radius = 20;
kicknose_angle = 18;
kicktail_angle = 18;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 9;
kicktail_radius = 9;
kick_to_kick = 20.25;
break;
case '8': //14-20-20-09
concave_radius = 20;
kicknose_angle = 20;
kicktail_angle = 20;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 9;
kicktail_radius = 9;
kick_to_kick = 20.125;
break;
case '9': //medium
concave_radius = 20;
kicknose_angle = 19;
kicktail_angle = 19;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 6;
kicktail_radius = 6;
kick_to_kick = 20.25;
break;
case '10': //14-18-21-05
concave_radius = 18;
kicknose_angle = 21;
kicktail_angle = 21;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 5;
kicktail_radius = 5;
kick_to_kick = 21.125;
break;
case '11': //big medium (hammerhead)
concave_radius = 19;
kicknose_angle = 20;
kicktail_angle = 20;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 9;
kicktail_radius = 9;
kick_to_kick = 21.25;
break;
case '12': //XL medium
concave_radius = 25;
kicknose_angle = 20;
kicktail_angle = 20;
nose_transition_length = 4;
tail_transition_length = 4;
kicknose_radius = 9;
kicktail_radius = 9;
kick_to_kick = 22.25;
break;
}
*/
kick_to_kick = wheelbase + (2*bolt_pattern_length)+ (2*kick_gap);
var kicknose_length = (wheelbase/2) + bolt_pattern_length + nose_length - (kick_to_kick/2);
var kicktail_length = (wheelbase/2) + bolt_pattern_length + tail_length - (kick_to_kick/2);
var slice_thickness = parseFloat(parameters.resolution);
var min_radius = concave_radius;
var length = wheelbase + (bolt_pattern_length*2) + tail_length + nose_length;
var concave_length = length - (kicktail_length + kicknose_length + nose_transition_length + tail_transition_length);
var flat_concave_length = concave_length + nose_transition_length + tail_transition_length;
//find kicknose translation parameters
var kicknose_hypotenuse = 2*(kicknose_radius*sin(kicknose_angle/2));
var kicknose_radius_length = kicknose_hypotenuse*cos(kicknose_angle/2);
var kicknose_radius_height = kicknose_hypotenuse*sin(kicknose_angle/2);
//find kicktail translation parameters
var kicktail_hypotenuse = 2*(kicktail_radius*sin(kicktail_angle/2));
var kicktail_radius_length = kicktail_hypotenuse*cos(kicktail_angle/2);
var kicktail_radius_height = kicktail_hypotenuse*sin(kicktail_angle/2);
var number_of_segments = 10; //for transition section resolution
var skateboard;
var depth = 1;
console.log("test");
if (showProfile == true) {
if (make_cutouts == false) {
skateboard = make_profile(width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, depth);
}
else {
skateboard = make_lb_profile(width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, depth, noseLipX, noseLipY, noseY, tailLipX, tailLipY, tailY)
}
}
else {
if (display == 1) {
skateboard = make_concave(concave_radius, thickness, concave_length, width,flat_concave_length).translate([0,0,thickness]);
if (kicknose_angle !== 0) {
skateboard = skateboard.union(make_kicknose_curve(kicknose_radius, thickness, width, kicknose_angle, nose_transition_length, concave_length));
}
else {
skateboard = skateboard.union(make_concave(concave_radius, thickness, concave_length, width,flat_concave_length).translate([concave_length,0,thickness]));
}
if (kicktail_angle !== 0) {
skateboard = skateboard.union(make_kicktail_curve(kicktail_radius, thickness, width, kicktail_angle, tail_transition_length, concave_length));
}
else {
skateboard = skateboard.union(make_concave(concave_radius, thickness, concave_length, width,flat_concave_length).translate([-concave_length,0,thickness]));
}
if (kicknose_angle !== 0) {
skateboard = skateboard.union(make_kicknose_section(wheelbase, bolt_pattern_length, nose_length, kicknose_length, kicknose_radius_length, width, kicknose_radius_height, thickness, kicknose_angle, nose_transition_length, concave_length));
}
if (kicktail_angle !== 0) {
skateboard = skateboard.union(make_kicktail_section(wheelbase, bolt_pattern_length, tail_length, kicktail_length, kicktail_radius_length, width, kicktail_radius_height, thickness, kicktail_angle, tail_transition_length, concave_length));
}
if (concave_radius!==0) {
if (kicknose_angle !== 0) {
skateboard = skateboard.union(
((rotate([0,0,90], make_transition_section(nose_transition_length, thickness, slice_thickness, width, min_radius, number_of_segments)))).translate([concave_length/2+nose_transition_length,0,0]));
}
if (kicktail_angle !== 0) {
skateboard = skateboard.union(
((rotate([0,0,-90], make_transition_section(tail_transition_length, thickness, slice_thickness, width, min_radius, number_of_segments)))).translate([-(concave_length/2+tail_transition_length),0,0]));
}
}
var profile;
if (make_cutouts == false) {
profile = make_profile(width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, 10);
}
else {
profile = make_lb_profile(width, wheelbase, bolt_pattern_length, nose_length, tail_length, length, taperN, taperT, 10, noseLipX, noseLipY, noseY, tailLipX, tailLipY, tailY)
}
skateboard = skateboard.intersect(profile);
}
else {
if (kicknose_angle !== 0) {
kicknose = make_mold_kicknose_curve(kicknose_radius, mold_width, kicknose_angle, nose_transition_length, concave_length, kicknose_length);
}
else {
kicknose = make_mold_concave(concave_radius, mold_height, concave_length, mold_width,flat_concave_length).translate([concave_length,0,0]);
}
if (kicktail_angle !== 0) {
kicktail = make_mold_kicktail_curve(kicktail_radius, mold_width, kicktail_angle, tail_transition_length, concave_length, kicktail_length);
}
else {
kicktail = make_mold_concave(concave_radius, mold_height, concave_length, mold_width,flat_concave_length).translate([-concave_length,0,0]);
}
var mold = color([0.7,0.7,0.7],make_mold_concave(concave_radius, mold_height, concave_length, mold_width, flat_concave_length));
mold = mold.union(color([.5,.5,.5],kicknose));
mold = mold.union(color([.5,.5,.5],kicktail));
if (concave_radius !== 0) {
var nose_transition = make_mold_transition_section(nose_transition_length, mold_height+2, slice_thickness, mold_width, min_radius, number_of_segments);
var tail_transition = mirror([1,0,0], make_mold_transition_section(tail_transition_length, mold_height+2, slice_thickness, mold_width, min_radius, number_of_segments));
if (kicknose_angle !== 0) {
mold = mold.union(color([0.2,0.2,0.2],nose_transition.translate([concave_length/2+nose_transition_length,0,0])));
}
if (kicktail_angle !== 0) {
mold = mold.union(color([0.2,0.2,0.2],tail_transition.translate([-concave_length/2-tail_transition_length,0,0])));
}
}
mold = mold.intersect(color([0.7,0.7,0.7], cube({size: [mold_length, mold_width, mold_height], center: true}).translate([(nose_transition_length-tail_transition_length+nose_length-tail_length)/2,0,-mold_height/2])));
skateboard = mold;
}
}
var mDia = 0.5; //notch diameter
if (display == '0') {
skateboard = skateboard.subtract(make_markers(mold_width, wheelbase, nose_length, tail_length, bolt_pattern_length, mDia, kick_gap, nose_transition_length, tail_transition_length));
}
if (display !== '0' || showProfile == true) {
skateboard = skateboard.subtract(make_wheelbase(bolt_pattern_length, bolt_pattern_width,wheelbase));
}
skateboard = color([0,0.99,0],skateboard);
return skateboard;
}
function make_origin(origin)
{
var result = new CSG();
var height = 20;
result = union(
cylinder({d: 0.25, h: height, center: true}).translate([0,0,height/2]),
union(
rotate([-90,0,0],cylinder({d: 0.25, h: height, center: true}).translate([0,0,height/2])),
rotate([0,90,0],cylinder({d: 0.25, h: height, center: true}).translate([0,0,height/2]))
)
);
return result;
}
function make_markers(width, wheelbase, nose_length, tail_length, boltL, mDia, kick_gap, noseT, tailT) {
var result = new CSG();
result = sphere({r: mDia/2, center: true});
result = result.translate([(wheelbase/2+boltL+kick_gap+((noseT-tailT)/2)),(width/2),0]);
result = result.union(sphere({r: mDia/2, center: true}).translate([(wheelbase/2+boltL+kick_gap+((noseT-tailT)/2)),-(width/2),0]));
result = result.union(sphere({r: mDia/2, center: true}).translate([-(wheelbase/2+boltL+kick_gap-((noseT-tailT)/2)),-(width/2),0]));
result = result.union(sphere({r: mDia/2, center: true}).translate([-(wheelbase/2+boltL+kick_gap-((noseT-tailT)/2)),(width/2),0]));
return result;
}
function make_bolt_pattern(bolt_pattern_length, bolt_pattern_width)
{
var result = new CSG();
result = (cylinder({d: 0.1875, h: 6, center: false}).translate([bolt_pattern_length/2,bolt_pattern_width/2,0])).union(cylinder({d: 0.1875, h: 6, center: false}).translate([bolt_pattern_length/2,-bolt_pattern_width/2,0]));
result = result.union(cylinder({d: 0.1875, h: 6, center: false}).translate([-bolt_pattern_length/2,-bolt_pattern_width/2,0]));
result = result.union(cylinder({d: 0.1875, h: 6, center: false}).translate([-bolt_pattern_length/2,bolt_pattern_width/2,0]));
return result;
}
function make_wheelbase(bolt_pattern_length, bolt_pattern_width, wheelbase)
{
var result = new CSG();
result = (make_bolt_pattern(bolt_pattern_length,bolt_pattern_width).translate([(wheelbase/2)+(bolt_pattern_length/2),0,-1])).union(make_bolt_pattern(bolt_pattern_length,bolt_pattern_width).translate([-((wheelbase/2)+(bolt_pattern_length/2)),0,-1]));
return result;
}
function make_concave(concave_radius, thickness, concave_length, width, flat_concave_length)
{
var result = new CSG();
if(concave_radius==0){
result = cube({size:[flat_concave_length,width,thickness]});
result = result.translate([-flat_concave_length/2,-width/2,-thickness]);
return result;
}
else{
result=
difference(
difference(
difference(
(rotate([90,0,90], difference(
cylinder({r: (concave_radius + thickness), h: concave_length, center: true, fn: 500}),
cylinder({r: concave_radius, h:concave_length+2, center: true, fn: 500}).translate([0,0,1])))
).translate([-concave_length/2,0,concave_radius]),
cube({size: [concave_length*2, concave_radius*4, concave_radius*4]}).translate([-concave_length, -concave_radius * 2 + 10, concave_radius])
),
cube({size: [concave_length*4, concave_radius*2, concave_radius*2], center: false}).translate([-concave_length*2, width/2, 0])
),
mirror([0,1,0], cube({size: [concave_length*4, concave_radius*2, concave_radius*2], center: false}).translate([-concave_length*2, width/2, 0]))
);
return result.translate([concave_length/2,0,0]);
}
}
function make_mold_concave(concave_radius, thickness, concave_length, width, flat_concave_length)
{
var result = new CSG();
if(concave_radius==0){
result = cube({size:[flat_concave_length,width,thickness]});
result = result.translate([-flat_concave_length/2,-width/2,-thickness]);
return result;
}
else{
result = rotate([90,0,90],cylinder({r: concave_radius, h: concave_length, center: true, fn: 500})).translate([0,0,-concave_radius]);
return result;
/*result=
difference(
difference(
difference(
(rotate([90,0,90], difference(
cylinder({r: (concave_radius + thickness), h: concave_length, center: true, fn: 100}),
cylinder({r: concave_radius, h:concave_length+2, center: true, fn: 100}).translate([0,0,1])))
).translate([-concave_length/2,0,concave_radius]),
cube({size: [concave_length*2, concave_radius*4, concave_radius*4]}).translate([-concave_length, -concave_radius * 2 + 10, concave_radius])
),
cube({size: [concave_length*4, concave_radius*2, concave_radius*2], center: false}).translate([-concave_length*2, width/2, 0])
),
mirror([0,1,0], cube({size: [concave_length*4, concave_radius*2, concave_radius*2], center: false}).translate([-concave_length*2, width/2, 0]))
);
return result.translate([concave_length/2,0,0]);*/
}
}
function make_kicknose_curve(kicknose_radius, thickness, width, kicknose_angle, nose_transition_length, concave_length)
{
var result = new CSG();
result =
difference(
difference(
rotate([90,0,90], difference(
cylinder({r: kicknose_radius+thickness, h: width, center: false, fn: 100}),
cylinder({r: kicknose_radius, h: width+2, center: false, fn: 100}).translate([0,0,-1])
)),
rotate([0,0,90], cube({size: [kicknose_radius*2, width*4, kicknose_radius*4], center: false}).translate([-kicknose_radius*2, -width*2, -kicknose_radius-2])
)),
mirror([1,0,0], rotate([0, kicknose_angle, -90], cube({size: [kicknose_radius*2, width*4, kicknose_radius*4], center: false}).translate([-kicknose_radius*2, -width*2, -kicknose_radius*2])))
).translate([0,0,kicknose_radius+thickness]);
result = rotate([0,0,-90],(result.translate([-width/2,0,0])));
result = result.translate([concave_length/2+nose_transition_length,0,0]);
return result;
}
function make_kicktail_curve(kicktail_radius, thickness, width, kicktail_angle, tail_transition_length, concave_length)
{
var result = new CSG();
result =
mirror([0,1,0],
difference(
difference(
rotate([90,0,90], difference(
cylinder({r: kicktail_radius+thickness, h: width, center: false, fn: 100}),
cylinder({r: kicktail_radius, h: width+2, center: false, fn: 100}).translate([0,0,-1])
)),
rotate([0,0,90], cube({size: [kicktail_radius*2, width*4, kicktail_radius*4], center: false}).translate([-kicktail_radius*2, -width*2, -kicktail_radius-2])
)),
mirror([1,0,0], rotate([0, kicktail_angle, -90], cube({size: [kicktail_radius*2, width*4, kicktail_radius*4], center: false}).translate([-kicktail_radius*2, -width*2, -kicktail_radius*2])))
).translate([0,0,kicktail_radius+thickness])
);
result = rotate([0,0,-90],(result.translate([-width/2,0,0])));
result = result.translate([-concave_length/2-tail_transition_length,0,0]);
return result;
}
function make_mold_kicknose_curve(kicknose_radius, width, kicknose_angle, nose_transition_length, concave_length, kicknose_length)
{
var result = new CSG();
result = rotate([90,0,0],cylinder({r: kicknose_radius, h:width, center: false, fn: 500}));
result = difference(result,cube({size: [kicknose_radius*2, width*4, kicknose_radius*4]}).translate([-kicknose_radius*2, -width*2, -kicknose_radius-2]))
result = result.subtract((rotate([0,kicknose_angle,0], cube({size: [kicknose_length+kicknose_radius, width, kicknose_radius*2], center: false}).translate([0,-width,0]))));
result = result.subtract(cube({size: [kicknose_radius+2,width,kicknose_radius], center: false}).translate([0,-width,-kicknose_radius]));
result = result.union(rotate([0,kicknose_angle,0],cube({size:[kicknose_length+10,width,kicknose_radius]})).translate([0,-width,0]));
result = result.translate([(concave_length/2+nose_transition_length),width/2,-kicknose_radius]);
// result = result.intersect((rotate([0,kicknose_angle,0], cube({size: [kicknose_length+10, width, kicknose_radius*4], center: false}))).translate([-(kicknose_length+10)/2,0,0]));
//result = result.union((rotate([0,kicknose_angle,0], cube({size: [kicknose_length+10, width, kicknose_radius*2], center: false}))).translate([-(kicknose_length+10)/2,0,0]));
return result;
}
function make_mold_kicktail_curve(kicktail_radius, width, kicktail_angle, tail_transition_length, concave_length, kicktail_length)
{
var result = new CSG();
result = rotate([90,0,0],cylinder({r: kicktail_radius, h:width, center: false, fn: 500}));
result = difference(result,cube({size: [kicktail_radius*2, width*4, kicktail_radius*4]}).translate([-kicktail_radius*2, -width*2, -kicktail_radius-2]))
result = result.subtract((rotate([0,kicktail_angle,0], cube({size: [kicktail_length+kicktail_radius, width, kicktail_radius*2], center: false}).translate([0,-width,0]))));
result = result.subtract(cube({size: [kicktail_radius+2,width,kicktail_radius], center: false}).translate([0,-width,-kicktail_radius]));
result = result.union(rotate([0,kicktail_angle,0],cube({size:[kicktail_length+10,width,kicktail_radius]})).translate([0,-width,0]));
result = mirror([1,0,0], result);
result = result.translate([(-(concave_length/2+tail_transition_length)),width/2,-kicktail_radius]);
//result = result.intersect((rotate([0,kicktail_angle,0], cube({size: [kicktail_length+10, width, kicktail_radius*4], center: false}))).translate([-(kicktail_length+10)/2,0,0]));
//result = result.union((rotate([0,kicktail_angle,0], cube({size: [kicktail_length+10, width, kicktail_radius*2], center: false}))).translate([-(kicktail_length+10)/2,0,0]));
return result;
}
function make_kicknose_section(wheelbase, bolt_pattern_length, nose_length, kicknose_length, kicknose_radius_length, width, kicknose_radius_height, thickness, kicknose_angle, nose_transition_length, concave_length)
{
var result = new CSG();
result = mirror([0,0,1], cube({size: [kicknose_length, width, thickness]}));
result = rotate([0,-kicknose_angle,0],result);
result = result.translate([concave_length/2+nose_transition_length+kicknose_radius_length,-width/2,kicknose_radius_height+thickness]);
return result;
}
function make_kicktail_section(wheelbase, bolt_pattern_length, tail_length, kicktail_length, kicktail_radius_length, width, kicktail_radius_height, thickness, kicktail_angle, tail_transition_length, concave_length)
{
var result = new CSG();
result = mirror([0,0,1], cube({size: [kicktail_length, width, thickness]}));
result = rotate([0,-kicktail_angle,0],result);
result = mirror([1,0,0], result);
result = result.translate([-(concave_length/2+tail_transition_length+kicktail_radius_length),-width/2,kicktail_radius_height+thickness]);
return result;
}
function make_transition_section(transition_length, thickness, slice_thickness, width, min_radius, number_of_segments)
{
var result = new CSG();
var number_of_steps = transition_length/slice_thickness;
var concave_depth = (2*min_radius-sqrt(pow(2*min_radius,2)-(4*1*pow(width,2)/4)))/(2*1);
var mid_depth = concave_depth/2;
var mid_radius = (pow(mid_depth,2)+(pow(width,2)/4))/(2*mid_depth);
// var max_radius = pow(mid_radius,2);
//if poor transition, uncomment the following and comment the above:
var max_radius = 6*mid_radius;
var correction = mid_radius;
var radius_range = max_radius - min_radius;
var radius_offset = min_radius;
var sub_radius_range = (max_radius+thickness) - (min_radius+thickness);
var sub_radius_offset = min_radius+thickness;
//y values for edges of arc
var normal_y = ((2*min_radius)-Math.sqrt(Math.pow(2*min_radius,2)-(4*Math.pow((width/2),2))))/(2); //concave depth
var flat_y = 0; //no concave
//1/16/21 EDIT: change to cubic Bezier curve
// B(t) = [(1-t)^3]P0 + 3[(1-t)^2]tP1 + 3[(1-t)t^2]P2 + (t^3)P3
var i_range = 1; //range for t, which must be 0 <= t <= 1
var i_size = i_range/number_of_steps; //change in x value per change in step
var origin_x = 0;
var origin_y = 0;
var a = 0; //initial t value of Bezier
a = a+i_size; //prevent dividing by 0
var x0 = 0;
var x1 = transition_length/4;
var x2 = transition_length*(2/3);
var x3 = transition_length;
var y0 = 0;
var y1 = 0;
var y2 = concave_depth;
var y3 = concave_depth;
var slice_adj = 0;
var x_val_last = 0;
for (var i = a; i <= i_range; i=i+i_size) //starting at 0, going until 1, increment at i_size
{
/* if (i < 0) {
var y_val = normal_y+((flat_y-normal_y)/(1+Math.exp(i*1.25)));
}
else {
var y_val = normal_y+((flat_y-normal_y)/(1+Math.exp(i)));
}
*/
// 1/16/21 EDIT: Bezier curve:
var t = i;
var x_val = ((Math.pow((1-t),3))*x0)+(3*(Math.pow((1-t),2))*t*x1)+(3*((1-t))*Math.pow(t,2)*x2)+(Math.pow(t,3)*x3);
var y_val = ((Math.pow((1-t),3))*y0)+(3*(Math.pow((1-t),2))*t*y1)+(3*((1-t))*Math.pow(t,2)*y2)+(Math.pow(t,3)*y3);
console.log(x_val + ',' + y_val);
var reg_radius = (Math.pow((width/2),2) + Math.pow(y_val,2))/(2*y_val);
var reg_half_angle = asin((width/2)/reg_radius);
var reg_segment_angle = reg_half_angle/number_of_segments;
var sub_radius = reg_radius+thickness;
var sub_half_angle = asin((width/2)/sub_radius);
var sub_segment_angle = sub_half_angle/number_of_segments;
result = result.union(
linear_extrude({height: x_val-x_val_last, center: false},
polygon({ //currently set up for 20 segments per full arc:
points: [
[(sub_radius*sin(sub_segment_angle*0)),(sub_radius*cos(sub_segment_angle*0))],
[(sub_radius*sin(sub_segment_angle*1)),(sub_radius*cos(sub_segment_angle*1))],
[(sub_radius*sin(sub_segment_angle*2)),(sub_radius*cos(sub_segment_angle*2))],
[(sub_radius*sin(sub_segment_angle*3)),(sub_radius*cos(sub_segment_angle*3))],
[(sub_radius*sin(sub_segment_angle*4)),(sub_radius*cos(sub_segment_angle*4))],
[(sub_radius*sin(sub_segment_angle*5)),(sub_radius*cos(sub_segment_angle*5))],
[(sub_radius*sin(sub_segment_angle*6)),(sub_radius*cos(sub_segment_angle*6))],
[(sub_radius*sin(sub_segment_angle*7)),(sub_radius*cos(sub_segment_angle*7))],
[(sub_radius*sin(sub_segment_angle*8)),(sub_radius*cos(sub_segment_angle*8))],
[(sub_radius*sin(sub_segment_angle*9)),(sub_radius*cos(sub_segment_angle*9))],
[(sub_radius*sin(sub_segment_angle*10)),(sub_radius*cos(sub_segment_angle*10))],
[(reg_radius*sin(reg_segment_angle*10)),(reg_radius*cos(reg_segment_angle*10))],
[(reg_radius*sin(reg_segment_angle*9)),(reg_radius*cos(reg_segment_angle*9))],
[(reg_radius*sin(reg_segment_angle*8)),(reg_radius*cos(reg_segment_angle*8))],
[(reg_radius*sin(reg_segment_angle*7)),(reg_radius*cos(reg_segment_angle*7))],
[(reg_radius*sin(reg_segment_angle*6)),(reg_radius*cos(reg_segment_angle*6))],
[(reg_radius*sin(reg_segment_angle*5)),(reg_radius*cos(reg_segment_angle*5))],
[(reg_radius*sin(reg_segment_angle*4)),(reg_radius*cos(reg_segment_angle*4))],
[(reg_radius*sin(reg_segment_angle*3)),(reg_radius*cos(reg_segment_angle*3))],
[(reg_radius*sin(reg_segment_angle*2)),(reg_radius*cos(reg_segment_angle*2))],
[(reg_radius*sin(reg_segment_angle*1)),(reg_radius*cos(reg_segment_angle*1))],
[(reg_radius*sin(reg_segment_angle*0)),(reg_radius*cos(reg_segment_angle*0))]
]
})).translate([0,-sub_radius,x_val_last])
);
x_val_last = x_val;
slice_adj = slice_adj + slice_thickness;
}
result = result.union(mirror([1,0,0],result));
result = rotate([-90,0,0],result);
return result;
}
function make_mold_transition_section(transition_length, thickness, slice_thickness, width, min_radius, number_of_segments)
{
var result = new CSG();
var number_of_steps = transition_length/slice_thickness;
var concave_depth = (2*min_radius-sqrt(pow(2*min_radius,2)-(4*1*pow(width,2)/4)))/(2*1);
var mid_depth = concave_depth/2;
var mid_radius = (pow(mid_depth,2)+(pow(width,2)/4))/(2*mid_depth);
// var max_radius = pow(mid_radius,2);
//if poor transition, uncomment the following and comment the above:
var max_radius = 6*mid_radius;
var correction = mid_radius;
var radius_range = max_radius - min_radius;
var radius_offset = min_radius;
var sub_radius_range = (max_radius+thickness) - (min_radius+thickness);
var sub_radius_offset = min_radius+thickness;
//y values for edges of arc
var normal_y = ((2*min_radius)-Math.sqrt(Math.pow(2*min_radius,2)-(4*Math.pow((width/2),2))))/(2);
var flat_y = 0;
//for start and end tangency, plot hollow cylindrical arcs as a sigmoid function... y = 1/(1+e^x). Adjust for the radius size (multiply by the range), then offset for the minimum (add min_radius)
//1/16/21 EDIT: change to cubic Bezier curve
// B(t) = [(1-t)^3]P0 + 3[(1-t)^2]tP1 + 3[(1-t)t^2]P2 + (t^3)P3
var i_range = 1; //range for t, which must be 0 <= t <= 1
var i_size = i_range/number_of_steps; //change in x value per change in step
var origin_x = 0;
var origin_y = 0;
var a = 0; //initial t value of Bezier
a = a+i_size; //prevent dividing by 0
var x0 = 0;
var x1 = transition_length/4;
var x2 = transition_length*(2/3);
var x3 = transition_length;
var y0 = 0;
var y1 = 0;
var y2 = concave_depth;
var y3 = concave_depth;
var slice_adj = 0;
var x_val_last = 0;
for (var i = a; i <= i_range; i=i+i_size) //starting at 0, going until 1, increment at i_size
{
/*if (i < 0) {
var y_val = normal_y+((flat_y-normal_y)/(1+Math.exp(i*1.25)));
}
else {
var y_val = normal_y+((flat_y-normal_y)/(1+Math.exp(i)));
}*/
//(x - h)^2 + (y - k)^2 = R^2, where (h,k) is the center of the concave circle
//we know h = 0, since it is in line with the bottom of the circle
//we know two points: (0,0) and (width/2,y_val)
//Two equations:
//(0 - 0)^2 + (0 - k)^2 = R^2
// ---> k = R
//(width/2 - 0)^2 + (y_val - R)^2 = R^2
//(width/2)^2 + y_val^2 - 2R*y_val = 0
//2R*y_val = (width/2)^2 + y_val^2
// 1/16/21 EDIT: Bezier curve:
var t = i;
var x_val = ((Math.pow((1-t),3))*x0)+(3*(Math.pow((1-t),2))*t*x1)+(3*((1-t))*Math.pow(t,2)*x2)+(Math.pow(t,3)*x3);
var y_val = ((Math.pow((1-t),3))*y0)+(3*(Math.pow((1-t),2))*t*y1)+(3*((1-t))*Math.pow(t,2)*y2)+(Math.pow(t,3)*y3);
console.log(x_val + ',' + y_val);
var reg_radius = (Math.pow((width/2),2) + Math.pow(y_val,2))/(2*y_val);
// console.log("reg_radius is ");
console.log(reg_radius);
//var reg_radius = radius_offset+(radius_range/(1+Math.exp(i)));
var reg_half_angle = asin((width/2)/reg_radius);
var reg_segment_angle = reg_half_angle/number_of_segments;
//console.log("half angle is ");
// console.log(reg_half_angle);
result = result.union(
linear_extrude({height: x_val-x_val_last, center: false},
polygon({ //currently set up for 20 segments per full arc:
points: [
[(reg_radius*sin(reg_segment_angle*10)),(reg_radius*cos(reg_segment_angle*10))],
[(reg_radius*sin(reg_segment_angle*9)),(reg_radius*cos(reg_segment_angle*9))],
[(reg_radius*sin(reg_segment_angle*8)),(reg_radius*cos(reg_segment_angle*8))],
[(reg_radius*sin(reg_segment_angle*7)),(reg_radius*cos(reg_segment_angle*7))],
[(reg_radius*sin(reg_segment_angle*6)),(reg_radius*cos(reg_segment_angle*6))],
[(reg_radius*sin(reg_segment_angle*5)),(reg_radius*cos(reg_segment_angle*5))],
[(reg_radius*sin(reg_segment_angle*4)),(reg_radius*cos(reg_segment_angle*4))],
[(reg_radius*sin(reg_segment_angle*3)),(reg_radius*cos(reg_segment_angle*3))],
[(reg_radius*sin(reg_segment_angle*2)),(reg_radius*cos(reg_segment_angle*2))],
[(reg_radius*sin(reg_segment_angle*1)),(reg_radius*cos(reg_segment_angle*1))],
[(reg_radius*sin(reg_segment_angle*0)),(reg_radius*cos(reg_segment_angle*0))],
[(reg_radius*sin(reg_segment_angle*0)),(reg_radius*cos(reg_segment_angle*0))-5],
[(reg_radius*sin(reg_segment_angle*10)),(reg_radius*cos(reg_segment_angle*10))-5]
]
})).translate([0,-reg_radius,x_val_last])
//each slice is slice_thickness wide, so move that much each time
);
x_val_last = x_val;
slice_adj = slice_adj + slice_thickness;
}
result = result.union(mirror([1,0,0],result));
result = rotate([90,0,-90],result);
result = result.translate([0,0,0]);
return result;
}
function make_profile(width, wheelbase, boltL, nose_length, tail_length, length, taperN, taperT, nose_shape, tail_shape, depth)
{
var profile = new CSG.Path2D([[0,(width/2)],[(((wheelbase/2)+boltL+nose_length)-taperN),(width/2)]]);
profile = profile.appendBezier([[((((wheelbase/2)+boltL+nose_length)-taperN)+(nose_shape*(taperN))),(width/2)],[((wheelbase/2)+boltL+nose_length),(nose_shape*(width/2))],[((wheelbase/2)+boltL+nose_length),0]], {resolution: 100});
profile = profile.appendBezier([[((wheelbase/2)+boltL+nose_length),(-(nose_shape*(width/2)))],[((((wheelbase/2)+boltL+nose_length)-taperN)+(nose_shape*(taperN))),(-(width/2))],[(((wheelbase/2)+boltL+nose_length)-taperN),(-(width/2))]], {resolution: 100});
profile = profile.appendPoint([0,(-(width/2))]);
profile = profile.appendPoint([-(((wheelbase/2)+boltL+tail_length)-taperT),-(width/2)]);
profile = profile.appendBezier([[-((((wheelbase/2)+boltL+tail_length)-taperT)+(tail_shape*(taperT))),-(width/2)],[-((wheelbase/2)+boltL+tail_length),-(tail_shape*(width/2))],[-((wheelbase/2)+boltL+tail_length),0]], {resolution: 100});
profile = profile.appendBezier([[-((wheelbase/2)+boltL+tail_length),((tail_shape*(width/2)))],[-((((wheelbase/2)+boltL+tail_length)-taperT)+(tail_shape*(taperT))),((width/2))],[-(((wheelbase/2)+boltL+tail_length)-taperT),((width/2))]], {resolution: 100});
profile = profile.appendPoint([0,(width/2)]);
profile = profile.close();
var skateboard = profile.innerToCAG();
skateboard = linear_extrude({height: depth}, skateboard);
return skateboard;
}
function make_lb_profile(width, wheelbase, boltL, nose_length, tail_length, length, taperN, taperT, depth, noseLipX, noseLipY, noseY, tailLipX, tailLipY, tailY)
{
var res = 100; //resolution of bezier curves
var profile = new CSG.Path2D([[0,(width/2)],[(((wheelbase/2)+boltL+nose_length)-taperN),(width/2)]]);
profile = profile.appendBezier([[(noseLipX),(width/2)],[(noseLipX),(noseLipY)],[((wheelbase/2)+boltL+nose_length),(noseY)],[((wheelbase/2)+boltL+nose_length),0]], {resolution: res});
profile = profile.appendBezier([[((wheelbase/2)+boltL+nose_length),(-noseY)],[noseLipX,(-noseLipY)],[noseLipX,(-(width/2))],[(((wheelbase/2)+boltL+nose_length)-taperN),-(width/2)]], {resolution: res});
profile = profile.appendPoint([0,(-(width/2))]);
profile = profile.appendPoint([-(((wheelbase/2)+boltL+tail_length)-taperT),-(width/2)]);
profile = profile.appendBezier([[(-tailLipX),-(width/2)],[(-tailLipX),(-tailLipY)],[-(((wheelbase/2)+boltL+tail_length)),-(tailY)],[-(((wheelbase/2)+boltL+tail_length)),0]], {resolution: res});
profile = profile.appendBezier([[-(((wheelbase/2)+boltL+tail_length)),(tailY)],[-tailLipX,(tailLipY)],[-tailLipX,((width/2))],[-((((wheelbase/2)+boltL+tail_length))-taperT),(width/2)]], {resolution: res});
profile = profile.appendPoint([0,(width/2)]);
profile = profile.close();
var skateboard = profile.innerToCAG();
skateboard = linear_extrude({height: depth}, skateboard);
return skateboard;
}
Please consider donating.
Skatebird will be stoked for any contribution you can afford.
...
CNC Machined Foam Mold
Domestic (USA) shipping only at this time.
If you live outside of the US and would like to order, please contact Open Source Skateboards for a shipping quote.
Mold Info: Molds are CNC machined using high-density foam blanks. The top surface will have clear tape applied as a mold release, and 1/2" diameter notches will be made as shown to aid with board alignment.
Shipping: Molds ship in about 5-7 business days. Default shipping is economy ground - contact us if you'd like to know about alternative shipping methods, to pick up your mold, or for larger order quantities.
International customers: Please contact us for a shipping quote to place your order.
If you'd like additional customization - wheel flares, rocker, camber, alternative concaves, etc., please contact us for our design services.
Kraft Paper Template
$14.95
Example template
Templates are laser cut from kraft paper. Templates are custom made to order and typically ship within 3-7 business days.