BevelEffectLib — 3D Bevel & Emboss Effect

Creates a GPU-accelerated 3D bevel/emboss effect on any visual control, making elements appear raised above or sunken into the surface. The effect simulates a directional light source casting highlights and shadows along the edges of the control. Wraps FireMonkey’s TBevelEffect. Perfect for classic UI button styles, panel borders, picture frames, and retro 3D interface elements. 14 functions.

CategoryCountDescription
Error Handling4bevel_error, errormsg$, strerror$, clearerror
Creation & Destruction2bevel# (create), bevel_free (destroy)
Bevel Properties4direction, size (get/set)
Effect Control4enabled, trigger (get/set)
ⓘ Effect Ownership: The effect is owned by its parent control, not managed by garbage collection. Destroying the parent also destroys the effect. Use bevel_free only to remove the effect while keeping the parent alive.

Cross-Platform Support

PlatformStatusNotes
Windows✅ Full SupportGPU-accelerated via Direct2D
Linux✅ Full SupportSoftware rendering fallback
Android✅ Full SupportGPU-accelerated

Error Handling

All functions set an error code on failure. Check with bevel_error() after operations. Error code 0 means success.

FunctionSignatureDescription
bevel_error()bevel_error@Returns last error code (0 = no error)
bevel_errormsg$()bevel_errormsg$@Returns last error message as string
bevel_strerror$(code)bevel_strerror$@nConverts an error code to descriptive text
bevel_clearerror()bevel_clearerror@Clears the error state

Error Codes

CodeConstantMeaning
0ERR_NONENo error
1ERR_NIL_EFFECTEffect pointer is nil
2ERR_INVALID_EFFECTPointer is not a valid TBevelEffect
3ERR_INVALID_VALUEProperty value out of range
4ERR_NIL_PARENTParent control pointer is nil
5ERR_INVALID_PARENTPointer is not a valid TFmxObject

Creation & Destruction

