Rendering these values. This takes a few seconds.
Download STL
Read this model as text

A MagSafe card wallet that prints flat in one go on a sheet of tulle and folds into shape. The panels are rigid plastic, the folds are fabric: between the panels there is no plastic at all, only the tulle that was printed into them. It has a card pocket, a note pocket, a seat for a stick-on magnet ring, and a phone stand whose foot slides in rails and clicks into place.

The image shows the solid OpenSCAD renders at cards 4 · cash_room 1.2 · magnet_diameter 56 · panel_thickness 1 · card_play 1 · fold 0 · stand 0 · color_wallet SteelBlue.

MIT

Origami MagSafe wallet and phone stand, printed flat on tulle

mick/origami-magsafe-wallet@1.0.0

Remix this
Report

For a legal or policy problem: a license violation, personal data, somebody else’s work republished as their own. A model that prints badly is a comment, not a report.

Sign in to report

0reused0 remixes · 0 imports1downloads1.0.0latest

Parameters

from source
25, steps of 1
0.62.4, steps of 0.2
5060, steps of 0.5
0.81.6, steps of 0.2
0.52, steps of 0.25
0100, steps of 5
0100, steps of 10

Showing the render for these values.

Description

What is this

A MagSafe card wallet that prints flat in one go on a sheet of tulle and folds into shape. The panels are rigid plastic, the folds are fabric: between the panels there is no plastic at all, only the tulle that was printed into them. It has a card pocket, a note pocket, a seat for a stick-on magnet ring, and a phone stand whose foot slides in rails and clicks into place.

What you use it for

Carrying three to five cards and a few notes on the back of a phone with a magnet ring, and propping the phone up on a desk. Sized to print in one piece on a 180 mm bed (Bambu A1 mini).

Printing: slice at 0.2 mm layers and add a pause at the start of layer 3. At the pause, lay polyester tulle over the whole print, pull it taut, fix it outside the print area and resume. The remaining layers print through the mesh and lock it in. Afterwards trim the tulle along the outlines but leave it in the four fold gaps: beside the back panel, below it, between the two legs of the stand and before the foot, and between front panel and divider. Slit the tulle with a knife in the thumb slot, around the two spring tongues and between the foot and its two spring arms.

Folding: divider up onto the front panel, front panel over the tray, stand flap around the bottom and flat onto the front, then slide the foot up into the rails until it clicks at the top. Stick the magnet ring into the groove on the outside of the back. For the stand, push the foot down to the first or second click while you lift the crease. To close, push the foot firmly back up.

Design notes

Earlier versions used folds of one or two plastic layers, and those split along the print lines. Fabric carries load in every direction, folds sharply and does not fatigue, so the folds are now tulle and the plastic only has to be stiff. The tulle lies 0.4 mm above the bed, two layers below it and three above.

The back is a shallow tray: a plate with a wall along the bottom and both sides, which is what makes the wallet rigid. The front panel hinges on the lower half of one side wall and lies on the walls. The divider hangs on the bottom of the front panel and folds up inside: cards between back and divider, notes folded in thirds between divider and front, both open at the top. The front panel stops 11 mm below the top of the back, so notes and cards stand proud of it.

The upper half of both side walls is taller and carries a rail with a 45 degree lip that prints without support. The foot of the stand is a crossbar captured under both lips. Because the foot always sits in the rails, it also holds the front panel shut, so the wallet needs no separate lock. The front panel is cut back beside the hinge-side rail so it can swing past it.

The foot has a spring arm on each side, cut in the plane of the sheet, with a tooth that drops into notches in the rail walls: top for closed, two lower ones for the stand. The tooth is gentle on the way down and steep on the way up, because the weight of the phone spreads the legs and pushes the foot up. A small bump at the lower end of each rail keeps the foot from sliding out. The back panel has a groove one layer deep for the magnet ring, a thumb slot inside the ring to slide the cards up when the wallet is off the phone, and two spring tongues with a low bump that keep the cards in.

The preview at fold above 0 shows the tulle in the folds as grey strips. They are not part of the print.

Parameters

cards and cash_room set how deep the tray is, and with that the width of the fold gaps. magnet_diameter is the outer diameter of your stick-on ring, the groove assumes a ring 5 mm wide. panel_thickness is the plastic, five layers of 0.2 by default, the tulle always goes in after two. card_play is the room around a card. fold and stand are preview only: fold 0 is what you print and 100 shows it folded, stand slides the foot down once fold is 100 and shows the phone. color_wallet is the display colour.

Use with your agent
{
  "mcpServers": {
    "remixcad": {
      "type": "http",
      "url": "https://remix-cad.vercel.app/api/mcp"
    }
  }
}
get_model("mick/origami-magsafe-wallet@1.0.0")

