Recently, I switched to Ubuntu Studio 26.04. I’d been wanting to make this switch for years but I was stuck on Windows primarily because of Adobe. Let’s be honest here. Adobe is an addiction. I’ve used Adobe products for years—going back to the late ’80s with the first release of Adobe Illustrator in elementary school. Essentially, I’ve been using Adobe products my entire life, and replacing that pipe-line was difficult the first time I tried around twenty years ago.
Well, fast-forward to June 2024 when Adobe dropped that murky ToS change that seemed to suggest that they could use your artwork to train their AI. Even though they later clarified their ToS after the backlash, the damage was done. At that point, I decided that I was done with them and switched to Affinity. I haven’t looked back since.
Then the next thing to happen was Windows 10 reaching end of life in October 2025, and there was no way in hell that I was switching to Windows 11, and honestly, I was tired of the privacy and security hell that the Windows ecosystem was quickly becoming.
However, that still left one problem: Poser. Which wasn’t that big of an issue since most of my workflow had moved to Blender, and I’m in the process of writing a CR2 importer for Blender. It also turns out that Poser handles (its🥴) Wine just fine. Which is especially important since I needed FBX exports from Poser for testing.
Anyway, here are the steps I took to install Poser 13 on Ubuntu Studio 26.04, though this should work for any Debian-based OS🤞The pitfalls are the areas where I ran into issues during the Wine installation process, prior to actually installing Poser 13.
Table of Contents
Installing Poser 13 on Wine in Ubuntu 26.04
YMMV Note: Keep in mind that Poser 13 under Wine isn’t officially supported by Bondware. This guide reflects what worked for me in practice on Ubuntu 26.04 and may require adjustments for future OS or Wine versions.
Prerequisites
Update your system before starting:
sudo apt update && sudo apt upgrade -y
Step 1 — Enable 32-bit Architecture
Poser’s installer and some Wine components require 32-bit support.
sudo sh -c 'echo "amd64" >> /var/lib/dpkg/arch'
sudo sh -c 'echo "i386" >> /var/lib/dpkg/arch'
Verify both are listed:
cat /var/lib/dpkg/arch
Expected output:
amd64
i386
Pitfall:
sudo dpkg --add-architectureisn’t supported on Ubuntu 26.04. Runningdpkg --helpshows that the option is no longer available. Writing directly to/var/lib/dpkg/archachieves the same result.Pitfall:
amd64may not be present in/var/lib/dpkg/archby default and must be added manually alongsidei386.
Aside — Fix Duplicate apt Sources (if applicable)
This happened to me early on, and it was namely due to me working out some issues I was having with Spotify refusing to play local files (that is another article in and of itself). What it boiled down to is that running sudo apt update may warn about duplicate repository entries. I think what happened is that when I initially installed Spotify, I somehow ended up with a legacy .list file that didn’t get removed when I uninstalled it. I got the newer .sources file when I reinstalled Spotfy. If this happens to you with Spotify or any other program, remove the old one:
sudo rm /etc/apt/sources.list.d/spotify.list
sudo apt update
Pitfall: Ubuntu 26.04 uses the newer
.sourcesformat. Older third-party repo installers may have left behind legacy.listfiles that cause duplicate warnings. Remove the.listversion and keep.sources.
Step 2 — Install Wine
sudo apt install wine wine64 wine32:i386 -y
Verify the install:
wine --version
💡
At the time this blog post was created, wine-10.0 (Ubuntu 10.0~repack-12ubuntu1) was the version available through apt
Pitfall:
wineserveris not on PATH by default in Ubuntu 26.04’s Wine packages. It lives at:
/usr/lib/x86_64-linux-gnu/wine/wineserver(64-bit)/usr/lib/i386-linux-gnu/wine/wineserver(32-bit)Use the full path when you need to call it directly.
👉🏼
Experiment a little bit. If you’re already comfortable in a *nix environment, try creating aliases in your .bashrc or .profile files that point to the 64- and 32-bit versions of wineserver:
alias wineserver64='/usr/lib/x86_64-linux-gnu/wine/wineserver'
alias wineserver32='/usr/lib/i386-linux-gnu/wine/wineserver'
Step 3 — Create a Dedicated Wine Prefix
Using an isolated prefix keeps Poser’s dependencies from affecting other Wine applications.
export WINEPREFIX="$HOME/.wine-poser13"
export WINEARCH=win64
winecfg
In the winecfg dialog that opens, set the Windows version to Windows 10, then close it.
Fix HiDPI Scaling (recommended)
If you are on a HiDPI monitor, Wine windows will appear very small by default. Set a higher DPI in the Graphics tab of winecfg, or via the command line:
WINEPREFIX="$HOME/.wine-poser13" wine reg add "HKCU\Control Panel\Desktop" /v LogPixels /t REG_DWORD /d 192 /f
Adjust 192 to match your display (120 = 125%, 144 = 150%, 192 = 200%).
💡
Generally advised if you’re running a 4k or higher monitor. I’m running a 5k (5120×2160) monitor, and my eyesight isn’t the greatest so my DPI settings are at 216.
Also note that you will have to do a similar adjustment in Poser’s Preferences once you get it running. Poser does not scale well on HiDPI monitors.
Step 4 — Install Winetricks (upstream version)
The Debian-packaged winetricks on Ubuntu 26.04 is severely stripped down and missing most DLL verbs including all vcrun entries. Replace it with the upstream version:
sudo rm /usr/bin/winetricks
sudo wget -O /usr/bin/winetricks https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
sudo chmod +x /usr/bin/winetricks
Verify:
winetricks --version
Pitfall: The Debian-packaged winetricks strips out a large portion of the verb database for maintenance reasons. Verbs like
vcrun2022anddotnet48will silently fail withUnknown argunless you replace it with the upstream version.Pitfall: The winetricks privacy warning about latest version checks is harmless and can be ignored:
winetricks latest version check update disabled in the Debian package for privacy reasons.
Step 5 — Install Dependencies
WINEPREFIX="$HOME/.wine-poser13" winetricks -q vcrun2022 dotnet48 d3dcompiler_47 corefonts
This will take several minutes, particularly dotnet48. Let it run to completion.
Pitfall:
vcredist2019andvcredist2022are not valid winetricks verb names. The correct names arevcrun2019andvcrun2022.
Pitfall: Without
tahomaorcalibri, text in Poser’s Library search field and other UI input fields may appear invisible. These fonts are not included incorefontsand must be installed separately.WINEPREFIX="$HOME/.wine-poser13" winetricks -q tahoma calibri
Step 6 — Run the Poser 13 Installer
WINEPREFIX="$HOME/.wine-poser13" wine /path/to/Install Poser 13.exe
Replace /path/to/Install Poser 13.exe with your actual installer path (e.g. ~/Downloads/Install Poser 13.exe). If your installer is named differently, replace Install Poser 13.exe with the installer name.
Follow the installer as normal. Leave the default install location (C:\Program Files\Poser Software\Poser 13\) as-is.
Step 7 — Handle the Restart Prompt
When the installer prompts to restart your computer, do not restart. Instead, restart only the Wine server for your prefix:
WINEPREFIX="$HOME/.wine-poser13" /usr/lib/x86_64-linux-gnu/wine/wineserver -k
Pitfall:
wineserveris not on PATH, so the obvious commandwineserver -kwill returncommand not found. Use the full path above.
💡
If you want to avoid that headache, it wouldn’t be a bad idea to add the path in your .bash_profile or .profile file. Especially if you add more programs besides Poser to WINE.
Step 8 — Launch Poser 13
WINEPREFIX="$HOME/.wine-poser13" wine "$HOME/.wine-poser13/drive_c/Program Files/Poser Software/Poser 13/Poser.exe"
If the path doesn’t exist, check what was installed:
ls "$HOME/.wine-poser13/drive_c/Program Files/Poser Software/"
Pitfall: The installer places Poser under
C:\Program Files\Poser Software\Poser 13\, notBondwareas some guides suggest. Verify the actual path withls "$HOME/.wine-poser13/drive_c/Program Files/"if the executable is not found.
Step 9 (Optional) — Create a Desktop Launcher
Only do this if for some reason, the Poser installer didn’t create a desktop shortcut. When I ran the installer, it created shortcuts on the desktop for both Poser and Queue Manager—which I have no idea if Queue Manager works or not since I never use it.
[Desktop Entry]
Name=Poser 13
Exec=env WINEPREFIX="/home/<user-dir>/.wine-poser13" wine-stable C:\\\\users\\\\Public\\\\Desktop\\\\Poser\\ 13.lnk
Type=Application
StartupNotify=true
Path=/home/<user-dir>/.wine-poser13/dosdevices/c:/Program Files/Poser Software/Poser 13
Icon=D6CD_Poser.0
StartupWMClass=poser.exe
Copy and paste the above into a text editor, then save the file as Poser 13.desktop on your desktop. You may need to adjust the paths to match your system.
Known Issues and Limitations
Activation — While I didn’t have a problem with this, online activation may be unreliable under Wine. Bondware doesn’t offer an offline activation option, though they really should.
OpenGL / rendering — Poser relies heavily on OpenGL. If you see artifacts or crashes, ensure your GPU drivers are current. NVIDIA proprietary drivers generally work better than nouveau.
Python scripting — Poser 13’s embedded Python may not function correctly under Wine. Basic scene work should be fine, but Python-dependent features may be unreliable.
Runtime paths — If Poser cannot find your Runtime folders, set them manually in Poser’s preferences. Paths will use Wine’s Z:\ drive to reference your Linux filesystem (e.g. Z:\home\yourname\Documents\Poser\Runtime).
Quick Reference — Environment Variables
Always export these before running Wine or winetricks commands for this install:
export WINEPREFIX="$HOME/.wine-poser13"
export WINEARCH=win64
These do not persist across terminal sessions, so either re-export them each time or add them to a launch script.
Bonus: Populate LibraryPrefs.xml file
If you’ve been using Poser for a long-time, you might have multiple runtime folders set up. In my case, I had those multiple runtime folders in a centralized location, so I came up with a Python script to automatically update the LibraryPrefs.xml file—which is the file where Poser’s library preferences are stored. Below is the script I used. It also backs up the current LibraryPrefs.xml file before modification.
Click for Python script for populating LibraryPrefs.xml
#!/usr/bin/env python3
"""
add_poser_runtimes.py
Scans a parent directory for Poser Runtime folders and registers them
in Poser's LibraryPrefs.xml file as ContentFolder entries.
Usage:
python3 add_poser_runtimes.py <scan_directory> [options]
Options:
--prefs PATH Path to LibraryPrefs.xml
(default: ~/.wine-poser13/drive_c/users/<user>/AppData/Roaming/Poser/13/LibraryPrefs.xml)
--depth N How many directory levels deep to scan (default: 3)
--dry-run Print what would be added without modifying the file
"""
import argparse
import os
import shutil
import sys
import xml.etree.ElementTree as ET
from datetime import datetime
from pathlib import Path
# ---------------------------------------------------------------------------
# Path conversion
# ---------------------------------------------------------------------------
def linux_to_wine(path: str) -> str:
"""
Convert an absolute Linux path to a Wine-style Z:\ path.
e.g. /home/<user>/Runtimes -> Z:\\home\\<user>\\Runtimes
"""
return "Z:" + path.replace("/", "\\")
# ---------------------------------------------------------------------------
# Runtime discovery
# ---------------------------------------------------------------------------
def find_runtimes(scan_root: str, max_depth: int) -> list[str]:
"""
Walk scan_root up to max_depth levels deep and return absolute Linux
paths to every directory named 'Runtime' that is found.
"""
scan_root = os.path.abspath(scan_root)
found = []
def _walk(current: str, depth: int):
if depth > max_depth:
return
try:
entries = os.scandir(current)
except PermissionError:
return
for entry in entries:
if not entry.is_dir(follow_symlinks=False):
continue
if entry.name == "Runtime":
found.append(entry.path)
# Don't descend into the Runtime folder itself
else:
_walk(entry.path, depth + 1)
_walk(scan_root, 1)
return sorted(found)
# ---------------------------------------------------------------------------
# XML handling
# ---------------------------------------------------------------------------
def parse_prefs(prefs_path: str):
"""
Parse LibraryPrefs.xml and return (tree, root, existing_folders, max_index).
existing_folders is a set of normalized folder strings already in the file.
"""
tree = ET.parse(prefs_path)
root = tree.getroot()
existing = set()
max_index = -1
for el in root.findall("ContentFolder"):
folder = el.get("folder", "")
existing.add(folder.lower()) # case-insensitive comparison
try:
idx = int(el.get("index", -1))
if idx > max_index:
max_index = idx
except ValueError:
pass
return tree, root, existing, max_index
def add_entries(root, existing_folders: set, max_index: int, new_paths: list[str]):
"""
Append ContentFolder elements for each path in new_paths that isn't
already registered. Returns a list of (wine_path, index) for added entries.
"""
added = []
next_index = max_index + 1
for linux_path in new_paths:
libraries_path = os.path.join(linux_path, "libraries")
wine_path = linux_to_wine(libraries_path)
if wine_path.lower() in existing_folders:
print(f" [skip] Already registered: {wine_path}")
continue
el = ET.Element("ContentFolder")
el.set("folder", wine_path)
el.set("index", str(next_index))
# Insert before any CollectionFolder elements to keep grouping tidy
collection_els = root.findall("CollectionFolder")
if collection_els:
insert_pos = list(root).index(collection_els[0])
root.insert(insert_pos, el)
else:
root.append(el)
# Indent the new element to match existing style (tab character)
el.tail = "\n\t"
added.append[2]
existing_folders.add(wine_path.lower())
next_index += 1
return added
def backup_prefs(prefs_path: str) -> str:
"""
Copy LibraryPrefs.xml to LibraryPrefs.xml.YYYYMMDD-HHMMSS.bak
Returns the backup path.
"""
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
backup_path = f"{prefs_path}.{timestamp}.bak"
shutil.copy2(prefs_path, backup_path)
return backup_path
def write_prefs(tree, prefs_path: str):
"""
Write the modified tree back to disk, preserving the XML declaration and
ensuring the two Poser comment lines appear at lines 2-3 with a refreshed
timestamp matching Poser's own format (e.g. Sat May 23 12:11:54 2026).
"""
ET.indent(tree, space="\t", level=0)
# Write without xml_declaration so ET doesn't emit its single-quoted
# variant — we'll prepend the correct double-quoted form ourselves below.
tree.write(
prefs_path,
encoding="unicode",
xml_declaration=False,
)
# Read back the raw XML body ET wrote (no declaration yet).
with open(prefs_path, "r", encoding="UTF-8") as f:
body = f.read()
# Build the file from scratch with the correct header:
# line 1: double-quoted XML declaration (matches Poser's own format)
# line 2: LibraryPreferences comment
# line 3: Created comment with refreshed timestamp
# line 4+: XML body from ET
timestamp = datetime.now().ctime() # e.g. "Sat May 23 12:11:54 2026"
header = (
'<?xml version="1.0" encoding="UTF-8"?>\n'
"<!-- LibraryPreferences.\t\t\t\t\t -->\n"
f"<!-- Created: {timestamp}\t\t\t -->\n"
)
with open(prefs_path, "w", encoding="UTF-8") as f:
f.write(header + body)
# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------
def default_prefs_path() -> str:
username = os.environ.get("USER", os.environ.get("USERNAME", ""))
return os.path.expanduser(
f"~/.wine-poser13/drive_c/users/{username}/AppData/Roaming/Poser/13/LibraryPrefs.xml"
)
def main():
parser = argparse.ArgumentParser(
description="Scan for Poser Runtime folders and register them in LibraryPrefs.xml"
)
parser.add_argument(
"scan_directory",
help="Parent directory to scan for Runtime folders",
)
parser.add_argument(
"--prefs",
default=default_prefs_path(),
help="Path to LibraryPrefs.xml (default: auto-detected from $USER)",
)
parser.add_argument(
"--depth",
type=int,
default=3,
help="Maximum directory depth to scan (default: 3)",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Show what would be added without modifying the file",
)
args = parser.parse_args()
# Validate inputs
if not os.path.isdir(args.scan_directory):
print(f"Error: scan directory does not exist: {args.scan_directory}", file=sys.stderr)
sys.exit(1)
if not os.path.isfile(args.prefs):
print(f"Error: LibraryPrefs.xml not found at: {args.prefs}", file=sys.stderr)
print("Use --prefs to specify the correct path.", file=sys.stderr)
sys.exit(1)
print(f"Scanning: {args.scan_directory} (depth={args.depth})")
runtimes = find_runtimes(args.scan_directory, args.depth)
if not runtimes:
print("No Runtime folders found.")
sys.exit(0)
print(f"Found {len(runtimes)} Runtime folder(s):")
for r in runtimes:
print(f" {r}")
print()
tree, root, existing_folders, max_index = parse_prefs(args.prefs)
if args.dry_run:
print("Dry run — the following would be added:")
next_index = max_index + 1
any_new = False
for r in runtimes:
wine_path = linux_to_wine(os.path.join(r, "libraries"))
if wine_path.lower() in existing_folders:
print(f" [skip] {wine_path}")
else:
print(f" [add] index={next_index} {wine_path}")
next_index += 1
any_new = True
if not any_new:
print(" Nothing new to add.")
sys.exit(0)
added = add_entries(root, existing_folders, max_index, runtimes)
if not added:
print("Nothing new to add — all runtimes already registered.")
sys.exit(0)
backup_path = backup_prefs(args.prefs)
print(f"Backed up to: {backup_path}")
write_prefs(tree, args.prefs)
print(f"Added {len(added)} new runtime(s) to {args.prefs}:")
for wine_path, index in added:
print(f" index={index} {wine_path}")
print("\nDone. Restart Poser for changes to take effect.")
if __name__ == "__main__":
main()
So, that is it. These are the steps I took to get Poser 13 working on Ubuntu Studio 26.04, and aside from the dpkg hang-ups and the missing winetricks dependencies, it actually wasn’t that bad. I now have Poser working on my system, though I have noticed some “glitches” in Poser’s interface that actually aren’t that bad to work around.
Keep in mind that I haven’t tested Firefly or Superfly. My main goal in getting Poser installed was to export my assets to Blender using the FBX exporter, so as far as renders go, your mileage may vary.
Anywho, I hope this helps out anyone who have decided that they’ve had enough of Micro$lop’s shenanigans and want to make the move to Ubuntu, or Linux distro of choice.
Later!