FunctionSignatureDescription
bevel#(parent#)bevel#@#Creates a bevel effect attached to the given control. Returns the effect pointer.
bevel_free(effect#)bevel_free@#Destroys the effect and removes it from the parent control.

The parent# can be any visual control. The effect is applied immediately with default values (direction 45°, size 1).

╯ create-effect.bas
' Create bevel effect on a rectangle
let bvl# = bevel#(rect#)

' Later, remove the effect
bevel_free(bvl#)

Direction (Light Angle)

The direction property sets the angle of the simulated light source in degrees (0–360). This determines which edges appear highlighted (lit) and which appear shadowed, creating the 3D raised or sunken illusion. Default is 45° (light from top-right).

FunctionSignatureDescription
bevel_direction#(effect#, degrees)bevel_direction#@#nSets light source angle (0–360)
bevel_direction(effect#)bevel_direction@#Gets current direction

Light Direction Reference

AngleLight PositionVisual EffectClassic Use
RightLeft edge lit, right shadowed
45°Top-rightTop & left edges lit — raisedDefault button, toolbar
90°TopTop edge lit, bottom shadowedHorizontal divider
135°Top-leftTop & right edges litAlternate raised style
180°LeftRight edge lit, left shadowed
225°Bottom-leftBottom & right edges lit — sunkenPressed button, inset panel
270°BottomBottom edge lit, top shadowedHorizontal groove
315°Bottom-rightBottom & left edges litAlternate sunken style
ⓘ Raised vs Sunken: The classic pairing is 45° = raised and 225° = sunken. Swapping the light direction by 180° inverts the perceived depth — a raised button becomes a pressed button.
╯ direction.bas
' Raised look (default)
bevel_direction#(bvl#, 45)

' Sunken/pressed look
bevel_direction#(bvl#, 225)

' Light from directly above
bevel_direction#(bvl#, 90)

let dir = bevel_direction(bvl#)
print "Light angle: " + str$(dir)

Bevel Size

Controls the thickness of the bevel edge in pixels. Larger values create a wider highlight/shadow band. Default is 1. Range is 0–10.

FunctionSignatureDescription
bevel_size#(effect#, pixels)bevel_size#@#nSets bevel edge thickness (0–10)
bevel_size(effect#)bevel_size@#Gets current size
SizeVisual EffectUse Case
0No bevel visibleEffectively disabled
1–2Subtle, thin edgeElegant UI elements, small buttons
3–4Clearly visible 3D edgeClassic toolbar buttons, panel borders
5–7Prominent bevelDecorative frames, emphasized panels
8–10Very thick, dramatic edgeStylized borders, retro UI chrome
╯ bevel-size.bas
' Subtle bevel
bevel_size#(bvl#, 1)

' Classic 3D button look
bevel_size#(bvl#, 3)

' Dramatic picture frame
bevel_size#(bvl#, 8)

Effect Control

Enabled

Toggles the effect on or off without destroying it.

FunctionSignatureDescription
bevel_enabled#(effect#, value)bevel_enabled#@#nEnables (1) or disables (0) the effect
bevel_enabled(effect#)bevel_enabled@#Gets enabled state (1 = on, 0 = off)

Trigger

The trigger property is a string used by FireMonkey’s animation system.

FunctionSignatureDescription
bevel_trigger#(effect#, trigger$)bevel_trigger#@#$Sets trigger string
bevel_trigger$(effect#)bevel_trigger$@#Gets current trigger string

Complete Examples

Basic Bevel on a Rectangle

Applies a raised 3D bevel to a gray rectangle.

╯ bevel-basic.bas
let frm# = Pointer#(0)
let rect# = Pointer#(0)
let bvl# = Pointer#(0)

frm# = form#("Bevel Demo", 400, 300)

rect# = rectangle#(frm#)
rectangle_bounds#(rect#, 100, 80, 200, 120)
rectangle_fill#(rect#, "Gray")

bvl# = bevel#(rect#)
bevel_direction#(bvl#, 45)
bevel_size#(bvl#, 3)

form_show(frm#)

Raised vs Sunken Comparison

Side-by-side rectangles showing the raised (45°) and sunken (225°) bevel look.

╯ bevel-raised-sunken.bas
let frm# = Pointer#(0)
let rect1# = Pointer#(0)
let rect2# = Pointer#(0)
let bvl1# = Pointer#(0)
let bvl2# = Pointer#(0)

frm# = form#("Raised vs Sunken", 450, 250)

' Raised (light from top-right)
rect1# = rectangle#(frm#)
rectangle_bounds#(rect1#, 50, 70, 150, 100)
rectangle_fill#(rect1#, "Silver")
bvl1# = bevel#(rect1#)
bevel_direction#(bvl1#, 45)
bevel_size#(bvl1#, 3)
let lbl1# = label#(frm#, "Raised (45)", 85, 180)

' Sunken (light from bottom-left)
rect2# = rectangle#(frm#)
rectangle_bounds#(rect2#, 250, 70, 150, 100)
rectangle_fill#(rect2#, "Silver")
bvl2# = bevel#(rect2#)
bevel_direction#(bvl2#, 225)
bevel_size#(bvl2#, 3)
let lbl2# = label#(frm#, "Sunken (225)", 280, 180)

form_show(frm#)

Interactive Direction Control

Four buttons to switch the bevel light direction in real time.

╯ bevel-direction-control.bas
let frm# = Pointer#(0)
let rect# = Pointer#(0)
let bvl# = Pointer#(0)
let lbl# = Pointer#(0)

frm# = form#("Bevel Direction", 450, 320)

rect# = rectangle#(frm#)
rectangle_bounds#(rect#, 125, 40, 200, 100)
rectangle_fill#(rect#, "Silver")

bvl# = bevel#(rect#)
bevel_direction#(bvl#, 45)
bevel_size#(bvl#, 4)

lbl# = label#(frm#, "Direction: 45", 170, 160)

let btn1# = button#(frm#, "45 (TR)")
button_bounds#(btn1#, 40, 200, 80, 30)
button_onclick#(btn1#, "SetDir45")

let btn2# = button#(frm#, "135 (TL)")
button_bounds#(btn2#, 130, 200, 80, 30)
button_onclick#(btn2#, "SetDir135")

let btn3# = button#(frm#, "225 (BL)")
button_bounds#(btn3#, 220, 200, 80, 30)
button_onclick#(btn3#, "SetDir225")

let btn4# = button#(frm#, "315 (BR)")
button_bounds#(btn4#, 310, 200, 80, 30)
button_onclick#(btn4#, "SetDir315")

form_show(frm#)

function SetDir45(sender#)
  bevel_direction#(bvl#, 45)
  label_text#(lbl#, "Direction: 45 (Raised)")
endfunction

function SetDir135(sender#)
  bevel_direction#(bvl#, 135)
  label_text#(lbl#, "Direction: 135")
endfunction

function SetDir225(sender#)
  bevel_direction#(bvl#, 225)
  label_text#(lbl#, "Direction: 225 (Sunken)")
endfunction

function SetDir315(sender#)
  bevel_direction#(bvl#, 315)
  label_text#(lbl#, "Direction: 315")
endfunction

Best Practices

PracticeWhy
Use direction 45° for raised, 225° for sunkenThe classic pairing — 180° apart creates the most natural raised/pressed illusion
Keep size between 1–4 for subtle effectsLarge bevel sizes can look exaggerated on small controls
Use gray or neutral-colored parent controlsBevel highlights and shadows are most visible on mid-tone backgrounds
Swap direction on click for button press effectToggle 45° ↔ 225° on mousedown/mouseup for interactive 3D buttons
Combine with ShadowEffectLib for depthBevel for edge definition + shadow for floating depth = convincing 3D
Use on rectangles and panels for classic UIRecreates the Windows 95 / classic Mac OS toolbar aesthetic
Use bevel_enabled# to toggle instead of bevel_freeFaster than destroying and recreating for on/off scenarios
Keep all bevels in a UI with the same directionConsistent light direction across all elements looks more natural

Quick Reference

FunctionSignatureDescription
ERROR HANDLING
bevel_error()bevel_error@Last error code
bevel_errormsg$()bevel_errormsg$@Last error message
bevel_strerror$(code)bevel_strerror$@nError code to text
bevel_clearerror()bevel_clearerror@Clear error state
CREATION & DESTRUCTION
bevel#(parent#)bevel#@#Create effect on control
bevel_free(effect#)bevel_free@#Destroy effect
BEVEL PROPERTIES
bevel_direction#(effect#, deg)bevel_direction#@#nSet light angle (0–360)
bevel_direction(effect#)bevel_direction@#Get light angle
bevel_size#(effect#, px)bevel_size#@#nSet edge thickness (0–10)
bevel_size(effect#)bevel_size@#Get edge thickness
EFFECT CONTROL
bevel_enabled#(effect#, val)bevel_enabled#@#nEnable (1) / disable (0)
bevel_enabled(effect#)bevel_enabled@#Get enabled state
bevel_trigger#(effect#, str$)bevel_trigger#@#$Set trigger string
bevel_trigger$(effect#)bevel_trigger$@#Get trigger string

14 functions. Part of the Plan9Basic visual effects library system.

See Also

  • ShadowEffectLib — Drop shadow for floating depth
  • GlowEffectLib — Outer glow around controls
  • InnerGlowEffectLib — Inner glow for inset lighting
  • EmbossEffectLib — Image-based emboss/relief filter
  • ReflectionEffectLib — Mirror reflection beneath controls