Returns the manifest, the source, the import closure and the license obligations. Full MCP setup.

Parameter table

Parsed from the Customizer annotations in main.scad
Parameters of Origami MagSafe wallet and phone stand, printed flat on tulle, with the ranges the source declares
NameDefaultRangeUnitDescription
cards42 to 5 step 1
cash_room1.20.6 to 2.4 step 0.2
magnet_diameter5650 to 60 step 0.5
panel_thickness10.8 to 1.6 step 0.2
card_play10.5 to 2 step 0.25
fold00 to 100 step 5
stand00 to 100 step 10
color_wallet"SteelBlue"SteelBlue, Silver, Gainsboro, White, DimGray, Black, SlateGray, FireBrick, ForestGreen, Goldenrod

Lineage

0 models depend on this one

Only what this model came from and what came from it.

Remix, the code changed Import, used unchanged and pinned The version you are on Withdrawn, still recorded

License

Whoever downloads this takes these obligations along
  • mick/origami-magsafe-wallet@1.0.0 is MIT

Source

main.scad is the entrypoint
main.scad
// A MagSafe card wallet printed flat on a sheet of tulle and folded into shape.
// Panels are rigid plastic, folds are fabric: the gaps between panels hold no plastic,
// only the tulle that is printed into the panels (pause after two layers, lay the tulle,
// resume). A tray with walls makes it stiff, the stand foot slides in rails and clicks.

/* [Wallet] */
// Number of cards it should hold.
cards = 4; // [2:1:5]
// Room for folded bank notes, in mm.
cash_room = 1.2; // [0.6:0.2:2.4]
// Outer diameter of the stick-on magnet ring.
magnet_diameter = 56; // [50:0.5:60]

/* [Print] */
// Thickness of the panels. Five layers of 0.2, the tulle goes in after two.
panel_thickness = 1; // [0.8:0.2:1.6]
// Room around a card, per side.
card_play = 1; // [0.5:0.25:2]

/* [Preview] */
// 0 is the flat sheet you print. 100 shows it folded.
fold = 0; // [0:5:100]
// Slides the foot down into a phone stand. Works when fold is 100.
stand = 0; // [0:10:100]

/* [Colour] */
// Display only, the STL carries no colour.
color_wallet = "SteelBlue"; // [SteelBlue, Silver, Gainsboro, White, DimGray, Black, SlateGray, FireBrick, ForestGreen, Goldenrod]

/* [Hidden] */
$fn = 64;
card_long = 85.6;
card_short = 54;
card_t = 0.76;

t = panel_thickness;
zf = 0.4;                  // height of the tulle above the bed: two layers
t_div = 2 * zf;            // the divider only separates, it can be thin
wall = 2.4;

W_out = max(card_short + 2 * card_play + 2 * wall, magnet_diameter + 2);
W_in = W_out - 2 * wall;
H = wall + card_long - 1;  // cards stand 1.5 mm proud of the back
inner = cards * card_t + t_div + cash_room + 0.4;   // depth of the tray
lid_top = 2 * t + inner;   // outer face of the closed front panel, above the bed side of the back

// Fold gaps. Tulle bends sharply, so a gap is simply the path the fabric has to cover.
g_lid = lid_top - 2 * zf + 0.3;          // up the side wall to the front panel
g_bot = lid_top + t - 2 * zf + 0.6;      // up the bottom wall to the stand flap on top of the front panel
g_div = cash_room + t + 0.3;             // around the notes to the divider
g_crease = 3;                            // between the two legs
g_foot = 2.5;                            // between second leg and foot

// Stand: two legs and a foot that slides in rails.
leg = 28;
leg_half_w = 26;
foot_h = 13;
flap_len = 2 * leg + g_crease;
foot_end = flap_len + g_foot + foot_h;   // folded height of the far end of the foot, closed
slides = [0, 14, 23];                    // how far the foot sits below closed: closed, stand, steep stand
foot_w = W_in - 0.6;
arm_w = 1.2;
arm_gap = 1.6;
tooth = 1.1;
tooth_len = 2.7;

// Rails on the upper half of both side walls.
rail_y0 = foot_end - slides[2] - tooth_len - 7;
rail_y1 = foot_end + 1.5;                // also the top edge of the front panel
channel_h = t + 0.5;                     // room for the foot under the lip
lip = 1.2;                               // 45 degree overhang, prints without support
rail_top = lid_top + channel_h + lip + 0.4;
hinge_clear = 5.2;                       // front panel is cut back here to swing past the rail

r = 3;                     // corner radius of the panels
edge = r + 1;
divider_h = 52;

// Magnet ring, high on the back so the wallet hangs low on the phone.
ring_w = 5;
ring_cy = H - magnet_diameter / 2 - 2.5;

