diff --git a/code/game/objects/effects/decals/contraband.dm b/code/game/objects/effects/decals/contraband.dm
index 5dd0707fcb9..1e62b6a5a9e 100644
--- a/code/game/objects/effects/decals/contraband.dm
+++ b/code/game/objects/effects/decals/contraband.dm
@@ -352,12 +352,12 @@ obj/structure/sign/poster/attackby(obj/item/I, mob/user, params)
if(!P.resulting_poster) return
var/stuff_on_wall = 0
- for(var/obj/O in contents) //Let's see if it already has a poster on it or too much stuff
- if(istype(O,/obj/structure/sign/poster))
+ for(var/obj/O in user.loc.contents) //Let's see if it already has a poster on it or too much stuff
+ if(istype(O,/obj/structure/sign))
user << "The wall is far too cluttered to place a poster!"
return
stuff_on_wall++
- if(stuff_on_wall == 3)
+ if(stuff_on_wall >= 4)
user << "The wall is far too cluttered to place a poster!"
return
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 11db68ec671..f90fe9cbb02 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -152,6 +152,7 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \
new/datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("apiary", /obj/item/apiary, 10, time = 25, one_per_turf = 0, on_floor = 0), \
new/datum/stack_recipe("easel", /obj/structure/easel, 3, one_per_turf = 1, on_floor = 1), \
+ new/datum/stack_recipe("wooden picture frame", /obj/item/weapon/picture_frame/wooden, 1), \
new/datum/stack_recipe("wooden buckler", /obj/item/weapon/shield/riot/buckler, 20, time = 40), \
)
diff --git a/code/modules/paperwork/frames.dm b/code/modules/paperwork/frames.dm
new file mode 100644
index 00000000000..9e16a8391d5
--- /dev/null
+++ b/code/modules/paperwork/frames.dm
@@ -0,0 +1,218 @@
+/obj/item/weapon/picture_frame
+ name = "picture frame"
+ desc = "Its patented design allows it to be folded larger or smaller to accommodate standard paper, photo, and poster sizes."
+ icon = 'icons/obj/bureaucracy.dmi'
+
+ var/icon_base
+ var/obj/displayed
+
+ var/list/wide_posters = list(
+ "poster22_legit", "poster23", "poster23_legit", "poster24", "poster24_legit",
+ "poster25", "poster27_legit", "poster28", "poster29")
+
+/obj/item/weapon/picture_frame/New(loc, obj/item/weapon/D)
+ ..()
+ if(D)
+ insert(D)
+ update_icon()
+
+/obj/item/weapon/picture_frame/Destroy()
+ if(displayed)
+ displayed = null
+ for(var/A in contents)
+ qdel(A)
+ ..()
+
+/obj/item/weapon/picture_frame/update_icon()
+ overlays.Cut()
+
+ if(displayed)
+ overlays |= getFlatIcon(displayed)
+
+ if(istype(displayed, /obj/item/weapon/photo))
+ icon_state = "[icon_base]-photo"
+ else if(istype(displayed, /obj/structure/sign/poster))
+ icon_state = "[icon_base]-[(displayed.icon_state in wide_posters) ? "wposter" : "poster"]"
+ else
+ icon_state = "[icon_base]-paper"
+
+ overlays |= icon_state
+
+/obj/item/weapon/picture_frame/proc/insert(obj/D)
+ if(istype(D, /obj/item/weapon/contraband/poster))
+ var/obj/item/weapon/contraband/poster/P = D
+ displayed = P.resulting_poster
+ P.resulting_poster = null
+ else
+ displayed = D
+
+ name = displayed.name
+ displayed.pixel_x = 0
+ displayed.pixel_y = 0
+ displayed.forceMove(src)
+ if(istype(D, /obj/item/weapon/contraband/poster))
+ qdel(D)
+
+/obj/item/weapon/picture_frame/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/weapon/screwdriver))
+ if(displayed)
+ playsound(src, 'sound/items/Screwdriver.ogg', 100, 1)
+ user.visible_message("[user] unfastens \the [displayed] out of \the [src].", "You unfasten \the [displayed] out of \the [src].")
+
+ if(istype(displayed, /obj/structure/sign/poster))
+ var/obj/structure/sign/poster/P = displayed
+ P.roll_and_drop(user.loc)
+ else
+ displayed.forceMove(user.loc)
+ displayed = null
+ name = initial(name)
+ update_icon()
+ else
+ user << "There is nothing to remove from \the [src]."
+ else if(istype(I, /obj/item/weapon/crowbar))
+ playsound(src, 'sound/items/Crowbar.ogg', 100, 1)
+ user.visible_message("[user] breaks down \the [src].", "You break down \the [src].")
+ for(var/A in contents)
+ if(istype(A, /obj/structure/sign/poster))
+ var/obj/structure/sign/poster/P = A
+ P.roll_and_drop(user.loc)
+ else
+ var/obj/O = A
+ O.forceMove(user.loc)
+ displayed = null
+ qdel(src)
+ else if(istype(I, /obj/item/weapon/paper) || istype(I, /obj/item/weapon/photo) || istype(I, /obj/item/weapon/contraband/poster))
+ if(!displayed)
+ user.unEquip(I)
+ insert(I)
+ update_icon()
+ else
+ user << "\The [src] already contains \a [displayed]."
+ else
+ ..()
+
+/obj/item/weapon/picture_frame/afterattack(atom/target, mob/user, proximity_flag)
+ if(proximity_flag && istype(target, /turf/simulated/wall))
+ place(target, user)
+ else
+ ..()
+
+/obj/item/weapon/picture_frame/proc/place(turf/T, mob/user)
+ var/stuff_on_wall = 0
+ for(var/obj/O in user.loc.contents) //Let's see if it already has a poster on it or too much stuff
+ if(istype(O, /obj/structure/sign))
+ user << "\The [T] is far too cluttered to place \a [src]!"
+ return
+ stuff_on_wall++
+ if(stuff_on_wall >= 4)
+ user << "\The [T] is far too cluttered to place \a [src]!"
+ return
+
+ user << "You start place \the [src] on \the [T]."
+
+ var/px = 0
+ var/py = 0
+
+ switch(getRelativeDirection(user, T))
+ if(NORTH)
+ py = 32
+ if(EAST)
+ px = 32
+ if(SOUTH)
+ py = -32
+ if(WEST)
+ px = -32
+ else
+ user << "You cannot reach \the [T] from here!"
+ return
+
+ user.unEquip(src)
+ var/obj/structure/sign/picture_frame/PF = new(user.loc, src)
+ PF.pixel_x = px
+ PF.pixel_y = py
+
+ playsound(PF.loc, 'sound/items/Deconstruct.ogg', 100, 1)
+
+/obj/item/weapon/picture_frame/examine(mob/user, var/distance = -1, var/infix = "", var/suffix = "")
+ ..()
+ if(displayed)
+ displayed.examine(user, distance, infix, suffix)
+
+/obj/item/weapon/picture_frame/attack_self(mob/user)
+ if(displayed)
+ if(istype(displayed, /obj/item))
+ var/obj/item/I = displayed
+ I.attack_self(user)
+ else
+ ..()
+
+
+
+/obj/item/weapon/picture_frame/glass
+ icon_base = "glass"
+ icon_state = "glass-poster"
+
+/obj/item/weapon/picture_frame/wooden
+ icon_base = "wood"
+ icon_state = "wood-poster"
+
+/obj/item/weapon/picture_frame/wooden/New()
+ ..()
+ new /obj/item/stack/sheet/wood(src, 1)
+
+
+
+/obj/structure/sign/picture_frame
+ icon = 'icons/obj/bureaucracy.dmi'
+ icon_state = "glass-poster"
+ var/obj/item/weapon/picture_frame/frame
+
+/obj/structure/sign/picture_frame/New(loc, F)
+ ..()
+ frame = F
+ frame.pixel_x = 0
+ frame.pixel_y = 0
+ frame.forceMove(src)
+ name = frame.name
+ update_icon()
+
+/obj/structure/sign/picture_frame/Destroy()
+ if(frame)
+ qdel(frame)
+ frame = null
+ ..()
+
+/obj/structure/sign/picture_frame/update_icon()
+ overlays.Cut()
+ if(frame)
+ icon = null
+ icon_state = null
+ overlays |= getFlatIcon(frame)
+ else
+ icon = initial(icon)
+ icon_state = initial(icon_state)
+
+/obj/structure/sign/picture_frame/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/weapon/screwdriver))
+ playsound(src, 'sound/items/Screwdriver.ogg', 100, 1)
+ user.visible_message("[user] begins to unfasten \the [src] from the wall.", "You begin to unfasten \the [src] from the wall.")
+ if(do_after(user, 100, target = src))
+ playsound(src, 'sound/items/Deconstruct.ogg', 100, 1)
+ user.visible_message("[user] unfastens \the [src] from the wall.", "You unfasten \the [src] from the wall.")
+ frame.forceMove(user.loc)
+ frame = null
+ qdel(src)
+ else
+ ..()
+
+/obj/structure/sign/picture_frame/examine(mob/user, var/distance = -1, var/infix = "", var/suffix = "")
+ if(frame)
+ frame.examine(user, distance, infix, suffix)
+ else
+ ..()
+
+/obj/structure/sign/picture_frame/attack_hand(mob/user)
+ if(frame)
+ frame.attack_self(user)
+ else
+ ..()
\ No newline at end of file
diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm
index 6e5bcf0389b..68b0090e317 100644
--- a/code/modules/research/designs/autolathe_designs.dm
+++ b/code/modules/research/designs/autolathe_designs.dm
@@ -273,6 +273,14 @@
materials = list(MAT_METAL = 100)
build_path = /obj/item/weapon/canvas/twentythreeXtwentythree
category = list("initial", "Miscellaneous")
+
+/datum/design/glass_picture_frame
+ name = "Glass Picture Frame"
+ id = "glass_picture_frame"
+ build_type = AUTOLATHE
+ materials = list(MAT_METAL = 25, MAT_GLASS = 75)
+ build_path = /obj/item/weapon/picture_frame/glass
+ category = list("initial", "Miscellaneous")
/datum/design/camera_assembly
name = "Camera Assembly"
diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi
index 159d2f572f2..351635143af 100644
Binary files a/icons/obj/bureaucracy.dmi and b/icons/obj/bureaucracy.dmi differ
diff --git a/icons/obj/contraband.dmi b/icons/obj/contraband.dmi
index 4a187225cd3..91432c14d1a 100644
Binary files a/icons/obj/contraband.dmi and b/icons/obj/contraband.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 4c6959933ec..b611994a112 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1585,6 +1585,7 @@
#include "code\modules\paperwork\faxmachine.dm"
#include "code\modules\paperwork\filingcabinet.dm"
#include "code\modules\paperwork\folders.dm"
+#include "code\modules\paperwork\frames.dm"
#include "code\modules\paperwork\handlabeler.dm"
#include "code\modules\paperwork\paper.dm"
#include "code\modules\paperwork\paper_bundle.dm"