• Win a Free Custom Engraved Brass Coin!!!
    As a way to introduce our brass coins to the community, we will raffle off a free coin during the month of August. Follow link ABOVE for instructions for entering.
  • SUBSCRIBE TO SHIPS IN SCALE TODAY!

    The beloved Ships in Scale Magazine is back and charting a new course for 2026!
    Discover new skills, new techniques, and new inspirations in every issue.

    NOTE THAT OUR NEXT ISSUE WILL BE MARCH/APRIL 2026

Viking Ship (Sail) - Revell 1:60

Nearly finished. I see now I might fill the vessels with something.
Pictures could be better also.
I have to say, life was pretty cramped on those ships. Even more so since this ship can have 32 rowers, and I only have 24 aboard.
20260419_125158.JPG
 
Here are the final (I hope) pictures.
I put some water, wine and gold in the vessels, be it a bit hard to see. (The wine should become transparent when the gel dries)

With hindsight I should have put a bit of a gap between yard and sail and I wish I would have been bolder with weathering the deck and mast and other woodwork; could have profited from more contrast I think.
Well, I am content with the result though! :p
IMG_8585h.jpgIMG_8587.jpgIMG_8591h.JPGIMG_8597.jpgIMG_8601h.JPGIMG_8606h.JPG
 
For those who are interested and also a bit into FreeCAD; this in the script to model the 3D sail mold.
It was such a bother and so much effort it would be a waste to keep it to myself. :p
Just open a python console (View - Panels - Python Console), copy paste the script and give enter once or twice.
You have to play a bit with the 'X_positions' and the 'horizontal_profiles' (which defines the basic paraboles defining the shape) to adapt the script for your own sails.
Then in the Surface and Part Workbenches you can turn it into a solid. Export it as an stl and it is 3D printable.

Python:
import FreeCAD, Part
import numpy as np

doc = FreeCAD.ActiveDocument

# -------------------------------------------------------
# Variables
# -------------------------------------------------------

X_positions = [0.0, 2.78, 5.56, 8.33, 11.11, 13.89, 16.67, 19.44, 22.22, 25.0]
num_points_vertical = 20
num_points_horizontal = 40
Z_plane = -3

horizontal_profiles = [
    [(0,0,0), (12.5,0,0), (25,0,0)],        
    [(0,-6,0.5), (12.5,-6,2), (25,-6,0.5)],  
    [(0,-10,-2), (12.5,-9,1), (25,-10,-2)]  
]

# -------------------------------------------------------
# Helpfunction paraboles
# -------------------------------------------------------

def parabola_3points(x_pts, y_pts):
    A = np.array([[x_pts[0]**2, x_pts[0],1],
                  [x_pts[1]**2, x_pts[1],1],
                  [x_pts[2]**2, x_pts[2],1]])
    Y = np.array(y_pts)
    return np.linalg.solve(A,Y)

# -------------------------------------------------------
# Calculate paraboles
# -------------------------------------------------------

top_a, top_b, top_c = parabola_3points(
    [p[0] for p in horizontal_profiles[0]],
    [p[2] for p in horizontal_profiles[0]]
)

mid_a, mid_b, mid_c = parabola_3points(
    [p[0] for p in horizontal_profiles[1]],
    [p[2] for p in horizontal_profiles[1]]
)

bot_a_z, bot_b_z, bot_c_z = parabola_3points(
    [p[0] for p in horizontal_profiles[2]],
    [p[2] for p in horizontal_profiles[2]]
)

bot_a_y, bot_b_y, bot_c_y = parabola_3points(
    [p[0] for p in horizontal_profiles[2]],
    [p[1] for p in horizontal_profiles[2]]
)

# -------------------------------------------------------
# Vertical splines
# -------------------------------------------------------

vertical_splines = []

for X in X_positions:

    Z_top = top_a*X**2 + top_b*X + top_c
    Z_mid = mid_a*X**2 + mid_b*X + mid_c
    Z_bot = bot_a_z*X**2 + bot_b_z*X + bot_c_z

    Y_top = horizontal_profiles[0][0][1]
    Y_mid = horizontal_profiles[1][0][1]
    Y_bot = bot_a_y*X**2 + bot_b_y*X + bot_c_y

    A = np.array([[Y_top**2, Y_top,1],
                  [Y_mid**2, Y_mid,1],
                  [Y_bot**2, Y_bot,1]])

    Z_vec = np.array([Z_top, Z_mid, Z_bot])
    a_v, b_v, c_v = np.linalg.solve(A, Z_vec)

    Y_sample = np.linspace(Y_top, Y_bot, num_points_vertical)
    pts = []

    for Y in Y_sample:
        Z = a_v*Y**2 + b_v*Y + c_v
        pts.append(FreeCAD.Vector(X,Y,Z))

    spline = Part.BSplineCurve()
    spline.interpolate(pts)
    edge = spline.toShape()

    vertical_splines.append(edge)
    Part.show(edge)

# -------------------------------------------------------
# Upper spline
# -------------------------------------------------------

top_pts = []
for X in np.linspace(0,25,num_points_horizontal):
    Z = top_a*X**2 + top_b*X + top_c
    Y = horizontal_profiles[0][0][1]
    top_pts.append(FreeCAD.Vector(X,Y,Z))

top_edge = Part.BSplineCurve()
top_edge.interpolate(top_pts)
top_edge = top_edge.toShape()
Part.show(top_edge)

# -------------------------------------------------------
# Lower spline
# -------------------------------------------------------

bottom_pts = []
for X in np.linspace(0,25,num_points_horizontal):
    Y = bot_a_y*X**2 + bot_b_y*X + bot_c_y
    Z = bot_a_z*X**2 + bot_b_z*X + bot_c_z
    bottom_pts.append(FreeCAD.Vector(X,Y,Z))

bottom_edge = Part.BSplineCurve()
bottom_edge.interpolate(bottom_pts)
bottom_edge = bottom_edge.toShape()
Part.show(bottom_edge)

doc.recompute()

# -------------------------------------------------------
# Show length
# -------------------------------------------------------

print("Spline 1 lengte :", vertical_splines[0].Length)
print("Spline 5 lengte :", vertical_splines[4].Length)

# -------------------------------------------------------
# Determine corners
# -------------------------------------------------------

left_top     = vertical_splines[0].Vertexes[0].Point
right_top    = vertical_splines[-1].Vertexes[0].Point
right_bottom = vertical_splines[-1].Vertexes[-1].Point
left_bottom  = vertical_splines[0].Vertexes[-1].Point

corner_points = [left_top, right_top, right_bottom, left_bottom]

# -------------------------------------------------------
# Extra spline between original lower corners
# -------------------------------------------------------

extra_bottom_spline = Part.BSplineCurve()
extra_bottom_spline.interpolate([left_bottom, right_bottom])
Part.show(extra_bottom_spline.toShape())

# -------------------------------------------------------
# Perpendicular splines to Z=-3
# -------------------------------------------------------

bottom_plane_points = []

for pt in corner_points:
    target = FreeCAD.Vector(pt.x, pt.y, Z_plane)
    spline = Part.BSplineCurve()
    spline.interpolate([pt, target])
    Part.show(spline.toShape())
    bottom_plane_points.append(target)

# -------------------------------------------------------
# Splines in Z=-3
# -------------------------------------------------------

for i in range(4):
    p1 = bottom_plane_points[i]
    p2 = bottom_plane_points[(i+1)%4]
    spline = Part.BSplineCurve()
    spline.interpolate([p1, p2])
    Part.show(spline.toShape())

doc.recompute()

print("Script execution is ready.")
 
Back
Top