// Spring tongues in the back that press on the cards, below the ring.
tongue_x = 16;
tongue_w = 7;
tongue_y0 = wall + 8;       // free tip
tongue_y1 = wall + 27;      // root, toward the card opening so cards slide onto it
kerf = 0.8;
bump_h = 0.8;

// Triangle of the stand, for the preview.
f = fold / 100;
k = fold >= 100 ? stand / 100 : 0;
slide = slides[2] * k;
l1 = leg + g_crease / 2;
l2 = leg + g_crease / 2 + g_foot / 2;
base = l1 + l2 - slide;
function clamp1(v) = min(1, max(-1, v));
alpha = acos(clamp1((l1 * l1 + base * base - l2 * l2) / (2 * l1 * base)));
beta = acos(clamp1((l2 * l2 + base * base - l1 * l1) / (2 * l2 * base)));
A = 90 * f;                 // a fabric fold turns 90 degrees at both edges of its gap

xl0 = W_out / 2 + g_lid;    // where the front panel starts in the flat sheet
yl0 = wall + 0.4;           // its bottom edge, just inside the bottom wall

echo(str("Flat sheet: ", 2 * W_out + g_lid, " x ", H + g_bot + flap_len + g_foot + foot_h, " mm"));

// ---- helpers ----
module rounded(rad) { offset(r = rad) offset(delta = -rad) children(); }
module fillet(rad) { offset(r = -rad) offset(delta = rad) children(); }
module slot(l, w) { hull() for (s = [-1, 1]) translate([s * (l - w) / 2, 0]) circle(d = w); }
module body() { color(color_wallet) children(); }
// The tulle in a fold gap. Preview only, it is not printed.
module fabric() { if (fold > 0) color([0.75, 0.75, 0.75]) translate([0, 0, zf - 0.08]) linear_extrude(height = 0.16) children(); }
module ext(h) { linear_extrude(height = h) children(); }
// Turn the children around a fold line in the tulle: along x at height y, or along y at x.
module hinge_x(y, a) { translate([0, y, zf]) rotate(a = a, v = [1, 0, 0]) translate([0, -y, -zf]) children(); }
module hinge_y(x, a) { translate([x, 0, zf]) rotate(a = a, v = [0, 1, 0]) translate([-x, 0, -zf]) children(); }

// ---- Back: a tray with walls, phone side down ----
module back_outline2d() { rounded(r) translate([-W_out / 2, 0]) square([W_out, H]); }

module tongue_cut2d(x) {
  difference() {
    translate([x - tongue_w / 2 - kerf, tongue_y0 - kerf]) square([tongue_w + 2 * kerf, tongue_y1 - tongue_y0 + kerf]);
    translate([x - tongue_w / 2, tongue_y0]) square([tongue_w, tongue_y1 - tongue_y0 + 1]);
  }
}

// One tall side wall with its rail, drawn on the right.
module rail_wall() {
  x0 = W_in / 2;
  difference() {
    translate([0, rail_y1, 0]) rotate([90, 0, 0]) linear_extrude(height = rail_y1 - rail_y0)
      polygon([[x0, 0], [W_out / 2, 0], [W_out / 2, rail_top], [x0 - lip, rail_top],
               [x0 - lip, rail_top - 0.4], [x0, lid_top + channel_h]]);
    // notches for the tooth: closed and the two stand positions
    for (s = slides)
      translate([x0 - 0.01, foot_end - s - tooth_len - 0.3, lid_top])
        cube([tooth + 0.2, tooth_len + 0.6, channel_h]);
  }
  // bump at the lower end of the rail so the foot does not slide out
  translate([x0 + 0.1, rail_y0 + 2, lid_top]) cylinder(r = 0.6, h = channel_h);
}

module back3d() {
  difference() {
    ext(t) difference() {
      back_outline2d();
      // thumb slot inside the ring, to slide the cards up
      translate([0, ring_cy]) rotate(90) slot(36, 16);
      for (s = [-1, 1]) tongue_cut2d(s * tongue_x);
    }
    // groove one layer deep on the bed side that centres the magnet ring
    translate([0, ring_cy, -0.01]) linear_extrude(height = 0.21) difference() {
      circle(d = magnet_diameter + 0.6);
      circle(d = magnet_diameter - 2 * ring_w - 0.6);
    }
  }
  // low bump near the tip of each tongue, on the card side
  for (s = [-1, 1]) translate([s * tongue_x, tongue_y0 + 3.5, t - 0.01]) cylinder(h = bump_h, d1 = 6, d2 = 3);
  // bottom wall, level with the closed front panel
  ext(lid_top) intersection() { back_outline2d(); translate([-W_out / 2, 0]) square([W_out, wall]); }
  // low side walls: the front panel lies on them
  ext(t + inner) intersection() {
    back_outline2d();
    for (s = [-1, 1]) translate([s * (W_out / 2 - wall / 2) - wall / 2, 0]) {
      square([wall, rail_y0]);
      translate([0, rail_y1]) square([wall, H - rail_y1]);
    }
  }
  // tall side walls with the rails
  rail_wall();
  mirror([1, 0, 0]) rail_wall();
}

// ---- Front panel and divider, to the right of the back in the flat sheet ----
// A point that ends up at folded x sits at xl0 + W_out/2 - x in the sheet.
module lid2d() {
  fillet(2) rounded(2) {
    translate([xl0, yl0]) square([W_out, rail_y0 - 0.5 - yl0]);
    translate([xl0 + hinge_clear, yl0]) square([W_out / 2 + W_in / 2 - 0.3 - hinge_clear, rail_y1 - yl0]);
  }
}

module divider2d() {
  difference() {
    rounded(r) translate([xl0 + W_out / 2 - W_in / 2 + 1, yl0 - g_div - divider_h]) square([W_in - 2, divider_h]);
    // scoop in what becomes the top edge of the divider
    translate([xl0 + W_out / 2, yl0 - g_div - divider_h - 3]) circle(r = 10);
  }
}

module lid_chain() {
  hinge_y(W_out / 2, -A) {
    fabric() translate([W_out / 2, edge]) square([g_lid, rail_y0 - 2 - edge]);
    hinge_y(xl0, -A) {
      body() ext(t) lid2d();
      hinge_x(yl0, -A) {
        fabric() translate([xl0 + W_out / 2 - W_in / 2 + edge, yl0 - g_div]) square([W_in - 2 * edge, g_div]);
        hinge_x(yl0 - g_div, -A) body() ext(t_div) divider2d();
      }
    }
  }
}

// ---- Stand flap, below the back in the flat sheet ----
module leg2d(y0) { rounded(2) translate([-leg_half_w, y0]) square([2 * leg_half_w, leg]); }

// The foot: a crossbar with a spring arm and a tooth on each side.
module foot2d(y_far, y_near) {
  bw = foot_w / 2 - arm_w - arm_gap;
  rounded(1) translate([-bw, y_far]) square([2 * bw, y_near - y_far]);
  translate([-foot_w / 2, y_near - 2.5]) square([foot_w, 2.5]);
  for (s = [-1, 1]) {
    translate([s > 0 ? foot_w / 2 - arm_w : -foot_w / 2, y_far]) square([arm_w, y_near - y_far - 2.4]);
    // steep toward the top of the wallet, gentle toward the hinge
    polygon([[s * foot_w / 2, y_far], [s * (foot_w / 2 + tooth), y_far + 0.35],
             [s * (foot_w / 2 + tooth), y_far + 1.1], [s * foot_w / 2, y_far + tooth_len]]);
  }
}

module stand_chain() {
  y1 = -g_bot;                 // near edge of the first leg
  y2 = y1 - leg;               // crease
  y3 = y2 - g_crease;          // near edge of the second leg
  y4 = y1 - flap_len;          // gap before the foot
  y5 = y4 - g_foot;            // near edge of the foot
  turn = (alpha + beta) / 2;
  hinge_x(0, -A) {
    fabric() translate([-(W_out / 2 - edge), y1]) square([W_out - 2 * edge, g_bot]);
    hinge_x(y1, -(A - alpha * f)) {
      body() ext(t) leg2d(y2);
      hinge_x(y2, -turn * f) {
        fabric() translate([-22, y3]) square([44, g_crease]);
        hinge_x(y3, -turn * f) {
          body() ext(t) leg2d(y4);
          hinge_x(y4, beta * f / 2) {
            fabric() translate([-22, y5]) square([44, g_foot]);
            hinge_x(y5, beta * f / 2) body() ext(t) foot2d(y5 - foot_h, y5);
          }
        }
      }
    }
  }
}

body() back3d();
lid_chain();
stand_chain();

// Preview only: the magnet ring once folded, the phone once the stand is out.
if (fold > 0)
  color("Goldenrod") translate([0, ring_cy, -0.8]) linear_extrude(height = 1) difference() {
    circle(d = magnet_diameter);
    circle(d = magnet_diameter - 2 * ring_w);
  }
if (k > 0)
  color("DimGray") translate([-35.5, ring_cy - 80, -8.8]) linear_extrude(height = 8) rounded(8) square([71, 147]);

Comments

Context, not a score. Comments never move a model up or down the results.

No comments yet

Printed it? A note about your material and the clearance you landed on saves the next person a failed print.

Sign in to comment